diff --git a/multi-release-jar/src/main/groovy/net/woggioni/gradle/multi/release/jar/MultiReleaseJarPlugin.groovy b/multi-release-jar/src/main/groovy/net/woggioni/gradle/multi/release/jar/MultiReleaseJarPlugin.groovy index 387c988..cec96e2 100644 --- a/multi-release-jar/src/main/groovy/net/woggioni/gradle/multi/release/jar/MultiReleaseJarPlugin.groovy +++ b/multi-release-jar/src/main/groovy/net/woggioni/gradle/multi/release/jar/MultiReleaseJarPlugin.groovy @@ -10,20 +10,111 @@ import org.gradle.api.attributes.java.TargetJvmVersion import org.gradle.api.file.FileCollection import org.gradle.api.file.SourceDirectorySet import org.gradle.api.internal.plugins.DslObject +import org.gradle.api.model.ObjectFactory import org.gradle.api.plugins.JavaPlugin import org.gradle.api.plugins.JavaPluginExtension -import org.gradle.api.tasks.SourceSet -import org.gradle.api.tasks.TaskProvider +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.* import org.gradle.api.tasks.compile.JavaCompile import org.gradle.jvm.tasks.Jar +import org.gradle.process.CommandLineArgumentProvider + +import java.lang.module.ModuleDescriptor +import java.util.jar.JarFile +import java.util.stream.Collectors +import java.util.zip.ZipFile import static org.gradle.api.attributes.LibraryElements.JAR import static org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE class MultiReleaseJarPlugin implements Plugin { + + private static void jpmsModuleName(File file) { + JarFile jarFile = new JarFile(file).with { + if (it.isMultiRelease()) { + new JarFile( + file, + false, + ZipFile.OPEN_READ, + Runtime.version() + ) + } else { + it + } + } + String automaticModuleName = jarFile.manifest?.with {it.mainAttributes.getValue("Automatic-Module-Name") } + def moduleInfoEntry = jarFile.getJarEntry("module-info.class") + moduleInfoEntry + ?.with(jarFile.&getInputStream) + ?.withCloseable(ModuleDescriptor.&read) ?: automaticModuleName + ModuleDescriptor.read() + } + +// @Canonical + static class CompilerArgumentProvider implements CommandLineArgumentProvider { + + private final Project project + + private final ObjectFactory objects + + @Input + final Provider jpmsModuleName + + private final Map> patchModules + + @InputFiles + @CompileClasspath + final FileCollection sourceSetOutput + +// @InputFiles +// FileCollection getPatchModules() { +// return project.files(patchModules.entrySet().stream().flatMap { +// it.getValue().get().stream() +// }.toArray(String::new)) +// } + + CompilerArgumentProvider( + Project project, + ObjectFactory objects, + Provider jpmsModuleName, + Map> patchModules, + FileCollection sourceSetOutput) { + this.project = project + this.objects = objects + this.jpmsModuleName = jpmsModuleName + this.patchModules = patchModules + this.sourceSetOutput = sourceSetOutput + } + + @Override + Iterable asArguments() { + Map> patchModules = new HashMap<>(patchModules) + + String name = jpmsModuleName.get() + if(name) { + patchModules.computeIfAbsent(name) { + objects.listProperty(String.class).convention(new ArrayList()) + }.addAll(sourceSetOutput.collect { it.toString() }) + } else { + throw new GradleException("Missing property 'jpms.module.name'") + } + String sep = System.getProperty('path.separator') + List result = new ArrayList<>() + for(Map.Entry> entry : patchModules.entrySet()) { + String arg = entry.getValue().get().stream().collect(Collectors.joining(sep)) + result += '--patch-module' + result += "${entry.getKey()}=${arg}" + } + result + } + } + @Override void apply(Project project) { project.pluginManager.apply(JavaPlugin) + MultiReleaseJarPluginExtension mrjpe = new MultiReleaseJarPluginExtension(project.objects) + project.extensions.add('multiReleaseJar', mrjpe) JavaPluginExtension javaPluginExtension = project.extensions.findByType(JavaPluginExtension.class) JavaVersion binaryVersion = javaPluginExtension.targetCompatibility ?: javaPluginExtension.toolchain?.with { it.languageVersion.get() @@ -64,14 +155,18 @@ class MultiReleaseJarPlugin implements Plugin { TaskProvider compileTask = project.tasks.register(JavaPlugin.COMPILE_JAVA_TASK_NAME + javaVersion.majorVersion, JavaCompile, { javaCompileTask -> javaCompileTask.options.release.set(javaVersion.majorVersion.toInteger()) javaCompileTask.classpath = compileClasspathConfiguration + compileOutputs.stream().reduce { fc1, fc2 -> fc1 + fc2 }.get() - javaCompileTask.doFirst { - if(project.hasProperty("jpms.module.name")) { - javaCompileTask.options.compilerArgs << "--patch-module" << - "${project.property("jpms.module.name")}=${mainSourceSet.output.asPath}" - } else { - throw new GradleException("Missing property 'jpms.module.name'") - } - } + javaCompileTask.options.compilerArgumentProviders.add( + new CompilerArgumentProvider( + project, + project.objects, + project.provider { + project.hasProperty("jpms.module.name") ? + project.property("jpms.module.name") : null + }, + mrjpe.patchModules, + mainSourceSet.output + ) + ) javaCompileTask.source = sourceDirectorySet javaCompileTask.destinationDirectory.set(sourceDirectorySet.destinationDirectory) javaCompileTask.options.annotationProcessorPath = mainSourceSet.annotationProcessorPath diff --git a/multi-release-jar/src/main/java/net/woggioni/gradle/multi/release/jar/MultiReleaseJarPluginExtension.java b/multi-release-jar/src/main/java/net/woggioni/gradle/multi/release/jar/MultiReleaseJarPluginExtension.java new file mode 100644 index 0000000..08d2132 --- /dev/null +++ b/multi-release-jar/src/main/java/net/woggioni/gradle/multi/release/jar/MultiReleaseJarPluginExtension.java @@ -0,0 +1,33 @@ +package net.woggioni.gradle.multi.release.jar; + +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Provider; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class MultiReleaseJarPluginExtension { + + private final ObjectFactory objects; + private final Map> patchModules; + + @Inject + public MultiReleaseJarPluginExtension(ObjectFactory objects) { + this.objects = objects; + patchModules = new HashMap<>(); + } + + public void patchModule(String moduleName, Provider path) { + this.patchModules + .computeIfAbsent(moduleName, key -> objects.listProperty(String.class) + .convention(new ArrayList<>())) + .add(path); + } + + public Map> getPatchModules() { + return patchModules; + } +}