aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2019-04-25 16:44:20 -0400
committerAaron Hill <aa1ronham@gmail.com>2019-04-25 21:47:24 -0400
commit747c582804bdcd0409417fdd92f7a3042d80b6b5 (patch)
tree945e46af6d7359a987d31a30c162bc167e741407
parent37d713bdb7459cdd44707b350fd12fd59517b415 (diff)
downloadArtifactural-747c582804bdcd0409417fdd92f7a3042d80b6b5.tar.gz
Artifactural-747c582804bdcd0409417fdd92f7a3042d80b6b5.tar.bz2
Artifactural-747c582804bdcd0409417fdd92f7a3042d80b6b5.zip
Add compatibility with Gradle 4.10 and above
This commits adds compatibility for Gradle 4.10 onward (tested on 4.10 and 5,4), while retainting compatibiliy with 4.9 Due to the ABI-incompatible changes in some internal gradle classes, we need to use bytecode manipulation to ensure that our built class files are compatible with both Gradle 4.9 and Gradle >= 4.10 Bytecode manipulation is performed at built time. A custom Gradle task is used to read in the compiled class files from disk, and write out a modified version to the final jar artifact. In order to make as few bytecode modifications as possible, this commit bumps the Gradle wrapper version to 4.10. This means that we're compiling against Gradle 4.10, and using bytecode manipulation to retain compatibility with 4.9. Doing the reverse (compiling against 4.9) would be significantly more difficult, as we would need to statically reference classes that exist in Gradle 4.10 but not 4.9 (specifically, RepositoryDescriptor) We perform two different bytecode transformations: 1. We modify the call to 'super()' in GradleRepositoryAdapter. In Gradle 4.10, the suepr constructor takes one argument, but in 4.9, it takes zero arguments. In order to allow GradleRepositoryAdapter to compile normally, we write a 'fake' call to 'super(null)', and replace with a call to 'super()'. 2. We delete the method 'getDescriptor' from GradleRepositoryAdapter. In Gradle 4.9, its return type does not exist, and will cause a NoClassDefFoundError when Gradle attempts to classload it via Class#getDeclaredMethods. However, it's necessary to include 'getDescriptor' so that GradleRepositoryAdapter (we need to override the abstract method in a parent class).
-rw-r--r--build.gradle158
-rw-r--r--gradle.properties1
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin52271 -> 54413 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties4
-rwxr-xr-xgradlew78
-rw-r--r--gradlew.bat174
-rw-r--r--src/gradlecomp/java/com/amadornes/artifactural/gradle/Gradle410RepositoryAdapter.java42
-rw-r--r--src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleRepositoryAdapter.java54
8 files changed, 381 insertions, 130 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) {
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1 @@
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 30d399d..0d4a951 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 5aa013a..2e7105d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sat Jun 09 16:26:43 CEST 2018
+#Thu Apr 25 19:18:54 EDT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip
diff --git a/gradlew b/gradlew
index 91a7e26..cccdd3d 100755
--- a/gradlew
+++ b/gradlew
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
##############################################################################
##
@@ -6,20 +6,38 @@
##
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
-warn ( ) {
+warn () {
echo "$*"
}
-die ( ) {
+die () {
echo
echo "$*"
echo
@@ -30,6 +48,7 @@ die ( ) {
cygwin=false
msys=false
darwin=false
+nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
@@ -40,31 +59,11 @@ case "`uname`" in
MINGW* )
msys=true
;;
+ NONSTOP* )
+ nonstop=true
+ ;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -90,7 +89,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +113,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +154,19 @@ if $cygwin ; then
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 8a0b282..e95643d 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,90 +1,84 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/gradlecomp/java/com/amadornes/artifactural/gradle/Gradle410RepositoryAdapter.java b/src/gradlecomp/java/com/amadornes/artifactural/gradle/Gradle410RepositoryAdapter.java
new file mode 100644
index 0000000..ceaf989
--- /dev/null
+++ b/src/gradlecomp/java/com/amadornes/artifactural/gradle/Gradle410RepositoryAdapter.java
@@ -0,0 +1,42 @@
+/*
+ * Artifactural
+ * Copyright (c) 2018.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package com.amadornes.artifactural.gradle;
+
+import com.amadornes.artifactural.api.repository.Repository;
+import org.gradle.api.internal.artifacts.repositories.DefaultMavenLocalArtifactRepository;
+import org.gradle.api.internal.artifacts.repositories.descriptor.FlatDirRepositoryDescriptor;
+import org.gradle.api.internal.artifacts.repositories.descriptor.RepositoryDescriptor;
+import org.gradle.api.model.ObjectFactory;
+
+import java.util.ArrayList;
+
+public class Gradle410RepositoryAdapter extends GradleRepositoryAdapter {
+
+ Gradle410RepositoryAdapter(ObjectFactory objectFactory, Repository repository, DefaultMavenLocalArtifactRepository local) {
+ super(objectFactory, repository, local);
+ }
+
+
+ @Override
+ public RepositoryDescriptor getDescriptor() {
+ return new FlatDirRepositoryDescriptor("ArtifacturalRepository", new ArrayList<>());
+ }
+
+}
diff --git a/src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleRepositoryAdapter.java b/src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleRepositoryAdapter.java
index 64d6652..669ad4c 100644
--- a/src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleRepositoryAdapter.java
+++ b/src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleRepositoryAdapter.java
@@ -37,11 +37,14 @@ import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.Resol
import org.gradle.api.internal.artifacts.repositories.AbstractArtifactRepository;
import org.gradle.api.internal.artifacts.repositories.DefaultMavenLocalArtifactRepository;
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
+import org.gradle.api.internal.artifacts.repositories.descriptor.FlatDirRepositoryDescriptor;
+import org.gradle.api.internal.artifacts.repositories.descriptor.RepositoryDescriptor;
import org.gradle.api.internal.artifacts.repositories.resolver.ExternalResourceArtifactResolver;
import org.gradle.api.internal.artifacts.repositories.resolver.ExternalResourceResolver;
import org.gradle.api.internal.artifacts.repositories.resolver.MavenResolver;
import org.gradle.api.internal.artifacts.repositories.resolver.MetadataFetchingCost;
import org.gradle.api.internal.component.ArtifactType;
+import org.gradle.api.model.ObjectFactory;
import org.gradle.internal.action.InstantiatingAction;
import org.gradle.internal.component.external.model.ModuleComponentResolveMetadata;
import org.gradle.internal.component.external.model.ModuleDependencyMetadata;
@@ -65,10 +68,12 @@ import org.gradle.internal.resource.local.LocalFileStandInExternalResource;
import org.gradle.internal.resource.local.LocallyAvailableExternalResource;
import org.gradle.internal.resource.metadata.ExternalResourceMetaData;
import org.gradle.internal.resource.transfer.DefaultCacheAwareExternalResourceAccessor;
+import org.gradle.util.GradleVersion;
import java.io.File;
import java.io.IOException;
import java.net.URI;
+import java.util.ArrayList;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -85,7 +90,18 @@ public class GradleRepositoryAdapter extends AbstractArtifactRepository implemen
maven.setUrl(local);
maven.setName(name);
- GradleRepositoryAdapter repo = new GradleRepositoryAdapter(repository, maven);
+ GradleRepositoryAdapter repo;
+
+ // On Gradle 4.10 above, we need to use the constructor with the 'ObjectFactory' parameter
+ // (which can be safely passed as null - see BaseMavenInstaller).
+ // We use Gradle410RepositoryAdapter, which actually overrides 'getDescriptor'
+ if (GradleVersion.current().compareTo(GradleVersion.version("4.10")) >= 0) {
+ repo = new Gradle410RepositoryAdapter(null, repository, maven);
+ } else {
+ // On versions of gradle older than 4.10, we use the no-arg super constructor
+ repo = new GradleRepositoryAdapter(repository, maven);
+ }
+
repo.setName(name);
handler.add(repo);
return repo;
@@ -96,7 +112,25 @@ public class GradleRepositoryAdapter extends AbstractArtifactRepository implemen
private final String root;
private final LocatedArtifactCache cache;
+
+ // This constructor is modified via bytecode manipulation in 'build.gradle'
+ // DO NOT change this without modifying 'build.gradle'
+ // This contructor is used on Gradle 4.9 and below
private GradleRepositoryAdapter(Repository repository, DefaultMavenLocalArtifactRepository local) {
+ // This is replaced with a call to 'super()', with no arguments
+ super(null);
+ this.repository = repository;
+ this.local = local;
+ this.root = cleanRoot(local.getUrl());
+ this.cache = new LocatedArtifactCache(new File(root));
+ }
+
+
+ // This constructor is used on Gradle 4.10 and above
+ GradleRepositoryAdapter(ObjectFactory objectFactory, Repository repository, DefaultMavenLocalArtifactRepository local) {
+ super(objectFactory);
+ // This duplication from the above two-argument constructor is unfortunate,
+ // but unavoidable
this.repository = repository;
this.local = local;
this.root = cleanRoot(local.getUrl());
@@ -182,6 +216,24 @@ public class GradleRepositoryAdapter extends AbstractArtifactRepository implemen
};
}
+ // This method will be deleted entirely in build.gradle
+ // In order for this class to compile, this method needs to exist
+ // at compile-time. However, the class 'RepositoryDescriptor' doesn't
+ // exist in Gradle 4.9. If we try to classload a class
+ // that contains RepositoryDescriptor as a method return type,
+ // the JVM will try to classload RepositoryDescriptor, leading
+ // to a NoClassDefFoundError
+
+ // To fix this, we strip out this method at build time.
+ // At runtime, we instantiate Gradle410RepositoryAdapter
+ // when we're running on Gradle 4.10 on above.
+ // This ensures that 'getDescriptor' exists on Gradle 4.10,
+ // and doesn't existon Gradle 4.9
+ public RepositoryDescriptor getDescriptor() {
+ throw new Error("This method should be been stripped at build time!");
+ }
+
+
private static String cleanRoot(URI uri) {
String ret = uri.normalize().getPath().replace('\\', '/');
if (!ret.endsWith("/")) ret += '/';