name.remal.building.gradle_plugins.CopyDependenciesPlugin.kt Maven / Gradle / Ivy
package name.remal.building.gradle_plugins
import mu.KLogging
import name.remal.building.gradle_plugins.artifact.ArtifactsCacheCleanerPlugin
import name.remal.building.gradle_plugins.artifact.CachedArtifactsCollection
import name.remal.building.gradle_plugins.classes_relocation.DoNotProcessAnnotationAdder
import name.remal.building.gradle_plugins.dsl.createParentDirectories
import name.remal.building.gradle_plugins.dsl.java
import name.remal.building.gradle_plugins.dsl.use
import name.remal.building.gradle_plugins.utils.*
import name.remal.building.gradle_plugins.utils.Constants.CLASS_FILE_NAME_SUFFIX
import name.remal.building.gradle_plugins.utils.PluginIds.JAVA_PLUGIN_ID
import org.gradle.api.Project
import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
import org.gradle.api.tasks.compile.AbstractCompile
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import java.io.File
import kotlin.text.RegexOption.IGNORE_CASE
open class CopyDependenciesPlugin : ProjectPlugin() {
companion object : KLogging() {
const val COPY_CONFIGURATION_NAME = "copy"
private val EXCLUDE_ENTRY_NAME_REGEX = Regex("^META-INF/[^/]+\\.(MF|SF|DSA|RSA)\$", IGNORE_CASE)
}
override fun apply(project: Project) {
project.applyPlugin(ArtifactsCacheCleanerPlugin::class.java)
project.withPlugin(JAVA_PLUGIN_ID) {
val copyConf = project.configurations.create(COPY_CONFIGURATION_NAME) {
it.description = "Dependencies that will be copied directly to build output"
}
val mainSourceSet = project.java.sourceSets[MAIN_SOURCE_SET_NAME]
project.java.sourceSets.configure { sourceSet ->
val confName = if (sourceSet.name == mainSourceSet.name) sourceSet.compileOnlyConfigurationName else sourceSet.compileConfigurationName
project.configurations.findByName(confName)?.extendsFrom(copyConf)
}
project.afterEvaluateOrdered {
if (copyConf.allDependencies.isEmpty()) return@afterEvaluateOrdered
fun executeCopy(destDir: File) {
val artifacts = CachedArtifactsCollection(copyConf)
artifacts.entryNames.forEach { entryName ->
if (EXCLUDE_ENTRY_NAME_REGEX.matches(entryName)) return@forEach
destDir.resolve(entryName).createParentDirectories().outputStream().use { outputStream ->
artifacts.openStream(entryName).use { inputStream ->
if (entryName.endsWith(CLASS_FILE_NAME_SUFFIX)) {
val classWriter = ClassWriter(0)
ClassReader(inputStream.readBytes()).accept(DoNotProcessAnnotationAdder(classWriter), 0)
outputStream.write(classWriter.toByteArray())
} else {
inputStream.copyTo(outputStream)
}
}
}
}
}
val compileJavaTask = project.tasks.findByName(mainSourceSet.compileJavaTaskName)?.apply {
doLastOrdered(1000) {
it as AbstractCompile
executeCopy(it.destinationDir)
}
}
project.tasks[mainSourceSet.classesTaskName].doLastOrdered(1000) {
if (null == compileJavaTask || compileJavaTask.state.noSource) { // TODO: test
val classesDir = mainSourceSet.output.classesDirs.iterator().next()
executeCopy(classesDir)
}
}
}
}
}
}