From 4144e2802ff8c63f0643f68d76a1b7ca5d948850 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 13 Nov 2025 19:17:58 -0700 Subject: [PATCH 1/2] Add support for config cache for the CompileDex and MakePluginsJson tasks There are still some more tasks not yet supporting, but this at least partially adds support for configuration cache and Gradle 10. --- .../gradle/tasks/CompileDexTask.kt | 27 ++++++---- .../gradle/tasks/MakePluginsJsonTask.kt | 27 +++------- .../cloudstream3/gradle/tasks/Tasks.kt | 51 +++++++++++-------- 3 files changed, 52 insertions(+), 53 deletions(-) diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileDexTask.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileDexTask.kt index 37d4104..870ce89 100644 --- a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileDexTask.kt +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileDexTask.kt @@ -12,6 +12,7 @@ import com.google.common.io.Closer import org.gradle.api.DefaultTask import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.objectweb.asm.ClassReader import org.objectweb.asm.tree.ClassNode @@ -33,22 +34,27 @@ abstract class CompileDexTask : DefaultTask() { @get:OutputFile abstract val pluginClassFile: RegularFileProperty - @TaskAction - fun compileDex() { - val android = project.extensions.getByName("android") as BaseExtension + @get:Internal + abstract val pluginClassName: Property + + @get:Input + abstract val minSdk: Property - val minSdk = android.defaultConfig.minSdk ?: 21 + @get:InputFiles + abstract val bootClasspath: ConfigurableFileCollection + @TaskAction + fun compileDex() { val dexOutputDir = outputFile.get().asFile.parentFile Closer.create().use { closer -> val dexBuilder = DexArchiveBuilder.createD8DexBuilder( DexParameters( - minSdkVersion = minSdk, + minSdkVersion = minSdk.get(), debuggable = true, dexPerClass = false, withDesugaring = true, // Make all plugins work on lower android versions - desugarBootclasspath = ClassFileProviderFactory(android.bootClasspath.map(File::toPath)) + desugarBootclasspath = ClassFileProviderFactory(bootClasspath.files.map(File::toPath)) .also { closer.register(it) }, desugarClasspath = ClassFileProviderFactory(listOf()).also { closer.register( @@ -86,14 +92,13 @@ abstract class CompileDexTask : DefaultTask() { for (annotation in classNode.visibleAnnotations.orEmpty() + classNode.invisibleAnnotations.orEmpty()) { if (annotation.desc == "Lcom/lagradost/cloudstream3/plugins/CloudstreamPlugin;") { - val cloudstream = project.extensions.getCloudstream() - - require(cloudstream.pluginClassName == null) { + require(pluginClassName.orNull == null) { "Only 1 active plugin class per project is supported" } - cloudstream.pluginClassName = classNode.name.replace('/', '.') - .also { pluginClassFile.asFile.orNull?.writeText(it) } + val detectedName = classNode.name.replace('/', '.') + pluginClassFile.asFile.orNull?.writeText(detectedName) + pluginClassName.set(detectedName) } } } diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/MakePluginsJsonTask.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/MakePluginsJsonTask.kt index 09b8220..7a006b2 100644 --- a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/MakePluginsJsonTask.kt +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/MakePluginsJsonTask.kt @@ -1,38 +1,23 @@ package com.lagradost.cloudstream3.gradle.tasks -import com.lagradost.cloudstream3.gradle.findCloudstream -import com.lagradost.cloudstream3.gradle.makePluginEntry -import com.lagradost.cloudstream3.gradle.entities.PluginEntry -import groovy.json.JsonBuilder -import groovy.json.JsonGenerator import org.gradle.api.DefaultTask import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction -import java.util.LinkedList -import java.lang.Thread abstract class MakePluginsJsonTask : DefaultTask() { @get:OutputFile abstract val outputFile: RegularFileProperty + @get:Input + abstract val pluginEntriesJson: Property + @TaskAction fun makePluginsJson() { - val lst = LinkedList() - - for (subproject in project.allprojects) { - subproject.extensions.findCloudstream() ?: continue - - lst.add(subproject.makePluginEntry()) - } - outputFile.asFile.get().writeText( - JsonBuilder( - lst, - JsonGenerator.Options() - .excludeNulls() - .build() - ).toPrettyString() + pluginEntriesJson.get() ) logger.lifecycle("Created ${outputFile.asFile.get()}") diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt index a2048d9..a432311 100644 --- a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt @@ -22,12 +22,18 @@ fun registerTasks(project: Project) { val intermediates = project.buildDir.resolve("intermediates") if (project.rootProject.tasks.findByName("makePluginsJson") == null) { - project.rootProject.tasks.register("makePluginsJson", MakePluginsJsonTask::class.java) { - it.group = TASK_GROUP - - it.outputs.upToDateWhen { false } - - it.outputFile.set(it.project.buildDir.resolve("plugins.json")) + project.rootProject.tasks.register("makePluginsJson", MakePluginsJsonTask::class.java) { task -> + task.group = TASK_GROUP + task.outputs.upToDateWhen { false } + task.outputFile.set(task.project.layout.buildDirectory.file("plugins.json")) + task.pluginEntriesJson.set( + task.project.provider { + val lst = task.project.allprojects.mapNotNull { sub -> + sub.extensions.findCloudstream()?.let { sub.makePluginEntry() } + } + JsonBuilder(lst, JsonGenerator.Options().excludeNulls().build()).toPrettyString() + } + ) } } @@ -35,28 +41,31 @@ fun registerTasks(project: Project) { it.group = TASK_GROUP } - val pluginClassFile = intermediates.resolve("pluginClass") + val pluginClassFile = intermediatesDir.map { it.file("pluginClass") } - val compileDex = project.tasks.register("compileDex", CompileDexTask::class.java) { - it.group = TASK_GROUP + val compileDex = project.tasks.register("compileDex", CompileDexTask::class.java) { task -> + task.group = TASK_GROUP - it.pluginClassFile.set(pluginClassFile) + task.pluginClassFile.set(pluginClassFile) + task.outputFile.set(intermediatesDir.map { dir -> dir.file("classes.dex") }) + + val android = project.extensions.findByName("android") as? BaseExtension + ?: error("Android plugin not found") + task.minSdk.set(android.defaultConfig.minSdk ?: 21) + task.bootClasspath.from(android.bootClasspath) + + val extension = project.extensions.getCloudstream() + task.pluginClassName.set(extension.pluginClassName) val kotlinTask = project.tasks.findByName("compileDebugKotlin") as KotlinCompile? if (kotlinTask != null) { - it.dependsOn(kotlinTask) - it.input.from(kotlinTask.destinationDirectory) + task.dependsOn(kotlinTask) + task.input.from(kotlinTask.destinationDirectory) } - // This task does not seem to be required for a successful cs3 file - -// val javacTask = project.tasks.findByName("compileDebugJavaWithJavac") as AbstractCompile? -// if (javacTask != null) { -// it.dependsOn(javacTask) -// it.input.from(javacTask.destinationDirectory) -// } - - it.outputFile.set(intermediates.resolve("classes.dex")) + task.doLast { + extension.pluginClassName = task.pluginClassName.orNull + } } val compileResources = From 76a0a6008e6bf331a1d6799ffd67a479bc12c4cf Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sun, 16 Nov 2025 16:30:08 -0700 Subject: [PATCH 2/2] Add support for CompilePluginJar task --- .../gradle/tasks/CompilePluginJarTask.kt | 48 +++++++++++++++++++ .../cloudstream3/gradle/tasks/Tasks.kt | 43 ++++++----------- 2 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompilePluginJarTask.kt diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompilePluginJarTask.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompilePluginJarTask.kt new file mode 100644 index 0000000..1bc27a1 --- /dev/null +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompilePluginJarTask.kt @@ -0,0 +1,48 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction + +abstract class CompilePluginJarTask : DefaultTask() { + + @get:Input + abstract val hasCrossPlatformSupport: Property + + @get:InputFile + abstract val pluginClassFile: RegularFileProperty + + @get:Internal + abstract val pluginClassName: Property + + @get:Internal + abstract val jarFileSize: Property + + @get:InputFile + abstract val jarInputFile: RegularFileProperty + + @get:OutputFile + abstract val targetJarFile: RegularFileProperty + + @TaskAction + fun compileJar() { + if (pluginClassName.orNull == null) { + val file = pluginClassFile.get().asFile + if (file.exists()) { + pluginClassName.set(file.readText()) + } + } + + if (!hasCrossPlatformSupport.get()) return + + val jarFile = jarInputFile.get().asFile + val targetFile = targetJarFile.get().asFile + + jarFile.copyTo(targetFile, overwrite = true) + jarFileSize.set(jarFile.length()) + logger.lifecycle("Made Cloudstream cross-platform package at ${targetFile.absolutePath}") + } +} diff --git a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt index a432311..3be92ff 100644 --- a/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt +++ b/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/Tasks.kt @@ -95,35 +95,22 @@ fun registerTasks(project: Project) { } } - val compilePluginJar = project.tasks.register("compilePluginJar") { - it.group = TASK_GROUP - it.dependsOn("createFullJarDebug") // Ensure JAR is built before copying - - it.doFirst { - if (extension.pluginClassName == null) { - if (pluginClassFile.exists()) { - extension.pluginClassName = pluginClassFile.readText() - } - } - } - - it.doLast { - if (!extension.isCrossPlatform) { - return@doLast - } + val compilePluginJar = project.tasks.register("compilePluginJar", CompilePluginJarTask::class.java) { task -> + task.group = TASK_GROUP + task.dependsOn("createFullJarDebug") // Ensure JAR is built before copying + task.dependsOn("compileDex") // compileDex creates pluginClass + val jarTask = project.tasks.named("createFullJarDebug") - val jarTask = project.tasks.findByName("createFullJarDebug") ?: return@doLast - val jarFile = - jarTask.outputs.files.singleFile // Output directory of createFullJarDebug - if (jarFile != null) { - val targetDir = project.buildDir // Top-level build directory - val targetFile = targetDir.resolve("${project.name}.jar") - jarFile.copyTo(targetFile, overwrite = true) - extension.jarFileSize = jarFile.length() - it.logger.lifecycle("Made Cloudstream cross-platform package at ${targetFile.absolutePath}") - } else { - it.logger.warn("Could not find JAR file!") - } + task.hasCrossPlatformSupport.set(extension.isCrossPlatform) + task.pluginClassFile.set(pluginClassFile) + task.pluginClassName.set(extension.pluginClassName) + task.jarInputFile.fileProvider(jarTask.map { it.outputs.files.singleFile }) + task.targetJarFile.set(project.layout.buildDirectory.file("${project.name}.jar")) + task.jarFileSize.set(extension.jarFileSize) + + task.doLast { + extension.pluginClassName = task.pluginClassName.orNull + extension.jarFileSize = task.jarFileSize.orNull } }