From 6962fc2f4c0f0c96e88a823be64f8ebd1312ee17 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 30 Apr 2023 03:14:38 +0200 Subject: [PATCH 1/6] feat: add appreciation message for new contributors --- .github/config.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/config.yml diff --git a/.github/config.yml b/.github/config.yml new file mode 100644 index 0000000..09ed019 --- /dev/null +++ b/.github/config.yml @@ -0,0 +1,2 @@ +firstPRMergeComment: > + Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role. From 2f5577e4648f53ed7e10adfc054e976b57f9283f Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 30 Apr 2023 05:27:23 +0200 Subject: [PATCH 2/6] chore: update gradle and dependencies --- build.gradle.kts | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 2e11b8d..77547ea 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,12 +23,12 @@ repositories { } dependencies { - implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.10") + implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.20-RC") implementation("app.revanced:revanced-patcher:7.0.0") implementation("info.picocli:picocli:4.7.1") implementation("com.github.revanced:jadb:master-SNAPSHOT") // updated fork - implementation("com.android.tools.build:apksig:7.2.2") + implementation("com.android.tools.build:apksig:8.1.0-alpha09") implementation("org.bouncycastle:bcpkix-jdk15on:1.70") implementation("cc.ekblad:4koma:1.1.0") } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 92f06b5..1f017e4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 379687c81409d633026d2d22b45a0f9ebc5ec50b Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 1 May 2023 05:23:17 +0200 Subject: [PATCH 3/6] fix!: support null as option value (#221) BREAKING-CHANGE: serialize options as JSON instead of TOML --- build.gradle.kts | 9 +- .../app/revanced/cli/command/MainCommand.kt | 19 +++- .../app/revanced/cli/patcher/Patcher.kt | 5 +- src/main/kotlin/app/revanced/utils/Options.kt | 103 ++++++++++++++++++ .../app/revanced/utils/OptionsLoader.kt | 77 ------------- .../app/revanced/utils/patcher/Patcher.kt | 3 +- .../patcher/options/PatchOptionOptionsTest.kt | 52 +++++++++ 7 files changed, 182 insertions(+), 86 deletions(-) create mode 100644 src/main/kotlin/app/revanced/utils/Options.kt delete mode 100644 src/main/kotlin/app/revanced/utils/OptionsLoader.kt create mode 100644 src/test/kotlin/app/revanced/patcher/options/PatchOptionOptionsTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 77547ea..08c9cef 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,10 +30,17 @@ dependencies { implementation("com.github.revanced:jadb:master-SNAPSHOT") // updated fork implementation("com.android.tools.build:apksig:8.1.0-alpha09") implementation("org.bouncycastle:bcpkix-jdk15on:1.70") - implementation("cc.ekblad:4koma:1.1.0") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.+") + testImplementation("org.jetbrains.kotlin:kotlin-test:1.8.20-RC") } tasks { + test { + useJUnitPlatform() + testLogging { + events("PASSED", "SKIPPED", "FAILED") + } + } build { dependsOn(shadowJar) } diff --git a/src/main/kotlin/app/revanced/cli/command/MainCommand.kt b/src/main/kotlin/app/revanced/cli/command/MainCommand.kt index 93e1626..0d3b954 100644 --- a/src/main/kotlin/app/revanced/cli/command/MainCommand.kt +++ b/src/main/kotlin/app/revanced/cli/command/MainCommand.kt @@ -7,16 +7,24 @@ import app.revanced.cli.patcher.logging.impl.PatcherLogger import app.revanced.cli.signing.Signing import app.revanced.cli.signing.SigningOptions import app.revanced.patcher.PatcherOptions +import app.revanced.patcher.data.Context import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.extensions.PatchExtensions.description import app.revanced.patcher.extensions.PatchExtensions.patchName +import app.revanced.patcher.patch.Patch import app.revanced.patcher.util.patch.PatchBundle -import app.revanced.utils.OptionsLoader +import app.revanced.utils.Options +import app.revanced.utils.Options.setOptions import app.revanced.utils.adb.Adb import picocli.CommandLine.* import java.io.File import java.nio.file.Files +/** + * Alias for return type of [PatchBundle.loadPatches]. + */ +internal typealias PatchList = List>> + private class CLIVersionProvider : IVersionProvider { override fun getVersion() = arrayOf( MainCommand::class.java.`package`.implementationVersion ?: "unknown" @@ -55,8 +63,8 @@ internal object MainCommand : Runnable { @Option(names = ["-b", "--bundle"], description = ["One or more bundles of patches"], required = true) var patchBundles = arrayOf() - @Option(names = ["--options"], description = ["Configuration file for all patch options"]) - var options: File = File("options.toml") + @Option(names = ["--options"], description = ["Path to patch options JSON file"]) + var optionsFile: File = File("options.json") @ArgGroup(exclusive = false) var listingArgs: ListingArgs? = null @@ -134,7 +142,10 @@ internal object MainCommand : Runnable { PatchBundle.Jar(bundle).loadPatches() } - OptionsLoader.init(args.patchArgs!!.options, allPatches) + args.patchArgs!!.optionsFile.let { + if (it.exists()) allPatches.setOptions(it, logger) + else Options.serialize(allPatches, prettyPrint = true).let(it::writeText) + } val patcher = app.revanced.patcher.Patcher( PatcherOptions( diff --git a/src/main/kotlin/app/revanced/cli/patcher/Patcher.kt b/src/main/kotlin/app/revanced/cli/patcher/Patcher.kt index d1e5333..180703e 100644 --- a/src/main/kotlin/app/revanced/cli/patcher/Patcher.kt +++ b/src/main/kotlin/app/revanced/cli/patcher/Patcher.kt @@ -1,8 +1,7 @@ package app.revanced.cli.patcher +import app.revanced.cli.command.PatchList import app.revanced.patcher.PatcherResult -import app.revanced.patcher.data.Context -import app.revanced.patcher.patch.Patch import app.revanced.utils.patcher.addPatchesFiltered import app.revanced.utils.patcher.applyPatchesVerbose import app.revanced.utils.patcher.mergeFiles @@ -10,7 +9,7 @@ import app.revanced.utils.patcher.mergeFiles internal object Patcher { internal fun start( patcher: app.revanced.patcher.Patcher, - allPatches: List>> + allPatches: PatchList ): PatcherResult { // merge files like necessary integrations patcher.mergeFiles() diff --git a/src/main/kotlin/app/revanced/utils/Options.kt b/src/main/kotlin/app/revanced/utils/Options.kt new file mode 100644 index 0000000..e430265 --- /dev/null +++ b/src/main/kotlin/app/revanced/utils/Options.kt @@ -0,0 +1,103 @@ +package app.revanced.utils + +import app.revanced.cli.command.PatchList +import app.revanced.cli.logging.CliLogger +import app.revanced.patcher.extensions.PatchExtensions.options +import app.revanced.patcher.extensions.PatchExtensions.patchName +import app.revanced.patcher.patch.NoSuchOptionException +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import java.io.File + + +internal object Options { + private var mapper = jacksonObjectMapper() + + /** + * Serializes the options for the patches in the list. + * + * @param patches The list of patches to serialize. + * @param prettyPrint Whether to pretty print the JSON. + * @return The JSON string containing the options. + * @see PatchList + */ + fun serialize(patches: PatchList, prettyPrint: Boolean = false): String = patches + .filter { it.options?.any() == true } + .map { patch -> + PatchOption( + patch.patchName, + patch.options!!.map { option -> PatchOption.Option(option.key, option.value) } + ) + }.let { + if (prettyPrint) + mapper.writerWithDefaultPrettyPrinter().writeValueAsString(it) + else + mapper.writeValueAsString(it) + } + + /** + * Deserializes the options for the patches in the list. + * + * @param json The JSON string containing the options. + * @return The list of [PatchOption]s. + * @see PatchOption + * @see PatchList + */ + @Suppress("MemberVisibilityCanBePrivate") + fun deserialize(json: String): Array = mapper.readValue(json, Array::class.java) + + /** + * Sets the options for the patches in the list. + * + * @param json The JSON string containing the options. + * @param logger The logger to use for logging. + */ + fun PatchList.setOptions(json: String, logger: CliLogger? = null) { + filter { it.options?.any() == true }.let { patches -> + if (patches.isEmpty()) return + + val patchOptions = deserialize(json) + + patches.forEach { patch -> + patchOptions.find { option -> option.patchName == patch.patchName }?.let { + it.options.forEach { option -> + try { + patch.options?.set(option.key, option.value) + ?: logger?.warn("${patch.patchName} has no options") + } catch (e: NoSuchOptionException) { + logger?.error(e.message ?: "Unknown error") + } + } + } + } + } + } + + /** + * Sets the options for the patches in the list. + * + * @param file The file containing the JSON string containing the options. + * @param logger The logger to use for logging. + * @see setOptions + */ + fun PatchList.setOptions(file: File, logger: CliLogger? = null) = setOptions(file.readText(), logger) + + /** + * Data class for a patch and its [Option]s. + * + * @property patchName The name of the patch. + * @property options The [Option]s for the patch. + */ + internal data class PatchOption( + val patchName: String, + val options: List