Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow listing patches without other parameters #42

Merged
merged 2 commits into from
Jun 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 90 additions & 67 deletions src/main/kotlin/app/revanced/cli/command/MainCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,100 +8,123 @@ import app.revanced.patcher.util.patch.implementation.JarPatchBundle
import app.revanced.utils.adb.Adb
import picocli.CommandLine.Command
import picocli.CommandLine.Option
import picocli.CommandLine.ArgGroup
import java.io.File
import java.nio.file.Files

@Command(
name = "ReVanced-CLI", version = ["1.0.0"], mixinStandardHelpOptions = true,
)
internal object MainCommand : Runnable {
@Option(names = ["-a", "--apk"], description = ["Input file to be patched"], required = true)
lateinit var inputFile: File

@Option(names = ["-o", "--out"], description = ["Output file path"], required = true)
lateinit var outputPath: String

@Option(
names = ["-i", "--include"],
description = ["Which patches to include. If none is specified, all compatible default patches will be included"]
)
var includedPatches = arrayOf<String>()

@Option(names = ["-r", "--resource-patcher"], description = ["Disable patching resources"])
var disableResourcePatching: Boolean = false

@Option(names = ["--debugging"], description = ["Disable patch version compatibility"])
var debugging: Boolean = false

@Option(names = ["-m", "--merge"], description = ["One or more dex file containers to merge"])
var mergeFiles = listOf<File>()

@Option(names = ["-b", "--bundles"], description = ["One or more bundles of patches"])
var patchBundles = arrayOf<String>()

@Option(names = ["-l", "--list"], description = ["List patches only"])
var listOnly: Boolean = false

@Option(names = ["--install"], description = ["If specified, instead of mounting, install"])
var install: Boolean = false

@Option(names = ["--cn"], description = ["Overwrite the default CN for the signed file"])
var cn = "ReVanced"

@Option(names = ["-p", "--password"], description = ["Overwrite the default password for the signed file"])
var password = "ReVanced"

@Option(names = ["-d", "--deploy-on"], description = ["If specified, deploy to adb device with given name"])
var deploy: String? = null

@Option(names = ["-t", "--temp-dir"], description = ["Temporal resource cache directory"])
var cacheDirectory = "revanced-cache"

@Option(
names = ["-c", "--clean"],
description = ["Clean the temporal resource cache directory. This will be done anyways when running the patcher"]
)
var clean: Boolean = false

override fun run() {
if (listOnly) {
for (patchBundlePath in patchBundles) for (patch in JarPatchBundle(patchBundlePath).loadPatches()) {
println("[available] ${patch.patchName}")
}
return
}

val patcher = app.revanced.patcher.Patcher(PatcherOptions(inputFile, cacheDirectory, !disableResourcePatching))

val outputFile = File(outputPath)

val adb: Adb? = deploy?.let {
Adb(outputFile, patcher.data.packageMetadata.packageName, deploy!!, install)
@ArgGroup(exclusive = false, multiplicity="1")
lateinit var args: Args

class Args
{
@Option(names = ["-b", "--bundles"], description = ["One or more bundles of patches"], required = true)
var patchBundles = arrayOf<String>()

@ArgGroup(exclusive = false)
lateinit var lArgs: ListingArgs

@ArgGroup(exclusive = false)
lateinit var pArgs: PatchingArgs
}

class ListingArgs {
@Option(names = ["-l", "--list"], description = ["List patches only"], required = true)
public var listOnly: Boolean = false
}

class PatchingArgs {
@Option(names = ["-a", "--apk"], description = ["Input file to be patched"], required = true)
lateinit var inputFile: File

@Option(names = ["-o", "--out"], description = ["Output file path"], required = true)
lateinit var outputPath: String

@Option(
names = ["-i", "--include"],
description = ["Which patches to include. If none is specified, all compatible default patches will be included"]
)
var includedPatches = arrayOf<String>()

@Option(names = ["-r", "--resource-patcher"], description = ["Disable patching resources"])
var disableResourcePatching: Boolean = false

@Option(names = ["--debugging"], description = ["Disable patch version compatibility"])
var debugging: Boolean = false

@Option(names = ["-m", "--merge"], description = ["One or more dex file containers to merge"])
var mergeFiles = listOf<File>()

@Option(names = ["--install"], description = ["If specified, instead of mounting, install"])
var install: Boolean = false

@Option(names = ["--cn"], description = ["Overwrite the default CN for the signed file"])
var cn = "ReVanced"

@Option(names = ["-p", "--password"], description = ["Overwrite the default password for the signed file"])
var password = "ReVanced"

@Option(names = ["-d", "--deploy-on"], description = ["If specified, deploy to adb device with given name"])
var deploy: String? = null

@Option(names = ["-t", "--temp-dir"], description = ["Temporal resource cache directory"])
var cacheDirectory = "revanced-cache"

@Option(
names = ["-c", "--clean"],
description = ["Clean the temporal resource cache directory. This will be done anyways when running the patcher"]
)
var clean: Boolean = false
}

override fun run() {
try
{
if (args.lArgs.listOnly) {
for (patchBundlePath in args.patchBundles) for (patch in JarPatchBundle(patchBundlePath).loadPatches()) {
println("[available] ${patch.patchName}")
}
return
}
} catch (e: UninitializedPropertyAccessException) {}

val args = args.pArgs;

val patcher = app.revanced.patcher.Patcher(PatcherOptions(args.inputFile, args.cacheDirectory, !args.disableResourcePatching))

val outputFile = File(args.outputPath)

val adb: Adb? = args.deploy?.let {
Adb(outputFile, patcher.data.packageMetadata.packageName, args.deploy!!, args.install)
}

val patchedFile = if (install) File(cacheDirectory).resolve("${outputFile.nameWithoutExtension}_raw.apk") else outputFile
val patchedFile = if (args.install) File(args.cacheDirectory).resolve("${outputFile.nameWithoutExtension}_raw.apk") else outputFile

Patcher.start(patcher, patchedFile)

println("[aligning & signing]")

if (install) {
if (args.install) {
Signing.start(
patchedFile,
outputFile,
cn,
password,
args.cn,
args.password,
)
}

if (clean) File(cacheDirectory).deleteRecursively()
if (args.clean) File(args.cacheDirectory).deleteRecursively()

adb?.let {
println("[deploying]")
it.deploy()
}

if (clean && deploy != null) Files.delete(outputFile.toPath())
if (args.clean && args.deploy != null) Files.delete(outputFile.toPath())

println("[done]")
}
Expand Down
15 changes: 7 additions & 8 deletions src/main/kotlin/app/revanced/cli/patcher/Patcher.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package app.revanced.cli.patcher

import app.revanced.cli.command.MainCommand.cacheDirectory
import app.revanced.cli.command.MainCommand.disableResourcePatching
import app.revanced.cli.command.MainCommand
import app.revanced.cli.command.MainCommand.includedPatches
import app.revanced.cli.command.MainCommand.args
import app.revanced.utils.filesystem.ZipFileSystemUtils
import app.revanced.utils.patcher.addPatchesFiltered
import app.revanced.utils.patcher.applyPatchesVerbose
Expand All @@ -13,16 +10,18 @@ import java.nio.file.Files

internal object Patcher {
internal fun start(patcher: app.revanced.patcher.Patcher, output: File) {
val args = args.pArgs;

// merge files like necessary integrations
patcher.mergeFiles()
// add patches, but filter incompatible or excluded patches
patcher.addPatchesFiltered(includeFilter = includedPatches.isNotEmpty())
patcher.addPatchesFiltered(includeFilter = args.includedPatches.isNotEmpty())
// apply patches
patcher.applyPatchesVerbose()

// write output file
if (output.exists()) Files.delete(output.toPath())
MainCommand.inputFile.copyTo(output)
args.inputFile.copyTo(output)

ZipFileSystemUtils(output).use { fileSystem ->
// replace all dex files
Expand All @@ -32,8 +31,8 @@ internal object Patcher {
}

// write resources
if (!disableResourcePatching) {
fileSystem.writePathRecursively(File(cacheDirectory).resolve("build").toPath())
if (!args.disableResourcePatching) {
fileSystem.writePathRecursively(File(args.cacheDirectory).resolve("build").toPath())
fileSystem.uncompress(*result.doNotCompress!!.toTypedArray())
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/app/revanced/cli/signing/Signing.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package app.revanced.cli.signing

import app.revanced.cli.command.MainCommand.cacheDirectory
import app.revanced.cli.command.MainCommand.args
import app.revanced.utils.signing.Signer
import app.revanced.utils.signing.align.ZipAligner
import java.io.File

object Signing {
fun start(inputFile: File, outputFile: File, cn: String, password: String) {
val cacheDirectory = File(cacheDirectory)
val cacheDirectory = File(args.pArgs.cacheDirectory)
val alignedOutput = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_aligned.apk")
val signedOutput = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_signed.apk")

Expand Down
15 changes: 8 additions & 7 deletions src/main/kotlin/app/revanced/utils/patcher/Patcher.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package app.revanced.utils.patcher

import app.revanced.cli.command.MainCommand
import app.revanced.cli.command.MainCommand.debugging
import app.revanced.cli.command.MainCommand.patchBundles
import app.revanced.cli.command.MainCommand.args
import app.revanced.patcher.Patcher
import app.revanced.patcher.data.base.Data
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
Expand All @@ -17,16 +16,18 @@ fun Patcher.addPatchesFiltered(
val packageName = this.data.packageMetadata.packageName
val packageVersion = this.data.packageMetadata.packageVersion

patchBundles.forEach { bundle ->
MainCommand.args.patchBundles.forEach { bundle ->
val includedPatches = mutableListOf<Class<out Patch<Data>>>()
JarPatchBundle(bundle).loadPatches().forEach patch@{ patch ->
val compatiblePackages = patch.compatiblePackages
val patchName = patch.patchName

val prefix = "[skipped] $patchName"

val args = MainCommand.args.pArgs

if (includeFilter) {
if (!MainCommand.includedPatches.contains(patchName)) {
if (!args.includedPatches.contains(patchName)) {
println("$prefix: Explicitly excluded.")
return@patch
}
Expand All @@ -42,7 +43,7 @@ fun Patcher.addPatchesFiltered(
return@patch
}

if (!(debugging || compatiblePackages.any { it.versions.isEmpty() || it.versions.any { version -> version == packageVersion }})) {
if (!(args.debugging || compatiblePackages.any { it.versions.isEmpty() || it.versions.any { version -> version == packageVersion }})) {
println("$prefix: The package version is $packageVersion and is incompatible.")
return@patch
}
Expand All @@ -67,5 +68,5 @@ fun Patcher.applyPatchesVerbose() {
}

fun Patcher.mergeFiles() {
this.addFiles(MainCommand.mergeFiles)
}
this.addFiles(MainCommand.args.pArgs.mergeFiles)
}