Skip to content

Commit

Permalink
feat: Set patch options via CLI (#336)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: This commit changes various CLI options and removes the `options.json` file. Instead, patch options can now be passed via CLI options
  • Loading branch information
oSumAtrIX authored Aug 12, 2024
1 parent 54ae01c commit 2300243
Show file tree
Hide file tree
Showing 10 changed files with 419 additions and 213 deletions.
91 changes: 81 additions & 10 deletions docs/1_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ java -jar revanced-cli.jar -h
## 📃 List patches

```bash
java -jar revanced-cli.jar list-patches --with-descriptions --with-packages --with-versions --with-options --with-universal-patches revanced-patches.rvp
java -jar revanced-cli.jar list-patches --with-packages --with-versions --with-options revanced-patches.rvp
```

## 💉 Patch an app with the default list of patches
## 💉 Patch an app

To patch an app using the default list of patches, use the `patch` command:

```bash
java -jar revanced-cli.jar patch -b revanced-patches.rvp input.apk
Expand All @@ -28,22 +30,37 @@ You can also use multiple patch bundles:
java -jar revanced-cli.jar patch -b revanced-patches.rvp -b another-patches.rvp input.apk
```

To manually include or exclude patches, use the options `-i` and `-e`.
Keep in mind the name of the patch must be an exact match.
You can also use the options `--ii` and `--ie` to include or exclude patches by their index
if two patches have the same name.
To know the indices of patches, use the option `--with-indices` when listing patches:
To change the default set of used patches, use the option `-i` or `-e` to use or disuse specific patches.
You can use the `list-patches` command to see which patches are used by default.

To only use specific patches, you can use the option `--exclusive` combined with `-i`.
Remember that the options `-i` and `-e` match the patch's name exactly. Here is an example:

```bash
java -jar revanced-cli.jar list-patches --with-indices revanced-patches.rvp
java -jar revanced-cli.jar patch -b revanced-patches.rvp --exclusive -i "Patch name" -i "Another patch name" input.apk
```

Then you can use the indices to include or exclude patches:
You can also use the options `--ii` and `--ie` to use or disuse patches by their index.
This is useful, if two patches happen to have the same name.
To know the indices of patches, use the command `list-patches`:

```bash
java -jar revanced-cli.jar list-patches revanced-patches.rvp
```

Then you can use the indices to use or disuse patches:

```bash
java -jar revanced-cli.jar patch -b revanced-patches.rvp --ii 123 --ie 456 input.apk
```

You can combine the option `-i`, `-e`, `--ii`, `--ie` and `--exclusive`. Here is an example:

```bash
java -jar revanced-cli.jar patch -b revanced-patches.rvp --exclusive -i "Patch name" --ii 123 input.apk
```


> [!TIP]
> You can use the option `-d` to automatically install the patched app after patching.
> Make sure ADB is working:
Expand All @@ -62,7 +79,61 @@ java -jar revanced-cli.jar patch -b revanced-patches.rvp --ii 123 --ie 456 input
> adb install input.apk
> ```
## 📦 Install an app manually
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 `-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 -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 -i "Patch name" -Okey1 input.apk
```

> [!WARNING]
> Option values are usually typed. If you set a value with the wrong type, the patch can fail.
> Option value types can be seen when listing patches with the option `--with-options`.
>
> Example option values:
>
> - String: `string`
> - Boolean: `true`, `false`
> - Integer: `123`
> - Double: `1.0`
> - Float: `1.0f`
> - Long: `1234567890`, `1L`
> - List: `[item1,item2,item3]`
> - List of type `Any`: `[item1,123,true,1.0]`
> - Empty list of type `Any`: `[]`
> - Typed empty list: `int[]`
> - Typed and nested empty list: `[int[]]`
> - List with null value and two empty strings: `[null,\'\',\"\"]`
>
> Quotes and commas escaped in strings (`\"`, `\'`, `\,`) are parsed as part of the string.
> List items are recursively parsed, so you can escape values in lists:
>
> - Escaped integer as a string: `[\'123\']`
> - Escaped boolean as a string: `[\'true\']`
> - Escaped list as a string: `[\'[item1,item2]\']`
> - Escaped null value as a string: `[\'null\']`
> - List with an integer, an integer as a string and a string with a comma, and an escaped list: [`123,\'123\',str\,ing`,`\'[]\'`]
>
> Example command with an escaped integer as a string:
>
> ```bash
> java -jar revanced-cli.jar -b revanced-patches.rvp -i "Patch name" -OstringKey=\'1\' input.apk
> ```
## 📦 Install an app manually
```bash
java -jar revanced-cli.jar utility install -a input.apk
Expand Down
105 changes: 105 additions & 0 deletions src/main/kotlin/app/revanced/cli/command/CommandUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package app.revanced.cli.command

import picocli.CommandLine

class OptionKeyConverter : CommandLine.ITypeConverter<String> {
override fun convert(value: String): String = value
}

class OptionValueConverter : CommandLine.ITypeConverter<Any?> {
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<Int>()
value == "long[]" -> emptyList<Long>()
value == "double[]" -> emptyList<Double>()
value == "float[]" -> emptyList<Float>()
value == "boolean[]" -> emptyList<Boolean>()
value == "string[]" -> emptyList<String>()
else -> value
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package app.revanced.cli.command

import app.revanced.library.PackageName
import app.revanced.library.PatchUtils
import app.revanced.library.VersionMap
import app.revanced.library.mostCommonCompatibleVersions
import app.revanced.patcher.patch.loadPatchesFromJar
import picocli.CommandLine
import java.io.File
Expand All @@ -12,11 +12,11 @@ import java.util.logging.Logger
name = "list-versions",
description = [
"List the most common compatible versions of apps that are compatible " +
"with the patches in the supplied patch bundles.",
"with the patches in the supplied patch bundles.",
],
)
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."],
Expand Down Expand Up @@ -58,8 +58,7 @@ internal class ListCompatibleVersions : Runnable {

val patches = loadPatchesFromJar(patchBundles)

PatchUtils.getMostCommonCompatibleVersions(
patches,
patches.mostCommonCompatibleVersions(
packageNames,
countUnusedPatches,
).entries.joinToString("\n", transform = ::buildString).let(logger::info)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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."],
Expand Down Expand Up @@ -95,9 +95,11 @@ internal object ListPatchesCommand : Runnable {
} ?: append("Key: $key")

values?.let { values ->
appendLine("\nValid values:")
appendLine("\nPossible values:")
append(values.map { "${it.value} (${it.key})" }.joinToString("\n").prependIndent("\t"))
}

append("\nType: $type")
}

fun IndexedValue<Patch<*>>.buildString() =
Expand Down
1 change: 0 additions & 1 deletion src/main/kotlin/app/revanced/cli/command/MainCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ private object CLIVersionProvider : IVersionProvider {
versionProvider = CLIVersionProvider::class,
subcommands = [
PatchCommand::class,
OptionsCommand::class,
ListPatchesCommand::class,
ListCompatibleVersions::class,
UtilityCommand::class,
Expand Down
62 changes: 0 additions & 62 deletions src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt

This file was deleted.

Loading

0 comments on commit 2300243

Please sign in to comment.