mirror of
https://github.com/revanced/revanced-cli.git
synced 2024-08-25 08:40:50 +02:00
build: Refactor to DSL to bump ReVanced Patcher
This commit is contained in:
parent
40279e0369
commit
51773f30bc
@ -3,7 +3,7 @@ package app.revanced.cli.command
|
||||
import app.revanced.library.PackageName
|
||||
import app.revanced.library.PatchUtils
|
||||
import app.revanced.library.VersionMap
|
||||
import app.revanced.patcher.PatchBundleLoader
|
||||
import app.revanced.patcher.patch.loadPatchesFromJar
|
||||
import picocli.CommandLine
|
||||
import java.io.File
|
||||
import java.util.logging.Logger
|
||||
@ -22,7 +22,7 @@ internal class ListCompatibleVersions : Runnable {
|
||||
description = ["Paths to patch bundles."],
|
||||
arity = "1..*",
|
||||
)
|
||||
private lateinit var patchBundles: Array<File>
|
||||
private lateinit var patchBundles: Set<File>
|
||||
|
||||
@CommandLine.Option(
|
||||
names = ["-f", "--filter-package-names"],
|
||||
@ -38,8 +38,6 @@ internal class ListCompatibleVersions : Runnable {
|
||||
private var countUnusedPatches: Boolean = false
|
||||
|
||||
override fun run() {
|
||||
val patches = PatchBundleLoader.Jar(*patchBundles)
|
||||
|
||||
fun VersionMap.buildVersionsString(): String {
|
||||
if (isEmpty()) return "Any"
|
||||
|
||||
@ -58,6 +56,8 @@ internal class ListCompatibleVersions : Runnable {
|
||||
appendLine(versions.buildVersionsString().prependIndent("\t"))
|
||||
}
|
||||
|
||||
val patches = loadPatchesFromJar(patchBundles)
|
||||
|
||||
PatchUtils.getMostCommonCompatibleVersions(
|
||||
patches,
|
||||
packageNames,
|
||||
|
@ -1,12 +1,13 @@
|
||||
package app.revanced.cli.command
|
||||
|
||||
import app.revanced.patcher.PatchBundleLoader
|
||||
import app.revanced.patcher.patch.Package
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.options.PatchOption
|
||||
import app.revanced.patcher.patch.loadPatchesFromJar
|
||||
import picocli.CommandLine.*
|
||||
import picocli.CommandLine.Help.Visibility.ALWAYS
|
||||
import java.io.File
|
||||
import java.util.logging.Logger
|
||||
import app.revanced.patcher.patch.Option as PatchOption
|
||||
|
||||
@Command(
|
||||
name = "list-patches",
|
||||
@ -19,7 +20,7 @@ internal object ListPatchesCommand : Runnable {
|
||||
description = ["Paths to patch bundles."],
|
||||
arity = "1..*",
|
||||
)
|
||||
private lateinit var patchBundles: Array<File>
|
||||
private lateinit var patchBundles: Set<File>
|
||||
|
||||
@Option(
|
||||
names = ["-d", "--with-descriptions"],
|
||||
@ -70,16 +71,19 @@ internal object ListPatchesCommand : Runnable {
|
||||
private var packageName: String? = null
|
||||
|
||||
override fun run() {
|
||||
fun Patch.CompatiblePackage.buildString() =
|
||||
buildString {
|
||||
fun Package.buildString(): String {
|
||||
val (name, versions) = this
|
||||
|
||||
return 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun PatchOption<*>.buildString() =
|
||||
buildString {
|
||||
@ -126,10 +130,10 @@ internal object ListPatchesCommand : Runnable {
|
||||
}
|
||||
|
||||
fun Patch<*>.filterCompatiblePackages(name: String) =
|
||||
compatiblePackages?.any { it.name == name }
|
||||
compatiblePackages?.any { (compatiblePackageName, _) -> compatiblePackageName == name }
|
||||
?: withUniversalPatches
|
||||
|
||||
val patches = PatchBundleLoader.Jar(*patchBundles).withIndex().toList()
|
||||
val patches = loadPatchesFromJar(patchBundles).withIndex().toList()
|
||||
|
||||
val filtered =
|
||||
packageName?.let { patches.filter { (_, patch) -> patch.filterCompatiblePackages(it) } } ?: patches
|
||||
|
@ -2,7 +2,7 @@ package app.revanced.cli.command
|
||||
|
||||
import app.revanced.library.Options
|
||||
import app.revanced.library.Options.setOptions
|
||||
import app.revanced.patcher.PatchBundleLoader
|
||||
import app.revanced.patcher.patch.loadPatchesFromJar
|
||||
import picocli.CommandLine
|
||||
import picocli.CommandLine.Help.Visibility.ALWAYS
|
||||
import java.io.File
|
||||
@ -19,7 +19,7 @@ internal object OptionsCommand : Runnable {
|
||||
description = ["Paths to patch bundles."],
|
||||
arity = "1..*",
|
||||
)
|
||||
private lateinit var patchBundles: Array<File>
|
||||
private lateinit var patchBundles: Set<File>
|
||||
|
||||
@CommandLine.Option(
|
||||
names = ["-p", "--path"],
|
||||
@ -44,7 +44,7 @@ internal object OptionsCommand : Runnable {
|
||||
|
||||
override fun run() =
|
||||
try {
|
||||
PatchBundleLoader.Jar(*patchBundles).let { patches ->
|
||||
loadPatchesFromJar(patchBundles).let { patches ->
|
||||
val exists = filePath.exists()
|
||||
if (!exists || overwrite) {
|
||||
if (exists && update) patches.setOptions(filePath)
|
||||
|
@ -4,11 +4,11 @@ import app.revanced.library.ApkUtils
|
||||
import app.revanced.library.ApkUtils.applyTo
|
||||
import app.revanced.library.Options
|
||||
import app.revanced.library.Options.setOptions
|
||||
import app.revanced.library.adb.AdbManager
|
||||
import app.revanced.patcher.PatchBundleLoader
|
||||
import app.revanced.patcher.PatchSet
|
||||
import app.revanced.library.installation.installer.*
|
||||
import app.revanced.patcher.Patcher
|
||||
import app.revanced.patcher.PatcherConfig
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.loadPatchesFromJar
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import picocli.CommandLine
|
||||
import picocli.CommandLine.Help.Visibility.ALWAYS
|
||||
@ -31,7 +31,7 @@ internal object PatchCommand : Runnable {
|
||||
|
||||
private lateinit var apk: File
|
||||
|
||||
private var integrations = setOf<File>()
|
||||
private var integrations = emptySet<File>()
|
||||
|
||||
private var patchBundles = emptySet<File>()
|
||||
|
||||
@ -193,7 +193,7 @@ internal object PatchCommand : Runnable {
|
||||
description = ["One or more DEX files or containers to merge into the APK."],
|
||||
)
|
||||
@Suppress("unused")
|
||||
private fun setIntegrations(integrations: Array<File>) {
|
||||
private fun setIntegrations(integrations: Set<File>) {
|
||||
integrations.firstOrNull { !it.exists() }?.let {
|
||||
throw CommandLine.ParameterException(spec.commandLine(), "Integrations file ${it.path} does not exist.")
|
||||
}
|
||||
@ -256,7 +256,7 @@ internal object PatchCommand : Runnable {
|
||||
|
||||
logger.info("Loading patches")
|
||||
|
||||
val patches = PatchBundleLoader.Jar(*patchBundles.toTypedArray())
|
||||
val patches = loadPatchesFromJar(patchBundles)
|
||||
|
||||
// Warn if a patch can not be found in the supplied patch bundles.
|
||||
if (warn) {
|
||||
@ -271,6 +271,7 @@ internal object PatchCommand : Runnable {
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
val patcherTemporaryFilesPath = temporaryFilesPath.resolve("patcher")
|
||||
val (packageName, patcherResult) = Patcher(
|
||||
PatcherConfig(
|
||||
@ -295,8 +296,7 @@ internal object PatchCommand : Runnable {
|
||||
// region Patch
|
||||
|
||||
patcher.context.packageMetadata.packageName to patcher.apply {
|
||||
acceptIntegrations(integrations)
|
||||
acceptPatches(filteredPatches)
|
||||
accept(filteredPatches, integrations)
|
||||
|
||||
// Execute patches.
|
||||
runBlocking {
|
||||
@ -304,16 +304,18 @@ internal object PatchCommand : Runnable {
|
||||
patchResult.exception?.let {
|
||||
StringWriter().use { writer ->
|
||||
it.printStackTrace(PrintWriter(writer))
|
||||
logger.severe("${patchResult.patch.name} failed:\n$writer")
|
||||
logger.severe("\"${patchResult.patch.name}\" failed:\n$writer")
|
||||
}
|
||||
} ?: logger.info("${patchResult.patch.name} succeeded")
|
||||
} ?: logger.info("\"${patchResult.patch.name}\" succeeded")
|
||||
}
|
||||
}
|
||||
}.get()
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
// region Save
|
||||
|
||||
apk.copyTo(temporaryFilesPath.resolve(apk.name), overwrite = true).apply {
|
||||
patcherResult.applyTo(this)
|
||||
}.let { patchedApkFile ->
|
||||
@ -340,9 +342,23 @@ internal object PatchCommand : Runnable {
|
||||
|
||||
// region Install
|
||||
|
||||
deviceSerial?.let { serial ->
|
||||
AdbManager.getAdbManager(deviceSerial = serial.ifEmpty { null }, mount)
|
||||
}?.install(AdbManager.Apk(outputFilePath, packageName))
|
||||
deviceSerial?.let { it ->
|
||||
val deviceSerial = it.ifEmpty { null }
|
||||
|
||||
runBlocking {
|
||||
val result = if (mount) {
|
||||
AdbRootInstaller(deviceSerial)
|
||||
} else {
|
||||
AdbInstaller(deviceSerial)
|
||||
}.install(Installer.Apk(outputFilePath, packageName))
|
||||
|
||||
when (result) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
@ -358,7 +374,7 @@ internal object PatchCommand : Runnable {
|
||||
* @param patches The patches to filter.
|
||||
* @return The filtered patches.
|
||||
*/
|
||||
private fun Patcher.filterPatchSelection(patches: PatchSet): PatchSet =
|
||||
private fun Patcher.filterPatchSelection(patches: Set<Patch<*>>): Set<Patch<*>> =
|
||||
buildSet {
|
||||
val packageName = context.packageMetadata.packageName
|
||||
val packageVersion = context.packageMetadata.packageVersion
|
||||
@ -367,33 +383,32 @@ internal object PatchCommand : Runnable {
|
||||
val patchName = patch.name!!
|
||||
|
||||
val explicitlyExcluded = excludedPatches.contains(patchName) || excludedPatchesByIndex.contains(i)
|
||||
if (explicitlyExcluded) return@patch logger.info("Excluding $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.any { version -> version == packageVersion }
|
||||
} ?: true
|
||||
packages.singleOrNull { (name, _) -> name == packageName }?.let { (_, versions) ->
|
||||
val matchesVersion = force ||
|
||||
versions?.let { it.any { version -> version == packageVersion } }
|
||||
?: true
|
||||
|
||||
if (!matchesVersion) {
|
||||
return@patch logger.warning(
|
||||
"$patchName is incompatible with version $packageVersion. " +
|
||||
"The patch \"$patchName\" is incompatible with version $packageVersion. " +
|
||||
"This patch is only compatible with version " +
|
||||
packages.joinToString(";") { pkg ->
|
||||
pkg.versions!!.joinToString(", ")
|
||||
packages.joinToString(";") { (_, versions) ->
|
||||
versions!!.joinToString(", ")
|
||||
},
|
||||
)
|
||||
}
|
||||
} ?: return@patch logger.fine(
|
||||
"$patchName is incompatible with $packageName. " +
|
||||
"The patch \"$patchName\" is incompatible with $packageName. " +
|
||||
"This patch is only compatible with " +
|
||||
packages.joinToString(", ") { `package` -> `package`.name },
|
||||
packages.joinToString(", ") { (name, _) -> name },
|
||||
)
|
||||
|
||||
return@let
|
||||
} ?: logger.fine("$patchName has no constraint on packages.")
|
||||
} ?: logger.fine("\"$patchName\" has no constraint on packages.")
|
||||
|
||||
// If the patch is implicitly used, it will be only included if [exclusive] is false.
|
||||
val implicitlyIncluded = !exclusive && patch.use
|
||||
@ -401,9 +416,9 @@ internal object PatchCommand : Runnable {
|
||||
val explicitlyIncluded = includedPatches.contains(patchName) || includedPatchesByIndex.contains(i)
|
||||
|
||||
val included = implicitlyIncluded || explicitlyIncluded
|
||||
if (!included) return@patch logger.info("$patchName excluded") // Case 1.
|
||||
if (!included) return@patch logger.info("\"$patchName\" excluded") // Case 1.
|
||||
|
||||
logger.fine("Adding $patchName")
|
||||
logger.fine("Adding \"$patchName\"")
|
||||
|
||||
add(patch)
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package app.revanced.cli.command.utility
|
||||
|
||||
import app.revanced.library.adb.AdbManager
|
||||
import app.revanced.library.installation.installer.*
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import picocli.CommandLine.*
|
||||
import java.io.File
|
||||
import java.util.logging.Logger
|
||||
@ -32,13 +35,29 @@ internal object InstallCommand : Runnable {
|
||||
private var packageName: String? = null
|
||||
|
||||
override fun run() {
|
||||
fun install(deviceSerial: String? = null) =
|
||||
try {
|
||||
AdbManager.getAdbManager(deviceSerial, packageName != null).install(AdbManager.Apk(apk, packageName))
|
||||
} catch (e: AdbManager.DeviceNotFoundException) {
|
||||
suspend fun install(deviceSerial: String? = null) {
|
||||
val result = try {
|
||||
if (packageName != null) {
|
||||
AdbRootInstaller(deviceSerial)
|
||||
} else {
|
||||
AdbInstaller(deviceSerial)
|
||||
}.install(Installer.Apk(apk, packageName))
|
||||
} catch (e: Exception) {
|
||||
logger.severe(e.toString())
|
||||
}
|
||||
|
||||
deviceSerials?.forEach(::install) ?: install()
|
||||
when (result) {
|
||||
RootInstallerResult.FAILURE ->
|
||||
logger.severe("Failed to mount the APK file")
|
||||
is AdbInstallerResult.Failure ->
|
||||
logger.severe(result.exception.toString())
|
||||
else ->
|
||||
logger.info("Installed the APK file")
|
||||
}
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
deviceSerials?.map { async { install(it) } }?.awaitAll() ?: install()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package app.revanced.cli.command.utility
|
||||
|
||||
import app.revanced.library.adb.AdbManager
|
||||
import app.revanced.library.installation.installer.*
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import picocli.CommandLine.*
|
||||
import picocli.CommandLine.Help.Visibility.ALWAYS
|
||||
import java.util.logging.Logger
|
||||
@ -33,13 +36,28 @@ internal object UninstallCommand : Runnable {
|
||||
private var unmount: Boolean = false
|
||||
|
||||
override fun run() {
|
||||
fun uninstall(deviceSerial: String? = null) =
|
||||
try {
|
||||
AdbManager.getAdbManager(deviceSerial, unmount).uninstall(packageName)
|
||||
} catch (e: AdbManager.DeviceNotFoundException) {
|
||||
suspend fun uninstall(deviceSerial: String? = null) {
|
||||
val result = try {
|
||||
if (unmount) {
|
||||
AdbRootInstaller(deviceSerial)
|
||||
} else {
|
||||
AdbInstaller(deviceSerial)
|
||||
}.uninstall(packageName)
|
||||
} catch (e: Exception) {
|
||||
logger.severe(e.toString())
|
||||
}
|
||||
|
||||
deviceSerials?.forEach { uninstall(it) } ?: uninstall()
|
||||
when (result) {
|
||||
RootInstallerResult.FAILURE ->
|
||||
logger.severe("Failed to unmount the patched APK file")
|
||||
is AdbInstallerResult.Failure ->
|
||||
logger.severe(result.exception.toString())
|
||||
else -> logger.info("Uninstalled the patched APK file")
|
||||
}
|
||||
}
|
||||
|
||||
runBlocking {
|
||||
deviceSerials?.map { async { uninstall(it) } }?.awaitAll() ?: uninstall()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user