You've already forked revanced-patcher
mirror of
https://github.com/revanced/revanced-patcher
synced 2025-09-10 05:30:49 +02:00
Compare commits
96 Commits
v15.0.0-de
...
v18.0.0-de
Author | SHA1 | Date | |
---|---|---|---|
![]() |
167bd83f4e | ||
![]() |
aed1eac315 | ||
![]() |
54a2f8f16f | ||
![]() |
2ca543ffb9 | ||
![]() |
58e7f815a5 | ||
![]() |
15b38fc841 | ||
![]() |
e2ca50729d | ||
![]() |
6192089b71 | ||
![]() |
a4212f6bf9 | ||
![]() |
124a2e9d3e | ||
![]() |
f77624b3b9 | ||
![]() |
a76ac04214 | ||
![]() |
0447fa9c28 | ||
![]() |
54ac1394a9 | ||
![]() |
0b04c73ac5 | ||
![]() |
079de45238 | ||
![]() |
56ce9ec2f9 | ||
![]() |
1b52e4b0f9 | ||
![]() |
098c2c1efa | ||
![]() |
64343e5a7c | ||
![]() |
0caf6caeb9 | ||
![]() |
55f6c2a9fc | ||
![]() |
c6095bc38a | ||
![]() |
09cd6aa568 | ||
![]() |
ebbaafb78e | ||
![]() |
e6de90d300 | ||
![]() |
c7922e90d0 | ||
![]() |
c1f4c0445a | ||
![]() |
caa634fac6 | ||
![]() |
f28bfe0dbd | ||
![]() |
155e787ff4 | ||
![]() |
c38f0ef42a | ||
![]() |
4456031459 | ||
![]() |
5fb59a227f | ||
![]() |
d9fb241d57 | ||
![]() |
642c4ea97e | ||
![]() |
8c8a251626 | ||
![]() |
5953d6cfb5 | ||
![]() |
a1962fe600 | ||
![]() |
77dbee3d6a | ||
![]() |
cb5e39d73e | ||
![]() |
38ef2f470a | ||
![]() |
129d84e108 | ||
![]() |
affeba76b8 | ||
![]() |
6059d3ca26 | ||
![]() |
444dee5a16 | ||
![]() |
d314466ce2 | ||
![]() |
fdaf9c21c8 | ||
![]() |
06c2b76f11 | ||
![]() |
3896b30738 | ||
![]() |
2c4b88e1a0 | ||
![]() |
dfc7e1596b | ||
![]() |
f590436399 | ||
![]() |
cbfb9ba02f | ||
![]() |
b4cfe80ad5 | ||
![]() |
b37906fa35 | ||
![]() |
356f1f1553 | ||
![]() |
e882af74ee | ||
![]() |
46875fb28e | ||
![]() |
417c3e4234 | ||
![]() |
6d2c28807b | ||
![]() |
4d6e08a650 | ||
![]() |
5cebc1fd30 | ||
![]() |
ac61731dc6 | ||
![]() |
9e4ffabd5c | ||
![]() |
3f410bd39f | ||
![]() |
d51bc32e37 | ||
![]() |
b7f6aa94cc | ||
![]() |
ff965e6953 | ||
![]() |
468d5d7421 | ||
![]() |
fc95b28c49 | ||
![]() |
69184187d9 | ||
![]() |
a802d0df46 | ||
![]() |
8de30633ae | ||
![]() |
a1fbb7990f | ||
![]() |
aa71146b1b | ||
![]() |
9fdb8f087f | ||
![]() |
670f0153de | ||
![]() |
1d7aeca696 | ||
![]() |
4e7811ea07 | ||
![]() |
e11283744a | ||
![]() |
91cdfd53ef | ||
![]() |
bc7d6b9941 | ||
![]() |
6b1e0a1656 | ||
![]() |
72c9eb2129 | ||
![]() |
4bc4b0dc01 | ||
![]() |
637d48746f | ||
![]() |
9a109c129b | ||
![]() |
d49e4ee5ea | ||
![]() |
30f0ea29a3 | ||
![]() |
49930f6565 | ||
![]() |
909d89fa8d | ||
![]() |
81d1d7f544 | ||
![]() |
67b7dff67a | ||
![]() |
4b76d19596 | ||
![]() |
080fbe9feb |
6
.github/workflows/pull_request.yml
vendored
6
.github/workflows/pull_request.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: PR to main
|
name: Open a PR to main
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -7,7 +7,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
MESSAGE: merge branch `${{ github.head_ref || github.ref_name }}` to `main`
|
MESSAGE: Merge branch `${{ github.head_ref || github.ref_name }}` to `main`
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
pull-request:
|
pull-request:
|
||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Open pull request
|
- name: Open pull request
|
||||||
uses: repo-sync/pull-request@v2
|
uses: repo-sync/pull-request@v2
|
||||||
with:
|
with:
|
||||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
# Make sure the release step uses its own credentials:
|
# Make sure the release step uses its own credentials:
|
||||||
# https://github.com/cycjimmy/semantic-release-action#private-packages
|
# https://github.com/cycjimmy/semantic-release-action#private-packages
|
||||||
|
298
CHANGELOG.md
298
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,86 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.9.0" apply false
|
kotlin("jvm") version "1.9.10"
|
||||||
alias(libs.plugins.binary.compatibility.validator)
|
alias(libs.plugins.binary.compatibility.validator)
|
||||||
|
`maven-publish`
|
||||||
|
signing
|
||||||
|
java
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
group = "app.revanced"
|
||||||
apply(plugin = "maven-publish")
|
|
||||||
|
|
||||||
group = "app.revanced"
|
tasks {
|
||||||
|
processResources {
|
||||||
|
expand("projectVersion" to project.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
testLogging {
|
||||||
|
events("PASSED", "SKIPPED", "FAILED")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
mavenLocal()
|
||||||
|
maven { url = uri("https://jitpack.io") }
|
||||||
|
google()
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withJavadocJar()
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(11)
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
create<MavenPublication>("revanced-patcher-publication") {
|
||||||
|
from(components["java"])
|
||||||
|
|
||||||
|
version = project.version.toString()
|
||||||
|
|
||||||
|
pom {
|
||||||
|
name = "ReVanced Patcher"
|
||||||
|
description = "Patcher used by ReVanced."
|
||||||
|
url = "https://revanced.app"
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name = "GNU General Public License v3.0"
|
||||||
|
url = "https://www.gnu.org/licenses/gpl-3.0.en.html"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id = "ReVanced"
|
||||||
|
name = "ReVanced"
|
||||||
|
email = "contact@revanced.app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
connection = "scm:git:git://github.com/revanced/revanced-patcher.git"
|
||||||
|
developerConnection = "scm:git:git@github.com:revanced/revanced-patcher.git"
|
||||||
|
url = "https://github.com/revanced/revanced-patcher"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
org.gradle.caching = true
|
org.gradle.caching = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 15.0.0-dev.2
|
version = 18.0.0-dev.6
|
||||||
|
@@ -1,31 +1,23 @@
|
|||||||
[versions]
|
[versions]
|
||||||
android = "4.1.1.4"
|
android = "4.1.1.4"
|
||||||
kotlin-reflect = "1.9.0"
|
kotlin-reflect = "1.9.0"
|
||||||
apktool-lib = "2.8.2-6"
|
apktool-lib = "2.9.1"
|
||||||
kotlin-test = "1.8.20-RC"
|
kotlin-test = "1.8.20-RC"
|
||||||
kotlinx-coroutines-core = "1.7.1"
|
kotlinx-coroutines-core = "1.7.3"
|
||||||
multidexlib2 = "3.0.3.r2"
|
multidexlib2 = "3.0.3.r3"
|
||||||
smali = "3.0.3"
|
smali = "3.0.3"
|
||||||
symbol-processing-api = "1.9.0-1.0.11"
|
|
||||||
xpp3 = "1.1.4c"
|
xpp3 = "1.1.4c"
|
||||||
binary-compatibility-validator = "0.13.2"
|
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]
|
[libraries]
|
||||||
android = { module = "com.google.android:android", version.ref = "android" }
|
android = { module = "com.google.android:android", version.ref = "android" }
|
||||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin-reflect" }
|
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin-reflect" }
|
||||||
apktool-lib = { module = "app.revanced:apktool-lib", version.ref = "apktool-lib" }
|
apktool-lib = { module = "app.revanced:apktool", version.ref = "apktool-lib" }
|
||||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-test" }
|
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-test" }
|
||||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
|
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
|
||||||
multidexlib2 = { module = "app.revanced:multidexlib2", version.ref = "multidexlib2" }
|
multidexlib2 = { module = "app.revanced:multidexlib2", version.ref = "multidexlib2" }
|
||||||
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
|
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" }
|
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]
|
[plugins]
|
||||||
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
||||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
|
@@ -1,25 +0,0 @@
|
|||||||
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 <init> (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 <init> ()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;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,74 +0,0 @@
|
|||||||
plugins {
|
|
||||||
kotlin("jvm") version "1.9.0"
|
|
||||||
alias(libs.plugins.ksp)
|
|
||||||
}
|
|
||||||
|
|
||||||
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-patcher")
|
|
||||||
credentials {
|
|
||||||
username = System.getenv("GITHUB_ACTOR")
|
|
||||||
password = System.getenv("GITHUB_TOKEN")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
publications {
|
|
||||||
create<MavenPublication>("gpr") {
|
|
||||||
from(components["java"])
|
|
||||||
|
|
||||||
version = project.version.toString()
|
|
||||||
|
|
||||||
pom {
|
|
||||||
name = "ReVanced Patch annotations processor"
|
|
||||||
description = "Annotation processor for patches."
|
|
||||||
url = "https://revanced.app"
|
|
||||||
|
|
||||||
licenses {
|
|
||||||
license {
|
|
||||||
name = "GNU General Public License v3.0"
|
|
||||||
url = "https://www.gnu.org/licenses/gpl-3.0.en.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
developers {
|
|
||||||
developer {
|
|
||||||
id = "ReVanced"
|
|
||||||
name = "ReVanced"
|
|
||||||
email = "contact@revanced.app"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scm {
|
|
||||||
connection = "scm:git:git://github.com/revanced/revanced-patcher.git"
|
|
||||||
developerConnection = "scm:git:git@github.com:revanced/revanced-patcher.git"
|
|
||||||
url = "https://github.com/revanced/revanced-patcher"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,2 +0,0 @@
|
|||||||
rootProject.name = "revanced-patch-annotations-processor"
|
|
||||||
|
|
@@ -1,205 +0,0 @@
|
|||||||
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.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<KSAnnotated> {
|
|
||||||
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<KSType>).ifEmpty { null }
|
|
||||||
|
|
||||||
val compatiblePackages =
|
|
||||||
(annotation.property("compatiblePackages") as List<KSAnnotation>).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<ClassName>?,
|
|
||||||
val compatiblePackages: List<CodeBlock>?,
|
|
||||||
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<String>)
|
|
||||||
.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"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
)
|
|
||||||
.addInitializerBlock(
|
|
||||||
CodeBlock.builder()
|
|
||||||
.add(
|
|
||||||
"%T.options.forEach { (key, option) ->",
|
|
||||||
patchDeclaration.toClassName()
|
|
||||||
)
|
|
||||||
.addStatement(
|
|
||||||
"options.register(option)"
|
|
||||||
)
|
|
||||||
.add(
|
|
||||||
"}"
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
).build().writeTo(
|
|
||||||
codeGenerator,
|
|
||||||
Dependencies(false, patchDeclaration.containingFile!!)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,9 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
app.revanced.patcher.patch.annotations.processor.PatchProcessorProvider
|
|
@@ -1,130 +0,0 @@
|
|||||||
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.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")
|
|
||||||
|
|
||||||
assert(patch.options.isNotEmpty())
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,10 +0,0 @@
|
|||||||
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) {}
|
|
||||||
}
|
|
@@ -1,12 +0,0 @@
|
|||||||
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) {}
|
|
||||||
}
|
|
@@ -1,10 +0,0 @@
|
|||||||
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) { }
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
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) {}
|
|
||||||
}
|
|
@@ -1,19 +0,0 @@
|
|||||||
package app.revanced.patcher.patch.annotations.processor.samples.options
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
|
||||||
import app.revanced.patcher.patch.ResourcePatch
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.options.types.StringPatchOption.Companion.stringPatchOption
|
|
||||||
|
|
||||||
@Patch(name = "Options patch")
|
|
||||||
object OptionsPatch : ResourcePatch() {
|
|
||||||
override fun execute(context: ResourceContext) {}
|
|
||||||
|
|
||||||
@Suppress("unused")
|
|
||||||
private val printOption by stringPatchOption(
|
|
||||||
"print",
|
|
||||||
null,
|
|
||||||
"Print message",
|
|
||||||
"The message to print."
|
|
||||||
)
|
|
||||||
}
|
|
@@ -1,10 +0,0 @@
|
|||||||
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) {}
|
|
||||||
}
|
|
@@ -1,82 +0,0 @@
|
|||||||
plugins {
|
|
||||||
kotlin("jvm") version "1.9.0"
|
|
||||||
}
|
|
||||||
|
|
||||||
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(project(":revanced-patch-annotations-processor"))
|
|
||||||
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<MavenPublication>("gpr") {
|
|
||||||
from(components["java"])
|
|
||||||
|
|
||||||
version = project.version.toString()
|
|
||||||
|
|
||||||
pom {
|
|
||||||
name = "ReVanced Patcher"
|
|
||||||
description = "Patcher used by ReVanced."
|
|
||||||
url = "https://revanced.app"
|
|
||||||
|
|
||||||
licenses {
|
|
||||||
license {
|
|
||||||
name = "GNU General Public License v3.0"
|
|
||||||
url = "https://www.gnu.org/licenses/gpl-3.0.en.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
developers {
|
|
||||||
developer {
|
|
||||||
id = "ReVanced"
|
|
||||||
name = "ReVanced"
|
|
||||||
email = "contact@revanced.app"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scm {
|
|
||||||
connection = "scm:git:git://github.com/revanced/revanced-patcher.git"
|
|
||||||
developerConnection = "scm:git:git@github.com:revanced/revanced-patcher.git"
|
|
||||||
url = "https://github.com/revanced/revanced-patcher"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
rootProject.name = "revanced-patcher"
|
|
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patcher.fingerprint
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A ReVanced fingerprint.
|
|
||||||
* Can be a [MethodFingerprint].
|
|
||||||
*/
|
|
||||||
interface Fingerprint
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patcher.logging
|
|
||||||
|
|
||||||
@Deprecated("This will be removed in a future release")
|
|
||||||
interface Logger {
|
|
||||||
fun error(msg: String) {}
|
|
||||||
fun warn(msg: String) {}
|
|
||||||
fun info(msg: String) {}
|
|
||||||
fun trace(msg: String) {}
|
|
||||||
}
|
|
@@ -1,6 +0,0 @@
|
|||||||
package app.revanced.patcher.logging.impl
|
|
||||||
|
|
||||||
import app.revanced.patcher.logging.Logger
|
|
||||||
|
|
||||||
@Deprecated("This will be removed in a future release")
|
|
||||||
object NopLogger : Logger
|
|
@@ -1,27 +0,0 @@
|
|||||||
package app.revanced.patcher.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.PatchClass
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A ReVanced [Patch] that works on [BytecodeContext].
|
|
||||||
*
|
|
||||||
* @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(
|
|
||||||
internal val fingerprints: Set<MethodFingerprint> = emptySet(),
|
|
||||||
name: String? = null,
|
|
||||||
description: String? = null,
|
|
||||||
compatiblePackages: Set<CompatiblePackage>? = null,
|
|
||||||
dependencies: Set<PatchClass>? = null,
|
|
||||||
use: Boolean = true,
|
|
||||||
// TODO: Remove this property, once integrations are coupled with patches.
|
|
||||||
requiresIntegrations: Boolean = false,
|
|
||||||
) : Patch<BytecodeContext>(name, description, compatiblePackages, dependencies, use, requiresIntegrations)
|
|
@@ -1,71 +0,0 @@
|
|||||||
@file:Suppress("MemberVisibilityCanBePrivate", "UNUSED_PARAMETER")
|
|
||||||
|
|
||||||
package app.revanced.patcher.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.PatchClass
|
|
||||||
import app.revanced.patcher.Patcher
|
|
||||||
import app.revanced.patcher.data.Context
|
|
||||||
import app.revanced.patcher.patch.options.PatchOptions
|
|
||||||
import java.io.Closeable
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A ReVanced patch.
|
|
||||||
*
|
|
||||||
* If an implementation of [Patch] also implements [Closeable]
|
|
||||||
* it will be closed in reverse execution order of patches executed by ReVanced [Patcher].
|
|
||||||
*
|
|
||||||
* @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<out T : Context<*>>(
|
|
||||||
val name: String? = null,
|
|
||||||
val description: String? = null,
|
|
||||||
val compatiblePackages: Set<CompatiblePackage>? = null,
|
|
||||||
val dependencies: Set<PatchClass>? = null,
|
|
||||||
val use: Boolean = true,
|
|
||||||
// TODO: Remove this property, once integrations are coupled with patches.
|
|
||||||
val requiresIntegrations: Boolean = false,
|
|
||||||
) {
|
|
||||||
/**
|
|
||||||
* The options of the patch associated by the options key.
|
|
||||||
*/
|
|
||||||
val options = PatchOptions()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The execution function of the patch.
|
|
||||||
*
|
|
||||||
* @param context The [Context] the patch will work on.
|
|
||||||
* @return The result of executing the patch.
|
|
||||||
*/
|
|
||||||
abstract fun execute(context: @UnsafeVariance T)
|
|
||||||
|
|
||||||
override fun hashCode() = name.hashCode()
|
|
||||||
|
|
||||||
override fun toString() = name ?: this::class.simpleName ?: "Unnamed patch"
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as Patch<*>
|
|
||||||
|
|
||||||
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,
|
|
||||||
versions: Set<String>? = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@@ -1,24 +0,0 @@
|
|||||||
package app.revanced.patcher.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.PatchClass
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A ReVanced [Patch] that works on [ResourceContext].
|
|
||||||
*
|
|
||||||
* @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(
|
|
||||||
name: String? = null,
|
|
||||||
description: String? = null,
|
|
||||||
compatiblePackages: Set<CompatiblePackage>? = null,
|
|
||||||
dependencies: Set<PatchClass>? = null,
|
|
||||||
use: Boolean = true,
|
|
||||||
// TODO: Remove this property, once integrations are coupled with patches.
|
|
||||||
requiresIntegrations: Boolean = false,
|
|
||||||
) : Patch<ResourceContext>(name, description, compatiblePackages, dependencies, use, requiresIntegrations)
|
|
@@ -1,40 +0,0 @@
|
|||||||
package app.revanced.patcher.patch.options
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [Patch] option.
|
|
||||||
* @param key The identifier.
|
|
||||||
* @param default The default value.
|
|
||||||
* @param title The title.
|
|
||||||
* @param description A description.
|
|
||||||
* @param required Whether the option is required.
|
|
||||||
* @param validate The function to validate values of the option.
|
|
||||||
* @param T The value type of the option.
|
|
||||||
*/
|
|
||||||
abstract class PatchOption<T>(
|
|
||||||
val key: String,
|
|
||||||
default: T?,
|
|
||||||
val title: String?,
|
|
||||||
val description: String?,
|
|
||||||
val required: Boolean,
|
|
||||||
val validate: (T?) -> Boolean
|
|
||||||
) {
|
|
||||||
/**
|
|
||||||
* The value of the [PatchOption].
|
|
||||||
*/
|
|
||||||
var value: T? = default
|
|
||||||
set(value) {
|
|
||||||
if (required && value == null) throw PatchOptionException.ValueRequiredException(this)
|
|
||||||
if (!validate(value)) throw PatchOptionException.ValueValidationException(value, this)
|
|
||||||
|
|
||||||
field = value
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
|
|
||||||
|
|
||||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
|
|
||||||
this.value = value
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,48 +0,0 @@
|
|||||||
package app.revanced.patcher.patch.options.types
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import app.revanced.patcher.patch.options.PatchOption
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [PatchOption] representing a [Boolean].
|
|
||||||
*
|
|
||||||
* @param key The identifier.
|
|
||||||
* @param default The default value.
|
|
||||||
* @param title The title.
|
|
||||||
* @param description A description.
|
|
||||||
* @param required Whether the option is required.
|
|
||||||
*
|
|
||||||
* @see PatchOption
|
|
||||||
*/
|
|
||||||
class BooleanPatchOption private constructor(
|
|
||||||
key: String,
|
|
||||||
default: Boolean?,
|
|
||||||
title: String?,
|
|
||||||
description: String?,
|
|
||||||
required: Boolean,
|
|
||||||
validator: (Boolean?) -> Boolean
|
|
||||||
) : PatchOption<Boolean>(key, default, title, description, required, validator) {
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Create a new [BooleanPatchOption] and add it to the current [Patch].
|
|
||||||
*
|
|
||||||
* @param key The identifier.
|
|
||||||
* @param default The default value.
|
|
||||||
* @param title The title.
|
|
||||||
* @param description A description.
|
|
||||||
* @param required Whether the option is required.
|
|
||||||
* @return The created [BooleanPatchOption].
|
|
||||||
*
|
|
||||||
* @see BooleanPatchOption
|
|
||||||
* @see PatchOption
|
|
||||||
*/
|
|
||||||
fun <T : Patch<*>> T.booleanPatchOption(
|
|
||||||
key: String,
|
|
||||||
default: Boolean? = null,
|
|
||||||
title: String? = null,
|
|
||||||
description: String? = null,
|
|
||||||
required: Boolean = false,
|
|
||||||
validator: (Boolean?) -> Boolean = { true }
|
|
||||||
) = BooleanPatchOption(key, default, title, description, required, validator).also { options.register(it) }
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,48 +0,0 @@
|
|||||||
package app.revanced.patcher.patch.options.types
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import app.revanced.patcher.patch.options.PatchOption
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [PatchOption] representing a [Float].
|
|
||||||
*
|
|
||||||
* @param key The identifier.
|
|
||||||
* @param default The default value.
|
|
||||||
* @param title The title.
|
|
||||||
* @param description A description.
|
|
||||||
* @param required Whether the option is required.
|
|
||||||
*
|
|
||||||
* @see PatchOption
|
|
||||||
*/
|
|
||||||
class FloatPatchOption private constructor(
|
|
||||||
key: String,
|
|
||||||
default: Float?,
|
|
||||||
title: String?,
|
|
||||||
description: String?,
|
|
||||||
required: Boolean,
|
|
||||||
validator: (Float?) -> Boolean
|
|
||||||
) : PatchOption<Float>(key, default, title, description, required, validator) {
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Create a new [FloatPatchOption] and add it to the current [Patch].
|
|
||||||
*
|
|
||||||
* @param key The identifier.
|
|
||||||
* @param default The default value.
|
|
||||||
* @param title The title.
|
|
||||||
* @param description A description.
|
|
||||||
* @param required Whether the option is required.
|
|
||||||
* @return The created [FloatPatchOption].
|
|
||||||
*
|
|
||||||
* @see FloatPatchOption
|
|
||||||
* @see PatchOption
|
|
||||||
*/
|
|
||||||
fun <T : Patch<*>> T.floatPatchOption(
|
|
||||||
key: String,
|
|
||||||
default: Float? = null,
|
|
||||||
title: String? = null,
|
|
||||||
description: String? = null,
|
|
||||||
required: Boolean = false,
|
|
||||||
validator: (Float?) -> Boolean = { true }
|
|
||||||
) = FloatPatchOption(key, default, title, description, required, validator).also { options.register(it) }
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user