chore: Lint code

This commit is contained in:
oSumAtrIX 2023-11-26 05:56:31 +01:00
parent e7c3d64bf1
commit 5fd205f77d
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
7 changed files with 202 additions and 180 deletions

View File

@ -8,119 +8,126 @@ import picocli.CommandLine.Help.Visibility.ALWAYS
import java.io.File import java.io.File
import java.util.logging.Logger import java.util.logging.Logger
@Command( @Command(
name = "list-patches", name = "list-patches",
description = ["List patches from supplied patch bundles."] description = ["List patches from supplied patch bundles."],
) )
internal object ListPatchesCommand : Runnable { internal object ListPatchesCommand : Runnable {
private val logger = Logger.getLogger(ListPatchesCommand::class.java.name) private val logger = Logger.getLogger(ListPatchesCommand::class.java.name)
@Parameters( @Parameters(
description = ["Paths to patch bundles."], description = ["Paths to patch bundles."],
arity = "1..*" arity = "1..*",
) )
private lateinit var patchBundles: Array<File> private lateinit var patchBundles: Array<File>
@Option( @Option(
names = ["-d", "--with-descriptions"], names = ["-d", "--with-descriptions"],
description = ["List their descriptions."], description = ["List their descriptions."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var withDescriptions: Boolean = true private var withDescriptions: Boolean = true
@Option( @Option(
names = ["-p", "--with-packages"], names = ["-p", "--with-packages"],
description = ["List the packages the patches are compatible with."], description = ["List the packages the patches are compatible with."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var withPackages: Boolean = false private var withPackages: Boolean = false
@Option( @Option(
names = ["-v", "--with-versions"], names = ["-v", "--with-versions"],
description = ["List the versions of the apps the patches are compatible with."], description = ["List the versions of the apps the patches are compatible with."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var withVersions: Boolean = false private var withVersions: Boolean = false
@Option( @Option(
names = ["-o", "--with-options"], names = ["-o", "--with-options"],
description = ["List the options of the patches."], description = ["List the options of the patches."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var withOptions: Boolean = false private var withOptions: Boolean = false
@Option( @Option(
names = ["-u", "--with-universal-patches"], names = ["-u", "--with-universal-patches"],
description = ["List patches which are compatible with any app."], description = ["List patches which are compatible with any app."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var withUniversalPatches: Boolean = true private var withUniversalPatches: Boolean = true
@Option( @Option(
names = ["-i", "--index"], names = ["-i", "--index"],
description = ["List the index of each patch in relation to the supplied patch bundles."], description = ["List the index of each patch in relation to the supplied patch bundles."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var withIndex: Boolean = true private var withIndex: Boolean = true
@Option( @Option(
names = ["-f", "--filter-package-name"], names = ["-f", "--filter-package-name"],
description = ["Filter patches by package name."] description = ["Filter patches by package name."],
) )
private var packageName: String? = null private var packageName: String? = null
override fun run() { override fun run() {
fun Patch.CompatiblePackage.buildString() = buildString { fun Patch.CompatiblePackage.buildString() =
if (withVersions && versions != null) {
appendLine("Package name: $name")
appendLine("Compatible versions:")
append(versions!!.joinToString("\n") { version -> version }.prependIndent("\t"))
} else append("Package name: $name")
}
fun PatchOption<*>.buildString() = buildString {
appendLine("Title: $title")
description?.let { appendLine("Description: $it") }
default?.let {
appendLine("Key: $key")
append("Default: $it")
} ?: append("Key: $key")
values?.let { values ->
appendLine("\nValid values:")
append(values.map { "${it.value} (${it.key})" }.joinToString("\n").prependIndent("\t"))
}
}
fun IndexedValue<Patch<*>>.buildString() = let { (index, patch) ->
buildString { buildString {
if (withIndex) appendLine("Index: $index") if (withVersions && versions != null) {
appendLine("Package name: $name")
append("Name: ${patch.name}") appendLine("Compatible versions:")
append(versions!!.joinToString("\n") { version -> version }.prependIndent("\t"))
if (withDescriptions) append("\nDescription: ${patch.description}") } else {
append("Package name: $name")
if (withOptions && patch.options.isNotEmpty()) {
appendLine("\nOptions:")
append(
patch.options.values.joinToString("\n\n") { option ->
option.buildString()
}.prependIndent("\t")
)
}
if (withPackages && patch.compatiblePackages != null) {
appendLine("\nCompatible packages:")
append(patch.compatiblePackages!!.joinToString("\n") {
it.buildString()
}.prependIndent("\t"))
} }
} }
}
fun Patch<*>.filterCompatiblePackages(name: String) = compatiblePackages?.any { it.name == name } fun PatchOption<*>.buildString() =
?: withUniversalPatches buildString {
appendLine("Title: $title")
description?.let { appendLine("Description: $it") }
default?.let {
appendLine("Key: $key")
append("Default: $it")
} ?: append("Key: $key")
values?.let { values ->
appendLine("\nValid values:")
append(values.map { "${it.value} (${it.key})" }.joinToString("\n").prependIndent("\t"))
}
}
fun IndexedValue<Patch<*>>.buildString() =
let { (index, patch) ->
buildString {
if (withIndex) appendLine("Index: $index")
append("Name: ${patch.name}")
if (withDescriptions) append("\nDescription: ${patch.description}")
if (withOptions && patch.options.isNotEmpty()) {
appendLine("\nOptions:")
append(
patch.options.values.joinToString("\n\n") { option ->
option.buildString()
}.prependIndent("\t"),
)
}
if (withPackages && patch.compatiblePackages != null) {
appendLine("\nCompatible packages:")
append(
patch.compatiblePackages!!.joinToString("\n") {
it.buildString()
}.prependIndent("\t"),
)
}
}
}
fun Patch<*>.filterCompatiblePackages(name: String) =
compatiblePackages?.any { it.name == name }
?: withUniversalPatches
val patches = PatchBundleLoader.Jar(*patchBundles).withIndex().toList() val patches = PatchBundleLoader.Jar(*patchBundles).withIndex().toList()
@ -129,4 +136,4 @@ internal object ListPatchesCommand : Runnable {
if (filtered.isNotEmpty()) logger.info(filtered.joinToString("\n\n") { it.buildString() }) if (filtered.isNotEmpty()) logger.info(filtered.joinToString("\n\n") { it.buildString() })
} }
} }

View File

@ -7,23 +7,24 @@ import picocli.CommandLine.Command
import picocli.CommandLine.IVersionProvider import picocli.CommandLine.IVersionProvider
import java.util.* import java.util.*
fun main(args: Array<String>) { fun main(args: Array<String>) {
Logger.setDefault() Logger.setDefault()
CommandLine(MainCommand).execute(*args).let(System::exit) CommandLine(MainCommand).execute(*args).let(System::exit)
} }
private object CLIVersionProvider : IVersionProvider { private object CLIVersionProvider : IVersionProvider {
override fun getVersion() = arrayOf( override fun getVersion() =
MainCommand::class.java.getResourceAsStream( arrayOf(
"/app/revanced/cli/version.properties" MainCommand::class.java.getResourceAsStream(
)?.use { stream -> "/app/revanced/cli/version.properties",
Properties().apply { )?.use { stream ->
load(stream) Properties().apply {
}.let { load(stream)
"ReVanced CLI v${it.getProperty("version")}" }.let {
} "ReVanced CLI v${it.getProperty("version")}"
} ?: "ReVanced CLI") }
} ?: "ReVanced CLI",
)
} }
@Command( @Command(
@ -36,6 +37,6 @@ private object CLIVersionProvider : IVersionProvider {
PatchCommand::class, PatchCommand::class,
OptionsCommand::class, OptionsCommand::class,
UtilityCommand::class, UtilityCommand::class,
] ],
) )
private object MainCommand private object MainCommand

View File

@ -17,43 +17,46 @@ internal object OptionsCommand : Runnable {
@CommandLine.Parameters( @CommandLine.Parameters(
description = ["Paths to patch bundles."], description = ["Paths to patch bundles."],
arity = "1..*" arity = "1..*",
) )
private lateinit var patchBundles: Array<File> private lateinit var patchBundles: Array<File>
@CommandLine.Option( @CommandLine.Option(
names = ["-p", "--path"], names = ["-p", "--path"],
description = ["Path to patch options JSON file."], description = ["Path to patch options JSON file."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var filePath: File = File("options.json") private var filePath: File = File("options.json")
@CommandLine.Option( @CommandLine.Option(
names = ["-o", "--overwrite"], names = ["-o", "--overwrite"],
description = ["Overwrite existing options file."], description = ["Overwrite existing options file."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var overwrite: Boolean = false private var overwrite: Boolean = false
@CommandLine.Option( @CommandLine.Option(
names = ["-u", "--update"], names = ["-u", "--update"],
description = ["Update existing options by adding missing and removing non-existent options."], description = ["Update existing options by adding missing and removing non-existent options."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var update: Boolean = false private var update: Boolean = false
override fun run() = try { override fun run() =
PatchBundleLoader.Jar(*patchBundles).let { patches -> try {
val exists = filePath.exists() PatchBundleLoader.Jar(*patchBundles).let { patches ->
if (!exists || overwrite) { val exists = filePath.exists()
if (exists && update) patches.setOptions(filePath) if (!exists || overwrite) {
if (exists && update) patches.setOptions(filePath)
Options.serialize(patches, prettyPrint = true).let(filePath::writeText) Options.serialize(patches, prettyPrint = true).let(filePath::writeText)
} else throw OptionsFileAlreadyExistsException() } else {
throw OptionsFileAlreadyExistsException()
}
}
} catch (ex: OptionsFileAlreadyExistsException) {
logger.severe("Options file already exists, use --overwrite to override it")
} }
} catch (ex: OptionsFileAlreadyExistsException) {
logger.severe("Options file already exists, use --overwrite to override it")
}
class OptionsFileAlreadyExistsException : Exception() class OptionsFileAlreadyExistsException : Exception()
} }

View File

@ -219,20 +219,24 @@ internal object PatchCommand : Runnable {
override fun run() { override fun run() {
// region Setup // region Setup
val outputFilePath = outputFilePath ?: File("").absoluteFile.resolve( val outputFilePath =
"${apk.nameWithoutExtension}-patched.${apk.extension}", outputFilePath ?: File("").absoluteFile.resolve(
) "${apk.nameWithoutExtension}-patched.${apk.extension}",
)
val resourceCachePath = resourceCachePath ?: outputFilePath.parentFile.resolve( val resourceCachePath =
"${outputFilePath.nameWithoutExtension}-resource-cache", resourceCachePath ?: outputFilePath.parentFile.resolve(
) "${outputFilePath.nameWithoutExtension}-resource-cache",
)
val optionsFile = optionsFile ?: outputFilePath.parentFile.resolve( val optionsFile =
"${outputFilePath.nameWithoutExtension}-options.json", optionsFile ?: outputFilePath.parentFile.resolve(
) "${outputFilePath.nameWithoutExtension}-options.json",
)
val keystoreFilePath = keystoreFilePath ?: outputFilePath.parentFile val keystoreFilePath =
.resolve("${outputFilePath.nameWithoutExtension}.keystore") keystoreFilePath ?: outputFilePath.parentFile
.resolve("${outputFilePath.nameWithoutExtension}.keystore")
// endregion // endregion
@ -265,42 +269,45 @@ internal object PatchCommand : Runnable {
true, true,
), ),
).use { patcher -> ).use { patcher ->
val filteredPatches = patcher.filterPatchSelection(patches).also { patches -> val filteredPatches =
logger.info("Setting patch options") patcher.filterPatchSelection(patches).also { patches ->
logger.info("Setting patch options")
if (optionsFile.exists()) { if (optionsFile.exists()) {
patches.setOptions(optionsFile) patches.setOptions(optionsFile)
} else { } else {
Options.serialize(patches, prettyPrint = true).let(optionsFile::writeText) Options.serialize(patches, prettyPrint = true).let(optionsFile::writeText)
}
} }
}
// region Patch // region Patch
val patcherResult = patcher.apply { val patcherResult =
acceptIntegrations(integrations) patcher.apply {
acceptPatches(filteredPatches.toList()) acceptIntegrations(integrations)
acceptPatches(filteredPatches.toList())
// Execute patches. // Execute patches.
runBlocking { runBlocking {
apply(false).collect { patchResult -> apply(false).collect { patchResult ->
patchResult.exception?.let { patchResult.exception?.let {
StringWriter().use { writer -> StringWriter().use { writer ->
it.printStackTrace(PrintWriter(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()
}.get()
// endregion // endregion
// region Save // region Save
val alignedFile = resourceCachePath.resolve(apk.name).apply { val alignedFile =
ApkUtils.copyAligned(apk, this, patcherResult) resourceCachePath.resolve(apk.name).apply {
} ApkUtils.copyAligned(apk, this, patcherResult)
}
if (!mount) { if (!mount) {
ApkUtils.sign( ApkUtils.sign(
@ -341,61 +348,64 @@ internal object PatchCommand : Runnable {
* @param patches The patches to filter. * @param patches The patches to filter.
* @return The filtered patches. * @return The filtered patches.
*/ */
private fun Patcher.filterPatchSelection(patches: PatchSet): PatchSet = buildSet { private fun Patcher.filterPatchSelection(patches: PatchSet): PatchSet =
val packageName = context.packageMetadata.packageName buildSet {
val packageVersion = context.packageMetadata.packageVersion val packageName = context.packageMetadata.packageName
val packageVersion = context.packageMetadata.packageVersion
patches.withIndex().forEach patch@{ (i, patch) -> patches.withIndex().forEach patch@{ (i, patch) ->
val patchName = patch.name!! val patchName = patch.name!!
val explicitlyExcluded = excludedPatches.contains(patchName) || excludedPatchesByIndex.contains(i) 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. // Make sure the patch is compatible with the supplied APK files package name and version.
patch.compatiblePackages?.let { packages -> patch.compatiblePackages?.let { packages ->
packages.singleOrNull { it.name == packageName }?.let { `package` -> packages.singleOrNull { it.name == packageName }?.let { `package` ->
val matchesVersion = force || `package`.versions?.let { val matchesVersion =
it.any { version -> version == packageVersion } force || `package`.versions?.let {
} ?: true it.any { version -> version == packageVersion }
} ?: true
if (!matchesVersion) { if (!matchesVersion) {
return@patch logger.warning( return@patch logger.warning(
"$patchName is incompatible with version $packageVersion. " + "$patchName is incompatible with version $packageVersion. " +
"This patch is only compatible with version " + "This patch is only compatible with version " +
packages.joinToString(";") { pkg -> packages.joinToString(";") { pkg ->
pkg.versions!!.joinToString(", ") pkg.versions!!.joinToString(", ")
}, },
) )
} }
} ?: return@patch logger.fine( } ?: return@patch logger.fine(
"$patchName is incompatible with $packageName. " + "$patchName is incompatible with $packageName. " +
"This patch is only compatible with " + "This patch is only compatible with " +
packages.joinToString(", ") { `package` -> `package`.name }, packages.joinToString(", ") { `package` -> `package`.name },
) )
return@let 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. // If the patch is implicitly used, it will be only included if [exclusive] is false.
val implicitlyIncluded = !exclusive && patch.use val implicitlyIncluded = !exclusive && patch.use
// If the patch is explicitly used, it will be included even if [exclusive] is false. // If the patch is explicitly used, it will be included even if [exclusive] is false.
val explicitlyIncluded = includedPatches.contains(patchName) || includedPatchesByIndex.contains(i) val explicitlyIncluded = includedPatches.contains(patchName) || includedPatchesByIndex.contains(i)
val included = implicitlyIncluded || explicitlyIncluded 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) add(patch)
}
} }
}
private fun purge(resourceCachePath: File) { private fun purge(resourceCachePath: File) {
val result = if (resourceCachePath.deleteRecursively()) { val result =
"Purged resource cache directory" if (resourceCachePath.deleteRecursively()) {
} else { "Purged resource cache directory"
"Failed to purge resource cache directory" } else {
} "Failed to purge resource cache directory"
}
logger.info(result) logger.info(result)
} }
} }

View File

@ -32,11 +32,12 @@ internal object InstallCommand : Runnable {
private var packageName: String? = null private var packageName: String? = null
override fun run() { override fun run() {
fun install(deviceSerial: String? = null) = try { fun install(deviceSerial: String? = null) =
AdbManager.getAdbManager(deviceSerial, packageName != null).install(AdbManager.Apk(apk, packageName)) try {
} catch (e: AdbManager.DeviceNotFoundException) { AdbManager.getAdbManager(deviceSerial, packageName != null).install(AdbManager.Apk(apk, packageName))
logger.severe(e.toString()) } catch (e: AdbManager.DeviceNotFoundException) {
} logger.severe(e.toString())
}
deviceSerials?.forEach(::install) ?: install() deviceSerials?.forEach(::install) ?: install()
} }

View File

@ -5,41 +5,41 @@ import picocli.CommandLine.*
import picocli.CommandLine.Help.Visibility.ALWAYS import picocli.CommandLine.Help.Visibility.ALWAYS
import java.util.logging.Logger import java.util.logging.Logger
@Command( @Command(
name = "uninstall", name = "uninstall",
description = ["Uninstall a patched app from the devices with the supplied ADB device serials"] description = ["Uninstall a patched app from the devices with the supplied ADB device serials"],
) )
internal object UninstallCommand : Runnable { internal object UninstallCommand : Runnable {
private val logger = Logger.getLogger(UninstallCommand::class.java.name) private val logger = Logger.getLogger(UninstallCommand::class.java.name)
@Parameters( @Parameters(
description = ["ADB device serials. If not supplied, the first connected device will be used."], description = ["ADB device serials. If not supplied, the first connected device will be used."],
arity = "0..*" arity = "0..*",
) )
private var deviceSerials: Array<String>? = null private var deviceSerials: Array<String>? = null
@Option( @Option(
names = ["-p", "--package-name"], names = ["-p", "--package-name"],
description = ["Package name of the app to uninstall"], description = ["Package name of the app to uninstall"],
required = true required = true,
) )
private lateinit var packageName: String private lateinit var packageName: String
@Option( @Option(
names = ["-u", "--unmount"], names = ["-u", "--unmount"],
description = ["Uninstall by unmounting the patched APK file"], description = ["Uninstall by unmounting the patched APK file"],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var unmount: Boolean = false private var unmount: Boolean = false
override fun run() { override fun run() {
fun uninstall(deviceSerial: String? = null) = try { fun uninstall(deviceSerial: String? = null) =
AdbManager.getAdbManager(deviceSerial, unmount).uninstall(packageName) try {
} catch (e: AdbManager.DeviceNotFoundException) { AdbManager.getAdbManager(deviceSerial, unmount).uninstall(packageName)
logger.severe(e.toString()) } catch (e: AdbManager.DeviceNotFoundException) {
} logger.severe(e.toString())
}
deviceSerials?.forEach { uninstall(it) } ?: uninstall() deviceSerials?.forEach { uninstall(it) } ?: uninstall()
} }
} }

View File

@ -7,4 +7,4 @@ import picocli.CommandLine
description = ["Commands for utility purposes"], description = ["Commands for utility purposes"],
subcommands = [InstallCommand::class, UninstallCommand::class], subcommands = [InstallCommand::class, UninstallCommand::class],
) )
internal object UtilityCommand internal object UtilityCommand