mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2024-11-10 01:02:22 +01:00
feat: Add constructor to initialize patches without annotations
This commit is contained in:
parent
7aeae93f3d
commit
462fbe2cad
7 changed files with 154 additions and 24 deletions
|
@ -234,11 +234,14 @@ public abstract interface annotation class app/revanced/patcher/fingerprint/anno
|
||||||
|
|
||||||
public abstract class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch {
|
public abstract class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch {
|
||||||
public fun <init> ()V
|
public fun <init> ()V
|
||||||
|
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZLjava/util/Set;)V
|
||||||
|
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZLjava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
public fun <init> (Ljava/util/Set;)V
|
public fun <init> (Ljava/util/Set;)V
|
||||||
public synthetic fun <init> (Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
public synthetic fun <init> (Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class app/revanced/patcher/patch/Patch {
|
public abstract class app/revanced/patcher/patch/Patch {
|
||||||
|
public synthetic fun <init> (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 fun equals (Ljava/lang/Object;)Z
|
||||||
public abstract fun execute (Lapp/revanced/patcher/data/Context;)V
|
public abstract fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||||
public final fun getCompatiblePackages ()Ljava/util/Set;
|
public final fun getCompatiblePackages ()Ljava/util/Set;
|
||||||
|
@ -272,6 +275,8 @@ public final class app/revanced/patcher/patch/PatchResult {
|
||||||
|
|
||||||
public abstract class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch {
|
public abstract class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch {
|
||||||
public fun <init> ()V
|
public fun <init> ()V
|
||||||
|
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZ)V
|
||||||
|
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract interface annotation class app/revanced/patcher/patch/annotation/CompatiblePackage : java/lang/annotation/Annotation {
|
public abstract interface annotation class app/revanced/patcher/patch/annotation/CompatiblePackage : java/lang/annotation/Annotation {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.jar.JarFile
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of [Patch]es.
|
* A set of [Patch]es.
|
||||||
*/
|
*/
|
||||||
|
@ -73,7 +74,7 @@ sealed class PatchBundleLoader private constructor(
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
logger.fine(
|
logger.fine(
|
||||||
"Patch class '$name' has no INSTANCE field, therefor not a singleton. " +
|
"Patch class '$name' has no INSTANCE field, therefor not a singleton. " +
|
||||||
"Will try to instantiate it.",
|
"Attempting to instantiate it.",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +84,7 @@ sealed class PatchBundleLoader private constructor(
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
logger.severe(
|
logger.severe(
|
||||||
"Patch class '$name' is not singleton and has no suitable constructor, " +
|
"Patch class '$name' is not singleton and has no suitable constructor, " +
|
||||||
"therefor cannot be instantiated and will be ignored.",
|
"therefor cannot be instantiated and is ignored.",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,61 @@
|
||||||
package app.revanced.patcher.patch
|
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.BytecodeContext
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import java.io.Closeable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ReVanced [Patch] that works on [BytecodeContext].
|
* A ReVanced [Patch] that accesses a [BytecodeContext].
|
||||||
*
|
*
|
||||||
* @param fingerprints A list of [MethodFingerprint]s which will be resolved before the patch is executed.
|
* If an implementation of [Patch] also implements [Closeable]
|
||||||
|
* it will be closed in reverse execution order of patches executed by ReVanced [Patcher].
|
||||||
*/
|
*/
|
||||||
abstract class BytecodePatch(
|
@Suppress("unused")
|
||||||
internal val fingerprints: Set<MethodFingerprint> = emptySet(),
|
abstract class BytecodePatch : Patch<BytecodeContext> {
|
||||||
) : Patch<BytecodeContext>()
|
/**
|
||||||
|
* The fingerprints to resolve before executing the patch.
|
||||||
|
*/
|
||||||
|
internal val fingerprints: Set<MethodFingerprint>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new [BytecodePatch].
|
||||||
|
*
|
||||||
|
* @param fingerprints The fingerprints to resolve before executing the patch.
|
||||||
|
*/
|
||||||
|
constructor(fingerprints: Set<MethodFingerprint> = emptySet()) {
|
||||||
|
this.fingerprints = fingerprints
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new [BytecodePatch].
|
||||||
|
*
|
||||||
|
* @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 Other patches this patch depends on.
|
||||||
|
* @param use Weather or not the patch should be used.
|
||||||
|
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
name: String? = null,
|
||||||
|
description: String? = null,
|
||||||
|
compatiblePackages: Set<CompatiblePackage>? = null,
|
||||||
|
dependencies: Set<PatchClass>? = null,
|
||||||
|
use: Boolean = true,
|
||||||
|
requiresIntegrations: Boolean = false,
|
||||||
|
fingerprints: Set<MethodFingerprint> = emptySet(),
|
||||||
|
) : super(name, description, compatiblePackages, dependencies, use, requiresIntegrations) {
|
||||||
|
this.fingerprints = fingerprints
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new [BytecodePatch].
|
||||||
|
*/
|
||||||
|
@Deprecated(
|
||||||
|
"Use the constructor with fingerprints instead.",
|
||||||
|
ReplaceWith("BytecodePatch(emptySet())"),
|
||||||
|
)
|
||||||
|
constructor() : this(emptySet())
|
||||||
|
}
|
||||||
|
|
|
@ -8,10 +8,10 @@ import app.revanced.patcher.data.Context
|
||||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
||||||
import app.revanced.patcher.patch.options.PatchOptions
|
import app.revanced.patcher.patch.options.PatchOptions
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import app.revanced.patcher.patch.annotation.Patch as PatchAnnotation
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ReVanced patch.
|
* A ReVanced patch.
|
||||||
|
*
|
||||||
* If an implementation of [Patch] also implements [Closeable]
|
* If an implementation of [Patch] also implements [Closeable]
|
||||||
* it will be closed in reverse execution order of patches executed by ReVanced [Patcher].
|
* it will be closed in reverse execution order of patches executed by ReVanced [Patcher].
|
||||||
*
|
*
|
||||||
|
@ -55,25 +55,41 @@ sealed class Patch<out T : Context<*>> {
|
||||||
var requiresIntegrations = false
|
var requiresIntegrations = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
name: String?,
|
||||||
|
description: String?,
|
||||||
|
compatiblePackages: Set<CompatiblePackage>?,
|
||||||
|
dependencies: Set<PatchClass>?,
|
||||||
|
use: Boolean,
|
||||||
|
requiresIntegrations: Boolean,
|
||||||
|
) {
|
||||||
|
this.name = name
|
||||||
|
this.description = description
|
||||||
|
this.compatiblePackages = compatiblePackages
|
||||||
|
this.dependencies = dependencies
|
||||||
|
this.use = use
|
||||||
|
this.requiresIntegrations = requiresIntegrations
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this::class.findAnnotationRecursively(app.revanced.patcher.patch.annotation.Patch::class)?.let { annotation ->
|
||||||
|
this.name = annotation.name.ifEmpty { null }
|
||||||
|
this.description = annotation.description.ifEmpty { null }
|
||||||
|
this.compatiblePackages =
|
||||||
|
annotation.compatiblePackages
|
||||||
|
.map { CompatiblePackage(it.name, it.versions.toSet().ifEmpty { null }) }
|
||||||
|
.toSet().ifEmpty { null }
|
||||||
|
this.dependencies = annotation.dependencies.toSet().ifEmpty { null }
|
||||||
|
this.use = annotation.use
|
||||||
|
this.requiresIntegrations = annotation.requiresIntegrations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The options of the patch associated by the options key.
|
* The options of the patch associated by the options key.
|
||||||
*/
|
*/
|
||||||
val options = PatchOptions()
|
val options = PatchOptions()
|
||||||
|
|
||||||
init {
|
|
||||||
this::class.findAnnotationRecursively(PatchAnnotation::class)?.let { annotation ->
|
|
||||||
name = annotation.name.ifEmpty { null }
|
|
||||||
description = annotation.description.ifEmpty { null }
|
|
||||||
compatiblePackages =
|
|
||||||
annotation.compatiblePackages
|
|
||||||
.map { CompatiblePackage(it.name, it.versions.toSet().ifEmpty { null }) }
|
|
||||||
.toSet().ifEmpty { null }
|
|
||||||
dependencies = annotation.dependencies.toSet().ifEmpty { null }
|
|
||||||
use = annotation.use
|
|
||||||
requiresIntegrations = annotation.requiresIntegrations
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The execution function of the patch.
|
* The execution function of the patch.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,8 +1,38 @@
|
||||||
package app.revanced.patcher.patch
|
package app.revanced.patcher.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.PatchClass
|
||||||
|
import app.revanced.patcher.Patcher
|
||||||
import app.revanced.patcher.data.ResourceContext
|
import app.revanced.patcher.data.ResourceContext
|
||||||
|
import java.io.Closeable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ReVanced [Patch] that works on [ResourceContext].
|
* A ReVanced [Patch] that accesses a [ResourceContext].
|
||||||
|
*
|
||||||
|
* If an implementation of [Patch] also implements [Closeable]
|
||||||
|
* it will be closed in reverse execution order of patches executed by ReVanced [Patcher].
|
||||||
*/
|
*/
|
||||||
abstract class ResourcePatch : Patch<ResourceContext>()
|
abstract class ResourcePatch : Patch<ResourceContext> {
|
||||||
|
/**
|
||||||
|
* Create a new [ResourcePatch].
|
||||||
|
*/
|
||||||
|
constructor()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new [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 Other patches this patch depends on.
|
||||||
|
* @param use Weather or not the patch should be used.
|
||||||
|
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
name: String? = null,
|
||||||
|
description: String? = null,
|
||||||
|
compatiblePackages: Set<CompatiblePackage>? = null,
|
||||||
|
dependencies: Set<PatchClass>? = null,
|
||||||
|
use: Boolean = true,
|
||||||
|
requiresIntegrations: Boolean = false,
|
||||||
|
) : super(name, description, compatiblePackages, dependencies, use, requiresIntegrations)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package app.revanced.patcher.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.ResourceContext
|
||||||
|
import org.junit.jupiter.api.assertThrows
|
||||||
|
import kotlin.test.Test
|
||||||
|
import app.revanced.patcher.patch.annotation.Patch as PatchAnnotation
|
||||||
|
|
||||||
|
object PatchInitializationTest {
|
||||||
|
@Test
|
||||||
|
fun `initialize using constructor`() {
|
||||||
|
val patch =
|
||||||
|
object : ResourcePatch(name = "Resource patch test") {
|
||||||
|
override fun execute(context: ResourceContext) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(patch.name == "Resource patch test")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `initialize using annotation`() {
|
||||||
|
val patch =
|
||||||
|
@PatchAnnotation("Resource patch test")
|
||||||
|
object : ResourcePatch() {
|
||||||
|
override fun execute(context: ResourceContext) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(patch.name == "Resource patch test")
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,6 +90,7 @@ internal class PatchOptionsTest {
|
||||||
@Test
|
@Test
|
||||||
fun `getting default value should work`() = assertDoesNotThrow { assertNull(OptionsTestPatch.resettableOption.default) }
|
fun `getting default value should work`() = assertDoesNotThrow { assertNull(OptionsTestPatch.resettableOption.default) }
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
private object OptionsTestPatch : BytecodePatch() {
|
private object OptionsTestPatch : BytecodePatch() {
|
||||||
var booleanOption by booleanPatchOption(
|
var booleanOption by booleanPatchOption(
|
||||||
"bool",
|
"bool",
|
||||||
|
|
Loading…
Reference in a new issue