mirror of
https://github.com/thunderbird/thunderbird-android.git
synced 2024-09-19 11:42:14 +02:00
Add String resource mover cli script
This commit is contained in:
parent
06a6aa0ec3
commit
d8ca1c5144
17
cli/resource-mover-cli/README.md
Normal file
17
cli/resource-mover-cli/README.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Resource Mover CLI
|
||||
|
||||
This is a command line interface that will move resources from one module to another.
|
||||
|
||||
## Usage
|
||||
|
||||
You can run the script with the following command:
|
||||
|
||||
```bash
|
||||
./scripts/resource-mover --from <source-module-path> --to <target-module-path> --keys <keys-to-move>
|
||||
```
|
||||
|
||||
The **source-module-path** should be the path to the module that contains the resources you want to move.
|
||||
|
||||
The **target-module-path** should be the path to the module where you want to move the resources.
|
||||
|
||||
The **keys-to-move** should be the keys of the resources you want to move. You can pass multiple keys separated by a comma.
|
13
cli/resource-mover-cli/build.gradle.kts
Normal file
13
cli/resource-mover-cli/build.gradle.kts
Normal file
@ -0,0 +1,13 @@
|
||||
plugins {
|
||||
id(ThunderbirdPlugins.App.jvm)
|
||||
}
|
||||
|
||||
version = "unspecified"
|
||||
|
||||
application {
|
||||
mainClass.set("net.thunderbird.cli.resource.mover.MainKt")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.clikt)
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package net.thunderbird.cli.resource.mover
|
||||
|
||||
fun main(args: Array<String>) = ResourceMoverCli().main(args)
|
@ -0,0 +1,29 @@
|
||||
package net.thunderbird.cli.resource.mover
|
||||
|
||||
import com.github.ajalt.clikt.core.CliktCommand
|
||||
import com.github.ajalt.clikt.parameters.options.option
|
||||
import com.github.ajalt.clikt.parameters.options.required
|
||||
import com.github.ajalt.clikt.parameters.options.split
|
||||
|
||||
class ResourceMoverCli(
|
||||
private val stringResourceMover: StringResourceMover = StringResourceMover(),
|
||||
) : CliktCommand(
|
||||
name = "resource-mover",
|
||||
help = "Move string resources from one file to another",
|
||||
) {
|
||||
private val from: String by option(
|
||||
help = "Source module path",
|
||||
).required()
|
||||
|
||||
private val to: String by option(
|
||||
help = "Target module path",
|
||||
).required()
|
||||
|
||||
private val keys: List<String> by option(
|
||||
help = "Keys to move",
|
||||
).split(",").required()
|
||||
|
||||
override fun run() {
|
||||
stringResourceMover.moveKeys(from, to, keys)
|
||||
}
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
package net.thunderbird.cli.resource.mover
|
||||
|
||||
import java.io.File
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
class StringResourceMover {
|
||||
|
||||
fun moveKeys(source: String, target: String, keys: List<String>) {
|
||||
val sourcePath = File(source + RESOURCE_PATH)
|
||||
val targetPath = File(target + RESOURCE_PATH)
|
||||
|
||||
if (!sourcePath.exists()) {
|
||||
println("\nSource path does not exist: $sourcePath\n")
|
||||
return
|
||||
}
|
||||
|
||||
println("\nMoving keys $keys")
|
||||
println(" from \"$sourcePath\" -> \"$targetPath\"\n")
|
||||
for (key in keys) {
|
||||
moveKey(sourcePath, targetPath, key)
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveKey(sourcePath: File, targetPath: File, key: String) {
|
||||
println("\nMoving key: $key\n")
|
||||
|
||||
sourcePath.walk()
|
||||
.filter { it.name.startsWith(VALUES_PATH) }
|
||||
.forEach { sourceDir ->
|
||||
val sourceFile = sourceDir.resolve(STRING_RESOURCE_FILE_NAME)
|
||||
if (sourceFile.exists()) {
|
||||
moveKeyDeclaration(sourceFile, targetPath, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveKeyDeclaration(sourceFile: File, targetPath: File, key: String) {
|
||||
if (containsKey(sourceFile, key)) {
|
||||
println("\nFound key in file: ${sourceFile.path}\n")
|
||||
|
||||
val targetFile = getOrCreateTargetFile(targetPath, sourceFile)
|
||||
val keyDeclaration = extractKeyDeclaration(sourceFile, key)
|
||||
|
||||
println(" Key declaration: $keyDeclaration")
|
||||
|
||||
copyKeyToTarget(targetFile, keyDeclaration, key)
|
||||
deleteKeyFromSource(sourceFile, keyDeclaration)
|
||||
|
||||
if (isSourceFileEmpty(sourceFile)) {
|
||||
println(" Source file is empty: ${sourceFile.path} -> deleting it.")
|
||||
sourceFile.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun containsKey(sourceFile: File, key: String): Boolean {
|
||||
val keyPattern = createKeyPattern(key)
|
||||
val sourceContent = sourceFile.readText()
|
||||
return keyPattern.containsMatchIn(sourceContent)
|
||||
}
|
||||
|
||||
private fun extractKeyDeclaration(sourceFile: File, key: String): String {
|
||||
val keyPattern = createKeyPattern(key)
|
||||
val declaration = StringBuilder()
|
||||
var isTagClosed = true
|
||||
|
||||
sourceFile.forEachLine { line ->
|
||||
if (keyPattern.containsMatchIn(line)) {
|
||||
declaration.appendLine(line)
|
||||
isTagClosed = isTagClosed(line)
|
||||
} else if (!isTagClosed) {
|
||||
declaration.appendLine(line)
|
||||
isTagClosed = isTagClosed(line)
|
||||
}
|
||||
}
|
||||
|
||||
return declaration.toString()
|
||||
}
|
||||
|
||||
private fun createKeyPattern(key: String): Regex {
|
||||
return KEY_PATTERN.replace(KEY_PLACEHOLDER, Regex.escape(key)).toRegex()
|
||||
}
|
||||
|
||||
private fun isTagClosed(line: String): Boolean {
|
||||
return line.contains(STRING_CLOSING_TAG) || line.contains(PLURALS_CLOSING_TAG)
|
||||
}
|
||||
|
||||
private fun copyKeyToTarget(targetFile: File, keyDeclaration: String, key: String) {
|
||||
println(" Moving key to file: ${targetFile.path}")
|
||||
|
||||
if (containsKey(targetFile, key)) {
|
||||
println(" Key already exists in target file: ${targetFile.path} replacing it.")
|
||||
replaceKeyInTarget(targetFile, keyDeclaration, key)
|
||||
} else {
|
||||
addKeyToTarget(targetFile, keyDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addKeyToTarget(targetFile: File, keyDeclaration: String) {
|
||||
val targetContent = StringBuilder()
|
||||
|
||||
targetFile.forEachLine { line ->
|
||||
if (line.contains(RESOURCE_CLOSING_TAG)) {
|
||||
targetContent.appendLine(keyDeclaration.trimEnd())
|
||||
targetContent.appendLine(line)
|
||||
} else {
|
||||
targetContent.appendLine(line)
|
||||
}
|
||||
}
|
||||
|
||||
targetFile.writeText(targetContent.toString())
|
||||
}
|
||||
|
||||
private fun replaceKeyInTarget(targetFile: File, keyDeclaration: String, key: String) {
|
||||
println(" Replacing key in file: ${targetFile.path}")
|
||||
|
||||
val oldKeyDeclaration = extractKeyDeclaration(targetFile, key)
|
||||
val targetContent = targetFile.readText()
|
||||
|
||||
targetFile.writeText(targetContent.replace(oldKeyDeclaration, keyDeclaration))
|
||||
}
|
||||
|
||||
private fun deleteKeyFromSource(sourceFile: File, keyDeclaration: String) {
|
||||
println(" Deleting key from file: ${sourceFile.path}")
|
||||
|
||||
val sourceContent = sourceFile.readText()
|
||||
|
||||
sourceFile.writeText(sourceContent.replace(keyDeclaration, ""))
|
||||
}
|
||||
|
||||
private fun isSourceFileEmpty(sourceFile: File): Boolean {
|
||||
val sourceContent = sourceFile.readText()
|
||||
return sourceContent.contains(STRING_CLOSING_TAG).not() && sourceContent.contains(PLURALS_CLOSING_TAG).not()
|
||||
}
|
||||
|
||||
private fun getOrCreateTargetFile(targetPath: File, sourceFile: File): File {
|
||||
val targetFilePath = targetPath.resolve(sourceFile.parentFile.name)
|
||||
val targetFile = File(targetFilePath, sourceFile.name)
|
||||
val targetDirectory = targetFile.parentFile
|
||||
|
||||
if (!targetDirectory.exists()) {
|
||||
targetDirectory.mkdirs()
|
||||
println(" Target directory created: ${targetDirectory.path}")
|
||||
}
|
||||
|
||||
if (!targetFile.exists()) {
|
||||
createTargetFile(targetFile)
|
||||
}
|
||||
|
||||
return targetFile
|
||||
}
|
||||
|
||||
private fun createTargetFile(targetFile: File) {
|
||||
val isNewFileCreated: Boolean = targetFile.createNewFile()
|
||||
if (!isNewFileCreated) {
|
||||
printError("Target file could not be created: ${targetFile.path}")
|
||||
exitProcess(-1)
|
||||
}
|
||||
|
||||
targetFile.writeText(TARGET_FILE_CONTENT)
|
||||
println("Target file ${targetFile.path} created")
|
||||
}
|
||||
|
||||
private fun printError(message: String) {
|
||||
System.err.println("\n$message\n")
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val RESOURCE_PATH = "/src/main/res/"
|
||||
const val KEY_PLACEHOLDER = "{KEY}"
|
||||
const val KEY_PATTERN = """name="$KEY_PLACEHOLDER""""
|
||||
const val VALUES_PATH = "values"
|
||||
const val STRING_RESOURCE_FILE_NAME = "strings.xml"
|
||||
const val STRING_CLOSING_TAG = "</string>"
|
||||
const val PLURALS_CLOSING_TAG = "</plurals>"
|
||||
const val RESOURCE_CLOSING_TAG = "</resources>"
|
||||
|
||||
val TARGET_FILE_CONTENT = """
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
</resources>
|
||||
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
3
scripts/resource_mover
Executable file
3
scripts/resource_mover
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
./gradlew --quiet ":cli:resource-mover-cli:installDist" < /dev/null && ./cli/resource-mover-cli/build/install/resource-mover-cli/bin/resource-mover-cli "$@"
|
@ -115,6 +115,7 @@ include(":plugins:openpgp-api-lib:openpgp-api")
|
||||
include(
|
||||
":cli:autodiscovery-cli",
|
||||
":cli:html-cleaner-cli",
|
||||
":cli:resource-mover-cli",
|
||||
":cli:translation-cli",
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user