Commit bc90d867 authored by pengjunjing's avatar pengjunjing

feat:增加string资源分析的辅助脚本

parent 8365e6d4
...@@ -6,4 +6,8 @@ plugins { ...@@ -6,4 +6,8 @@ plugins {
java { java {
sourceCompatibility = JavaVersion.VERSION_1_7 sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7 targetCompatibility = JavaVersion.VERSION_1_7
}
dependencies{
implementation "org.jdom:jdom:2.0.2"
} }
\ No newline at end of file
package com.laihua.projecthelper.code
/**
* Author: pengjunjing
* Date: 2022/3/11
* Description:
*/
interface Code {
}
\ No newline at end of file
package com.laihua.projecthelper.code
import java.io.File
import java.io.FileReader
/**
* Author: pengjunjing
* Date: 2022/3/11
* Description:读取代码文件接口
*/
interface CodeReader {
fun targetCode(codeFile: File): List<String>
}
\ No newline at end of file
package com.laihua.projecthelper.code
/**
* Author: pengjunjing
* Date: 2022/3/11
* Description:扩展功能
*/
class FunExt {
}
/**
* 是否包含一个模块
*/
fun Collection<Module>.containModule(moduleName: String): Boolean {
for (module in this.iterator()) {
if (module.moduleName == moduleName) {
return true
}
}
return false
}
fun Collection<Module>.getModule(moduleName: String): Module? {
for (module in this.iterator()) {
if (module.moduleName == moduleName) {
return module
}
}
return null
}
\ No newline at end of file
package com.laihua.projecthelper.code
import java.io.File
/**
* Author: pengjunjing
* Date: 2022/3/11
* Description:
*/
class JavaKtXmlCode(val file: File, val codeList: List<String>) : Code
\ No newline at end of file
package com.laihua.projecthelper.code
/**
* 模块
*/
class Module(val moduleName: String) {
/**
* 该模块下的代码
*/
var codes: MutableList<Code> = mutableListOf()
override fun toString(): String = moduleName
}
\ No newline at end of file
package com.laihua.projecthelper.code
import com.laihua.projecthelper.implement.belongModule
import com.laihua.projecthelper.unuse.ReadUtil
import java.io.File
/**
* Author: pengjunjing
* Date: 2022/3/11
* Description:
*/
class ProjectCode {
/**
* 根据指定的规则,读取项目中的代码文件
*/
fun readCode(codeReader: CodeReader): MutableSet<Module> {
//项目根目录路径
val projectRoot = File("")
val projectPath = projectRoot.absolutePath
val projectRootF = File(projectPath)
val readCodeFile = ReadUtil().readCodeFile(projectRootF)
val moduleSet = mutableSetOf<Module>()
//遍历项目里的所有文件
for (file in readCodeFile) {
//过滤出需要的代码
val targetCode: List<String> = codeReader.targetCode(file)
if (targetCode.isNotEmpty()) {
//所处模块
file.belongModule()?.let {
if (!moduleSet.containModule(it)) {
//添加不存在的模块
moduleSet.add(Module(it))
}
//为该模块添加一份代码
moduleSet.getModule(it)!!.codes.add(JavaKtXmlCode(file, targetCode))
}
}
}
return moduleSet
}
}
\ No newline at end of file
package com.laihua.projecthelper.code
import java.io.File
/**
* Author: pengjunjing
* Date: 2022/3/11
* Description:引用了string资源读取器
*/
class StringRefCodeReader : CodeReader {
override fun targetCode(codeFile: File): List<String> {
//查找依赖了字符串资源的代码
return codeFile.readLines().filter {
it.contains("R.string.") || it.contains("@string/")
}
}
}
\ No newline at end of file
...@@ -17,7 +17,7 @@ import java.io.InputStreamReader ...@@ -17,7 +17,7 @@ import java.io.InputStreamReader
* 是否真的会执行移动操作的变量,请对当前git的操作进行贮存, * 是否真的会执行移动操作的变量,请对当前git的操作进行贮存,
* 确保项目没有其他操作后再执行,否则可能会操作记录混乱 * 确保项目没有其他操作后再执行,否则可能会操作记录混乱
*/ */
const val realExecuteCmd = true const val realExecuteCmd = false
fun main(args: Array<String>) { fun main(args: Array<String>) {
println("开始读取文件") println("开始读取文件")
......
package com.laihua.projecthelper.stringxml
import com.laihua.projecthelper.code.Module
import java.io.File
/**
* Author: pengjunjing
* Date: 2022/3/11
* Description:
*/
data class StringElement(
// 文件
val file: File,
// 所属模块,指的是代码所属的模块
val belongModule: String,
// 字符串节点名字
val attributeName: String,
// 值
val value: String,
) {
/**
* 被引用的地方
*/
val refer = mutableSetOf<Module>()
}
\ No newline at end of file
package com.laihua.projecthelper.stringxml
import com.laihua.projecthelper.code.*
import com.laihua.projecthelper.unuse.ReadUtil
import java.io.File
/**
* Author: pengjunjing
* Date: 2022/3/10
* Description:
*/
class StringPull {
}
fun main(args: Array<String>) {
println("开始读取文件")
val projectRoot = File("")
val projectPath = projectRoot.absolutePath
val projectRootF = File(projectPath)
//这里打印的应该会是as项目所处的路径
println(projectPath)
//要检查资源的目录,大小写敏感
val baseFile = File("$projectPath${File.separator}LaiHuaBase${File.separator}src${File.separator}")
//从项目根目录开始查找
// val baseFile = File("${projectRoot.absolutePath}")
println(baseFile.absolutePath + "\n")
//读取代码文件
val readCode = ProjectCode().readCode(StringRefCodeReader())
//读取string配置的文件
val readStringResFile = ReadUtil().readStringResFile(baseFile)
readStringResFile.forEach {
println("读取到的字符串资源文件:${it.absolutePath}")
}
//解析代码,得到依赖的结果
val stringXmlResReferList: List<StringXmlResCode> = readStringResFile.map {
parseStringResFile(it, readCode)
}
//未使用的string定义
for (stringXmlResCode in stringXmlResReferList) {
val filter = stringXmlResCode.stringElementList.filter {
it.refer.isEmpty()
}
println("未被使用的字符串一共有${filter.size}个")
filter.forEach {
println("未被使用的字符串 id:${it.attributeName} 内容是: ${it.value}")
StringXmlParse().deleteStringXmlElement(it)
}
}
println("\n--------------------------------\n")
for (stringXmlResCode in stringXmlResReferList) {
val filter = stringXmlResCode.stringElementList.filter {
it.refer.size == 1
}
println("${stringXmlResCode.stringXmlFile.absolutePath} 被一个模块依赖的字符串有:${filter.size}个")
filter.forEach { stringElement ->
val module = stringElement.refer.toList()[0]
println("模块 ${module.moduleName} 依赖了字符串:${stringElement.attributeName} , 内容是: ${stringElement.value}")
}
}
println("\n--------------------------------\n")
}
/**
* 解析一个string.xml文件,判断有多少个模块依赖
* @return 返回解析出来的依赖结果
*/
private fun parseStringResFile(file: File, readCode: MutableSet<Module>): StringXmlResCode {
//将一个xml文件解析成每个节点的值
val stringXmlResCode: StringXmlResCode = StringXmlParse().parseToObj(file)
//遍历xml文件的每个字符串
everyStringDef@ for (stringElement in stringXmlResCode.stringElementList) {
//遍历每个模块
everyModule@ for (module: Module in readCode) {
//遍历模块下的每个代码文件
everyCodeFile@ for (code: Code in module.codes) {
val javaKtXmlCode = code as JavaKtXmlCode
//某个代码文件的每行有调用string资源的代码
everyCode@ for (codeLine: String in javaKtXmlCode.codeList) {
if (
//代码中包含: "@string/tips_bind_phone"
codeLine.contains("\"@string/${stringElement.attributeName}\"")
//代码中包含: R.string.xxx
|| codeLine.contains("R.string.${stringElement.attributeName}")
) {
//添加到引用模块去
stringElement.refer.add(module)
//该字符串被该模块引用了则直接跳过该模块后面的代码判断了
break@everyCodeFile
}
}
}
}
}
return stringXmlResCode
}
package com.laihua.projecthelper.stringxml
import com.laihua.projecthelper.implement.belongModule
import org.jdom2.input.SAXBuilder
import java.io.File
/**
* Author: pengjunjing
* Date: 2022/3/11
* Description:string的xml文件解析类
*/
class StringXmlParse {
companion object {
const val resourcesStringDef = "resources"
}
/**
* 将字符串文件解析成对象
*/
fun parseToObj(stringXmlFile: File): StringXmlResCode {
val document = SAXBuilder().build(stringXmlFile)
val rootElement = document.rootElement
val belongModule = stringXmlFile.belongModule()
val stringXmlResCode = StringXmlResCode(stringXmlFile, belongModule)
//读取resources节点下的内容
if (belongModule != null && resourcesStringDef == rootElement.name) {
val children = rootElement.children
for (child in children) {
if (child.name == "string") {
//获取string节点的数据
val stringElement =
StringElement(stringXmlFile, belongModule, child.attributes[0].value, child.value)
stringXmlResCode.stringElementList.add(stringElement)
}
}
}
return stringXmlResCode
}
/**
* 删除掉一个xml文件字符串内容
*/
fun deleteStringXmlElement(stringElement: StringElement) {
val document = SAXBuilder().build(stringElement.file)
val rootElement = document.rootElement
rootElement.removeChild(stringElement.attributeName)
//todo 删除工作
}
}
\ No newline at end of file
package com.laihua.projecthelper.stringxml
import com.laihua.projecthelper.code.Code
import java.io.File
/**
* Author: pengjunjing
* Date: 2022/3/11
* Description:字符串资源文件
*/
class StringXmlResCode(val stringXmlFile: File, belongModule: String?) : Code {
//字符串列表
val stringElementList = mutableListOf<StringElement>()
}
\ No newline at end of file
...@@ -36,7 +36,8 @@ class ReadUtil { ...@@ -36,7 +36,8 @@ class ReadUtil {
return codeResult return codeResult
} }
private val excludeXml = arrayOf("values", "AndroidManifest","res/xml","res\\xml") val valuesDirName = "values"
private val excludeXml = arrayOf("values", "AndroidManifest", "res/xml", "res\\xml")
/** /**
* 读取xml图片文件 * 读取xml图片文件
...@@ -53,7 +54,7 @@ class ReadUtil { ...@@ -53,7 +54,7 @@ class ReadUtil {
var filterResult = true var filterResult = true
for (exclude in excludeXml) { for (exclude in excludeXml) {
//排除掉部分xml文件 //排除掉部分xml文件
if (it.absolutePath.contains(exclude,ignoreCase = true)) { if (it.absolutePath.contains(exclude, ignoreCase = true)) {
filterResult = false filterResult = false
break break
} }
...@@ -62,10 +63,59 @@ class ReadUtil { ...@@ -62,10 +63,59 @@ class ReadUtil {
} }
} }
/**
* 读取values文件夹下的文件
*/
private fun readValueFile(file: File): List<File> {
val result = mutableListOf<File>()
if (file.exists() && file.isDirectory) {
readChildFile(file, ".xml", resultList = result)
} else {
println("资源目录不存在或者传入的不是目录:${file.absolutePath}")
}
return result.filter {
//只需要values文件夹下的文件
it.absolutePath.contains(valuesDirName, ignoreCase = true)
}
}
/**
* 读取资源目录下的string文件
* @param file 指定目录
*/
fun readStringResFile(file: File): List<File> {
val readXmlFile = readValueFile(file)
val filter = readXmlFile.filter { xmlFile ->
val readLines = xmlFile.readLines()
//是否包含resources定义
var containResString = false
var containString = false
//读取文件每一行
for (readLine in readLines) {
//判断是否包含 resources 和 string的标签
if (readLine.contains(resourcesNode)) {
containResString = true
}
if (readLine.contains(StringNode)) {
containString = true
}
if (containResString && containString) {
//是定义字符串的资源文件
return@filter true
}
}
return@filter false
}
return filter
}
companion object { companion object {
//排除目录 //排除目录
private val excludeDir = arrayOf("build", ".git", ".gradle", ".idea") private val excludeDir = arrayOf("build", ".git", ".gradle", ".idea")
const val resourcesNode = "<resources>"
const val StringNode = "<string"
/** /**
* @param fileType 文件后缀名 * @param fileType 文件后缀名
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment