diff --git a/api/revanced-patcher.api b/api/revanced-patcher.api index 0c090962..2901751b 100644 --- a/api/revanced-patcher.api +++ b/api/revanced-patcher.api @@ -53,18 +53,13 @@ public final class app/revanced/patcher/PackageMetadata { public final fun getPackageVersion ()Ljava/lang/String; } -public abstract interface class app/revanced/patcher/PatchExecutorFunction : java/util/function/Function { -} - -public final class app/revanced/patcher/Patcher : app/revanced/patcher/PatchExecutorFunction, app/revanced/patcher/PatcherResultSupplier, app/revanced/patcher/PatchesConsumer { +public final class app/revanced/patcher/Patcher : java/io/Closeable { public fun (Lapp/revanced/patcher/PatcherConfig;)V - public fun accept (Ljava/util/Set;Ljava/util/Set;)V - public synthetic fun apply (Ljava/lang/Object;)Ljava/lang/Object; - public fun apply (Z)Lkotlinx/coroutines/flow/Flow; public fun close ()V - public fun get ()Lapp/revanced/patcher/PatcherResult; - public synthetic fun get ()Ljava/lang/Object; + public final fun execute ()Lkotlinx/coroutines/flow/Flow; + public final fun get ()Lapp/revanced/patcher/PatcherResult; public final fun getContext ()Lapp/revanced/patcher/PatcherContext; + public final fun plusAssign (Lkotlin/Pair;)V } public final class app/revanced/patcher/PatcherConfig { @@ -93,17 +88,6 @@ public final class app/revanced/patcher/PatcherResult$PatchedResources { public final fun getResourcesApk ()Ljava/io/File; } -public abstract interface class app/revanced/patcher/PatcherResultSupplier : java/io/Closeable, java/util/function/Supplier { -} - -public abstract interface class app/revanced/patcher/PatchesConsumer { - public abstract fun accept (Ljava/util/Set;Ljava/util/Set;)V -} - -public final class app/revanced/patcher/PatchesConsumer$DefaultImpls { - public static synthetic fun accept$default (Lapp/revanced/patcher/PatchesConsumer;Ljava/util/Set;Ljava/util/Set;ILjava/lang/Object;)V -} - public final class app/revanced/patcher/extensions/ExtensionsKt { public static final fun newLabel (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/Label; } diff --git a/docs/1_patcher_intro.md b/docs/1_patcher_intro.md index 08ebfc4d..6ef9957e 100644 --- a/docs/1_patcher_intro.md +++ b/docs/1_patcher_intro.md @@ -86,11 +86,11 @@ val patcherResult = Patcher(patcherConfig).use { patcher -> // such as package name, version code, version name, etc. // Add patches and integrations. - patcher.accept(patches, integrations) + patcher += patches to integrations // Execute the patches. runBlocking { - patcher.apply(returnOnError = false).collect { patchResult -> + patcher.execute().collect { patchResult -> if (patchResult.exception != null) logger.info("\"${patchResult.patchName}\" failed:\n${patchResult.exception}") else diff --git a/src/main/kotlin/app/revanced/patcher/Patcher.kt b/src/main/kotlin/app/revanced/patcher/Patcher.kt index 3eef2534..d822552f 100644 --- a/src/main/kotlin/app/revanced/patcher/Patcher.kt +++ b/src/main/kotlin/app/revanced/patcher/Patcher.kt @@ -1,41 +1,21 @@ package app.revanced.patcher import app.revanced.patcher.patch.* -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import java.io.Closeable import java.io.File -import java.util.function.Function -import java.util.function.Supplier import java.util.logging.Logger -@FunctionalInterface -interface PatchesConsumer { - fun accept(patches: Set>, integrations: Set = emptySet()) -} - -@FunctionalInterface -interface PatcherResultSupplier : - Supplier, - Closeable - -@FunctionalInterface -interface PatchExecutorFunction : Function> - /** * A Patcher. * * @param config The configuration to use for the patcher. */ -class Patcher( - private val config: PatcherConfig, -) : PatchExecutorFunction, - PatchesConsumer, - PatcherResultSupplier { - private val logger = Logger.getLogger(Patcher::class.java.name) +class Patcher(private val config: PatcherConfig) : Closeable { + private val logger = Logger.getLogger(this::class.java.name) /** - * A context for the patcher containing the current state of the patcher. + * The context containing the current state of the patcher. */ val context = PatcherContext(config) @@ -44,17 +24,17 @@ class Patcher( } /** - * Add [Patch]es and integrations to the [Patcher]. + * Add patches and integrations. * - * @param patches The [Patch]es to add. - * @param integrations The integrations to add. Must be a DEX file or container of DEX files. + * @param patchesIntegrationsPair The patches and integrations to add. */ - @Suppress("NAME_SHADOWING") - override fun accept(patches: Set>, integrations: Set) { + operator fun plusAssign(patchesIntegrationsPair: Pair>, Set>) { + val (patches, integrations) = patchesIntegrationsPair + // region Add patches // Add all patches to the executablePatches set. - context.executablePatches.addAll(patches) + context.executablePatches += patches // Add all patches and their dependencies to the allPatches set. patches.forEach { patch -> @@ -67,9 +47,8 @@ class Patcher( // TODO: Detect circular dependencies. /** - * Returns true if at least one patch or its dependencies matches the given predicate. - * * @param predicate The predicate to match. + * @return True if at least one patch or its dependencies matches the given predicate. */ fun Patch<*>.anyRecursively(predicate: (Patch<*>) -> Boolean): Boolean = predicate(this) || dependencies.any { dependency -> dependency.anyRecursively(predicate) } @@ -97,18 +76,17 @@ class Patcher( // region Add integrations - context.bytecodeContext.integrations.addAll(integrations) + context.bytecodeContext.integrations += integrations // endregion } /** - * Execute [Patch]es that were added to [Patcher]. + * Execute added patches. * - * @param returnOnError If true, [Patcher] will return immediately if a [Patch] fails. - * @return A pair of the name of the [Patch] and its [PatchResult]. + * @return A flow of [PatchResult]s. */ - override fun apply(returnOnError: Boolean) = flow { + fun execute() = flow { fun Patch<*>.execute( executedPatches: LinkedHashMap, PatchResult>, ): PatchResult { @@ -157,17 +135,10 @@ class Patcher( context.executablePatches.sortedBy { it.name }.forEach { patch -> val patchResult = patch.execute(executedPatches) - // If the patch failed, emit the result, even if it is closeable. - // 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) + // TODO: Only emit, if the patch has no finalizerBlock. + // if (patchResult.exception == null && patch.finalizerBlock != null) return@forEach - if (returnOnError) return@flow - } ?: run { - // TODO: Only emit, if the patch has no finalizerBlock. - emit(patchResult) - } + emit(patchResult) } executedPatches.values.filter { it.exception == null }.asReversed().forEach { executionResult -> @@ -184,21 +155,17 @@ class Patcher( PatchResult(patch, PatchException(exception)) } - result.exception?.let { + if (result.exception != null) { emit( PatchResult( patch, PatchException( - "The patch \"$patch\" raised an exception: ${it.stackTraceToString()}", + "The patch \"$patch\" raised an exception: ${result.exception.stackTraceToString()}", result.exception, ), ), ) - - if (returnOnError) return@flow - } ?: run { - patch.name ?: return@run - + } else if (patch.name != null) { emit(result) } } @@ -207,14 +174,10 @@ class Patcher( override fun close() = context.bytecodeContext.methodLookupMaps.close() /** - * Compile and save the patched APK file. + * Compile and save patched APK files. * - * @return The [PatcherResult] containing the patched input files. + * @return The [PatcherResult] containing the patched APK files. */ @OptIn(InternalApi::class) - override fun get() = - PatcherResult( - context.bytecodeContext.get(), - context.resourceContext.get(), - ) + fun get() = PatcherResult(context.bytecodeContext.get(), context.resourceContext.get()) }