This commit is contained in:
C10udburst 2022-08-04 09:52:23 +02:00
parent 6bb86e0b15
commit e0239f1e4c
5 changed files with 221 additions and 1 deletions

View file

@ -8,7 +8,11 @@ import javax.inject.Inject
abstract class CloudstreamExtension @Inject constructor(project: Project) {
val userCache = project.gradle.gradleUserHomeDir.resolve("caches").resolve("cloudstream")
var discord: ApkInfo? = null
var apkinfo: ApkInfo? = null
internal set
internal var pluginClassName: String? = null
}
class ApkInfo(extension: CloudstreamExtension, val version: Int) {
@ -20,4 +24,8 @@ class ApkInfo(extension: CloudstreamExtension, val version: Int) {
fun ExtensionContainer.getCloudstream(): CloudstreamExtension {
return getByName("cloudstream") as CloudstreamExtension
}
fun ExtensionContainer.findCloudstream(): CloudstreamExtension? {
return findByName("cloudstream") as CloudstreamExtension?
}

View file

@ -2,9 +2,12 @@ package com.lagradost.gradle
import org.gradle.api.Plugin
import org.gradle.api.Project
import com.lagradost.gradle.tasks.registerTasks
abstract class CloudstreamPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.extensions.create("cloudstream", CloudstreamExtension::class.java, project)
registerTasks(project)
}
}

View file

@ -0,0 +1,99 @@
package com.lagradost.gradle.tasks
import com.cloudstream.gradle.getCloudstream
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.internal.errors.MessageReceiverImpl
import com.android.build.gradle.options.SyncOptions.ErrorFormatMode
import com.android.builder.dexing.ClassFileInputs
import com.android.builder.dexing.DexArchiveBuilder
import com.android.builder.dexing.DexParameters
import com.android.builder.dexing.r8.ClassFileProviderFactory
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.tasks.*
import org.objectweb.asm.ClassReader
import org.objectweb.asm.tree.ClassNode
import org.slf4j.LoggerFactory
import java.io.File
import java.nio.file.Path
import java.util.*
import java.util.stream.Collectors
abstract class CompileDexTask : DefaultTask() {
@InputFiles
@SkipWhenEmpty
@IgnoreEmptyDirectories
val input: ConfigurableFileCollection = project.objects.fileCollection()
@get:OutputFile
abstract val outputFile: RegularFileProperty
@get:OutputFile
abstract val pluginClassFile: RegularFileProperty
@Suppress("UnstableApiUsage")
@TaskAction
fun compileDex() {
val android = project.extensions.getByName("android") as BaseExtension
val dexOutputDir = outputFile.get().asFile.parentFile
Closer.create().use { closer ->
val dexBuilder = DexArchiveBuilder.createD8DexBuilder(
DexParameters(
minSdkVersion = android.defaultConfig.maxSdkVersion ?: 24,
debuggable = true,
dexPerClass = false,
withDesugaring = true,
desugarBootclasspath = ClassFileProviderFactory(android.bootClasspath.map(File::toPath))
.also { closer.register(it) },
desugarClasspath = ClassFileProviderFactory(listOf<Path>()).also { closer.register(it) },
coreLibDesugarConfig = null,
coreLibDesugarOutputKeepRuleFile = null,
messageReceiver = MessageReceiverImpl(
ErrorFormatMode.HUMAN_READABLE,
LoggerFactory.getLogger(CompileDexTask::class.java)
)
)
)
val fileStreams =
input.map { input -> ClassFileInputs.fromPath(input.toPath()).use { it.entries { _, _ -> true } } }
.toTypedArray()
Arrays.stream(fileStreams).flatMap { it }
.use { classesInput ->
val files = classesInput.collect(Collectors.toList())
dexBuilder.convert(
files.stream(),
dexOutputDir.toPath()
)
for (file in files) {
val reader = ClassReader(file.readAllBytes())
val classNode = ClassNode()
reader.accept(classNode, 0)
for (annotation in classNode.visibleAnnotations.orEmpty() + classNode.invisibleAnnotations.orEmpty()) {
if (annotation.desc == "Lcom/lagradost/annotations/CloudstreamPlugin;") {
val cloudstream = project.extensions.getCloudstream()
require(cloudstream.pluginClassName == null) {
"Only 1 active plugin class per project is supported"
}
cloudstream.pluginClassName = classNode.name.replace('/', '.')
.also { pluginClassFile.asFile.orNull?.writeText(it) }
}
}
}
}
}
logger.lifecycle("Compiled dex to ${outputFile.get()}")
}
}

View file

@ -0,0 +1,43 @@
package com.lagradost.gradle.tasks
import com.cloudstream.gradle.getCloudstream
import jadx.api.JadxArgs
import jadx.api.JadxDecompiler
import jadx.api.impl.NoOpCodeCache
import jadx.api.impl.SimpleCodeWriter
import jadx.plugins.input.dex.DexInputPlugin
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import java.util.function.Function
abstract class GenSourcesTask : DefaultTask() {
@TaskAction
fun genSources() {
val extension = project.extensions.getAliucord()
val apkinfo = extension.apkinfo!!
val sourcesJarFile = apkinfo.cache.resolve("cloudstream-${apkinfo.version}-sources.jar")
val args = JadxArgs()
args.setInputFile(apkinfo.apkFile)
args.outDirSrc = sourcesJarFile
args.isSkipResources = true
args.isShowInconsistentCode = true
args.isRespectBytecodeAccModifiers = true
args.isFsCaseSensitive = true
args.isGenerateKotlinMetadata = false
args.isDebugInfo = false
args.isInlineAnonymousClasses = false
args.isInlineMethods = false
args.isReplaceConsts = false
args.codeCache = NoOpCodeCache()
args.codeWriterProvider = Function { SimpleCodeWriter(it) }
JadxDecompiler(args).use { decompiler ->
decompiler.registerPlugin(DexInputPlugin())
decompiler.load()
decompiler.save()
}
}
}

View file

@ -0,0 +1,67 @@
package com.lagradost.gradle.tasks
import com.cloudstream.gradle.getCloudstream
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.tasks.ProcessLibraryManifest
import groovy.json.JsonBuilder
import org.gradle.api.Project
import org.gradle.api.tasks.AbstractCopyTask
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.compile.AbstractCompile
const val TASK_GROUP = "cloudstream"
fun registerTasks(project: Project) {
val extension = project.extensions.getCloudstream()
val intermediates = project.buildDir.resolve("intermediates")
project.tasks.register("genSources", GenSourcesTask::class.java) {
it.group = TASK_GROUP
}
val pluginClassFile = intermediates.resolve("pluginClass")
val compileDex = project.tasks.register("compileDex", CompileDexTask::class.java) {
it.group = TASK_GROUP
it.pluginClassFile.set(pluginClassFile)
for (name in arrayOf("compileDebugJavaWithJavac", "compileDebugKotlin")) {
val task = project.tasks.findByName(name) as AbstractCompile?
if (task != null) {
it.dependsOn(task)
it.input.from(task.destinationDirectory)
}
}
it.outputFile.set(intermediates.resolve("classes.dex"))
}
project.afterEvaluate {
project.tasks.register("make", Copy::class.java)
{
val compileDexTask = compileDex.get()
it.dependsOn(compileDexTask)
it.doFirst {
require(project.version != "unspecified") {
"No version is set"
}
if (extension.pluginClassName == null) {
if (pluginClassFile.exists()) {
extension.pluginClassName = pluginClassFile.readText()
}
}
require(extension.pluginClassName != null) {
"No plugin class found, make sure your plugin class is annotated with @CloudstreamPlugin"
}
}
it.from(compileDexTask.outputFile)
it.into(project.buildDir)
it.rename { return@rename project.name }
}
}
}