gradle/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/CompileDexTask.kt

98 lines
3.9 KiB
Kotlin

package com.lagradost.cloudstream3.gradle.tasks
import com.lagradost.cloudstream3.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
@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/cloudstream3/plugins/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()}")
}
}