aboutsummaryrefslogtreecommitdiff
path: root/build.gradle
diff options
context:
space:
mode:
Diffstat (limited to 'build.gradle')
-rw-r--r--build.gradle158
1 files changed, 156 insertions, 2 deletions
diff --git a/build.gradle b/build.gradle
index 635950d..d6cbd04 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,9 +1,30 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ // Needed for bytecode manipulation
+ classpath 'org.ow2.asm:asm-all:5.2'
+ }
+}
+
plugins {
id 'net.minecrell.licenser' version '0.3'
id 'org.ajoberstar.grgit' version '2.3.0'
//id 'com.github.johnrengelman.shadow' version '2.0.4'
}
+import java.nio.file.Paths
+import org.objectweb.asm.ClassReader
+import org.objectweb.asm.ClassWriter
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.tree.ClassNode
+import org.objectweb.asm.tree.MethodInsnNode
+import org.objectweb.asm.tree.VarInsnNode
+import org.objectweb.asm.tree.InsnNode
+
+import java.util.jar.JarFile
+
apply plugin: 'java'
apply plugin: 'maven-publish'
@@ -15,7 +36,7 @@ def gitVersion() {
def hash = desc.remove(desc.size() - 1)
def offset = desc.remove(desc.size() - 1)
def tag = desc.join('-')
- def branch = grgit.branch.current().name
+ def branch = grgit.branch.current().name
return "${tag}.${offset}" //${t -> if (branch != 'master') t << '-' + branch}"
}
@@ -52,10 +73,143 @@ dependencies {
compile sourceSets.gradlecomp.output
}
+
+
+def gradleRepositoryAdapterPath = Paths.get("com", "amadornes", "artifactural", "gradle", "GradleRepositoryAdapter.class")
+def classesDirs = sourceSets.gradlecomp.output.classesDirs.getFiles().first().toPath()
+
+
+def _constructorName = "<init>"
+def _constructorDesc = "(Lcom/amadornes/artifactural/api/repository/Repository;Lorg/gradle/api/internal/artifacts/repositories/DefaultMavenLocalArtifactRepository;)V"
+def _modifiedSuperDesc = "()V"
+
+// This task patches 'GradleRepositoryAdapter' to make it compatibile with both Gradle 4.9 and 4.10
+// In Gradle 4.9, the constructor of AbstractArtifactRepository changes has zero arguments
+// (instead of the one-argument constructor in 4.10, which we compile against)
+// It's not possible to write a normal Java class that calls a constructor which doesn't exist at compile time.
+// Therefore, we need to patch the bytecode of the class to properly call the non-arg super() constrcutor
+class PatchGradleRepositoryAdapter extends DefaultTask {
+
+ @Input String constructorName
+ @Input String constructorDesc
+ @Input String modifiedSuperDesc
+ @Input File gradleRepositoryAdapter
+ @Input File classesDir
+ @OutputDirectory java.nio.file.Path outputDir
+
+
+ @TaskAction
+ void patchClass() {
+ def originalGradleRepositoryAdapter = Paths.get(classesDir.toString(), gradleRepositoryAdapter.toString())
+
+ ClassNode node = new ClassNode()
+ ClassReader reader = new ClassReader(new FileInputStream(originalGradleRepositoryAdapter.toFile()))
+ reader.accept(node, 0)
+
+
+ def constructor = node.methods.find {
+ it.name == constructorName && it.desc == constructorDesc
+ }
+
+ def getDescriptor = node.methods.find {
+ it.name == "getDescriptor"
+ }
+
+ if (constructor == null) {
+ throw new RuntimeException("Failed to find target constructor!")
+ }
+
+ if (getDescriptor == null) {
+ throw new RuntimeException("Failed to find getDescriptor()")
+ }
+
+ // Strip out this method - it only exists
+ // so that GradleRepositoryAdapter will compile
+ node.methods.remove(getDescriptor)
+
+ def superInvoc = constructor.instructions.find {
+ it instanceof MethodInsnNode && it.owner == "org/gradle/api/internal/artifacts/repositories/AbstractArtifactRepository"
+ } as MethodInsnNode
+
+ if (superInvoc == null) {
+ throw new RuntimeException("Failed to find target super() invocation!")
+ }
+
+ superInvoc.desc = modifiedSuperDesc
+
+ def aconstNull = superInvoc.previous
+ if (!(aconstNull instanceof InsnNode) || aconstNull.type != 0) {
+ throw new RuntimeException("Unexpected instruction: " + aconstNull)
+ }
+
+ constructor.instructions.remove(aconstNull)
+
+ // Push first parameter of constructor (the ObjectFactory) onto the stack.
+ // This has the effect of calling super(objectFactory)
+ //constructor.instructions.insertBefore(superInvoc, new VarInsnNode(Opcodes.ALOAD, 1))
+
+ ClassWriter writer = new ClassWriter(0)
+ node.accept(writer)
+
+ def outputFile = outputDir.resolve(gradleRepositoryAdapter.toPath()).toFile()
+
+ outputFile.parentFile.mkdirs()
+ FileOutputStream fs = new FileOutputStream(outputFile)
+ fs.write(writer.toByteArray())
+ }
+}
+
+
+
+task patchConstructor(type: PatchGradleRepositoryAdapter) {
+ constructorName = _constructorName
+ constructorDesc = _constructorDesc
+ modifiedSuperDesc = _modifiedSuperDesc
+ classesDir = classesDirs.toFile()
+ outputDir = Paths.get(buildDir.toString(), "modifiedclasses")
+ gradleRepositoryAdapter = gradleRepositoryAdapterPath.toFile()
+}
+
jar {
from sourceSets.api.output
from sourceSets.shared.output
- from sourceSets.gradlecomp.output
+ from(sourceSets.gradlecomp.output) {
+ exclude gradleRepositoryAdapterPath.toString()
+ }
+
+ from patchConstructor.outputs
+}
+
+jar.doLast {
+ def jarPath = it.outputs.files.getFiles().first()
+ def jarFile = new JarFile(jarPath)
+ def entry = jarFile.getEntry(gradleRepositoryAdapterPath.toString())
+ def stream = jarFile.getInputStream(entry)
+
+ ClassReader reader = new ClassReader(stream)
+ ClassNode node = new ClassNode()
+ reader.accept(node, 0)
+
+ def constructor = node.methods.find {
+ it.name == _constructorName && it.desc == _constructorDesc
+ }
+
+ def superInvoc = constructor.instructions.find {
+ it instanceof MethodInsnNode && it.owner == "org/gradle/api/internal/artifacts/repositories/AbstractArtifactRepository"
+ } as MethodInsnNode
+
+ if (superInvoc.desc == _modifiedSuperDesc) {
+ println("Successfully modified super() call!")
+ } else {
+ throw new RuntimeException("Failed to modify super() invocation - got desc of " + superInvoc.desc)
+ }
+
+ def getDescriptor = node.methods.find { it.name == "getDescriptor"}
+ if (getDescriptor != null) {
+ throw new RuntimeException("Failed to remove getDescriptor with signature: " + getDescriptor.signature)
+ } else {
+ println("Successfully stripped getDescriptor method!")
+ }
}
task sourcesJar(type: Jar, dependsOn: classes) {