diff --git a/CHANGELOG.md b/CHANGELOG.md
index cb23fd3..92b969b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,28 @@
+# [4.1.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.2...v4.1.0-dev.3) (2023-11-03)
+
+# [4.1.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.1...v4.1.0-dev.2) (2023-11-03)
+
+
+### Features
+
+* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](https://github.com/ReVanced/revanced-cli/commit/b2055ce07df3ab9a9f3f73ab17d8c2cf02f2ae62))
+
+
+### Performance Improvements
+
+* Use a `HashSet` to check for included and excluded patches ([616d14f](https://github.com/ReVanced/revanced-cli/commit/616d14f0097c1ee7ba6dc07be417590f6418e8e5))
+
+# [4.1.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.2...v4.1.0-dev.1) (2023-11-03)
+
+
+### Features
+
+* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](https://github.com/ReVanced/revanced-cli/commit/0139dfe0bfa06a13f56dc03e7718aaf644029614))
+
+## [4.0.3-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.1...v4.0.3-dev.2) (2023-10-30)
+
+## [4.0.3-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.0.3-dev.1) (2023-10-23)
+
## [4.0.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.1...v4.0.2) (2023-10-12)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8eeb27a..e3d551b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -39,7 +39,7 @@
Continuing the legacy of Vanced
-# 📙 ReVanced CLI contribution guidelines
+# 👋 Contribution guidelines
This document describes how to contribute to ReVanced CLI.
@@ -76,4 +76,4 @@ If you encounter a bug while using ReVanced CLI, open an issue using the
it will be merged into the `dev` branch and will be included in the next release of ReVanced CLI
❤️ Thank you for considering contributing to ReVanced CLI,
-ReVanced
\ No newline at end of file
+ReVanced
diff --git a/build.gradle.kts b/build.gradle.kts
index 536d172..fc12ab7 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,5 +1,5 @@
plugins {
- kotlin("jvm") version "1.9.0"
+ kotlin("jvm") version "1.9.10"
alias(libs.plugins.shadow)
}
diff --git a/docs/1_usage.md b/docs/1_usage.md
index e9fb42b..1a885b4 100644
--- a/docs/1_usage.md
+++ b/docs/1_usage.md
@@ -87,10 +87,25 @@ ReVanced CLI is divided into the following fundamental commands:
> adb install app.apk
> ```
+ > [!NOTE]
+ > You can use the option `--ii` to include or `--ie` to exclude
+ > patches by their index in relation to supplied patch bundles,
+ > similarly to the option `--include` and `--exclude`.
+ >
+ > This is useful in case two patches have the same name, and you need to include or exclude one of them.
+ > The index of a patch is calculated by the position of the patch in the list of patches
+ > from patch bundles supplied using the option `--patch-bundle`.
+ >
+ > You can list all patches with their indices using the command `list-patches`.
+ >
+ > Keep in mind, that the indices can change based on the order of the patch bundles supplied,
+ > as well if the patch bundles are updated, because patches can be added or removed.
+
```bash
java -jar revanced-cli.jar patch \
--patch-bundle revanced-patches.jar \
--include "Some patch" \
+ --ii 123 \
--exclude "Some other patch" \
--out patched-app.apk \
--device-serial \
diff --git a/gradle.properties b/gradle.properties
index dc74906..18b12a1 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
org.gradle.parallel = true
org.gradle.caching = true
kotlin.code.style = official
-version = 4.0.2
+version = 4.1.0-dev.3
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 213e17a..b6a699c 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -3,14 +3,14 @@ shadow = "8.1.1"
kotlin-test = "1.8.20-RC"
kotlinx-coroutines-core = "1.7.3"
picocli = "4.7.3"
-revanced-patcher = "17.0.0"
-revanced-library = "1.1.3"
+revanced-patcher = "19.0.0"
+revanced-library = "1.2.0"
[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-test" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
-revanced-patcher = { module = "app.revanced.revanced-patcher:revanced-patcher", version.ref = "revanced-patcher" }
+revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
revanced-library = { module = "app.revanced:revanced-library", version.ref = "revanced-library" }
[plugins]
diff --git a/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt b/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt
index 3c3aac2..b9e11b0 100644
--- a/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt
+++ b/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt
@@ -42,6 +42,20 @@ internal object ListPatchesCommand : Runnable {
)
private var withOptions: Boolean = false
+ @Option(
+ names = ["-u", "--with-universal-patches"],
+ description = ["List patches which are compatible with any app."],
+ showDefaultValue = ALWAYS
+ )
+ private var withUniversalPatches: Boolean = true
+
+ @Option(
+ names = ["-i", "--index"],
+ description = ["List the index of of each patch in relation to the supplied patch bundles."],
+ showDefaultValue = ALWAYS
+ )
+ private var withIndex: Boolean = true
+
@Option(
names = ["-f", "--filter-package-name"], description = ["Filter patches by package name."]
)
@@ -58,41 +72,51 @@ internal object ListPatchesCommand : Runnable {
fun PatchOption<*>.buildString() = buildString {
appendLine("Title: $title")
- appendLine("Description: $description")
-
- value?.let {
+ description?.let { appendLine("Description: $it") }
+ default?.let {
appendLine("Key: $key")
- append("Value: $it")
+ append("Default: $it")
} ?: append("Key: $key")
- }
- fun Patch<*>.buildString() = buildString {
- append("Name: $name")
-
- if (withDescriptions) append("\nDescription: $description")
-
- if (withOptions && options.isNotEmpty()) {
- appendLine("\nOptions:")
- append(
- options.values.joinToString("\n\n") { option ->
- option.buildString()
- }.prependIndent("\t")
- )
- }
-
- if (withPackages && compatiblePackages != null) {
- appendLine("\nCompatible packages:")
- append(
- compatiblePackages!!.joinToString("\n") { it.buildString() }.prependIndent("\t")
- )
+ values?.let { values ->
+ appendLine("\nValid values:")
+ append(values.map { "${it.value} (${it.key})" }.joinToString("\n").prependIndent("\t"))
}
}
- fun Patch<*>.anyPackageName(name: String) = compatiblePackages?.any { it.name == name } == true
+ fun IndexedValue>.buildString() = let { (index, patch) ->
+ buildString {
+ if (withIndex) appendLine("Index: $index")
- val patches = PatchBundleLoader.Jar(*patchBundles)
+ append("Name: ${patch.name}")
- val filtered = packageName?.let { patches.filter { patch -> patch.anyPackageName(it) } } ?: patches
+ if (withDescriptions) append("\nDescription: ${patch.description}")
+
+ if (withOptions && patch.options.isNotEmpty()) {
+ appendLine("\nOptions:")
+ append(
+ patch.options.values.joinToString("\n\n") { option ->
+ option.buildString()
+ }.prependIndent("\t")
+ )
+ }
+
+ if (withPackages && patch.compatiblePackages != null) {
+ appendLine("\nCompatible packages:")
+ append(patch.compatiblePackages!!.joinToString("\n") {
+ it.buildString()
+ }.prependIndent("\t"))
+ }
+ }
+ }
+
+ fun Patch<*>.filterCompatiblePackages(name: String) = compatiblePackages?.any { it.name == name }
+ ?: withUniversalPatches
+
+ val patches = PatchBundleLoader.Jar(*patchBundles).withIndex().toList()
+
+ val filtered =
+ packageName?.let { patches.filter { (_, patch) -> patch.filterCompatiblePackages(it) } } ?: patches
if (filtered.isNotEmpty()) logger.info(filtered.joinToString("\n\n") { it.buildString() })
}
diff --git a/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt b/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt
index 8781136..0603783 100644
--- a/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt
+++ b/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt
@@ -37,12 +37,24 @@ internal object PatchCommand : Runnable {
@CommandLine.Option(
names = ["-i", "--include"], description = ["List of patches to include."]
)
- private var includedPatches = arrayOf()
+ private var includedPatches = hashSetOf()
+
+ @CommandLine.Option(
+ names = ["--ii"],
+ description = ["List of patches to include by their index in relation to the supplied patch bundles."]
+ )
+ private var includedPatchesByIndex = arrayOf()
@CommandLine.Option(
names = ["-e", "--exclude"], description = ["List of patches to exclude."]
)
- private var excludedPatches = arrayOf()
+ private var excludedPatches = hashSetOf()
+
+ @CommandLine.Option(
+ names = ["--ei"],
+ description = ["List of patches to exclude by their index in relation to the supplied patch bundles."]
+ )
+ private var excludedPatchesByIndex = arrayOf()
@CommandLine.Option(
names = ["--options"], description = ["Path to patch options JSON file."], showDefaultValue = ALWAYS
@@ -188,7 +200,7 @@ internal object PatchCommand : Runnable {
// Warn if a patch can not be found in the supplied patch bundles.
if (warn) patches.map { it.name }.toHashSet().let { availableNames ->
- arrayOf(*includedPatches, *excludedPatches).filter { name ->
+ (includedPatches + excludedPatches).filter { name ->
!availableNames.contains(name)
}
}.let { unknownPatches ->
@@ -283,10 +295,10 @@ internal object PatchCommand : Runnable {
val packageName = context.packageMetadata.packageName
val packageVersion = context.packageMetadata.packageVersion
- patches.forEach patch@{ patch ->
+ patches.withIndex().forEach patch@{ (i, patch) ->
val patchName = patch.name!!
- val explicitlyExcluded = excludedPatches.contains(patchName)
+ val explicitlyExcluded = excludedPatches.contains(patchName) || excludedPatchesByIndex.contains(i)
if (explicitlyExcluded) return@patch logger.info("Excluding $patchName")
// Make sure the patch is compatible with the supplied APK files package name and version.
@@ -314,7 +326,7 @@ internal object PatchCommand : Runnable {
// If the patch is implicitly used, it will be only included if [exclusive] is false.
val implicitlyIncluded = !exclusive && patch.use
// If the patch is explicitly used, it will be included even if [exclusive] is false.
- val explicitlyIncluded = includedPatches.contains(patchName)
+ val explicitlyIncluded = includedPatches.contains(patchName) || includedPatchesByIndex.contains(i)
val included = implicitlyIncluded || explicitlyIncluded
if (!included) return@patch logger.info("$patchName excluded") // Case 1.