From 3b4db3ddb72cdcee8af2f787eadf58eeb37543de Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Fri, 1 Sep 2023 03:37:52 +0200 Subject: [PATCH 1/3] feat!: Remove patch annotations Annotations required reflection and working with them turned out to be rather cumbersome. The annotations have been replaced with properties for the most part. BREAKING CHANGE: Patch annotations have been removed. PatcherException is now thrown in various places. PatchBundleLoader is now a map of patches associated by their name. Patches are now instances. --- api/revanced-patcher.api | 153 +++++++-------- .../app/revanced/patcher/PatchBundleLoader.kt | 115 +++++++---- .../kotlin/app/revanced/patcher/Patcher.kt | 180 +++++++++++------- .../app/revanced/patcher/PatcherContext.kt | 13 +- .../app/revanced/patcher/PatcherException.kt | 16 ++ .../app/revanced/patcher/PatchesConsumer.kt | 4 +- .../annotation/CompatibilityAnnotation.kt | 23 --- .../patcher/annotation/MetadataAnnotation.kt | 21 -- .../revanced/patcher/data/BytecodeContext.kt | 1 - .../extensions/MethodFingerprintExtensions.kt | 8 +- .../patcher/extensions/PatchExtensions.kt | 64 ------- .../method/impl/MethodFingerprint.kt | 2 +- .../app/revanced/patcher/patch/Patch.kt | 84 ++++++-- .../app/revanced/patcher/patch/PatchResult.kt | 14 +- .../patcher/patch/annotations/Patch.kt | 7 + .../patch/annotations/PatchAnnotation.kt | 27 --- 16 files changed, 383 insertions(+), 349 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patcher/PatcherException.kt delete mode 100644 src/main/kotlin/app/revanced/patcher/annotation/CompatibilityAnnotation.kt delete mode 100644 src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt delete mode 100644 src/main/kotlin/app/revanced/patcher/extensions/PatchExtensions.kt create mode 100644 src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt delete mode 100644 src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotation.kt diff --git a/api/revanced-patcher.api b/api/revanced-patcher.api index 7a761a9..160d13b 100644 --- a/api/revanced-patcher.api +++ b/api/revanced-patcher.api @@ -7,54 +7,56 @@ public final class app/revanced/patcher/PackageMetadata { public final fun getPackageVersion ()Ljava/lang/String; } -public abstract class app/revanced/patcher/PatchBundleLoader : java/util/List, kotlin/jvm/internal/markers/KMutableList { - public synthetic fun (Ljava/lang/Iterable;Lkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun add (ILjava/lang/Class;)V - public synthetic fun add (ILjava/lang/Object;)V - public fun add (Ljava/lang/Class;)Z - public synthetic fun add (Ljava/lang/Object;)Z - public fun addAll (ILjava/util/Collection;)Z - public fun addAll (Ljava/util/Collection;)Z +public abstract class app/revanced/patcher/PatchBundleLoader : java/util/Map, kotlin/jvm/internal/markers/KMappedMarker { + public synthetic fun (Ljava/lang/ClassLoader;[Ljava/io/File;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public fun clear ()V - public fun contains (Ljava/lang/Class;)Z - public final fun contains (Ljava/lang/Object;)Z - public fun containsAll (Ljava/util/Collection;)Z - public fun get (I)Ljava/lang/Class; - public synthetic fun get (I)Ljava/lang/Object; + public synthetic fun compute (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object; + public fun compute (Ljava/lang/String;Ljava/util/function/BiFunction;)Lapp/revanced/patcher/patch/Patch; + public synthetic fun computeIfAbsent (Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object; + public fun computeIfAbsent (Ljava/lang/String;Ljava/util/function/Function;)Lapp/revanced/patcher/patch/Patch; + public synthetic fun computeIfPresent (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object; + public fun computeIfPresent (Ljava/lang/String;Ljava/util/function/BiFunction;)Lapp/revanced/patcher/patch/Patch; + public final fun containsKey (Ljava/lang/Object;)Z + public fun containsKey (Ljava/lang/String;)Z + public fun containsValue (Lapp/revanced/patcher/patch/Patch;)Z + public final fun containsValue (Ljava/lang/Object;)Z + public final fun entrySet ()Ljava/util/Set; + public final fun get (Ljava/lang/Object;)Lapp/revanced/patcher/patch/Patch; + public final synthetic fun get (Ljava/lang/Object;)Ljava/lang/Object; + public fun get (Ljava/lang/String;)Lapp/revanced/patcher/patch/Patch; + public fun getEntries ()Ljava/util/Set; + public fun getKeys ()Ljava/util/Set; public fun getSize ()I - public fun indexOf (Ljava/lang/Class;)I - public final fun indexOf (Ljava/lang/Object;)I + public fun getValues ()Ljava/util/Collection; public fun isEmpty ()Z - public fun iterator ()Ljava/util/Iterator; - public fun lastIndexOf (Ljava/lang/Class;)I - public final fun lastIndexOf (Ljava/lang/Object;)I - public fun listIterator ()Ljava/util/ListIterator; - public fun listIterator (I)Ljava/util/ListIterator; - public final fun remove (I)Ljava/lang/Class; - public synthetic fun remove (I)Ljava/lang/Object; - public fun remove (Ljava/lang/Class;)Z - public final fun remove (Ljava/lang/Object;)Z - public fun removeAll (Ljava/util/Collection;)Z - public fun removeAt (I)Ljava/lang/Class; - public fun retainAll (Ljava/util/Collection;)Z - public fun set (ILjava/lang/Class;)Ljava/lang/Class; - public synthetic fun set (ILjava/lang/Object;)Ljava/lang/Object; + public final fun keySet ()Ljava/util/Set; + public synthetic fun merge (Ljava/lang/Object;Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object; + public fun merge (Ljava/lang/String;Lapp/revanced/patcher/patch/Patch;Ljava/util/function/BiFunction;)Lapp/revanced/patcher/patch/Patch; + public synthetic fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public fun put (Ljava/lang/String;Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/patcher/patch/Patch; + public fun putAll (Ljava/util/Map;)V + public synthetic fun putIfAbsent (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public fun putIfAbsent (Ljava/lang/String;Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/patcher/patch/Patch; + public fun remove (Ljava/lang/Object;)Lapp/revanced/patcher/patch/Patch; + public synthetic fun remove (Ljava/lang/Object;)Ljava/lang/Object; + public fun remove (Ljava/lang/Object;Ljava/lang/Object;)Z + public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z + public fun replace (Ljava/lang/String;Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/patcher/patch/Patch; + public fun replace (Ljava/lang/String;Lapp/revanced/patcher/patch/Patch;Lapp/revanced/patcher/patch/Patch;)Z + public fun replaceAll (Ljava/util/function/BiFunction;)V public final fun size ()I - public fun subList (II)Ljava/util/List; - public fun toArray ()[Ljava/lang/Object; - public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object; + public final fun values ()Ljava/util/Collection; } public final class app/revanced/patcher/PatchBundleLoader$Dex : app/revanced/patcher/PatchBundleLoader { public fun ([Ljava/io/File;)V public fun ([Ljava/io/File;Ljava/io/File;)V public synthetic fun ([Ljava/io/File;Ljava/io/File;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public synthetic fun remove (I)Ljava/lang/Object; } public final class app/revanced/patcher/PatchBundleLoader$Jar : app/revanced/patcher/PatchBundleLoader { public fun ([Ljava/io/File;)V - public synthetic fun remove (I)Ljava/lang/Object; } public abstract interface class app/revanced/patcher/PatchExecutorFunction : java/util/function/Function { @@ -76,6 +78,14 @@ public final class app/revanced/patcher/PatcherContext { public final fun getPackageMetadata ()Lapp/revanced/patcher/PackageMetadata; } +public abstract class app/revanced/patcher/PatcherException : java/lang/Exception { + public synthetic fun (Ljava/lang/String;Ljava/lang/Throwable;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V +} + +public final class app/revanced/patcher/PatcherException$CircularDependencyException : app/revanced/patcher/PatcherException { +} + public final class app/revanced/patcher/PatcherOptions { public fun (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;)V public synthetic fun (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -115,23 +125,6 @@ public abstract interface class app/revanced/patcher/PatchesConsumer { public abstract fun acceptPatches (Ljava/util/List;)V } -public abstract interface annotation class app/revanced/patcher/annotation/Compatibility : java/lang/annotation/Annotation { - public abstract fun compatiblePackages ()[Lapp/revanced/patcher/annotation/Package; -} - -public abstract interface annotation class app/revanced/patcher/annotation/Description : java/lang/annotation/Annotation { - public abstract fun description ()Ljava/lang/String; -} - -public abstract interface annotation class app/revanced/patcher/annotation/Name : java/lang/annotation/Annotation { - public abstract fun name ()Ljava/lang/String; -} - -public abstract interface annotation class app/revanced/patcher/annotation/Package : java/lang/annotation/Annotation { - public abstract fun name ()Ljava/lang/String; - public abstract fun versions ()[Ljava/lang/String; -} - public final class app/revanced/patcher/data/BytecodeContext : app/revanced/patcher/data/Context { public final fun findClass (Ljava/lang/String;)Lapp/revanced/patcher/util/proxy/ClassProxy; public final fun findClass (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/proxy/ClassProxy; @@ -199,17 +192,6 @@ public final class app/revanced/patcher/extensions/InstructionExtensions { public final class app/revanced/patcher/extensions/MethodFingerprintExtensions { public static final field INSTANCE Lapp/revanced/patcher/extensions/MethodFingerprintExtensions; public final fun getFuzzyPatternScanMethod (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;)Lapp/revanced/patcher/fingerprint/method/annotation/FuzzyPatternScanMethod; - public final fun getName (Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;)Ljava/lang/String; -} - -public final class app/revanced/patcher/extensions/PatchExtensions { - public static final field INSTANCE Lapp/revanced/patcher/extensions/PatchExtensions; - public final fun getCompatiblePackages (Ljava/lang/Class;)[Lapp/revanced/patcher/annotation/Package; - public final fun getDependencies (Ljava/lang/Class;)[Lkotlin/reflect/KClass; - public final fun getDescription (Ljava/lang/Class;)Ljava/lang/String; - public final fun getInclude (Ljava/lang/Class;)Z - public final fun getOptions (Ljava/lang/Class;)Lapp/revanced/patcher/patch/PatchOptions; - public final fun getPatchName (Ljava/lang/Class;)Ljava/lang/String; } public abstract interface class app/revanced/patcher/fingerprint/Fingerprint { @@ -345,9 +327,7 @@ public final class app/revanced/patcher/logging/impl/NopLogger : app/revanced/pa } public abstract class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch { - public fun ()V - public fun (Ljava/lang/Iterable;)V - public synthetic fun (Ljava/lang/Iterable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Lapp/revanced/patcher/patch/Patch$Manifest;[Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;)V } public final class app/revanced/patcher/patch/IllegalValueException : java/lang/Exception { @@ -372,8 +352,34 @@ public abstract class app/revanced/patcher/patch/OptionsContainer { protected final fun option (Lapp/revanced/patcher/patch/PatchOption;)Lapp/revanced/patcher/patch/PatchOption; } -public abstract interface class app/revanced/patcher/patch/Patch { +public abstract class app/revanced/patcher/patch/Patch { + public synthetic fun (Lapp/revanced/patcher/patch/Patch$Manifest;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun equals (Ljava/lang/Object;)Z public abstract fun execute (Lapp/revanced/patcher/data/Context;)V + public final fun getManifest ()Lapp/revanced/patcher/patch/Patch$Manifest; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class app/revanced/patcher/patch/Patch$Manifest { + public fun (Ljava/lang/String;Ljava/lang/String;ZLjava/util/Set;Ljava/util/Set;ZLapp/revanced/patcher/patch/PatchOptions;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;ZLjava/util/Set;Ljava/util/Set;ZLapp/revanced/patcher/patch/PatchOptions;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun equals (Ljava/lang/Object;)Z + public final fun getCompatiblePackages ()Ljava/util/Set; + public final fun getDependencies ()Ljava/util/Set; + public final fun getDescription ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public final fun getOptions ()Lapp/revanced/patcher/patch/PatchOptions; + public final fun getRequiresIntegrations ()Z + public final fun getUse ()Z + public fun hashCode ()I +} + +public final class app/revanced/patcher/patch/Patch$Manifest$CompatiblePackage { + public fun (Ljava/lang/String;Ljava/util/Set;)V + public synthetic fun (Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getName ()Ljava/lang/String; + public final fun getVersions ()Ljava/util/Set; } public final class app/revanced/patcher/patch/PatchException : java/lang/Exception { @@ -429,26 +435,21 @@ public final class app/revanced/patcher/patch/PatchOptions : java/lang/Iterable, } public final class app/revanced/patcher/patch/PatchResult { + public fun equals (Ljava/lang/Object;)Z public final fun getException ()Lapp/revanced/patcher/patch/PatchException; - public final fun getPatchName ()Ljava/lang/String; + public final fun getPatch ()Lapp/revanced/patcher/patch/Patch; + public fun hashCode ()I } public final class app/revanced/patcher/patch/RequirementNotMetException : java/lang/Exception { public static final field INSTANCE Lapp/revanced/patcher/patch/RequirementNotMetException; } -public abstract interface class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch { -} - -public abstract interface annotation class app/revanced/patcher/patch/annotations/DependsOn : java/lang/annotation/Annotation { - public abstract fun dependencies ()[Ljava/lang/Class; +public abstract class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch { + public fun (Lapp/revanced/patcher/patch/Patch$Manifest;)V } public abstract interface annotation class app/revanced/patcher/patch/annotations/Patch : java/lang/annotation/Annotation { - public abstract fun include ()Z -} - -public abstract interface annotation class app/revanced/patcher/patch/annotations/RequiresIntegrations : java/lang/annotation/Annotation { } public final class app/revanced/patcher/util/DomFileEditor : java/io/Closeable { diff --git a/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt b/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt index b69b140..246b4c9 100644 --- a/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt +++ b/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt @@ -3,36 +3,85 @@ package app.revanced.patcher import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively -import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.patch.Patch -import app.revanced.patcher.patch.PatchClass import dalvik.system.DexClassLoader import lanchon.multidexlib2.BasicDexFileNamer import lanchon.multidexlib2.MultiDexIO import java.io.File import java.net.URLClassLoader import java.util.jar.JarFile +import java.util.logging.Logger +import kotlin.reflect.KClass /** - * A patch bundle. + * [Patch]es mapped by their name. + */ +typealias PatchMap = Map> + +/** + * A [Patch] class. + */ +typealias PatchClass = KClass> + +/** + * A loader of [Patch]es from patch bundles. + * This will load all [Patch]es from the given patch bundles. * - * - * @param fromClasses The classes to get [Patch]es from. + * @param getBinaryClassNames A function that returns the binary names of all classes in a patch bundle. + * @param classLoader The [ClassLoader] to use for loading the classes. */ sealed class PatchBundleLoader private constructor( - fromClasses: Iterable> -) : MutableList by mutableListOf() { + classLoader: ClassLoader, + patchBundles: Array, + getBinaryClassNames: (patchBundle: File) -> List, +) : PatchMap by mutableMapOf() { + private val logger = Logger.getLogger(PatchBundleLoader::class.java.name) + init { - fromClasses.filter { + patchBundles.flatMap(getBinaryClassNames).map { + classLoader.loadClass(it) + }.filter { if (it.isAnnotation) return@filter false it.findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class) != null - }.map { + }.mapNotNull { patchClass -> + patchClass.getInstance(logger) + }.associateBy { it.manifest.name } + let { patches -> @Suppress("UNCHECKED_CAST") - it as PatchClass - }.sortedBy { - it.patchName - }.let { addAll(it) } + (this as MutableMap>).putAll(patches) + } + } + + + internal companion object Utils { + /** + * Instantiates a [Patch]. If the class is a singleton, the INSTANCE field will be used. + * + * @param logger The [Logger] to use for logging. + * @return The instantiated [Patch] or `null` if the [Patch] could not be instantiated. + */ + internal fun Class<*>.getInstance(logger: Logger): Patch<*>? { + return try { + getField("INSTANCE").get(null) + } catch (exception: NoSuchFileException) { + logger.fine( + "Patch class '${name}' has no INSTANCE field, therefor not a singleton. " + + "Will try to instantiate it." + ) + + try { + getDeclaredConstructor().newInstance() + } catch (exception: Exception) { + logger.severe( + "Patch class '${name}' is not singleton and has no suitable constructor, " + + "therefor cannot be instantiated and will be ignored." + ) + + return null + } + } as Patch<*> + } } /** @@ -41,18 +90,13 @@ sealed class PatchBundleLoader private constructor( * @param patchBundles The path to patch bundles of JAR format. */ class Jar(vararg patchBundles: File) : PatchBundleLoader( - with( - URLClassLoader(patchBundles.map { it.toURI().toURL() }.toTypedArray()) - ) { - patchBundles.flatMap { patchBundle -> - // Get the names of all classes in the DEX file. - - JarFile(patchBundle).entries().asSequence() - .filter { it.name.endsWith(".class") } - .map { it.name.replace('/', '.').replace(".class", "") } - .map { loadClass(it) } - } - }) + URLClassLoader(patchBundles.map { it.toURI().toURL() }.toTypedArray()), + patchBundles, + { patchBundle -> + JarFile(patchBundle).entries().toList().filter { it.name.endsWith(".class") } + .map { it.name.replace('/', '.').replace(".class", "") } + } + ) /** * A [PatchBundleLoader] for [Dex] files. @@ -62,20 +106,19 @@ sealed class PatchBundleLoader private constructor( * This parameter is deprecated and has no effect since API level 26. */ class Dex(vararg patchBundles: File, optimizedDexDirectory: File? = null) : PatchBundleLoader( - with( - DexClassLoader( + DexClassLoader( patchBundles.joinToString(File.pathSeparator) { it.absolutePath }, optimizedDexDirectory?.absolutePath, null, PatchBundleLoader::class.java.classLoader - ) - ) { - patchBundles - .flatMap { - MultiDexIO.readDexFile(true, it, BasicDexFileNamer(), null, null).classes - } - .map { classDef -> classDef.type.substring(1, classDef.length - 1) } - .map { loadClass(it) } - }) { + ), + patchBundles, + { patchBundle -> + MultiDexIO.readDexFile(true, patchBundle, BasicDexFileNamer(), null, null).classes + .map { classDef -> + classDef.type.substring(1, classDef.length - 1) + } + } + ) { @Deprecated("This constructor is deprecated. Use the constructor with the second parameter instead.") constructor(vararg patchBundles: File) : this(*patchBundles, optimizedDexDirectory = null) } diff --git a/src/main/kotlin/app/revanced/patcher/Patcher.kt b/src/main/kotlin/app/revanced/patcher/Patcher.kt index 2959f6b..160859a 100644 --- a/src/main/kotlin/app/revanced/patcher/Patcher.kt +++ b/src/main/kotlin/app/revanced/patcher/Patcher.kt @@ -1,11 +1,8 @@ package app.revanced.patcher -import app.revanced.patcher.data.Context +import app.revanced.patcher.PatchBundleLoader.Utils.getInstance import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively -import app.revanced.patcher.extensions.PatchExtensions.dependencies -import app.revanced.patcher.extensions.PatchExtensions.patchName -import app.revanced.patcher.extensions.PatchExtensions.requiresIntegrations import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolveUsingLookupMap import app.revanced.patcher.patch.* @@ -49,32 +46,78 @@ class Patcher( context.resourceContext.decodeResources(ResourceContext.ResourceDecodingMode.MANIFEST_ONLY) } - override fun acceptPatches(patches: List) { + /** + * Add [Patch]es to ReVanced [Patcher]. + * It is not guaranteed that all supplied [Patch]es will be accepted, if an exception is thrown. + * + * @param patches The [Patch]es to add. + * @throws PatcherException.CircularDependencyException If a circular dependency is detected. + */ + @Suppress("NAME_SHADOWING") + override fun acceptPatches(patches: List>) { /** - * Returns true if at least one patches or its dependencies matches the given predicate. + * Add dependencies of a [Patch] recursively to [PatcherContext.allPatches]. + * If a [Patch] is already in [PatcherContext.allPatches], it will not be added again. */ - fun PatchClass.anyRecursively(predicate: (PatchClass) -> Boolean): Boolean = - predicate(this) || dependencies?.any { dependency -> - dependency.java.anyRecursively(predicate) + fun PatchClass.putDependenciesRecursively() { + if (context.allPatches.contains(this)) return + + val dependency = this.java.getInstance(logger)!! + context.allPatches[this] = dependency + + dependency.manifest.dependencies?.forEach { it.putDependenciesRecursively() } + } + + // Add all patches and their dependencies to the context. + for (patch in patches) context.executablePatches.putIfAbsent(patch::class, patch) ?: { + context.allPatches[patch::class] = patch + + patch.manifest.dependencies?.forEach { it.putDependenciesRecursively() } + } + + /* TODO: Fix circular dependency detection. + val graph = mutableMapOf>() + fun PatchClass.visit() { + if (this in graph) return + + val group = graph.getOrPut(this) { mutableListOf(this) } + + val dependencies = context.allPatches[this]!!.manifest.dependencies ?: return + dependencies.forEach { dependency -> + if (group == graph[dependency]) + throw PatcherException.CircularDependencyException(context.allPatches[this]!!.manifest.name) + + graph[dependency] = group.apply { add(dependency) } + dependency.visit() + } + } + */ + + /** + * Returns true if at least one patch or its dependencies matches the given predicate. + * + * @param predicate The predicate to match. + */ + fun Patch<*>.anyRecursively(predicate: (Patch<*>) -> Boolean): Boolean = + predicate(this) || manifest.dependencies?.any { dependency -> + context.allPatches[dependency]!!.anyRecursively(predicate) } ?: false - // Determine if resource patching is required. - for (patch in patches) { - if (patch.anyRecursively { ResourcePatch::class.java.isAssignableFrom(it) }) { - options.resourceDecodingMode = ResourceContext.ResourceDecodingMode.FULL - break - } - } + context.allPatches.values.let { patches -> + // Determine, if resource patching is required. + for (patch in patches) + if (patch.anyRecursively { patch is ResourcePatch }) { + options.resourceDecodingMode = ResourceContext.ResourceDecodingMode.FULL + break + } - // Determine if merging integrations is required. - for (patch in patches) { - if (patch.anyRecursively { it.requiresIntegrations }) { - context.bytecodeContext.integrations.merge = true - break - } + // Determine, if merging integrations is required. + for (patch in patches) + if (!patch.anyRecursively { it.manifest.requiresIntegrations }) { + context.bytecodeContext.integrations.merge = true + break + } } - - context.patches.addAll(patches) } /** @@ -93,50 +136,44 @@ class Patcher( * @return A pair of the name of the [Patch] and its [PatchResult]. */ override fun apply(returnOnError: Boolean) = flow { - class ExecutedPatch(val patchInstance: Patch>, val patchResult: PatchResult) /** * Execute a [Patch] and its dependencies recursively. * - * @param patchClass The [Patch] to execute. + * @param patch The [Patch] to execute. * @param executedPatches A map to prevent [Patch]es from being executed twice due to dependencies. * @return The result of executing the [Patch]. */ fun executePatch( - patchClass: PatchClass, - executedPatches: LinkedHashMap + patch: Patch<*>, + executedPatches: LinkedHashMap, PatchResult> ): PatchResult { - val patchName = patchClass.patchName + val patchName = patch.manifest.name - executedPatches[patchName]?.let { executedPatch -> - executedPatch.patchResult.exception ?: return executedPatch.patchResult + executedPatches[patch]?.let { patchResult -> + patchResult.exception ?: return patchResult // Return a new result with an exception indicating that the patch was not executed previously, // because it is a dependency of another patch that failed. - return PatchResult(patchName, PatchException("'$patchName' did not succeed previously")) + return PatchResult(patch, PatchException("'$patchName' did not succeed previously")) } // Recursively execute all dependency patches. - patchClass.dependencies?.forEach { dependencyClass -> - val dependency = dependencyClass.java - + patch.manifest.dependencies?.forEach { dependencyName -> + val dependency = context.executablePatches[dependencyName]!! val result = executePatch(dependency, executedPatches) result.exception?.let { return PatchResult( - patchName, - PatchException( - "'$patchName' depends on '${dependency.patchName}' that raised an exception: $it" - ) + patch, + PatchException("'$patchName' depends on '${dependency}' that raised an exception: $it") ) } } // TODO: Implement this in a more polymorphic way. - val patchInstance = patchClass.getDeclaredConstructor().newInstance() - - val patchContext = if (patchInstance is BytecodePatch) { - patchInstance.fingerprints?.resolveUsingLookupMap(context.bytecodeContext) + val patchContext = if (patch is BytecodePatch) { + patch.fingerprints.asList().resolveUsingLookupMap(context.bytecodeContext) context.bytecodeContext } else { @@ -144,14 +181,14 @@ class Patcher( } return try { - patchInstance.execute(patchContext) + patch.execute(patchContext) - PatchResult(patchName) + PatchResult(patch) } catch (exception: PatchException) { - PatchResult(patchName, exception) + PatchResult(patch, exception) } catch (exception: Exception) { - PatchResult(patchName, PatchException(exception)) - }.also { executedPatches[patchName] = ExecutedPatch(patchInstance, it) } + PatchResult(patch, PatchException(exception)) + }.also { executedPatches[patch] = it } } if (context.bytecodeContext.integrations.merge) context.bytecodeContext.integrations.flush() @@ -164,51 +201,54 @@ class Patcher( logger.info("Executing patches") - val executedPatches = LinkedHashMap() // Key is name. + val executedPatches = LinkedHashMap, PatchResult>() // Key is name. - context.patches.forEach { patch -> - val result = executePatch(patch, executedPatches) + context.executablePatches.map { it.value }.sortedBy { it.manifest.name }.forEach { patch -> + val patchResult = executePatch(patch, executedPatches) - // If the patch failed, or if the patch is not closeable, emit the result. - // Results of patches that are closeable will be emitted later. - result.exception?.let { - emit(result) + // If the patch failed, emit the result, even if it is closeable. + // Results of successfully executed patches that are closeable will be emitted later. + patchResult.exception?.let { + // Propagate exception to caller instead of wrapping it in a new exception. + emit(patchResult) if (returnOnError) return@flow } ?: run { - if (executedPatches[result.patchName]!!.patchInstance is Closeable) return@run + if (patch is Closeable) return@run - emit(result) + emit(patchResult) } } executedPatches.values - .filter { it.patchResult.exception == null } - .filter { it.patchInstance is Closeable }.asReversed().forEach { executedPatch -> - val patchName = executedPatch.patchResult.patchName + .filter { it.exception == null } + .filter { it.patch is Closeable }.asReversed().forEach { executedPatch -> + val patch = executedPatch.patch val result = try { - (executedPatch.patchInstance as Closeable).close() + (patch as Closeable).close() - executedPatch.patchResult + executedPatch } catch (exception: PatchException) { - PatchResult(patchName, exception) + PatchResult(patch, exception) } catch (exception: Exception) { - PatchResult(patchName, PatchException(exception)) + PatchResult(patch, PatchException(exception)) } result.exception?.let { emit( PatchResult( - patchName, - PatchException("'$patchName' raised an exception while being closed: $it") + patch, + PatchException( + "'${patch.manifest.name}' raised an exception while being closed: $it", + result.exception + ) ) ) if (returnOnError) return@flow } ?: run { - executedPatch - .patchInstance::class + patch::class .java .findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class) ?: return@run @@ -218,9 +258,7 @@ class Patcher( } } - override fun close() { - MethodFingerprint.clearFingerprintResolutionLookupMaps() - } + override fun close() = MethodFingerprint.clearFingerprintResolutionLookupMaps() /** * Compile and save the patched APK file. diff --git a/src/main/kotlin/app/revanced/patcher/PatcherContext.kt b/src/main/kotlin/app/revanced/patcher/PatcherContext.kt index 4aa8396..c21cfa6 100644 --- a/src/main/kotlin/app/revanced/patcher/PatcherContext.kt +++ b/src/main/kotlin/app/revanced/patcher/PatcherContext.kt @@ -3,7 +3,6 @@ package app.revanced.patcher import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.Patch -import app.revanced.patcher.patch.PatchClass import brut.androlib.apk.ApkInfo import brut.directory.ExtFile @@ -19,9 +18,14 @@ class PatcherContext internal constructor(options: PatcherOptions) { val packageMetadata = PackageMetadata(ApkInfo(ExtFile(options.inputFile))) /** - * The list of [Patch]es to execute. + * The map of [Patch]es associated by their [PatchClass]. */ - internal val patches = mutableListOf() + internal val executablePatches = mutableMapOf>() + + /** + * The map of all [Patch]es and their dependencies associated by their [PatchClass]. + */ + internal val allPatches = mutableMapOf>() /** * The [ResourceContext] of this [PatcherContext]. @@ -33,5 +37,4 @@ class PatcherContext internal constructor(options: PatcherOptions) { * The [BytecodeContext] of this [PatcherContext]. * This holds the current state of the bytecode. */ - internal val bytecodeContext = BytecodeContext(options) -} \ No newline at end of file + internal val bytecodeContext = BytecodeContext(options) } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/PatcherException.kt b/src/main/kotlin/app/revanced/patcher/PatcherException.kt new file mode 100644 index 0000000..2313a99 --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/PatcherException.kt @@ -0,0 +1,16 @@ +package app.revanced.patcher + +/** + * An exception thrown by ReVanced [Patcher]. + * + * @param errorMessage The exception message. + * @param cause The corresponding [Throwable]. + */ +sealed class PatcherException(errorMessage: String?, cause: Throwable?) : Exception(errorMessage, cause) { + constructor(errorMessage: String) : this(errorMessage, null) + + + class CircularDependencyException internal constructor(dependant: String) : PatcherException( + "Patch '$dependant' causes a circular dependency" + ) +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/PatchesConsumer.kt b/src/main/kotlin/app/revanced/patcher/PatchesConsumer.kt index ed7780c..866b7e5 100644 --- a/src/main/kotlin/app/revanced/patcher/PatchesConsumer.kt +++ b/src/main/kotlin/app/revanced/patcher/PatchesConsumer.kt @@ -1,8 +1,8 @@ package app.revanced.patcher -import app.revanced.patcher.patch.PatchClass +import app.revanced.patcher.patch.Patch @FunctionalInterface interface PatchesConsumer { - fun acceptPatches(patches: List) + fun acceptPatches(patches: List>) } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/annotation/CompatibilityAnnotation.kt b/src/main/kotlin/app/revanced/patcher/annotation/CompatibilityAnnotation.kt deleted file mode 100644 index 19e61e8..0000000 --- a/src/main/kotlin/app/revanced/patcher/annotation/CompatibilityAnnotation.kt +++ /dev/null @@ -1,23 +0,0 @@ -package app.revanced.patcher.annotation - -import app.revanced.patcher.patch.Patch - -/** - * Annotation to constrain a [Patch] to compatible packages. - * @param compatiblePackages A list of packages a [Patch] is compatible with. - */ -@Target(AnnotationTarget.CLASS) -annotation class Compatibility( - val compatiblePackages: Array, -) - -/** - * Annotation to represent packages a patch can be compatible with. - * @param name The package identifier name. - * @param versions The versions of the package the [Patch] is compatible with. - */ -@Target() -annotation class Package( - val name: String, - val versions: Array = [], -) diff --git a/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt b/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt deleted file mode 100644 index 9f9cd3a..0000000 --- a/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt +++ /dev/null @@ -1,21 +0,0 @@ -package app.revanced.patcher.annotation - -import app.revanced.patcher.patch.Patch - -/** - * Annotation to name a [Patch]. - * @param name A suggestive name for the [Patch]. - */ -@Target(AnnotationTarget.CLASS) -annotation class Name( - val name: String, -) - -/** - * Annotation to describe a [Patch]. - * @param description A description for the [Patch]. - */ -@Target(AnnotationTarget.CLASS) -annotation class Description( - val description: String, -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/data/BytecodeContext.kt b/src/main/kotlin/app/revanced/patcher/data/BytecodeContext.kt index 3374930..439b430 100644 --- a/src/main/kotlin/app/revanced/patcher/data/BytecodeContext.kt +++ b/src/main/kotlin/app/revanced/patcher/data/BytecodeContext.kt @@ -4,7 +4,6 @@ import app.revanced.patcher.PatcherContext import app.revanced.patcher.PatcherOptions import app.revanced.patcher.PatcherResult import app.revanced.patcher.patch.Patch -import app.revanced.patcher.patch.annotations.RequiresIntegrations import app.revanced.patcher.util.ClassMerger.merge import app.revanced.patcher.util.ProxyClassList import app.revanced.patcher.util.method.MethodWalker diff --git a/src/main/kotlin/app/revanced/patcher/extensions/MethodFingerprintExtensions.kt b/src/main/kotlin/app/revanced/patcher/extensions/MethodFingerprintExtensions.kt index 1901044..e722f7d 100644 --- a/src/main/kotlin/app/revanced/patcher/extensions/MethodFingerprintExtensions.kt +++ b/src/main/kotlin/app/revanced/patcher/extensions/MethodFingerprintExtensions.kt @@ -5,13 +5,7 @@ import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object MethodFingerprintExtensions { - - /** - * The name of a [MethodFingerprint]. - */ - val MethodFingerprint.name: String - get() = this.javaClass.simpleName - + // TODO: Make this a property. /** * The [FuzzyPatternScanMethod] annotation of a [MethodFingerprint]. */ diff --git a/src/main/kotlin/app/revanced/patcher/extensions/PatchExtensions.kt b/src/main/kotlin/app/revanced/patcher/extensions/PatchExtensions.kt deleted file mode 100644 index 493056e..0000000 --- a/src/main/kotlin/app/revanced/patcher/extensions/PatchExtensions.kt +++ /dev/null @@ -1,64 +0,0 @@ -package app.revanced.patcher.extensions - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively -import app.revanced.patcher.patch.OptionsContainer -import app.revanced.patcher.patch.Patch -import app.revanced.patcher.patch.PatchClass -import app.revanced.patcher.patch.PatchOptions -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.RequiresIntegrations -import kotlin.reflect.KVisibility -import kotlin.reflect.full.companionObject -import kotlin.reflect.full.companionObjectInstance - -object PatchExtensions { - /** - * The name of a [Patch]. - */ - val PatchClass.patchName: String - get() = findAnnotationRecursively(Name::class)?.name ?: this.simpleName - - /** - * Weather or not a [Patch] should be included. - */ - val PatchClass.include - get() = findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class)!!.include - - /** - * The description of a [Patch]. - */ - val PatchClass.description - get() = findAnnotationRecursively(Description::class)?.description - - /** - * The dependencies of a [Patch]. - */ - val PatchClass.dependencies - get() = findAnnotationRecursively(DependsOn::class)?.dependencies - - /** - * The packages a [Patch] is compatible with. - */ - val PatchClass.compatiblePackages - get() = findAnnotationRecursively(Compatibility::class)?.compatiblePackages - - /** - * Weather or not a [Patch] requires integrations. - */ - internal val PatchClass.requiresIntegrations - get() = findAnnotationRecursively(RequiresIntegrations::class) != null - - /** - * The options of a [Patch]. - */ - val PatchClass.options: PatchOptions? - get() = kotlin.companionObject?.let { cl -> - if (cl.visibility != KVisibility.PUBLIC) return null - kotlin.companionObjectInstance?.let { - (it as? OptionsContainer)?.options - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt b/src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt index 4858721..3682a02 100644 --- a/src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt +++ b/src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt @@ -159,7 +159,7 @@ abstract class MethodFingerprint( * - Faster: Specify [accessFlags], [returnType] and [parameters]. * - Fastest: Specify [strings], with at least one string being an exact (non-partial) match. */ - internal fun Iterable.resolveUsingLookupMap(context: BytecodeContext) { + internal fun List.resolveUsingLookupMap(context: BytecodeContext) { if (methods.isEmpty()) throw PatchException("lookup map not initialized") for (fingerprint in this) { diff --git a/src/main/kotlin/app/revanced/patcher/patch/Patch.kt b/src/main/kotlin/app/revanced/patcher/patch/Patch.kt index 621145b..66b8b20 100644 --- a/src/main/kotlin/app/revanced/patcher/patch/Patch.kt +++ b/src/main/kotlin/app/revanced/patcher/patch/Patch.kt @@ -1,39 +1,97 @@ package app.revanced.patcher.patch +import app.revanced.patcher.PatchClass +import app.revanced.patcher.Patcher import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.Context import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import java.io.Closeable -typealias PatchClass = Class>> - /** * A ReVanced patch. * - * If it implements [Closeable], it will be closed after all patches have been executed. - * Closing will be done in reverse execution order. + * If an implementation of [Patch] also implements [Closeable] + * it will be closed in reverse execution order of patches executed by ReVanced [Patcher]. + * + * @param manifest The manifest of the [Patch]. + * @param T The [Context] type this patch will work on. */ -sealed interface Patch> { +sealed class Patch>(val manifest: Manifest) { /** - * The main function of the [Patch] which the patcher will call. + * The execution function of the patch. * * @param context The [Context] the patch will work on. * @return The result of executing the patch. */ - fun execute(context: @UnsafeVariance T) + abstract fun execute(context: @UnsafeVariance T) + + override fun hashCode() = manifest.hashCode() + + override fun equals(other: Any?) = other is Patch<*> && manifest == other.manifest + + override fun toString() = manifest.name + + /** + * The manifest of a [Patch]. + * + * @param name The name of the patch. + * @param description The description of the patch. + * @param use Weather or not the patch should be used. + * @param dependencies The names of patches this patch depends on. + * @param compatiblePackages The packages the patch is compatible with. + * @param requiresIntegrations Weather or not the patch requires integrations. + * @param options The options of the patch. + */ + class Manifest( + val name: String, + val description: String, + val use: Boolean = true, + val dependencies: Set? = null, + val compatiblePackages: Set? = null, + // TODO: Remove this property, once integrations are coupled with patches. + val requiresIntegrations: Boolean = false, + val options: PatchOptions? = null, + ) { + override fun hashCode() = name.hashCode() + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Manifest + + return name == other.name + } + + /** + * A package a [Patch] is compatible with. + * + * @param name The name of the package. + * @param versions The versions of the package. + */ + class CompatiblePackage( + val name: String, + val versions: Set? = null, + ) + } } /** - * Resource patch for the Patcher. + * A ReVanced [Patch] that works on [ResourceContext]. + * + * @param metadata The manifest of the [ResourcePatch]. */ -interface ResourcePatch : Patch +abstract class ResourcePatch( + metadata: Manifest, +) : Patch(metadata) /** - * Bytecode patch for the Patcher. + * A ReVanced [Patch] that works on [BytecodeContext]. * - * @param fingerprints A list of [MethodFingerprint] this patch relies on. + * @param manifest The manifest of the [BytecodePatch]. + * @param fingerprints A list of [MethodFingerprint]s which will be resolved before the patch is executed. */ abstract class BytecodePatch( - internal val fingerprints: Iterable? = null -) : Patch \ No newline at end of file + manifest: Manifest, + internal vararg val fingerprints: MethodFingerprint, +) : Patch(manifest) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt b/src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt index 01fab9c..5be69f5 100644 --- a/src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt +++ b/src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt @@ -3,8 +3,18 @@ package app.revanced.patcher.patch /** * A result of executing a [Patch]. * - * @param patchName The name of the [Patch]. + * @param patch The [Patch] that was executed. * @param exception The [PatchException] thrown, if any. */ @Suppress("MemberVisibilityCanBePrivate") -class PatchResult internal constructor(val patchName: String, val exception: PatchException? = null) \ No newline at end of file +class PatchResult internal constructor(val patch: Patch<*>, val exception: PatchException? = null) { + override fun hashCode() = patch.hashCode() + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as PatchResult + + return patch == other.patch + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt b/src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt new file mode 100644 index 0000000..4928d87 --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt @@ -0,0 +1,7 @@ +package app.revanced.patcher.patch.annotations + +/** + * Annotation to mark a class as a patch. + */ +@Target(AnnotationTarget.CLASS) +annotation class Patch \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotation.kt b/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotation.kt deleted file mode 100644 index 4e45c38..0000000 --- a/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotation.kt +++ /dev/null @@ -1,27 +0,0 @@ -package app.revanced.patcher.patch.annotations - -import app.revanced.patcher.data.Context -import app.revanced.patcher.patch.Patch -import kotlin.reflect.KClass - -/** - * Annotation to mark a class as a patch. - * @param include If false, the patch should be treated as optional by default. - */ -@Target(AnnotationTarget.CLASS) -annotation class Patch(val include: Boolean = true) - -/** - * Annotation for dependencies of [Patch]es. - */ -@Target(AnnotationTarget.CLASS) -annotation class DependsOn( - val dependencies: Array>>> = [] -) - -// TODO: Remove this annotation, once integrations are coupled with patches. -/** - * Annotation to mark [Patch]es which depend on integrations. - */ -@Target(AnnotationTarget.CLASS) -annotation class RequiresIntegrations \ No newline at end of file From 4dd04975d931970daf6fad8a00ab07cf29376fbe Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 4 Sep 2023 05:37:13 +0200 Subject: [PATCH 2/3] refactor: Move ReVanced Patcher to sub-project This allows other sub-projects to exist. --- build.gradle.kts | 56 +----------------- .../api}/revanced-patcher.api | 0 revanced-patcher/build.gradle.kts | 57 +++++++++++++++++++ revanced-patcher/settings.gradle.kts | 1 + .../revanced/patcher/IntegrationsConsumer.kt | 0 .../app/revanced/patcher/PackageMetadata.kt | 0 .../app/revanced/patcher/PatchBundleLoader.kt | 0 .../revanced/patcher/PatchExecutorFunction.kt | 0 .../kotlin/app/revanced/patcher/Patcher.kt | 0 .../app/revanced/patcher/PatcherContext.kt | 0 .../app/revanced/patcher/PatcherException.kt | 0 .../app/revanced/patcher/PatcherOptions.kt | 0 .../app/revanced/patcher/PatcherResult.kt | 0 .../app/revanced/patcher/PatchesConsumer.kt | 0 .../revanced/patcher/data/BytecodeContext.kt | 0 .../app/revanced/patcher/data/Context.kt | 0 .../revanced/patcher/data/ResourceContext.kt | 0 .../extensions/AnnotationExtensions.kt | 0 .../revanced/patcher/extensions/Extensions.kt | 0 .../extensions/InstructionExtensions.kt | 0 .../extensions/MethodFingerprintExtensions.kt | 0 .../patcher/fingerprint/Fingerprint.kt | 0 .../annotation/MethodFingerprintMetadata.kt | 0 .../method/impl/MethodFingerprint.kt | 0 .../app/revanced/patcher/logging/Logger.kt | 0 .../patcher/logging/impl/NopLogger.kt | 0 .../patcher/patch/OptionsContainer.kt | 0 .../app/revanced/patcher/patch/Patch.kt | 0 .../revanced/patcher/patch/PatchException.kt | 0 .../app/revanced/patcher/patch/PatchOption.kt | 0 .../app/revanced/patcher/patch/PatchResult.kt | 0 .../patcher/patch/annotations/Patch.kt | 0 .../app/revanced/patcher/util/ClassMerger.kt | 0 .../revanced/patcher/util/DomFileEditor.kt | 0 .../revanced/patcher/util/ProxyClassList.kt | 0 .../patcher/util/method/MethodWalker.kt | 0 .../revanced/patcher/util/proxy/ClassProxy.kt | 0 .../proxy/mutableTypes/MutableAnnotation.kt | 0 .../mutableTypes/MutableAnnotationElement.kt | 0 .../util/proxy/mutableTypes/MutableClass.kt | 0 .../util/proxy/mutableTypes/MutableField.kt | 0 .../util/proxy/mutableTypes/MutableMethod.kt | 0 .../mutableTypes/MutableMethodParameter.kt | 0 .../MutableAnnotationEncodedValue.kt | 0 .../encodedValue/MutableArrayEncodedValue.kt | 0 .../MutableBooleanEncodedValue.kt | 0 .../encodedValue/MutableByteEncodedValue.kt | 0 .../encodedValue/MutableCharEncodedValue.kt | 0 .../encodedValue/MutableDoubleEncodedValue.kt | 0 .../encodedValue/MutableEncodedValue.kt | 0 .../encodedValue/MutableEnumEncodedValue.kt | 0 .../encodedValue/MutableFieldEncodedValue.kt | 0 .../encodedValue/MutableFloatEncodedValue.kt | 0 .../encodedValue/MutableIntEncodedValue.kt | 0 .../encodedValue/MutableLongEncodedValue.kt | 0 .../encodedValue/MutableMethodEncodedValue.kt | 0 .../MutableMethodHandleEncodedValue.kt | 0 .../MutableMethodTypeEncodedValue.kt | 0 .../encodedValue/MutableNullEncodedValue.kt | 0 .../encodedValue/MutableShortEncodedValue.kt | 0 .../encodedValue/MutableStringEncodedValue.kt | 0 .../encodedValue/MutableTypeEncodedValue.kt | 0 .../patcher/util/smali/ExternalLabel.kt | 0 .../patcher/util/smali/InlineSmaliCompiler.kt | 0 .../app/revanced/patcher/version.properties | 0 .../extensions/InstructionExtensionsTest.kt | 0 .../app/revanced/patcher/issues/Issue98.kt | 0 .../patcher/patch/PatchOptionsTest.kt | 0 .../usage/bytecode/ExampleBytecodePatch.kt | 20 ++++--- .../usage/bytecode/ExampleFingerprint.kt | 0 .../resource/patch/ExampleResourcePatch.kt | 10 +--- .../util/smali/InlineSmaliCompilerTest.kt | 0 settings.gradle.kts | 2 +- .../bytecode/ExampleBytecodeCompatibility.kt | 13 ----- .../ExampleResourceCompatibility.kt | 13 ----- 75 files changed, 72 insertions(+), 100 deletions(-) rename {api => revanced-patcher/api}/revanced-patcher.api (100%) create mode 100644 revanced-patcher/build.gradle.kts create mode 100644 revanced-patcher/settings.gradle.kts rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/IntegrationsConsumer.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/PackageMetadata.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/PatchExecutorFunction.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/Patcher.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/PatcherContext.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/PatcherException.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/PatcherOptions.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/PatcherResult.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/PatchesConsumer.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/data/BytecodeContext.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/data/Context.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/data/ResourceContext.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/extensions/AnnotationExtensions.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/extensions/Extensions.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/extensions/InstructionExtensions.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/extensions/MethodFingerprintExtensions.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/fingerprint/Fingerprint.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/fingerprint/method/annotation/MethodFingerprintMetadata.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/logging/Logger.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/logging/impl/NopLogger.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/patch/OptionsContainer.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/patch/Patch.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/patch/PatchException.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/patch/PatchOption.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/patch/PatchResult.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/ClassMerger.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/DomFileEditor.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/ProxyClassList.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/ClassProxy.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableClass.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableField.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableMethod.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/smali/ExternalLabel.kt (100%) rename {src => revanced-patcher/src}/main/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompiler.kt (100%) rename {src => revanced-patcher/src}/main/resources/app/revanced/patcher/version.properties (100%) rename {src => revanced-patcher/src}/test/kotlin/app/revanced/patcher/extensions/InstructionExtensionsTest.kt (100%) rename {src => revanced-patcher/src}/test/kotlin/app/revanced/patcher/issues/Issue98.kt (100%) rename {src => revanced-patcher/src}/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt (100%) rename {src => revanced-patcher/src}/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt (94%) rename {src => revanced-patcher/src}/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleFingerprint.kt (100%) rename {src => revanced-patcher/src}/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt (60%) rename {src => revanced-patcher/src}/test/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompilerTest.kt (100%) delete mode 100644 src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodeCompatibility.kt delete mode 100644 src/test/kotlin/app/revanced/patcher/usage/resource/annotation/ExampleResourceCompatibility.kt diff --git a/build.gradle.kts b/build.gradle.kts index 402fc71..dc5e76f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,58 +1,4 @@ plugins { - kotlin("jvm") version "1.8.20" - `maven-publish` + kotlin("jvm") version "1.9.0" apply false alias(libs.plugins.binary.compatibility.validator) } - -group = "app.revanced" - -dependencies { - implementation(libs.kotlinx.coroutines.core) - implementation(libs.xpp3) - implementation(libs.smali) - implementation(libs.multidexlib2) - implementation(libs.apktool.lib) - implementation(libs.kotlin.reflect) - - compileOnly(libs.android) - - testImplementation(libs.kotlin.test) -} - -tasks { - test { - useJUnitPlatform() - testLogging { - events("PASSED", "SKIPPED", "FAILED") - } - } - - processResources { - expand("projectVersion" to project.version) - } -} - -kotlin { jvmToolchain(11) } - -java { - withSourcesJar() -} - -publishing { - repositories { - mavenLocal() - maven { - name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/revanced/revanced-patcher") - credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") - } - } - } - publications { - create("gpr") { - from(components["java"]) - } - } -} diff --git a/api/revanced-patcher.api b/revanced-patcher/api/revanced-patcher.api similarity index 100% rename from api/revanced-patcher.api rename to revanced-patcher/api/revanced-patcher.api diff --git a/revanced-patcher/build.gradle.kts b/revanced-patcher/build.gradle.kts new file mode 100644 index 0000000..e9fcb12 --- /dev/null +++ b/revanced-patcher/build.gradle.kts @@ -0,0 +1,57 @@ +plugins { + kotlin("jvm") version "1.9.0" + `maven-publish` +} + +group = "app.revanced" + +dependencies { + implementation(libs.kotlinx.coroutines.core) + implementation(libs.xpp3) + implementation(libs.smali) + implementation(libs.multidexlib2) + implementation(libs.apktool.lib) + implementation(libs.kotlin.reflect) + + compileOnly(libs.android) + + testImplementation(libs.kotlin.test) +} + +tasks { + test { + useJUnitPlatform() + testLogging { + events("PASSED", "SKIPPED", "FAILED") + } + } + + processResources { + expand("projectVersion" to project.version) + } +} + +kotlin { jvmToolchain(11) } + +java { + withSourcesJar() +} + +publishing { + repositories { + mavenLocal() + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/revanced/revanced-patcher") + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } + publications { + create("gpr") { + from(components["java"]) + } + } +} diff --git a/revanced-patcher/settings.gradle.kts b/revanced-patcher/settings.gradle.kts new file mode 100644 index 0000000..2a8c853 --- /dev/null +++ b/revanced-patcher/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "revanced-patcher" \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/IntegrationsConsumer.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/IntegrationsConsumer.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/IntegrationsConsumer.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/IntegrationsConsumer.kt diff --git a/src/main/kotlin/app/revanced/patcher/PackageMetadata.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/PackageMetadata.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/PackageMetadata.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/PackageMetadata.kt diff --git a/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt diff --git a/src/main/kotlin/app/revanced/patcher/PatchExecutorFunction.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatchExecutorFunction.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/PatchExecutorFunction.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/PatchExecutorFunction.kt diff --git a/src/main/kotlin/app/revanced/patcher/Patcher.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/Patcher.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/Patcher.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/Patcher.kt diff --git a/src/main/kotlin/app/revanced/patcher/PatcherContext.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatcherContext.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/PatcherContext.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/PatcherContext.kt diff --git a/src/main/kotlin/app/revanced/patcher/PatcherException.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatcherException.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/PatcherException.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/PatcherException.kt diff --git a/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/PatcherOptions.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt diff --git a/src/main/kotlin/app/revanced/patcher/PatcherResult.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatcherResult.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/PatcherResult.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/PatcherResult.kt diff --git a/src/main/kotlin/app/revanced/patcher/PatchesConsumer.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatchesConsumer.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/PatchesConsumer.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/PatchesConsumer.kt diff --git a/src/main/kotlin/app/revanced/patcher/data/BytecodeContext.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/data/BytecodeContext.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/data/BytecodeContext.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/data/BytecodeContext.kt diff --git a/src/main/kotlin/app/revanced/patcher/data/Context.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/data/Context.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/data/Context.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/data/Context.kt diff --git a/src/main/kotlin/app/revanced/patcher/data/ResourceContext.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/data/ResourceContext.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/data/ResourceContext.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/data/ResourceContext.kt diff --git a/src/main/kotlin/app/revanced/patcher/extensions/AnnotationExtensions.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/extensions/AnnotationExtensions.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/extensions/AnnotationExtensions.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/extensions/AnnotationExtensions.kt diff --git a/src/main/kotlin/app/revanced/patcher/extensions/Extensions.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/extensions/Extensions.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/extensions/Extensions.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/extensions/Extensions.kt diff --git a/src/main/kotlin/app/revanced/patcher/extensions/InstructionExtensions.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/extensions/InstructionExtensions.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/extensions/InstructionExtensions.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/extensions/InstructionExtensions.kt diff --git a/src/main/kotlin/app/revanced/patcher/extensions/MethodFingerprintExtensions.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/extensions/MethodFingerprintExtensions.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/extensions/MethodFingerprintExtensions.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/extensions/MethodFingerprintExtensions.kt diff --git a/src/main/kotlin/app/revanced/patcher/fingerprint/Fingerprint.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/fingerprint/Fingerprint.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/fingerprint/Fingerprint.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/fingerprint/Fingerprint.kt diff --git a/src/main/kotlin/app/revanced/patcher/fingerprint/method/annotation/MethodFingerprintMetadata.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/fingerprint/method/annotation/MethodFingerprintMetadata.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/fingerprint/method/annotation/MethodFingerprintMetadata.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/fingerprint/method/annotation/MethodFingerprintMetadata.kt diff --git a/src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt diff --git a/src/main/kotlin/app/revanced/patcher/logging/Logger.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/logging/Logger.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/logging/Logger.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/logging/Logger.kt diff --git a/src/main/kotlin/app/revanced/patcher/logging/impl/NopLogger.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/logging/impl/NopLogger.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/logging/impl/NopLogger.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/logging/impl/NopLogger.kt diff --git a/src/main/kotlin/app/revanced/patcher/patch/OptionsContainer.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/OptionsContainer.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/patch/OptionsContainer.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/OptionsContainer.kt diff --git a/src/main/kotlin/app/revanced/patcher/patch/Patch.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/Patch.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/patch/Patch.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/Patch.kt diff --git a/src/main/kotlin/app/revanced/patcher/patch/PatchException.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/PatchException.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/patch/PatchException.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/PatchException.kt diff --git a/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt diff --git a/src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt diff --git a/src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/ClassMerger.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/ClassMerger.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/ClassMerger.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/ClassMerger.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/DomFileEditor.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/DomFileEditor.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/DomFileEditor.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/DomFileEditor.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/ProxyClassList.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/ProxyClassList.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/ProxyClassList.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/ProxyClassList.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/ClassProxy.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/ClassProxy.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/ClassProxy.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/ClassProxy.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableClass.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableClass.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableClass.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableClass.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableField.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableField.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableField.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableField.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableMethod.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableMethod.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableMethod.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableMethod.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/smali/ExternalLabel.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/smali/ExternalLabel.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/smali/ExternalLabel.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/smali/ExternalLabel.kt diff --git a/src/main/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompiler.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompiler.kt similarity index 100% rename from src/main/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompiler.kt rename to revanced-patcher/src/main/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompiler.kt diff --git a/src/main/resources/app/revanced/patcher/version.properties b/revanced-patcher/src/main/resources/app/revanced/patcher/version.properties similarity index 100% rename from src/main/resources/app/revanced/patcher/version.properties rename to revanced-patcher/src/main/resources/app/revanced/patcher/version.properties diff --git a/src/test/kotlin/app/revanced/patcher/extensions/InstructionExtensionsTest.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/extensions/InstructionExtensionsTest.kt similarity index 100% rename from src/test/kotlin/app/revanced/patcher/extensions/InstructionExtensionsTest.kt rename to revanced-patcher/src/test/kotlin/app/revanced/patcher/extensions/InstructionExtensionsTest.kt diff --git a/src/test/kotlin/app/revanced/patcher/issues/Issue98.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/issues/Issue98.kt similarity index 100% rename from src/test/kotlin/app/revanced/patcher/issues/Issue98.kt rename to revanced-patcher/src/test/kotlin/app/revanced/patcher/issues/Issue98.kt diff --git a/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt similarity index 100% rename from src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt rename to revanced-patcher/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt diff --git a/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt similarity index 94% rename from src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt rename to revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt index f41a682..e6aa88a 100644 --- a/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt +++ b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt @@ -1,7 +1,5 @@ package app.revanced.patcher.usage.bytecode -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction @@ -9,9 +7,7 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.OptionsContainer import app.revanced.patcher.patch.PatchOption -import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.usage.resource.annotation.ExampleResourceCompatibility import app.revanced.patcher.usage.resource.patch.ExampleResourcePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable @@ -32,11 +28,17 @@ import com.android.tools.smali.dexlib2.util.Preconditions import com.google.common.collect.ImmutableList @Patch -@Name("example-bytecode-patch") -@Description("Example demonstration of a bytecode patch.") -@ExampleResourceCompatibility -@DependsOn([ExampleResourcePatch::class]) -class ExampleBytecodePatch : BytecodePatch(listOf(ExampleFingerprint)) { +class ExampleBytecodePatch : BytecodePatch( + Manifest( + "Example patch", + "Example demonstration of a bytecode patch.", + dependencies = setOf(ExampleResourcePatch::class), + compatiblePackages = setOf( + Manifest.CompatiblePackage("com.example.examplePackage", setOf("0.0.1", "0.0.2")) + ) + ), + ExampleFingerprint +) { // This function will be executed by the patcher. // You can treat it as a constructor override fun execute(context: BytecodeContext) { diff --git a/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleFingerprint.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleFingerprint.kt similarity index 100% rename from src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleFingerprint.kt rename to revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleFingerprint.kt diff --git a/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt similarity index 60% rename from src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt rename to revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt index 6c45b0a..974d885 100644 --- a/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt +++ b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt @@ -1,18 +1,10 @@ package app.revanced.patcher.usage.resource.patch -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.usage.resource.annotation.ExampleResourceCompatibility import org.w3c.dom.Element -@Patch -@Name("example-resource-patch") -@Description("Example demonstration of a resource patch.") -@ExampleResourceCompatibility -class ExampleResourcePatch : ResourcePatch { +class ExampleResourcePatch : ResourcePatch(Manifest("Example name", "Example description")) { override fun execute(context: ResourceContext) { context.xmlEditor["AndroidManifest.xml"].use { editor -> val element = editor // regular DomFileEditor diff --git a/src/test/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompilerTest.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompilerTest.kt similarity index 100% rename from src/test/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompilerTest.kt rename to revanced-patcher/src/test/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompilerTest.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index d398cc6..1f9503f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,4 +19,4 @@ dependencyResolutionManagement { } } -rootProject.name = "revanced-patcher" +include("revanced-patcher") \ No newline at end of file diff --git a/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodeCompatibility.kt b/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodeCompatibility.kt deleted file mode 100644 index 85f0a32..0000000 --- a/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodeCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patcher.usage.bytecode - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.example.examplePackage", arrayOf("0.0.1", "0.0.2") - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class ExampleBytecodeCompatibility - diff --git a/src/test/kotlin/app/revanced/patcher/usage/resource/annotation/ExampleResourceCompatibility.kt b/src/test/kotlin/app/revanced/patcher/usage/resource/annotation/ExampleResourceCompatibility.kt deleted file mode 100644 index 059649e..0000000 --- a/src/test/kotlin/app/revanced/patcher/usage/resource/annotation/ExampleResourceCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patcher.usage.resource.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.example.examplePackage", arrayOf("0.0.1", "0.0.2") - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class ExampleResourceCompatibility - From 3fc6a139eef67237c116fb4e3e29bf9542d3a981 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 4 Sep 2023 05:38:35 +0200 Subject: [PATCH 3/3] feat!: Add patch annotation processor This commit introduces an annotation processor for patches. Patches can use the `@Patch` instead of super constructor parameters. BREAKING CHANGE: The manifest for patches has been removed, and the properties have been added to patches. Patches are now `OptionsContainer`. The `@Patch` annotation has been removed in favour of the `@Patch` annotation from the annotation processor. --- gradle/libs.versions.toml | 8 + .../revanced-patch-annotations-processor.api | 25 +++ .../build.gradle.kts | 50 +++++ .../settings.gradle.kts | 2 + .../patch/annotations/PatchAnnotations.kt | 38 ++++ .../annotations/processor/PatchProcessor.kt | 198 ++++++++++++++++++ .../processor/PatchProcessorProvider.kt | 9 + ...ols.ksp.processing.SymbolProcessorProvider | 1 + .../processor/TestPatchAnnotationProcessor.kt | 131 ++++++++++++ .../samples/dependencies/DependencyPatch.kt | 10 + .../samples/dependencies/DependentPatch.kt | 12 ++ .../manualdependency/DependencyPatch.kt | 10 + .../manualdependency/DependentPatch.kt | 17 ++ .../processor/samples/options/OptionsPatch.kt | 21 ++ .../samples/processing/ProcessablePatch.kt | 10 + revanced-patcher/api/revanced-patcher.api | 32 ++- revanced-patcher/build.gradle.kts | 1 + .../app/revanced/patcher/PatchBundleLoader.kt | 17 +- .../kotlin/app/revanced/patcher/Patcher.kt | 56 ++--- .../patcher/patch/OptionsContainer.kt | 7 +- .../app/revanced/patcher/patch/Patch.kt | 112 +++++----- .../app/revanced/patcher/patch/PatchOption.kt | 2 - .../patcher/patch/annotations/Patch.kt | 7 - .../extensions/InstructionExtensionsTest.kt | 2 +- .../patcher/patch/PatchOptionsTest.kt | 4 +- .../{bytecode => }/ExampleBytecodePatch.kt | 77 +++---- .../{bytecode => }/ExampleFingerprint.kt | 2 +- .../patch => }/ExampleResourcePatch.kt | 5 +- settings.gradle.kts | 2 +- 29 files changed, 707 insertions(+), 161 deletions(-) create mode 100644 revanced-patch-annotations-processor/api/revanced-patch-annotations-processor.api create mode 100644 revanced-patch-annotations-processor/build.gradle.kts create mode 100644 revanced-patch-annotations-processor/settings.gradle.kts create mode 100644 revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotations.kt create mode 100644 revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/processor/PatchProcessor.kt create mode 100644 revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/processor/PatchProcessorProvider.kt create mode 100644 revanced-patch-annotations-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider create mode 100644 revanced-patch-annotations-processor/src/test/kotlin/app/revanced/patcher/patch/annotations/processor/TestPatchAnnotationProcessor.kt create mode 100644 revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/dependencies/DependencyPatch.kt create mode 100644 revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/dependencies/DependentPatch.kt create mode 100644 revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/limitations/manualdependency/DependencyPatch.kt create mode 100644 revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/limitations/manualdependency/DependentPatch.kt create mode 100644 revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/options/OptionsPatch.kt create mode 100644 revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/processing/ProcessablePatch.kt delete mode 100644 revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt rename revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/{bytecode => }/ExampleBytecodePatch.kt (82%) rename revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/{bytecode => }/ExampleFingerprint.kt (93%) rename revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/{resource/patch => }/ExampleResourcePatch.kt (79%) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4b214cb..512c296 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,8 +6,12 @@ kotlin-test = "1.8.20-RC" kotlinx-coroutines-core = "1.7.1" multidexlib2 = "3.0.3.r2" smali = "3.0.3" +symbol-processing-api = "1.9.0-1.0.11" xpp3 = "1.1.4c" binary-compatibility-validator = "0.13.2" +kotlin-compile-testing-ksp = "1.5.0" +kotlinpoet-ksp = "1.14.2" +ksp = "1.9.0-1.0.11" [libraries] android = { module = "com.google.android:android", version.ref = "android" } @@ -17,7 +21,11 @@ kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotl kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" } multidexlib2 = { module = "app.revanced:multidexlib2", version.ref = "multidexlib2" } smali = { module = "com.android.tools.smali:smali", version.ref = "smali" } +symbol-processing-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "symbol-processing-api" } xpp3 = { module = "xpp3:xpp3", version.ref = "xpp3" } +kotlin-compile-testing = { module = "com.github.tschuchortdev:kotlin-compile-testing-ksp", version.ref = "kotlin-compile-testing-ksp" } +kotlinpoet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlinpoet-ksp" } [plugins] binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file diff --git a/revanced-patch-annotations-processor/api/revanced-patch-annotations-processor.api b/revanced-patch-annotations-processor/api/revanced-patch-annotations-processor.api new file mode 100644 index 0000000..87bc05c --- /dev/null +++ b/revanced-patch-annotations-processor/api/revanced-patch-annotations-processor.api @@ -0,0 +1,25 @@ +public abstract interface annotation class app/revanced/patcher/patch/annotations/CompatiblePackage : java/lang/annotation/Annotation { + public abstract fun name ()Ljava/lang/String; + public abstract fun versions ()[Ljava/lang/String; +} + +public abstract interface annotation class app/revanced/patcher/patch/annotations/Patch : java/lang/annotation/Annotation { + public abstract fun compatiblePackages ()[Lapp/revanced/patcher/patch/annotations/CompatiblePackage; + public abstract fun dependencies ()[Ljava/lang/Class; + public abstract fun description ()Ljava/lang/String; + public abstract fun name ()Ljava/lang/String; + public abstract fun requiresIntegrations ()Z + public abstract fun use ()Z +} + +public final class app/revanced/patcher/patch/annotations/processor/PatchProcessor : com/google/devtools/ksp/processing/SymbolProcessor { + public fun (Lcom/google/devtools/ksp/processing/CodeGenerator;Lcom/google/devtools/ksp/processing/KSPLogger;)V + public fun process (Lcom/google/devtools/ksp/processing/Resolver;)Ljava/util/List; +} + +public final class app/revanced/patcher/patch/annotations/processor/PatchProcessorProvider : com/google/devtools/ksp/processing/SymbolProcessorProvider { + public fun ()V + public fun create (Lcom/google/devtools/ksp/processing/SymbolProcessorEnvironment;)Lapp/revanced/patcher/patch/annotations/processor/PatchProcessor; + public synthetic fun create (Lcom/google/devtools/ksp/processing/SymbolProcessorEnvironment;)Lcom/google/devtools/ksp/processing/SymbolProcessor; +} + diff --git a/revanced-patch-annotations-processor/build.gradle.kts b/revanced-patch-annotations-processor/build.gradle.kts new file mode 100644 index 0000000..7b0f0be --- /dev/null +++ b/revanced-patch-annotations-processor/build.gradle.kts @@ -0,0 +1,50 @@ +plugins { + kotlin("jvm") version "1.9.0" + `maven-publish` + alias(libs.plugins.ksp) +} + +group = "app.revanced" + +dependencies { + implementation(libs.symbol.processing.api) + implementation(libs.kotlinpoet.ksp) + implementation(project(":revanced-patcher")) + + testImplementation(libs.kotlin.test) + testImplementation(libs.kotlin.compile.testing) +} + +tasks { + test { + useJUnitPlatform() + testLogging { + events("PASSED", "SKIPPED", "FAILED") + } + } +} + +kotlin { jvmToolchain(11) } + +java { + withSourcesJar() +} + +publishing { + repositories { + mavenLocal() + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/revanced/revanced-patch-annotations-processor") + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } + publications { + create("gpr") { + from(components["java"]) + } + } +} \ No newline at end of file diff --git a/revanced-patch-annotations-processor/settings.gradle.kts b/revanced-patch-annotations-processor/settings.gradle.kts new file mode 100644 index 0000000..a376e09 --- /dev/null +++ b/revanced-patch-annotations-processor/settings.gradle.kts @@ -0,0 +1,2 @@ +rootProject.name = "revanced-patch-annotations-processor" + diff --git a/revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotations.kt b/revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotations.kt new file mode 100644 index 0000000..6c28e6e --- /dev/null +++ b/revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotations.kt @@ -0,0 +1,38 @@ +package app.revanced.patcher.patch.annotations + +import java.lang.annotation.Inherited +import kotlin.reflect.KClass + +/** + * Annotation for [app.revanced.patcher.patch.Patch] classes. + * + * @param name The name of the patch. If empty, the patch will be unnamed. + * @param description The description of the patch. If empty, no description will be used. + * @param dependencies The patches this patch depends on. + * @param compatiblePackages The packages this patch is compatible with. + * @param use Whether this patch should be used. + * @param requiresIntegrations Whether this patch requires integrations. + */ +@Retention(AnnotationRetention.SOURCE) +@Target(AnnotationTarget.CLASS) +@Inherited +annotation class Patch( + val name: String = "", + val description: String = "", + val dependencies: Array>> = [], + val compatiblePackages: Array = [], + val use: Boolean = true, + // TODO: Remove this property, once integrations are coupled with patches. + val requiresIntegrations: Boolean = false, +) + +/** + * A package that a [app.revanced.patcher.patch.Patch] is compatible with. + * + * @param name The name of the package. + * @param versions The versions of the package. + */ +annotation class CompatiblePackage( + val name: String, + val versions: Array = [], +) \ No newline at end of file diff --git a/revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/processor/PatchProcessor.kt b/revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/processor/PatchProcessor.kt new file mode 100644 index 0000000..f597e8d --- /dev/null +++ b/revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/processor/PatchProcessor.kt @@ -0,0 +1,198 @@ +package app.revanced.patcher.patch.annotations.processor + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchOptions +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.Patch +import com.google.devtools.ksp.processing.* +import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSAnnotation +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSType +import com.google.devtools.ksp.validate +import com.squareup.kotlinpoet.* +import com.squareup.kotlinpoet.ksp.toClassName +import com.squareup.kotlinpoet.ksp.writeTo +import kotlin.reflect.KClass + +class PatchProcessor( + private val codeGenerator: CodeGenerator, + private val logger: KSPLogger +) : SymbolProcessor { + + private fun KSAnnotated.isSubclassOf(cls: KClass<*>): Boolean { + if (this !is KSClassDeclaration) return false + + if (qualifiedName?.asString() == cls.qualifiedName) return true + + return superTypes.any { it.resolve().declaration.isSubclassOf(cls) } + } + + @Suppress("UNCHECKED_CAST") + override fun process(resolver: Resolver): List { + val executablePatches = buildMap { + resolver.getSymbolsWithAnnotation(Patch::class.qualifiedName!!).filter { + // Do not check here if Patch is super of the class, because it is expensive. + // Check it later when processing. + it.validate() && it.isSubclassOf(app.revanced.patcher.patch.Patch::class) + }.map { + it as KSClassDeclaration + }.forEach { patchDeclaration -> + patchDeclaration.annotations.find { + it.annotationType.resolve().declaration.qualifiedName!!.asString() == Patch::class.qualifiedName!! + }?.let { annotation -> + fun KSAnnotation.property(name: String) = + arguments.find { it.name!!.asString() == name }?.value!! + + val name = + annotation.property("name").toString().ifEmpty { null } + + val description = + annotation.property("description").toString().ifEmpty { null } + + val dependencies = + (annotation.property("dependencies") as List).ifEmpty { null } + + val compatiblePackages = + (annotation.property("compatiblePackages") as List).ifEmpty { null } + + val use = + annotation.property("use") as Boolean + + val requiresIntegrations = + annotation.property("requiresIntegrations") as Boolean + + // Data class for KotlinPoet + data class PatchData( + val name: String?, + val description: String?, + val dependencies: List?, + val compatiblePackages: List?, + val use: Boolean, + val requiresIntegrations: Boolean + ) + + this[patchDeclaration] = PatchData( + name, + description, + dependencies?.map { dependency -> dependency.toClassName() }, + compatiblePackages?.map { + val packageName = it.property("name") + val packageVersions = (it.property("versions") as List) + .joinToString(", ") { version -> "\"$version\"" } + + CodeBlock.of( + "%T(%S, setOf(%L))", + app.revanced.patcher.patch.Patch.CompatiblePackage::class, + packageName, + packageVersions + ) + }, + use, + requiresIntegrations + ) + } + } + } + + // If a patch depends on another, that is annotated, the dependency should be replaced with the generated patch, + // because the generated patch has all the necessary properties to invoke the super constructor, + // unlike the annotated patch. + val dependencyResolutionMap = buildMap { + executablePatches.values.filter { it.dependencies != null }.flatMap { + it.dependencies!! + }.distinct().forEach { dependency -> + executablePatches.keys.find { it.qualifiedName?.asString() == dependency.toString() } + ?.let { patch -> + this[dependency] = ClassName( + patch.packageName.asString(), + patch.simpleName.asString() + "Generated" + ) + } + } + } + + // kotlin poet generate a class for each patch + executablePatches.forEach { (patchDeclaration, patchAnnotation) -> + val isBytecodePatch = patchDeclaration.isSubclassOf(BytecodePatch::class) + + val superClass = if (isBytecodePatch) { + BytecodePatch::class + } else { + ResourcePatch::class + } + + val contextClass = if (isBytecodePatch) { + BytecodeContext::class + } else { + ResourceContext::class + } + + val generatedPatchClassName = ClassName( + patchDeclaration.packageName.asString(), + patchDeclaration.simpleName.asString() + "Generated" + ) + + FileSpec.builder(generatedPatchClassName) + .addType( + TypeSpec.objectBuilder(generatedPatchClassName) + .superclass(superClass).apply { + patchAnnotation.name?.let { name -> + addSuperclassConstructorParameter("name = %S", name) + } + + patchAnnotation.description?.let { description -> + addSuperclassConstructorParameter("description = %S", description) + } + + patchAnnotation.compatiblePackages?.let { compatiblePackages -> + addSuperclassConstructorParameter( + "compatiblePackages = setOf(%L)", + compatiblePackages.joinToString(", ") + ) + } + + patchAnnotation.dependencies?.let { dependencies -> + addSuperclassConstructorParameter( + "dependencies = setOf(%L)", + buildList { + addAll(dependencies) + // Also add the source class of the generated class so that it is also executed + add(patchDeclaration.toClassName()) + }.joinToString(", ") { dependency -> + "${(dependencyResolutionMap[dependency] ?: dependency)}::class" + } + ) + } + addSuperclassConstructorParameter( + "use = %L", patchAnnotation.use + ) + + addSuperclassConstructorParameter( + "requiresIntegrations = %L", + patchAnnotation.requiresIntegrations + ) + } + .addFunction( + FunSpec.builder("execute") + .addModifiers(KModifier.OVERRIDE) + .addParameter("context", contextClass) + .build() + ) + .addProperty( + PropertySpec.builder("options", PatchOptions::class, KModifier.OVERRIDE) + .initializer("%T.options", patchDeclaration.toClassName()) + .build() + ) + .build() + ).build().writeTo( + codeGenerator, + Dependencies(false, patchDeclaration.containingFile!!) + ) + } + + return emptyList() + } +} \ No newline at end of file diff --git a/revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/processor/PatchProcessorProvider.kt b/revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/processor/PatchProcessorProvider.kt new file mode 100644 index 0000000..95abc37 --- /dev/null +++ b/revanced-patch-annotations-processor/src/main/kotlin/app/revanced/patcher/patch/annotations/processor/PatchProcessorProvider.kt @@ -0,0 +1,9 @@ +package app.revanced.patcher.patch.annotations.processor + +import com.google.devtools.ksp.processing.SymbolProcessorEnvironment +import com.google.devtools.ksp.processing.SymbolProcessorProvider + +class PatchProcessorProvider : SymbolProcessorProvider { + override fun create(environment: SymbolProcessorEnvironment) = + PatchProcessor(environment.codeGenerator, environment.logger) +} \ No newline at end of file diff --git a/revanced-patch-annotations-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/revanced-patch-annotations-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider new file mode 100644 index 0000000..0a48684 --- /dev/null +++ b/revanced-patch-annotations-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider @@ -0,0 +1 @@ +app.revanced.patcher.patch.annotations.processor.PatchProcessorProvider \ No newline at end of file diff --git a/revanced-patch-annotations-processor/src/test/kotlin/app/revanced/patcher/patch/annotations/processor/TestPatchAnnotationProcessor.kt b/revanced-patch-annotations-processor/src/test/kotlin/app/revanced/patcher/patch/annotations/processor/TestPatchAnnotationProcessor.kt new file mode 100644 index 0000000..850f261 --- /dev/null +++ b/revanced-patch-annotations-processor/src/test/kotlin/app/revanced/patcher/patch/annotations/processor/TestPatchAnnotationProcessor.kt @@ -0,0 +1,131 @@ +package app.revanced.patcher.patch.annotations.processor + +import app.revanced.patcher.patch.Patch +import com.tschuchort.compiletesting.KotlinCompilation +import com.tschuchort.compiletesting.SourceFile +import com.tschuchort.compiletesting.kspWithCompilation +import com.tschuchort.compiletesting.symbolProcessorProviders +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class TestPatchAnnotationProcessor { + // region Processing + + @Test + fun testProcessing() = assertEquals( + "Processable patch", compile( + getSourceFile( + "processing", "ProcessablePatch" + ) + ).loadPatch("$SAMPLE_PACKAGE.processing.ProcessablePatchGenerated").name + ) + + // endregion + + // region Dependencies + + @Test + fun testDependencies() { + compile( + getSourceFile( + "dependencies", "DependentPatch" + ), getSourceFile( + "dependencies", "DependencyPatch" + ) + ).let { result -> + result.loadPatch("$SAMPLE_PACKAGE.dependencies.DependentPatchGenerated").let { + // Dependency as well as the source class of the generated class. + assertEquals( + 2, + it.dependencies!!.size + ) + + // The last dependency is always the source class of the generated class to respect + // order of dependencies. + assertEquals( + result.loadPatch("$SAMPLE_PACKAGE.dependencies.DependentPatch")::class, + it.dependencies!!.last() + ) + } + } + } + + // endregion + + // region Options + + @Test + fun testOptions() { + val patch = compile( + getSourceFile( + "options", "OptionsPatch" + ) + ).loadPatch("$SAMPLE_PACKAGE.options.OptionsPatchGenerated") + + assertNotNull(patch.options) + assertEquals(patch.options["print"].title, "Print message") + } + + // endregion + + // region Limitations + @Test + fun failingManualDependency() = assertNull( + compile( + getSourceFile( + "limitations/manualdependency", "DependentPatch" + ), getSourceFile( + "limitations/manualdependency", "DependencyPatch" + ) + ).loadPatch("$SAMPLE_PACKAGE.limitations.manualdependency.DependentPatchGenerated").dependencies + ) + + // endregion + + private companion object Utils { + const val SAMPLE_PACKAGE = "app.revanced.patcher.patch.annotations.processor.samples" + + /** + * Get a source file from the given sample and class name. + * + * @param sample The sample to get the source file from. + * @param className The name of the class to get the source file from. + * @return The source file. + */ + fun getSourceFile(sample: String, className: String) = SourceFile.kotlin( + "$className.kt", TestPatchAnnotationProcessor::class.java.classLoader.getResourceAsStream( + "app/revanced/patcher/patch/annotations/processor/samples/$sample/$className.kt" + )?.readAllBytes()?.toString(Charsets.UTF_8) ?: error("Could not find resource $className") + ) + + /** + * Compile the given source files and return the result. + * + * @param sourceFiles The source files to compile. + * @return The result of the compilation. + */ + fun compile(vararg sourceFiles: SourceFile) = KotlinCompilation().apply { + sources = sourceFiles.asList() + + symbolProcessorProviders = listOf(PatchProcessorProvider()) + + // Required until https://github.com/tschuchortdev/kotlin-compile-testing/issues/312 closed. + kspWithCompilation = true + + inheritClassPath = true + messageOutputStream = System.out + }.compile().also { result -> + assertEquals(KotlinCompilation.ExitCode.OK, result.exitCode) + } + + // region Class loading + + fun KotlinCompilation.Result.loadPatch(name: String) = classLoader.loadClass(name).loadPatch() + + fun Class<*>.loadPatch() = this.getField("INSTANCE").get(null) as Patch<*> + + // endregion + } +} \ No newline at end of file diff --git a/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/dependencies/DependencyPatch.kt b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/dependencies/DependencyPatch.kt new file mode 100644 index 0000000..c03169d --- /dev/null +++ b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/dependencies/DependencyPatch.kt @@ -0,0 +1,10 @@ +package app.revanced.patcher.patch.annotations.processor.samples.dependencies + +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.Patch + +@Patch(name = "Dependency patch") +object DependencyPatch : ResourcePatch() { + override fun execute(context: ResourceContext) {} +} \ No newline at end of file diff --git a/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/dependencies/DependentPatch.kt b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/dependencies/DependentPatch.kt new file mode 100644 index 0000000..44d6df0 --- /dev/null +++ b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/dependencies/DependentPatch.kt @@ -0,0 +1,12 @@ +package app.revanced.patcher.patch.annotations.processor.samples.dependencies +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotations.Patch + +@Patch( + name = "Dependent patch", + dependencies = [DependencyPatch::class], +) +object DependentPatch : BytecodePatch() { + override fun execute(context: BytecodeContext) {} +} \ No newline at end of file diff --git a/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/limitations/manualdependency/DependencyPatch.kt b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/limitations/manualdependency/DependencyPatch.kt new file mode 100644 index 0000000..d43bd2c --- /dev/null +++ b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/limitations/manualdependency/DependencyPatch.kt @@ -0,0 +1,10 @@ +package app.revanced.patcher.patch.annotations.processor.samples.limitations.manualdependency + +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.Patch + +@Patch(name = "Dependency patch") +object DependencyPatch : ResourcePatch() { + override fun execute(context: ResourceContext) { } +} \ No newline at end of file diff --git a/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/limitations/manualdependency/DependentPatch.kt b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/limitations/manualdependency/DependentPatch.kt new file mode 100644 index 0000000..60121ec --- /dev/null +++ b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/limitations/manualdependency/DependentPatch.kt @@ -0,0 +1,17 @@ +package app.revanced.patcher.patch.annotations.processor.samples.limitations.manualdependency +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotations.Patch + +@Patch(name = "Dependent patch") +object DependentPatch : BytecodePatch( + // Dependency will not be executed correctly if it is manually specified. + // The reason for this is that the dependency patch is annotated too, + // so the processor will generate a new patch class for it embedding the annotated information. + // Because the dependency is manually specified, + // the processor will not be able to change this dependency to the generated class, + // which means that the dependency will lose the annotated information. + dependencies = setOf(DependencyPatch::class) +) { + override fun execute(context: BytecodeContext) {} +} \ No newline at end of file diff --git a/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/options/OptionsPatch.kt b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/options/OptionsPatch.kt new file mode 100644 index 0000000..4aaf93e --- /dev/null +++ b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/options/OptionsPatch.kt @@ -0,0 +1,21 @@ +package app.revanced.patcher.patch.annotations.processor.samples.options + +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchOption +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.Patch + +@Patch(name = "Options patch") +object OptionsPatch : ResourcePatch() { + override fun execute(context: ResourceContext) {} + + @Suppress("unused") + private val printOption by option( + PatchOption.StringOption( + "print", + null, + "Print message", + "The message to print." + ) + ) +} \ No newline at end of file diff --git a/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/processing/ProcessablePatch.kt b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/processing/ProcessablePatch.kt new file mode 100644 index 0000000..28d04a0 --- /dev/null +++ b/revanced-patch-annotations-processor/src/test/resources/app/revanced/patcher/patch/annotations/processor/samples/processing/ProcessablePatch.kt @@ -0,0 +1,10 @@ +package app.revanced.patcher.patch.annotations.processor.samples.processing + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotations.Patch + +@Patch("Processable patch") +object ProcessablePatch : BytecodePatch() { + override fun execute(context: BytecodeContext) {} +} \ No newline at end of file diff --git a/revanced-patcher/api/revanced-patcher.api b/revanced-patcher/api/revanced-patcher.api index 160d13b..8987c4e 100644 --- a/revanced-patcher/api/revanced-patcher.api +++ b/revanced-patcher/api/revanced-patcher.api @@ -327,7 +327,9 @@ public final class app/revanced/patcher/logging/impl/NopLogger : app/revanced/pa } public abstract class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch { - public fun (Lapp/revanced/patcher/patch/Patch$Manifest;[Lapp/revanced/patcher/fingerprint/method/impl/MethodFingerprint;)V + public fun ()V + public fun (Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZ)V + public synthetic fun (Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V } public final class app/revanced/patcher/patch/IllegalValueException : java/lang/Exception { @@ -348,38 +350,29 @@ public final class app/revanced/patcher/patch/NoSuchOptionException : java/lang/ public abstract class app/revanced/patcher/patch/OptionsContainer { public fun ()V - public final fun getOptions ()Lapp/revanced/patcher/patch/PatchOptions; + public fun getOptions ()Lapp/revanced/patcher/patch/PatchOptions; protected final fun option (Lapp/revanced/patcher/patch/PatchOption;)Lapp/revanced/patcher/patch/PatchOption; } -public abstract class app/revanced/patcher/patch/Patch { - public synthetic fun (Lapp/revanced/patcher/patch/Patch$Manifest;Lkotlin/jvm/internal/DefaultConstructorMarker;)V +public abstract class app/revanced/patcher/patch/Patch : app/revanced/patcher/patch/OptionsContainer { + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZLkotlin/jvm/internal/DefaultConstructorMarker;)V public fun equals (Ljava/lang/Object;)Z public abstract fun execute (Lapp/revanced/patcher/data/Context;)V - public final fun getManifest ()Lapp/revanced/patcher/patch/Patch$Manifest; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class app/revanced/patcher/patch/Patch$Manifest { - public fun (Ljava/lang/String;Ljava/lang/String;ZLjava/util/Set;Ljava/util/Set;ZLapp/revanced/patcher/patch/PatchOptions;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;ZLjava/util/Set;Ljava/util/Set;ZLapp/revanced/patcher/patch/PatchOptions;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun equals (Ljava/lang/Object;)Z public final fun getCompatiblePackages ()Ljava/util/Set; public final fun getDependencies ()Ljava/util/Set; public final fun getDescription ()Ljava/lang/String; public final fun getName ()Ljava/lang/String; - public final fun getOptions ()Lapp/revanced/patcher/patch/PatchOptions; public final fun getRequiresIntegrations ()Z public final fun getUse ()Z public fun hashCode ()I + public fun toString ()Ljava/lang/String; } -public final class app/revanced/patcher/patch/Patch$Manifest$CompatiblePackage { +public final class app/revanced/patcher/patch/Patch$CompatiblePackage { public fun (Ljava/lang/String;Ljava/util/Set;)V public synthetic fun (Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun getName ()Ljava/lang/String; - public final fun getVersions ()Ljava/util/Set; } public final class app/revanced/patcher/patch/PatchException : java/lang/Exception { @@ -446,10 +439,9 @@ public final class app/revanced/patcher/patch/RequirementNotMetException : java/ } public abstract class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch { - public fun (Lapp/revanced/patcher/patch/Patch$Manifest;)V -} - -public abstract interface annotation class app/revanced/patcher/patch/annotations/Patch : java/lang/annotation/Annotation { + public fun ()V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZ)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V } public final class app/revanced/patcher/util/DomFileEditor : java/io/Closeable { diff --git a/revanced-patcher/build.gradle.kts b/revanced-patcher/build.gradle.kts index e9fcb12..f8a97f4 100644 --- a/revanced-patcher/build.gradle.kts +++ b/revanced-patcher/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { compileOnly(libs.android) + testImplementation(project(":revanced-patch-annotations-processor")) testImplementation(libs.kotlin.test) } diff --git a/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt index 246b4c9..d58cf41 100644 --- a/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt +++ b/revanced-patcher/src/main/kotlin/app/revanced/patcher/PatchBundleLoader.kt @@ -2,7 +2,6 @@ package app.revanced.patcher -import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively import app.revanced.patcher.patch.Patch import dalvik.system.DexClassLoader import lanchon.multidexlib2.BasicDexFileNamer @@ -25,7 +24,7 @@ typealias PatchClass = KClass> /** * A loader of [Patch]es from patch bundles. - * This will load all [Patch]es from the given patch bundles. + * This will load all [Patch]es from the given patch bundles that have a name. * * @param getBinaryClassNames A function that returns the binary names of all classes in a patch bundle. * @param classLoader The [ClassLoader] to use for loading the classes. @@ -38,22 +37,22 @@ sealed class PatchBundleLoader private constructor( private val logger = Logger.getLogger(PatchBundleLoader::class.java.name) init { - patchBundles.flatMap(getBinaryClassNames).map { + patchBundles.flatMap(getBinaryClassNames).asSequence().map { classLoader.loadClass(it) }.filter { - if (it.isAnnotation) return@filter false - - it.findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class) != null + it.isInstance(Patch::class.java) }.mapNotNull { patchClass -> patchClass.getInstance(logger) - }.associateBy { it.manifest.name } - let { patches -> + }.filter { + it.name != null + }.associateBy { + it.name!! + }.let { patches -> @Suppress("UNCHECKED_CAST") (this as MutableMap>).putAll(patches) } } - internal companion object Utils { /** * Instantiates a [Patch]. If the class is a singleton, the INSTANCE field will be used. diff --git a/revanced-patcher/src/main/kotlin/app/revanced/patcher/Patcher.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/Patcher.kt index 160859a..2874040 100644 --- a/revanced-patcher/src/main/kotlin/app/revanced/patcher/Patcher.kt +++ b/revanced-patcher/src/main/kotlin/app/revanced/patcher/Patcher.kt @@ -2,7 +2,6 @@ package app.revanced.patcher import app.revanced.patcher.PatchBundleLoader.Utils.getInstance import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolveUsingLookupMap import app.revanced.patcher.patch.* @@ -46,13 +45,19 @@ class Patcher( context.resourceContext.decodeResources(ResourceContext.ResourceDecodingMode.MANIFEST_ONLY) } + // TODO: Fix circular dependency detection. + // /** + // * Add [Patch]es to ReVanced [Patcher]. + // * It is not guaranteed that all supplied [Patch]es will be accepted, if an exception is thrown. + // * + // * @param patches The [Patch]es to add. + // * @throws PatcherException.CircularDependencyException If a circular dependency is detected. + // */ /** * Add [Patch]es to ReVanced [Patcher]. - * It is not guaranteed that all supplied [Patch]es will be accepted, if an exception is thrown. * * @param patches The [Patch]es to add. - * @throws PatcherException.CircularDependencyException If a circular dependency is detected. - */ + */ @Suppress("NAME_SHADOWING") override fun acceptPatches(patches: List>) { /** @@ -65,14 +70,14 @@ class Patcher( val dependency = this.java.getInstance(logger)!! context.allPatches[this] = dependency - dependency.manifest.dependencies?.forEach { it.putDependenciesRecursively() } + dependency.dependencies?.forEach { it.putDependenciesRecursively() } } // Add all patches and their dependencies to the context. for (patch in patches) context.executablePatches.putIfAbsent(patch::class, patch) ?: { context.allPatches[patch::class] = patch - patch.manifest.dependencies?.forEach { it.putDependenciesRecursively() } + patch.dependencies?.forEach { it.putDependenciesRecursively() } } /* TODO: Fix circular dependency detection. @@ -99,7 +104,7 @@ class Patcher( * @param predicate The predicate to match. */ fun Patch<*>.anyRecursively(predicate: (Patch<*>) -> Boolean): Boolean = - predicate(this) || manifest.dependencies?.any { dependency -> + predicate(this) || dependencies?.any { dependency -> context.allPatches[dependency]!!.anyRecursively(predicate) } ?: false @@ -113,7 +118,7 @@ class Patcher( // Determine, if merging integrations is required. for (patch in patches) - if (!patch.anyRecursively { it.manifest.requiresIntegrations }) { + if (!patch.anyRecursively { it.requiresIntegrations }) { context.bytecodeContext.integrations.merge = true break } @@ -148,7 +153,7 @@ class Patcher( patch: Patch<*>, executedPatches: LinkedHashMap, PatchResult> ): PatchResult { - val patchName = patch.manifest.name + val patchName = patch.name executedPatches[patch]?.let { patchResult -> patchResult.exception ?: return patchResult @@ -159,7 +164,7 @@ class Patcher( } // Recursively execute all dependency patches. - patch.manifest.dependencies?.forEach { dependencyName -> + patch.dependencies?.forEach { dependencyName -> val dependency = context.executablePatches[dependencyName]!! val result = executePatch(dependency, executedPatches) @@ -171,17 +176,17 @@ class Patcher( } } - // TODO: Implement this in a more polymorphic way. - val patchContext = if (patch is BytecodePatch) { - patch.fingerprints.asList().resolveUsingLookupMap(context.bytecodeContext) - - context.bytecodeContext - } else { - context.resourceContext - } - return try { - patch.execute(patchContext) + // TODO: Implement this in a more polymorphic way. + when (patch) { + is BytecodePatch -> { + patch.fingerprints.toList().resolveUsingLookupMap(context.bytecodeContext) + patch.execute(context.bytecodeContext) + } + is ResourcePatch -> { + patch.execute(context.resourceContext) + } + } PatchResult(patch) } catch (exception: PatchException) { @@ -203,11 +208,11 @@ class Patcher( val executedPatches = LinkedHashMap, PatchResult>() // Key is name. - context.executablePatches.map { it.value }.sortedBy { it.manifest.name }.forEach { patch -> + context.executablePatches.map { it.value }.sortedBy { it.name }.forEach { patch -> val patchResult = executePatch(patch, executedPatches) // If the patch failed, emit the result, even if it is closeable. - // Results of successfully executed patches that are closeable will be emitted later. + // Results of executed patches that are closeable will be emitted later. patchResult.exception?.let { // Propagate exception to caller instead of wrapping it in a new exception. emit(patchResult) @@ -240,7 +245,7 @@ class Patcher( PatchResult( patch, PatchException( - "'${patch.manifest.name}' raised an exception while being closed: $it", + "'${patch.name}' raised an exception while being closed: $it", result.exception ) ) @@ -248,10 +253,7 @@ class Patcher( if (returnOnError) return@flow } ?: run { - patch::class - .java - .findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class) - ?: return@run + patch.name ?: return@run emit(result) } diff --git a/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/OptionsContainer.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/OptionsContainer.kt index f14ca48..52320a3 100644 --- a/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/OptionsContainer.kt +++ b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/OptionsContainer.kt @@ -9,8 +9,13 @@ abstract class OptionsContainer { * @see PatchOptions */ @Suppress("MemberVisibilityCanBePrivate") - val options = PatchOptions() + open val options = PatchOptions() + /** + * Registers a [PatchOption]. + * @param opt The [PatchOption] to register. + * @return The registered [PatchOption]. + */ protected fun option(opt: PatchOption): PatchOption { options.register(opt) return opt diff --git a/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/Patch.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/Patch.kt index 66b8b20..549180e 100644 --- a/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/Patch.kt +++ b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/Patch.kt @@ -1,3 +1,5 @@ +@file:Suppress("MemberVisibilityCanBePrivate", "UNUSED_PARAMETER") + package app.revanced.patcher.patch import app.revanced.patcher.PatchClass @@ -14,10 +16,23 @@ import java.io.Closeable * If an implementation of [Patch] also implements [Closeable] * it will be closed in reverse execution order of patches executed by ReVanced [Patcher]. * - * @param manifest The manifest of the [Patch]. + * @param name The name of the patch. + * @param description The description of the patch. + * @param compatiblePackages The packages the patch is compatible with. + * @param dependencies The names of patches this patch depends on. + * @param use Weather or not the patch should be used. + * @param requiresIntegrations Weather or not the patch requires integrations. * @param T The [Context] type this patch will work on. */ -sealed class Patch>(val manifest: Manifest) { +sealed class Patch>( + val name: String? = null, + val description: String? = null, + val compatiblePackages: Set? = null, + val dependencies: Set? = null, + val use: Boolean = true, + // TODO: Remove this property, once integrations are coupled with patches. + val requiresIntegrations: Boolean = false, +) : OptionsContainer() { /** * The execution function of the patch. * @@ -26,72 +41,69 @@ sealed class Patch>(val manifest: Manifest) { */ abstract fun execute(context: @UnsafeVariance T) - override fun hashCode() = manifest.hashCode() + override fun hashCode() = name.hashCode() - override fun equals(other: Any?) = other is Patch<*> && manifest == other.manifest + override fun toString() = name ?: this::class.simpleName ?: "Unnamed patch" - override fun toString() = manifest.name + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Patch<*> + + return name == other.name + } /** - * The manifest of a [Patch]. + * A package a [Patch] is compatible with. * - * @param name The name of the patch. - * @param description The description of the patch. - * @param use Weather or not the patch should be used. - * @param dependencies The names of patches this patch depends on. - * @param compatiblePackages The packages the patch is compatible with. - * @param requiresIntegrations Weather or not the patch requires integrations. - * @param options The options of the patch. + * @param name The name of the package. + * @param versions The versions of the package. */ - class Manifest( + class CompatiblePackage( val name: String, - val description: String, - val use: Boolean = true, - val dependencies: Set? = null, - val compatiblePackages: Set? = null, - // TODO: Remove this property, once integrations are coupled with patches. - val requiresIntegrations: Boolean = false, - val options: PatchOptions? = null, - ) { - override fun hashCode() = name.hashCode() - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Manifest - - return name == other.name - } - - /** - * A package a [Patch] is compatible with. - * - * @param name The name of the package. - * @param versions The versions of the package. - */ - class CompatiblePackage( - val name: String, - val versions: Set? = null, - ) - } + versions: Set? = null, + ) } /** * A ReVanced [Patch] that works on [ResourceContext]. * - * @param metadata The manifest of the [ResourcePatch]. + * @param name The name of the patch. + * @param description The description of the patch. + * @param compatiblePackages The packages the patch is compatible with. + * @param dependencies The names of patches this patch depends on. + * @param use Weather or not the patch should be used. + * @param requiresIntegrations Weather or not the patch requires integrations. */ abstract class ResourcePatch( - metadata: Manifest, -) : Patch(metadata) + name: String? = null, + description: String? = null, + compatiblePackages: Set? = null, + dependencies: Set? = null, + use: Boolean = true, + // TODO: Remove this property, once integrations are coupled with patches. + requiresIntegrations: Boolean = false, +) : Patch(name, description, compatiblePackages, dependencies, use, requiresIntegrations) /** * A ReVanced [Patch] that works on [BytecodeContext]. * - * @param manifest The manifest of the [BytecodePatch]. * @param fingerprints A list of [MethodFingerprint]s which will be resolved before the patch is executed. + * @param name The name of the patch. + * @param description The description of the patch. + * @param compatiblePackages The packages the patch is compatible with. + * @param dependencies The names of patches this patch depends on. + * @param use Weather or not the patch should be used. + * @param requiresIntegrations Weather or not the patch requires integrations. */ abstract class BytecodePatch( - manifest: Manifest, - internal vararg val fingerprints: MethodFingerprint, -) : Patch(manifest) \ No newline at end of file + internal val fingerprints: Set = emptySet(), + name: String? = null, + description: String? = null, + compatiblePackages: Set? = null, + dependencies: Set? = null, + use: Boolean = true, + // TODO: Remove this property, once integrations are coupled with patches. + requiresIntegrations: Boolean = false, +) : Patch(name, description, compatiblePackages, dependencies, use, requiresIntegrations) \ No newline at end of file diff --git a/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt index ecf3a85..328debe 100644 --- a/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt +++ b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt @@ -2,8 +2,6 @@ package app.revanced.patcher.patch -import java.nio.file.Path -import kotlin.io.path.pathString import kotlin.reflect.KProperty class NoSuchOptionException(val option: String) : Exception("No such option: $option") diff --git a/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt b/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt deleted file mode 100644 index 4928d87..0000000 --- a/revanced-patcher/src/main/kotlin/app/revanced/patcher/patch/annotations/Patch.kt +++ /dev/null @@ -1,7 +0,0 @@ -package app.revanced.patcher.patch.annotations - -/** - * Annotation to mark a class as a patch. - */ -@Target(AnnotationTarget.CLASS) -annotation class Patch \ No newline at end of file diff --git a/revanced-patcher/src/test/kotlin/app/revanced/patcher/extensions/InstructionExtensionsTest.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/extensions/InstructionExtensionsTest.kt index feed3aa..a774634 100644 --- a/revanced-patcher/src/test/kotlin/app/revanced/patcher/extensions/InstructionExtensionsTest.kt +++ b/revanced-patcher/src/test/kotlin/app/revanced/patcher/extensions/InstructionExtensionsTest.kt @@ -19,7 +19,7 @@ import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21s import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test +import kotlin.test.Test import kotlin.test.assertEquals private object InstructionExtensionsTest { diff --git a/revanced-patcher/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt index 8d37011..778a3f4 100644 --- a/revanced-patcher/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt +++ b/revanced-patcher/src/test/kotlin/app/revanced/patcher/patch/PatchOptionsTest.kt @@ -1,8 +1,8 @@ package app.revanced.patcher.patch -import app.revanced.patcher.usage.bytecode.ExampleBytecodePatch -import org.junit.jupiter.api.Test +import app.revanced.patcher.usage.ExampleBytecodePatch import org.junit.jupiter.api.assertThrows +import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotEquals import kotlin.test.assertNotNull diff --git a/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/ExampleBytecodePatch.kt similarity index 82% rename from revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt rename to revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/ExampleBytecodePatch.kt index e6aa88a..e0f66c5 100644 --- a/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleBytecodePatch.kt +++ b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/ExampleBytecodePatch.kt @@ -1,14 +1,13 @@ -package app.revanced.patcher.usage.bytecode +package app.revanced.patcher.usage import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.or import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.OptionsContainer import app.revanced.patcher.patch.PatchOption +import app.revanced.patcher.patch.annotations.CompatiblePackage import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.usage.resource.patch.ExampleResourcePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import com.android.tools.smali.dexlib2.AccessFlags @@ -26,19 +25,19 @@ import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringRefere import com.android.tools.smali.dexlib2.immutable.value.ImmutableFieldEncodedValue import com.android.tools.smali.dexlib2.util.Preconditions import com.google.common.collect.ImmutableList +import kotlin.test.assertNotNull -@Patch -class ExampleBytecodePatch : BytecodePatch( - Manifest( - "Example patch", - "Example demonstration of a bytecode patch.", - dependencies = setOf(ExampleResourcePatch::class), - compatiblePackages = setOf( - Manifest.CompatiblePackage("com.example.examplePackage", setOf("0.0.1", "0.0.2")) - ) - ), - ExampleFingerprint +@Suppress("unused") +@Patch( + name = "Example bytecode patch", + description = "Example demonstration of a bytecode patch.", + dependencies = [ExampleResourcePatch::class], + compatiblePackages = [CompatiblePackage("com.example.examplePackage", arrayOf("0.0.1", "0.0.2"))] +) +object ExampleBytecodePatch : BytecodePatch( + setOf(ExampleFingerprint) ) { + // This function will be executed by the patcher. // You can treat it as a constructor override fun execute(context: BytecodeContext) { @@ -46,7 +45,7 @@ class ExampleBytecodePatch : BytecodePatch( val result = ExampleFingerprint.result!! // Patch options - println(key1) + assertNotNull(key1) key2 = false // Get the implementation for the resolved method @@ -161,32 +160,34 @@ class ExampleBytecodePatch : BytecodePatch( ) } - @Suppress("unused") - companion object : OptionsContainer() { - private var key1 by option( - PatchOption.StringOption( - "key1", "default", "title", "description", true - ) + private var key1 by option( + PatchOption.StringOption( + "key1", "default", "title", "description", true ) - private var key2 by option( - PatchOption.BooleanOption( - "key2", true, "title", "description" // required defaults to false - ) + ) + + private var key2 by option( + PatchOption.BooleanOption( + "key2", true, "title", "description" // required defaults to false ) - private var key3 by option( - PatchOption.StringListOption( - "key3", "TEST", listOf("TEST", "TEST1", "TEST2"), "title", "description" - ) + ) + + private var key3 by option( + PatchOption.StringListOption( + "key3", "TEST", listOf("TEST", "TEST1", "TEST2"), "title", "description" ) - private var key4 by option( - PatchOption.IntListOption( - "key4", 1, listOf(1, 2, 3), "title", "description" - ) + ) + + private var key4 by option( + PatchOption.IntListOption( + "key4", 1, listOf(1, 2, 3), "title", "description" ) - private var key5 by option( - PatchOption.StringOption( - "key5", null, "title", "description", true - ) + ) + + private var key5 by option( + PatchOption.StringOption( + "key5", null, "title", "description", true ) - } + ) } + diff --git a/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleFingerprint.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/ExampleFingerprint.kt similarity index 93% rename from revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleFingerprint.kt rename to revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/ExampleFingerprint.kt index 3cb5b06..4ec21e0 100644 --- a/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/bytecode/ExampleFingerprint.kt +++ b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/ExampleFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patcher.usage.bytecode +package app.revanced.patcher.usage import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/ExampleResourcePatch.kt similarity index 79% rename from revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt rename to revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/ExampleResourcePatch.kt index 974d885..3314e04 100644 --- a/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt +++ b/revanced-patcher/src/test/kotlin/app/revanced/patcher/usage/ExampleResourcePatch.kt @@ -1,10 +1,11 @@ -package app.revanced.patcher.usage.resource.patch +package app.revanced.patcher.usage import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import org.w3c.dom.Element -class ExampleResourcePatch : ResourcePatch(Manifest("Example name", "Example description")) { + +class ExampleResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { context.xmlEditor["AndroidManifest.xml"].use { editor -> val element = editor // regular DomFileEditor diff --git a/settings.gradle.kts b/settings.gradle.kts index 1f9503f..8fdd378 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,4 +19,4 @@ dependencyResolutionManagement { } } -include("revanced-patcher") \ No newline at end of file +include("revanced-patch-annotations-processor", "revanced-patcher") \ No newline at end of file