main.name.remal.gradle_plugins.dsl.utils.newFileCollection.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-plugins-kotlin-dsl Show documentation
Show all versions of gradle-plugins-kotlin-dsl Show documentation
Remal Gradle plugins: gradle-plugins-kotlin-dsl
The newest version!
package name.remal.gradle_plugins.dsl.utils
import name.remal.KotlinAllOpen
import name.remal.accept
import name.remal.gradle_plugins.dsl.extensions.defineClass
import name.remal.isFinal
import name.remal.toLoadVarInsn
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.file.AbstractFileCollection
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.ClassWriter.COMPUTE_FRAMES
import org.objectweb.asm.ClassWriter.COMPUTE_MAXS
import org.objectweb.asm.Opcodes.ACC_PUBLIC
import org.objectweb.asm.Opcodes.ALOAD
import org.objectweb.asm.Opcodes.ARETURN
import org.objectweb.asm.Opcodes.GETSTATIC
import org.objectweb.asm.Opcodes.INVOKESPECIAL
import org.objectweb.asm.Opcodes.RETURN
import org.objectweb.asm.Opcodes.V1_8
import org.objectweb.asm.Type.OBJECT
import org.objectweb.asm.Type.getArgumentTypes
import org.objectweb.asm.Type.getConstructorDescriptor
import org.objectweb.asm.Type.getDescriptor
import org.objectweb.asm.Type.getInternalName
import org.objectweb.asm.Type.getMethodDescriptor
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.FieldInsnNode
import org.objectweb.asm.tree.InsnList
import org.objectweb.asm.tree.InsnNode
import org.objectweb.asm.tree.LabelNode
import org.objectweb.asm.tree.MethodInsnNode
import org.objectweb.asm.tree.MethodNode
import org.objectweb.asm.tree.VarInsnNode
import org.objectweb.asm.util.CheckClassAdapter
import java.io.File
import java.lang.reflect.Constructor
fun newFileCollection(filesFactory: () -> Iterable): FileCollection {
val lazyFilesSet = lazy { filesFactory().toSet() }
return implClassCtor.newInstance(lazyFilesSet)
}
fun newFileCollection(files: Iterable) = newFileCollection({ files })
fun newFileCollection(vararg files: File) = newFileCollection(files.toList())
private val implClassCtor: Constructor by lazy {
return@lazy implClass.getDeclaredConstructor(Lazy::class.java)
}
private val implClass: Class by lazy> {
val packageName = BaseFileCollectionImpl::class.java.name.substringBeforeLast('.')
val className = "$packageName.FileCollectionImpl"
val classNode = ClassNode().apply classNode@{
version = V1_8
access = ACC_PUBLIC
name = classNameToClassInternalName(className)
superName = getInternalName(BaseFileCollectionImpl::class.java)
interfaces = listOf()
methods = mutableListOf()
val superCtor = BaseFileCollectionImpl::class.java.getConstructor(Lazy::class.java)
val superCtorDescr = getConstructorDescriptor(superCtor)
methods.add(MethodNode(ACC_PUBLIC, "", superCtorDescr, null, null).apply methodNode@{
instructions = InsnList().apply instructions@{
add(LabelNode())
add(VarInsnNode(ALOAD, 0))
getArgumentTypes(superCtorDescr).forEachIndexed { index, type ->
if (type.sort == OBJECT) {
add(VarInsnNode(ALOAD, index + 1))
} else {
add(type.toLoadVarInsn(index + 1))
}
}
add(MethodInsnNode(INVOKESPECIAL, [email protected], [email protected], superCtorDescr, false))
add(InsnNode(RETURN))
}
maxStack = 1
maxLocals = 1
})
val getBuildDependenciesMethod = BaseFileCollectionImpl::class.java.getMethod("getBuildDependencies")
if (!getBuildDependenciesMethod.isFinal) {
methods.add(MethodNode(ACC_PUBLIC, getBuildDependenciesMethod.name, getMethodDescriptor(getBuildDependenciesMethod), null, null).apply methodNode@{
instructions = InsnList().apply instructions@{
add(LabelNode())
val taskDependenciesInstanceField = EmptyTaskDependencies::class.java.getField("INSTANCE")
add(FieldInsnNode(GETSTATIC, getInternalName(taskDependenciesInstanceField.declaringClass), taskDependenciesInstanceField.name, getDescriptor(taskDependenciesInstanceField.type)))
add(InsnNode(ARETURN))
}
maxStack = 1
maxLocals = 1
})
}
}
val classWriter = ClassWriter(COMPUTE_MAXS or COMPUTE_FRAMES)
classNode.accept(classWriter)
val bytecode = classWriter.toByteArray()
ClassReader(bytecode).accept(CheckClassAdapter(ClassWriter(0)))
return@lazy BaseFileCollectionImpl::class.java.classLoader.defineClass(classNode.name.replace('/', '.'), bytecode)
}
@KotlinAllOpen
private abstract class BaseFileCollectionImpl(private val filesSet: Lazy>) : AbstractFileCollection() {
override fun getFiles(): Set = filesSet.value
override fun getDisplayName() = "file collection"
override fun equals(other: Any?) = other is FileCollection && other.files == files
override fun hashCode() = 1 + files.hashCode()
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy