Skip to content

Commit 2300243

Browse files
authored
feat: Set patch options via CLI (#336)
BREAKING CHANGE: This commit changes various CLI options and removes the `options.json` file. Instead, patch options can now be passed via CLI options
1 parent 54ae01c commit 2300243

File tree

10 files changed

+419
-213
lines changed

10 files changed

+419
-213
lines changed

docs/1_usage.md

+81-10
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ java -jar revanced-cli.jar -h
1313
## 📃 List patches
1414

1515
```bash
16-
java -jar revanced-cli.jar list-patches --with-descriptions --with-packages --with-versions --with-options --with-universal-patches revanced-patches.rvp
16+
java -jar revanced-cli.jar list-patches --with-packages --with-versions --with-options revanced-patches.rvp
1717
```
1818

19-
## 💉 Patch an app with the default list of patches
19+
## 💉 Patch an app
20+
21+
To patch an app using the default list of patches, use the `patch` command:
2022

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

31-
To manually include or exclude patches, use the options `-i` and `-e`.
32-
Keep in mind the name of the patch must be an exact match.
33-
You can also use the options `--ii` and `--ie` to include or exclude patches by their index
34-
if two patches have the same name.
35-
To know the indices of patches, use the option `--with-indices` when listing patches:
33+
To change the default set of used patches, use the option `-i` or `-e` to use or disuse specific patches.
34+
You can use the `list-patches` command to see which patches are used by default.
35+
36+
To only use specific patches, you can use the option `--exclusive` combined with `-i`.
37+
Remember that the options `-i` and `-e` match the patch's name exactly. Here is an example:
3638

3739
```bash
38-
java -jar revanced-cli.jar list-patches --with-indices revanced-patches.rvp
40+
java -jar revanced-cli.jar patch -b revanced-patches.rvp --exclusive -i "Patch name" -i "Another patch name" input.apk
3941
```
4042

41-
Then you can use the indices to include or exclude patches:
43+
You can also use the options `--ii` and `--ie` to use or disuse patches by their index.
44+
This is useful, if two patches happen to have the same name.
45+
To know the indices of patches, use the command `list-patches`:
46+
47+
```bash
48+
java -jar revanced-cli.jar list-patches revanced-patches.rvp
49+
```
50+
51+
Then you can use the indices to use or disuse patches:
4252

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

57+
You can combine the option `-i`, `-e`, `--ii`, `--ie` and `--exclusive`. Here is an example:
58+
59+
```bash
60+
java -jar revanced-cli.jar patch -b revanced-patches.rvp --exclusive -i "Patch name" --ii 123 input.apk
61+
```
62+
63+
4764
> [!TIP]
4865
> You can use the option `-d` to automatically install the patched app after patching.
4966
> Make sure ADB is working:
@@ -62,7 +79,61 @@ java -jar revanced-cli.jar patch -b revanced-patches.rvp --ii 123 --ie 456 input
6279
> adb install input.apk
6380
> ```
6481
65-
## 📦 Install an app manually
82+
Patches can have options you can set using the option `-O` alongside the option to include the patch by name or index.
83+
To know the options of a patch, use the option `--with-options` when listing patches:
84+
85+
```bash
86+
java -jar revanced-cli.jar list-patches --with-options revanced-patches.rvp
87+
```
88+
89+
Each patch can have multiple options. You can set them using the option `-O`.
90+
For example, to set the options for the patch with the name `Patch name`
91+
with the key `key1` and `key2` to `value1` and `value2` respectively, use the following command:
92+
93+
```bash
94+
java -jar revanced-cli.jar patch -b revanced-patches.rvp -i "Patch name" -Okey1=value1 -Okey2=value2 input.apk
95+
```
96+
97+
If you want to set a value to `null`, you can omit the value:
98+
99+
```bash
100+
java -jar revanced-cli.jar patch -b revanced-patches.rvp -i "Patch name" -Okey1 input.apk
101+
```
102+
103+
> [!WARNING]
104+
> Option values are usually typed. If you set a value with the wrong type, the patch can fail.
105+
> Option value types can be seen when listing patches with the option `--with-options`.
106+
>
107+
> Example option values:
108+
>
109+
> - String: `string`
110+
> - Boolean: `true`, `false`
111+
> - Integer: `123`
112+
> - Double: `1.0`
113+
> - Float: `1.0f`
114+
> - Long: `1234567890`, `1L`
115+
> - List: `[item1,item2,item3]`
116+
> - List of type `Any`: `[item1,123,true,1.0]`
117+
> - Empty list of type `Any`: `[]`
118+
> - Typed empty list: `int[]`
119+
> - Typed and nested empty list: `[int[]]`
120+
> - List with null value and two empty strings: `[null,\'\',\"\"]`
121+
>
122+
> Quotes and commas escaped in strings (`\"`, `\'`, `\,`) are parsed as part of the string.
123+
> List items are recursively parsed, so you can escape values in lists:
124+
>
125+
> - Escaped integer as a string: `[\'123\']`
126+
> - Escaped boolean as a string: `[\'true\']`
127+
> - Escaped list as a string: `[\'[item1,item2]\']`
128+
> - Escaped null value as a string: `[\'null\']`
129+
> - List with an integer, an integer as a string and a string with a comma, and an escaped list: [`123,\'123\',str\,ing`,`\'[]\'`]
130+
>
131+
> Example command with an escaped integer as a string:
132+
>
133+
> ```bash
134+
> java -jar revanced-cli.jar -b revanced-patches.rvp -i "Patch name" -OstringKey=\'1\' input.apk
135+
> ```
136+
## 📦 Install an app manually
66137
67138
```bash
68139
java -jar revanced-cli.jar utility install -a input.apk
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package app.revanced.cli.command
2+
3+
import picocli.CommandLine
4+
5+
class OptionKeyConverter : CommandLine.ITypeConverter<String> {
6+
override fun convert(value: String): String = value
7+
}
8+
9+
class OptionValueConverter : CommandLine.ITypeConverter<Any?> {
10+
override fun convert(value: String?): Any? {
11+
value ?: return null
12+
13+
return when {
14+
value.startsWith("[") && value.endsWith("]") -> {
15+
val innerValue = value.substring(1, value.length - 1)
16+
17+
buildList {
18+
var nestLevel = 0
19+
var insideQuote = false
20+
var escaped = false
21+
22+
val item = buildString {
23+
for (char in innerValue) {
24+
when (char) {
25+
'\\' -> {
26+
if (escaped || nestLevel != 0) {
27+
append(char)
28+
}
29+
30+
escaped = !escaped
31+
}
32+
33+
'"', '\'' -> {
34+
if (!escaped) {
35+
insideQuote = !insideQuote
36+
} else {
37+
escaped = false
38+
}
39+
40+
append(char)
41+
}
42+
43+
'[' -> {
44+
if (!insideQuote) {
45+
nestLevel++
46+
}
47+
48+
append(char)
49+
}
50+
51+
']' -> {
52+
if (!insideQuote) {
53+
nestLevel--
54+
55+
if (nestLevel == -1) {
56+
return value
57+
}
58+
}
59+
60+
append(char)
61+
}
62+
63+
',' -> if (nestLevel == 0) {
64+
if (insideQuote) {
65+
append(char)
66+
} else {
67+
add(convert(toString()))
68+
setLength(0)
69+
}
70+
} else {
71+
append(char)
72+
}
73+
74+
else -> append(char)
75+
}
76+
}
77+
}
78+
79+
if (item.isNotEmpty()) {
80+
add(convert(item))
81+
}
82+
}
83+
}
84+
85+
value.startsWith("\"") && value.endsWith("\"") -> value.substring(1, value.length - 1)
86+
value.startsWith("'") && value.endsWith("'") -> value.substring(1, value.length - 1)
87+
value.endsWith("f") -> value.dropLast(1).toFloat()
88+
value.endsWith("L") -> value.dropLast(1).toLong()
89+
value.equals("true", ignoreCase = true) -> true
90+
value.equals("false", ignoreCase = true) -> false
91+
value.toIntOrNull() != null -> value.toInt()
92+
value.toLongOrNull() != null -> value.toLong()
93+
value.toDoubleOrNull() != null -> value.toDouble()
94+
value.toFloatOrNull() != null -> value.toFloat()
95+
value == "null" -> null
96+
value == "int[]" -> emptyList<Int>()
97+
value == "long[]" -> emptyList<Long>()
98+
value == "double[]" -> emptyList<Double>()
99+
value == "float[]" -> emptyList<Float>()
100+
value == "boolean[]" -> emptyList<Boolean>()
101+
value == "string[]" -> emptyList<String>()
102+
else -> value
103+
}
104+
}
105+
}

src/main/kotlin/app/revanced/cli/command/ListCompatibleVersions.kt

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package app.revanced.cli.command
22

33
import app.revanced.library.PackageName
4-
import app.revanced.library.PatchUtils
54
import app.revanced.library.VersionMap
5+
import app.revanced.library.mostCommonCompatibleVersions
66
import app.revanced.patcher.patch.loadPatchesFromJar
77
import picocli.CommandLine
88
import java.io.File
@@ -12,11 +12,11 @@ import java.util.logging.Logger
1212
name = "list-versions",
1313
description = [
1414
"List the most common compatible versions of apps that are compatible " +
15-
"with the patches in the supplied patch bundles.",
15+
"with the patches in the supplied patch bundles.",
1616
],
1717
)
1818
internal class ListCompatibleVersions : Runnable {
19-
private val logger = Logger.getLogger(ListCompatibleVersions::class.java.name)
19+
private val logger = Logger.getLogger(this::class.java.name)
2020

2121
@CommandLine.Parameters(
2222
description = ["Paths to patch bundles."],
@@ -58,8 +58,7 @@ internal class ListCompatibleVersions : Runnable {
5858

5959
val patches = loadPatchesFromJar(patchBundles)
6060

61-
PatchUtils.getMostCommonCompatibleVersions(
62-
patches,
61+
patches.mostCommonCompatibleVersions(
6362
packageNames,
6463
countUnusedPatches,
6564
).entries.joinToString("\n", transform = ::buildString).let(logger::info)

src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import app.revanced.patcher.patch.Option as PatchOption
1414
description = ["List patches from supplied patch bundles."],
1515
)
1616
internal object ListPatchesCommand : Runnable {
17-
private val logger = Logger.getLogger(ListPatchesCommand::class.java.name)
17+
private val logger = Logger.getLogger(this::class.java.name)
1818

1919
@Parameters(
2020
description = ["Paths to patch bundles."],
@@ -95,9 +95,11 @@ internal object ListPatchesCommand : Runnable {
9595
} ?: append("Key: $key")
9696

9797
values?.let { values ->
98-
appendLine("\nValid values:")
98+
appendLine("\nPossible values:")
9999
append(values.map { "${it.value} (${it.key})" }.joinToString("\n").prependIndent("\t"))
100100
}
101+
102+
append("\nType: $type")
101103
}
102104

103105
fun IndexedValue<Patch<*>>.buildString() =

src/main/kotlin/app/revanced/cli/command/MainCommand.kt

-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ private object CLIVersionProvider : IVersionProvider {
3434
versionProvider = CLIVersionProvider::class,
3535
subcommands = [
3636
PatchCommand::class,
37-
OptionsCommand::class,
3837
ListPatchesCommand::class,
3938
ListCompatibleVersions::class,
4039
UtilityCommand::class,

src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt

-62
This file was deleted.

0 commit comments

Comments
 (0)