From a3fb678e17ec81a68d4f5648feacc5c488fbd19f Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 12 Aug 2024 21:26:50 +0200 Subject: [PATCH] feat: Merge selection and option commands to arg groups --- docs/1_usage.md | 10 +- .../app/revanced/cli/command/CommandUtils.kt | 105 ++++++ .../cli/command/ListCompatibleVersions.kt | 2 +- .../cli/command/ListPatchesCommand.kt | 2 +- .../app/revanced/cli/command/PatchCommand.kt | 339 +++++++----------- .../cli/command/utility/InstallCommand.kt | 2 +- .../cli/command/utility/UninstallCommand.kt | 7 +- 7 files changed, 255 insertions(+), 212 deletions(-) create mode 100644 src/main/kotlin/app/revanced/cli/command/CommandUtils.kt diff --git a/docs/1_usage.md b/docs/1_usage.md index 27296610..7e515426 100644 --- a/docs/1_usage.md +++ b/docs/1_usage.md @@ -79,25 +79,25 @@ java -jar revanced-cli.jar patch -b revanced-patches.rvp --exclusive -i "Patch n > adb install input.apk > ``` -Patches can have options you can set using the option `--set-options`. +Patches can have options you can set using the option `-O` alongside the option to include the patch by name or index. To know the options of a patch, use the option `--with-options` when listing patches: ```bash java -jar revanced-cli.jar list-patches --with-options revanced-patches.rvp ``` -Each patch can have multiple options. You can set them using the option `--set-options`. +Each patch can have multiple options. You can set them using the option `-O`. For example, to set the options for the patch with the name `Patch name` with the key `key1` and `key2` to `value1` and `value2` respectively, use the following command: ```bash -java -jar revanced-cli.jar patch -b revanced-patches.rvp --set-options "Patch name" -Okey1=value1 -Okey2=value2 input.apk +java -jar revanced-cli.jar patch -b revanced-patches.rvp -i "Patch name" -Okey1=value1 -Okey2=value2 input.apk ``` If you want to set a value to `null`, you can omit the value: ```bash -java -jar revanced-cli.jar patch -b revanced-patches.rvp --set-options "Patch name" -Okey1 input.apk +java -jar revanced-cli.jar patch -b revanced-patches.rvp -i "Patch name" -Okey1 input.apk ``` > [!WARNING] @@ -131,7 +131,7 @@ java -jar revanced-cli.jar patch -b revanced-patches.rvp --set-options "Patch na > Example command with an escaped integer as a string: > > ```bash -> java -jar revanced-cli.jar -b revanced-patches.rvp --set-options "Patch name" -OstringKey=\'1\' input.apk +> java -jar revanced-cli.jar -b revanced-patches.rvp -i "Patch name" -OstringKey=\'1\' input.apk > ``` ## 📦 Install an app manually diff --git a/src/main/kotlin/app/revanced/cli/command/CommandUtils.kt b/src/main/kotlin/app/revanced/cli/command/CommandUtils.kt new file mode 100644 index 00000000..afb365b6 --- /dev/null +++ b/src/main/kotlin/app/revanced/cli/command/CommandUtils.kt @@ -0,0 +1,105 @@ +package app.revanced.cli.command + +import picocli.CommandLine + +class OptionKeyConverter : CommandLine.ITypeConverter { + override fun convert(value: String): String = value +} + +class OptionValueConverter : CommandLine.ITypeConverter { + override fun convert(value: String?): Any? { + value ?: return null + + return when { + value.startsWith("[") && value.endsWith("]") -> { + val innerValue = value.substring(1, value.length - 1) + + buildList { + var nestLevel = 0 + var insideQuote = false + var escaped = false + + val item = buildString { + for (char in innerValue) { + when (char) { + '\\' -> { + if (escaped || nestLevel != 0) { + append(char) + } + + escaped = !escaped + } + + '"', '\'' -> { + if (!escaped) { + insideQuote = !insideQuote + } else { + escaped = false + } + + append(char) + } + + '[' -> { + if (!insideQuote) { + nestLevel++ + } + + append(char) + } + + ']' -> { + if (!insideQuote) { + nestLevel-- + + if (nestLevel == -1) { + return value + } + } + + append(char) + } + + ',' -> if (nestLevel == 0) { + if (insideQuote) { + append(char) + } else { + add(convert(toString())) + setLength(0) + } + } else { + append(char) + } + + else -> append(char) + } + } + } + + if (item.isNotEmpty()) { + add(convert(item)) + } + } + } + + value.startsWith("\"") && value.endsWith("\"") -> value.substring(1, value.length - 1) + value.startsWith("'") && value.endsWith("'") -> value.substring(1, value.length - 1) + value.endsWith("f") -> value.dropLast(1).toFloat() + value.endsWith("L") -> value.dropLast(1).toLong() + value.equals("true", ignoreCase = true) -> true + value.equals("false", ignoreCase = true) -> false + value.toIntOrNull() != null -> value.toInt() + value.toLongOrNull() != null -> value.toLong() + value.toDoubleOrNull() != null -> value.toDouble() + value.toFloatOrNull() != null -> value.toFloat() + value == "null" -> null + value == "int[]" -> emptyList() + value == "long[]" -> emptyList() + value == "double[]" -> emptyList() + value == "float[]" -> emptyList() + value == "boolean[]" -> emptyList() + value == "string[]" -> emptyList() + else -> value + } + } +} diff --git a/src/main/kotlin/app/revanced/cli/command/ListCompatibleVersions.kt b/src/main/kotlin/app/revanced/cli/command/ListCompatibleVersions.kt index 9816fcf2..ba993c7c 100644 --- a/src/main/kotlin/app/revanced/cli/command/ListCompatibleVersions.kt +++ b/src/main/kotlin/app/revanced/cli/command/ListCompatibleVersions.kt @@ -16,7 +16,7 @@ import java.util.logging.Logger ], ) internal class ListCompatibleVersions : Runnable { - private val logger = Logger.getLogger(ListCompatibleVersions::class.java.name) + private val logger = Logger.getLogger(this::class.java.name) @CommandLine.Parameters( description = ["Paths to patch bundles."], diff --git a/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt b/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt index 079d8c0d..fcdb3a57 100644 --- a/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt +++ b/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt @@ -14,7 +14,7 @@ import app.revanced.patcher.patch.Option as PatchOption description = ["List patches from supplied patch bundles."], ) internal object ListPatchesCommand : Runnable { - private val logger = Logger.getLogger(ListPatchesCommand::class.java.name) + private val logger = Logger.getLogger(this::class.java.name) @Parameters( description = ["Paths to patch bundles."], diff --git a/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt b/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt index c31afd18..96d8d7c4 100644 --- a/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt +++ b/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt @@ -24,57 +24,70 @@ import java.util.logging.Logger description = ["Patch an APK file."], ) internal object PatchCommand : Runnable { - private val logger = Logger.getLogger(PatchCommand::class.java.name) + private val logger = Logger.getLogger(this::class.java.name) @Spec - lateinit var spec: CommandSpec + private lateinit var spec: CommandSpec - private lateinit var apk: File + @ArgGroup(multiplicity = "0..*") + private lateinit var selection: Set - private var patchBundles = emptySet() + internal class Selection { + @ArgGroup(exclusive = false, multiplicity = "1") + internal var include: IncludeSelection? = null - @CommandLine.Option( - names = ["-i", "--include"], - description = ["List of patches to include by name."], - ) - private var includedPatches = hashSetOf() + internal class IncludeSelection { + @ArgGroup(multiplicity = "1") + internal lateinit var selector: IncludeSelector - @CommandLine.Option( - names = ["--ii"], - description = ["List of patches to include by their index in the combined list of all supplied patch bundles."], - ) - private var includedPatchesByIndex = setOf() + internal class IncludeSelector { + @CommandLine.Option( + names = ["-i", "--include"], + description = ["The name of the patch."], + required = true, + ) + internal var name: String? = null - @CommandLine.Option( - names = ["-e", "--exclude"], - description = ["List of patches to exclude."], - ) - private var excludedPatches = hashSetOf() + @CommandLine.Option( + names = ["--ii"], + description = ["The index of the patch in the combined list of all supplied patch bundles."], + required = true, + ) + internal var index: Int? = null + } - @CommandLine.Option( - names = ["--ei"], - description = ["List of patches to exclude by their index in the combined list of all supplied patch bundles."], - ) - private var excludedPatchesByIndex = setOf() - - @ArgGroup(exclusive = false, multiplicity = "0..*", heading = "Options:%n") - private lateinit var options: Set