diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0378477..2f3c07d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ kotlin-reflect = "1.9.0" kotlin-test = "1.8.20-RC" kotlinx-coroutines-core = "1.7.1" picocli = "4.7.3" -revanced-patcher = "14.2.1" +revanced-patcher = "15.0.0-dev.2" [libraries] apksig = { module = "com.android.tools.build:apksig", version.ref = "apksig" } @@ -22,4 +22,4 @@ picocli = { module = "info.picocli:picocli", version.ref = "picocli" } revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" } [plugins] -shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" } \ No newline at end of file +shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" } diff --git a/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt b/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt index 28419d9..3f5535a 100644 --- a/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt +++ b/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt @@ -1,13 +1,8 @@ package app.revanced.cli.command import app.revanced.patcher.PatchBundleLoader -import app.revanced.patcher.annotation.Package -import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages -import app.revanced.patcher.extensions.PatchExtensions.description -import app.revanced.patcher.extensions.PatchExtensions.options -import app.revanced.patcher.extensions.PatchExtensions.patchName -import app.revanced.patcher.patch.PatchClass -import app.revanced.patcher.patch.PatchOption +import app.revanced.patcher.patch.Patch +import app.revanced.patcher.patch.options.PatchOption import picocli.CommandLine.* import picocli.CommandLine.Help.Visibility.ALWAYS import java.io.File @@ -48,11 +43,11 @@ internal object ListPatchesCommand : Runnable { private var withOptions: Boolean = false override fun run() { - fun Package.buildString() = buildString { - if (withVersions && versions.isNotEmpty()) { + fun Patch.CompatiblePackage.buildString() = buildString { + if (withVersions && versions != null) { appendLine("Package name: $name") appendLine("Compatible versions:") - append(versions.joinToString("\n") { version -> version }.prependIndent("\t")) + append(versions!!.joinToString("\n") { version -> version }.prependIndent("\t")) } else append("Package name: $name") } @@ -66,15 +61,17 @@ internal object ListPatchesCommand : Runnable { } ?: append("Key: $key") } - fun PatchClass.buildString() = buildString { - append("Name: $patchName") + fun Patch<*>.buildString() = buildString { + append("Name: $name") if (withDescriptions) append("\nDescription: $description") - if (withOptions && options != null) { + if (withOptions && options.isNotEmpty()) { appendLine("\nOptions:") append( - options!!.joinToString("\n\n") { option -> option.buildString() }.prependIndent("\t") + options.values.joinToString("\n\n") { option -> + option.buildString() + }.prependIndent("\t") ) } diff --git a/src/main/kotlin/app/revanced/cli/command/MainCommand.kt b/src/main/kotlin/app/revanced/cli/command/MainCommand.kt index 99ac1b1..5d71526 100644 --- a/src/main/kotlin/app/revanced/cli/command/MainCommand.kt +++ b/src/main/kotlin/app/revanced/cli/command/MainCommand.kt @@ -1,7 +1,6 @@ package app.revanced.cli.command import app.revanced.cli.command.utility.UtilityCommand -import app.revanced.patcher.patch.PatchClass import picocli.CommandLine import picocli.CommandLine.Command import picocli.CommandLine.IVersionProvider @@ -40,8 +39,6 @@ fun main(args: Array) { CommandLine(MainCommand).execute(*args) } -internal typealias PatchList = List - private object CLIVersionProvider : IVersionProvider { override fun getVersion(): Array { Properties().apply { diff --git a/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt b/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt index 9d3796c..c446a2c 100644 --- a/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt +++ b/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt @@ -1,12 +1,6 @@ package app.revanced.cli.command -import app.revanced.patcher.PatchBundleLoader -import app.revanced.patcher.Patcher -import app.revanced.patcher.PatcherOptions -import app.revanced.patcher.PatcherResult -import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages -import app.revanced.patcher.extensions.PatchExtensions.include -import app.revanced.patcher.extensions.PatchExtensions.patchName +import app.revanced.patcher.* import app.revanced.utils.Options import app.revanced.utils.Options.setOptions import app.revanced.utils.adb.AdbManager @@ -187,9 +181,9 @@ internal object PatchCommand : Runnable { patchResult.exception?.let { StringWriter().use { writer -> it.printStackTrace(PrintWriter(writer)) - logger.severe("${patchResult.patchName} failed: $writer") + logger.severe("${patchResult.patch.name} failed: $writer") } - } ?: logger.info("${patchResult.patchName} succeeded") + } ?: logger.info("${patchResult.patch.name} succeeded") } } }.get() @@ -231,7 +225,7 @@ internal object PatchCommand : Runnable { * @param patches The patches to filter. * @return The filtered patches. */ - private fun Patcher.filterPatchSelection(patches: PatchList) = buildList { + private fun Patcher.filterPatchSelection(patches: PatchSet) = buildList { // TODO: Remove this eventually because // patches named "patch-name" and "patch name" will conflict. fun String.format() = lowercase().replace(" ", "-") @@ -243,39 +237,41 @@ internal object PatchCommand : Runnable { val packageVersion = context.packageMetadata.packageVersion patches.forEach patch@{ patch -> - val formattedPatchName = patch.patchName.format() + val patchName = patch.name!! + val formattedPatchName = patchName.format() val explicitlyExcluded = formattedExcludedPatches.contains(formattedPatchName) - if (explicitlyExcluded) return@patch logger.info("Excluding ${patch.patchName}") + if (explicitlyExcluded) return@patch logger.info("Excluding ${patchName}") // Make sure the patch is compatible with the supplied APK files package name and version. patch.compatiblePackages?.let { packages -> packages.singleOrNull { it.name == packageName }?.let { `package` -> - val matchesVersion = force || `package`.versions.let { - it.isEmpty() || it.any { version -> version == packageVersion } - } + val matchesVersion = force || `package`.versions?.let { + it.any { version -> version == packageVersion } + } ?: true if (!matchesVersion) return@patch logger.warning( - "${patch.patchName} is incompatible with version $packageVersion. " + "$patchName is incompatible with version $packageVersion. " + "This patch is only compatible with version " + packages.joinToString(";") { pkg -> - "${pkg.name}: ${pkg.versions.joinToString(", ")}" + "${pkg.name}: ${pkg.versions!!.joinToString(", ")}" } ) - } ?: return@patch logger.fine("${patch.patchName} is incompatible with $packageName. " + } ?: return@patch logger.fine( + "$patchName is incompatible with $packageName. " + "This patch is only compatible with " + packages.joinToString(", ") { `package` -> `package`.name }) return@let } ?: logger.fine("$formattedPatchName: No constraint on packages.") - // If the patch is implicitly included, it will be only included if [exclusive] is false. - val implicitlyIncluded = !exclusive && patch.include - // If the patch is explicitly included, it will be included even if [exclusive] is false. + // 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 = formattedIncludedPatches.contains(formattedPatchName) val included = implicitlyIncluded || explicitlyIncluded - if (!included) return@patch logger.info("${patch.patchName} excluded by default") // Case 1. + if (!included) return@patch logger.info("$patchName excluded by default") // Case 1. logger.fine("Adding $formattedPatchName") diff --git a/src/main/kotlin/app/revanced/utils/Options.kt b/src/main/kotlin/app/revanced/utils/Options.kt index 408e203..7891d4a 100644 --- a/src/main/kotlin/app/revanced/utils/Options.kt +++ b/src/main/kotlin/app/revanced/utils/Options.kt @@ -1,9 +1,8 @@ package app.revanced.utils -import app.revanced.cli.command.PatchList -import app.revanced.patcher.extensions.PatchExtensions.options -import app.revanced.patcher.extensions.PatchExtensions.patchName -import app.revanced.patcher.patch.NoSuchOptionException + +import app.revanced.patcher.PatchSet +import app.revanced.patcher.patch.options.PatchOptionException import app.revanced.utils.Options.PatchOption.Option import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import java.io.File @@ -21,14 +20,13 @@ internal object Options { * @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 } + fun serialize(patches: PatchSet, prettyPrint: Boolean = false): String = patches + .filter { it.options.any() } .map { patch -> PatchOption( - patch.patchName, - patch.options!!.map { option -> Option(option.key, option.value) } + patch.name!!, + patch.options.values.map { option -> Option(option.key, option.value) } ) } // See https://github.com/revanced/revanced-patches/pull/2434/commits/60e550550b7641705e81aa72acfc4faaebb225e7. @@ -56,23 +54,19 @@ internal object Options { * * @param json The JSON string containing the options. */ - fun PatchList.setOptions(json: String) { - filter { it.options?.any() == true }.let { patches -> + fun PatchSet.setOptions(json: String) { + filter { it.options.any() }.let { patches -> if (patches.isEmpty()) return val patchOptions = deserialize(json) patches.forEach patch@{ patch -> - patchOptions.find { option -> option.patchName == patch.patchName }?.let { + patchOptions.find { option -> option.patchName == patch.name!! }?.let { it.options.forEach { option -> try { - patch.options?.set(option.key, option.value) - ?: run{ - logger.warning("${patch.patchName} has no options") - return@patch - } - } catch (e: NoSuchOptionException) { - logger.info(e.toString()) + patch.options[option.key] = option.value + } catch (e: PatchOptionException) { + logger.severe(e.toString()) } } } @@ -86,7 +80,7 @@ internal object Options { * @param file The file containing the JSON string containing the options. * @see setOptions */ - fun PatchList.setOptions(file: File) = setOptions(file.readText()) + fun PatchSet.setOptions(file: File) = setOptions(file.readText()) /** * Data class for a patch and its [Option]s. diff --git a/src/test/kotlin/app/revanced/patcher/options/PatchOptionOptionsTest.kt b/src/test/kotlin/app/revanced/patcher/options/PatchOptionOptionsTest.kt index 9abfca5..9988e5b 100644 --- a/src/test/kotlin/app/revanced/patcher/options/PatchOptionOptionsTest.kt +++ b/src/test/kotlin/app/revanced/patcher/options/PatchOptionOptionsTest.kt @@ -1,11 +1,9 @@ package app.revanced.patcher.options import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.data.Context import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.OptionsContainer -import app.revanced.patcher.patch.Patch -import app.revanced.patcher.patch.PatchOption +import app.revanced.patcher.patch.options.types.BooleanPatchOption.Companion.booleanPatchOption +import app.revanced.patcher.patch.options.types.StringPatchOption.Companion.stringPatchOption import app.revanced.utils.Options import app.revanced.utils.Options.setOptions import org.junit.jupiter.api.MethodOrderer @@ -13,29 +11,19 @@ import org.junit.jupiter.api.Order import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestMethodOrder -class PatchOptionsTestPatch : BytecodePatch() { + +object PatchOptionsTestPatch : BytecodePatch(name = "PatchOptionsTestPatch") { + var key1 by stringPatchOption("key1", null, "title1", "description1") + var key2 by booleanPatchOption("key2", true, "title2", "description2") + override fun execute(context: BytecodeContext) { // Do nothing } - - companion object : OptionsContainer() { - var key1 by option( - PatchOption.StringOption( - "key1", null, "title1", "description1" - ) - ) - - var key2 by option( - PatchOption.BooleanOption( - "key2", true, "title2", "description2" - ) - ) - } } @TestMethodOrder(MethodOrderer.OrderAnnotation::class) internal object PatchOptionOptionsTest { - private var patches = listOf(PatchOptionsTestPatch::class.java as Class>>) + private var patches = setOf(PatchOptionsTestPatch) @Test @Order(1)