diff --git a/build.gradle.kts b/build.gradle.kts index 85d5664..5621648 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -42,6 +42,11 @@ dependencies { kotlin { compilerOptions { jvmTarget.set(JvmTarget.JVM_11) + + freeCompilerArgs.addAll( + "-Xexplicit-backing-fields", + "-Xcontext-parameters", + ) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 341a95b..3d6c116 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ bcpg-jdk18on = { module = "org.bouncycastle:bcpg-jdk18on", version.ref = "bcpg-j kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx" } picocli = { module = "info.picocli:picocli", version.ref = "picocli" } -revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" } +revanced-patcher = { module = "app.revanced:patcher", version.ref = "revanced-patcher" } revanced-library = { module = "app.revanced:revanced-library-jvm", version.ref = "revanced-library" } sigstore-java = { module = "dev.sigstore:sigstore-java", version.ref = "sigstore" } diff --git a/src/main/kotlin/app/revanced/cli/command/ListCompatibleVersions.kt b/src/main/kotlin/app/revanced/cli/command/ListCompatibleVersions.kt index aed66e9..25033e8 100644 --- a/src/main/kotlin/app/revanced/cli/command/ListCompatibleVersions.kt +++ b/src/main/kotlin/app/revanced/cli/command/ListCompatibleVersions.kt @@ -3,7 +3,7 @@ package app.revanced.cli.command import app.revanced.library.PackageName import app.revanced.library.VersionMap import app.revanced.library.mostCommonCompatibleVersions -import app.revanced.patcher.patch.loadPatchesFromJar +import app.revanced.patcher.patch.loadPatches import picocli.CommandLine import java.io.File import java.util.logging.Logger @@ -48,15 +48,14 @@ internal class ListCompatibleVersions : Runnable { } } - fun buildString(entry: Map.Entry) = - buildString { - val (name, versions) = entry - appendLine("Package name: $name") - appendLine("Most common compatible versions:") - appendLine(versions.buildVersionsString().prependIndent("\t")) - } + fun buildString(entry: Map.Entry) = buildString { + val (name, versions) = entry + appendLine("Package name: $name") + appendLine("Most common compatible versions:") + appendLine(versions.buildVersionsString().prependIndent("\t")) + } - val patches = loadPatchesFromJar(patchesFiles) + val patches = loadPatches(patchesFiles = patchesFiles.toTypedArray()) patches.mostCommonCompatibleVersions( packageNames, diff --git a/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt b/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt index 231017a..e8c6b43 100644 --- a/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt +++ b/src/main/kotlin/app/revanced/cli/command/ListPatchesCommand.kt @@ -2,7 +2,7 @@ package app.revanced.cli.command import app.revanced.patcher.patch.Package import app.revanced.patcher.patch.Patch -import app.revanced.patcher.patch.loadPatchesFromJar +import app.revanced.patcher.patch.loadPatches import picocli.CommandLine.* import picocli.CommandLine.Help.Visibility.ALWAYS import java.io.File @@ -86,13 +86,10 @@ internal object ListPatchesCommand : Runnable { } fun PatchOption<*>.buildString() = buildString { - appendLine("Title: $title") + appendLine("Name: $name") description?.let { appendLine("Description: $it") } appendLine("Required: $required") - default?.let { - appendLine("Key: $key") - append("Default: $it") - } ?: append("Key: $key") + default?.let { append("Default: $it") } values?.let { values -> appendLine("\nPossible values:") @@ -102,7 +99,7 @@ internal object ListPatchesCommand : Runnable { append("\nType: $type") } - fun IndexedValue>.buildString() = let { (index, patch) -> + fun IndexedValue.buildString() = let { (index, patch) -> buildString { if (withIndex) appendLine("Index: $index") @@ -132,10 +129,10 @@ internal object ListPatchesCommand : Runnable { } } - fun Patch<*>.filterCompatiblePackages(name: String) = compatiblePackages?.any { (compatiblePackageName, _) -> compatiblePackageName == name } + fun Patch.filterCompatiblePackages(name: String) = compatiblePackages?.any { (compatiblePackageName, _) -> compatiblePackageName == name } ?: withUniversalPatches - val patches = loadPatchesFromJar(patchesFiles).withIndex().toList() + val patches = loadPatches(patchesFiles = patchesFiles.toTypedArray()).withIndex().toList() val filtered = packageName?.let { patches.filter { (_, patch) -> patch.filterCompatiblePackages(it) } } ?: patches diff --git a/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt b/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt index ba6b044..99d1a3b 100644 --- a/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt +++ b/src/main/kotlin/app/revanced/cli/command/PatchCommand.kt @@ -4,10 +4,9 @@ import app.revanced.library.ApkUtils import app.revanced.library.ApkUtils.applyTo import app.revanced.library.installation.installer.* import app.revanced.library.setOptions -import app.revanced.patcher.Patcher -import app.revanced.patcher.PatcherConfig import app.revanced.patcher.patch.Patch -import app.revanced.patcher.patch.loadPatchesFromJar +import app.revanced.patcher.patch.loadPatches +import app.revanced.patcher.patcher import kotlinx.coroutines.runBlocking import picocli.CommandLine import picocli.CommandLine.ArgGroup @@ -123,7 +122,7 @@ internal object PatchCommand : Runnable { names = ["-i", "--install"], required = true, description = ["Serial of the ADB device to install to. If not specified, the first connected device will be used."], - fallbackValue = "", // Empty string is used to select the first of connected devices. + fallbackValue = "", // Empty string is used to select the first of connected devices. arity = "0..1", ) internal var deviceSerial: String? = null @@ -260,7 +259,7 @@ internal object PatchCommand : Runnable { } else { AdbInstaller(deviceSerial) } - } catch (e: DeviceNotFoundException) { + } catch (_: DeviceNotFoundException) { if (deviceSerial?.isNotEmpty() == true) { logger.severe( "Device with serial $deviceSerial not found to install to. " + @@ -285,62 +284,59 @@ internal object PatchCommand : Runnable { logger.info("Loading patches") - val patches = loadPatchesFromJar(patchesFiles) + val patches = loadPatches(patchesFiles = patchesFiles.toTypedArray()) { file, throwable -> + logger.severe("Failed to load patches from ${file.path}:\n$throwable") + } // endregion val patcherTemporaryFilesPath = temporaryFilesPath.resolve("patcher") - val (packageName, patcherResult) = Patcher( - PatcherConfig( - apk, - patcherTemporaryFilesPath, - aaptBinaryPath?.path, - patcherTemporaryFilesPath.absolutePath, - ), - ).use { patcher -> - val packageName = patcher.context.packageMetadata.packageName - val packageVersion = patcher.context.packageMetadata.packageVersion + lateinit var capturedPackageName: String - val filteredPatches = patches.filterPatchSelection(packageName, packageVersion) + val patch = patcher( + apk, + patcherTemporaryFilesPath, + aaptBinaryPath, + patcherTemporaryFilesPath.absolutePath, + ) { packageName, versionName -> + capturedPackageName = packageName + + val filteredPatches = patches.filterPatchSelection(packageName, versionName) logger.info("Setting patch options") val patchesList = patches.toList() + selection.filter { it.enabled != null }.associate { val enabledSelection = it.enabled!! + val name = enabledSelection.selector.name ?: patchesList[enabledSelection.selector.index!!].name!! - (enabledSelection.selector.name ?: patchesList[enabledSelection.selector.index!!].name!!) to - enabledSelection.options + name to enabledSelection.options }.let(filteredPatches::setOptions) - patcher += filteredPatches + filteredPatches + } - // Execute patches. - runBlocking { - patcher().collect { patchResult -> - val exception = patchResult.exception - ?: return@collect logger.info("\"${patchResult.patch}\" succeeded") + val patchesResult = patch { patchResult -> + val exception = patchResult.exception + ?: return@patch logger.info("\"${patchResult.patch}\" succeeded") - StringWriter().use { writer -> - exception.printStackTrace(PrintWriter(writer)) + StringWriter().use { writer -> + exception.printStackTrace(PrintWriter(writer)) - logger.severe("\"${patchResult.patch}\" failed:\n$writer") - } - } + logger.severe("\"${patchResult.patch}\" failed:\n$writer") } - - patcher.context.packageMetadata.packageName to patcher.get() } // region Save. - apk.copyTo(temporaryFilesPath.resolve(apk.name), overwrite = true).apply { - patcherResult.applyTo(this) - }.let { patchedApkFile -> + apk.copyTo(temporaryFilesPath.resolve(apk.name), overwrite = true).let { + patchesResult.applyTo(it) + if (installation?.mount != true) { ApkUtils.signApk( - patchedApkFile, + it, outputFilePath, signer, ApkUtils.KeyStoreDetails( @@ -351,7 +347,7 @@ internal object PatchCommand : Runnable { ), ) } else { - patchedApkFile.copyTo(outputFilePath, overwrite = true) + it.copyTo(outputFilePath, overwrite = true) } } @@ -363,7 +359,7 @@ internal object PatchCommand : Runnable { installation?.deviceSerial?.let { runBlocking { - when (val result = installer!!.install(Installer.Apk(outputFilePath, packageName))) { + when (val result = installer!!.install(Installer.Apk(outputFilePath, capturedPackageName))) { RootInstallerResult.FAILURE -> logger.severe("Failed to mount the patched APK file") is AdbInstallerResult.Failure -> logger.severe(result.exception.toString()) else -> logger.info("Installed the patched APK file") @@ -386,10 +382,10 @@ internal object PatchCommand : Runnable { * @param packageVersion The version of the APK file to be patched. * @return The filtered patches. */ - private fun Set>.filterPatchSelection( + private fun Set.filterPatchSelection( packageName: String, packageVersion: String, - ): Set> = buildSet { + ) = buildSet { val enabledPatchesByName = selection.mapNotNull { it.enabled?.selector?.name }.toSet() val enabledPatchesByIndex =