From 6f7ddc42cef704fb7b01cece7305cbb26e99f00b Mon Sep 17 00:00:00 2001 From: Walter Oggioni Date: Mon, 9 Nov 2020 09:14:15 +0100 Subject: [PATCH] added multi-release-jar plugin --- build.gradle.kts | 7 +- dependency-export/build.gradle.kts | 32 +++++++- jpms-check/build.gradle.kts | 14 ++-- .../plugins/jpms/check/JPMSCheckPlugin.groovy | 31 +++++--- multi-release-jar/build.gradle.kts | 23 ++++++ .../release/jar/MultiReleaseJarPlugin.groovy | 75 ++++++++++++++++++ .../release/jar/MultiVersionJarPlugin.groovy | 79 +++++++++++++++++++ settings.gradle.kts | 17 ++-- 8 files changed, 240 insertions(+), 38 deletions(-) create mode 100644 multi-release-jar/build.gradle.kts create mode 100644 multi-release-jar/src/main/groovy/net/woggioni/plugins/multi/release/jar/MultiReleaseJarPlugin.groovy create mode 100644 multi-release-jar/src/main/groovy/net/woggioni/plugins/multi/release/jar/MultiVersionJarPlugin.groovy diff --git a/build.gradle.kts b/build.gradle.kts index 6b0e06c..412c6b1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,3 @@ -plugins { - id("org.jetbrains.kotlin.jvm") version "1.3.72" apply false - id("com.gradle.plugin-publish") version "0.10.1" apply false -} - allprojects { apply() repositories { @@ -25,7 +20,7 @@ allprojects { } tasks.withType().configureEach { - gradleVersion = "6.6" + gradleVersion = "6.7" distributionType = Wrapper.DistributionType.ALL } diff --git a/dependency-export/build.gradle.kts b/dependency-export/build.gradle.kts index e8c96cb..cd79cdf 100644 --- a/dependency-export/build.gradle.kts +++ b/dependency-export/build.gradle.kts @@ -13,9 +13,33 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") } -gradlePlugin { - val dependencyExportPlugin by plugins.creating { - id = "net.woggioni.plugins.dependency-export" - implementationClass = "net.woggioni.plugins.dependency.export.DependencyExportPlugin" +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +arrayOf("apiElements", "runtimeElements").forEach { name : String -> + val conf = project.configurations.getByName(name) + conf.attributes { + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8) } } + + +gradlePlugin { + plugins { + create("DependencyExportPlugin") { + id = "net.woggioni.plugins.dependency-export" + implementationClass = "net.woggioni.plugins.dependency.export.DependencyExportPlugin" + } + } +} + +tasks.withType().configureEach { + kotlinOptions { + languageVersion = "1.3" + apiVersion = "1.3" + jvmTarget = "1.8" + javaParameters = true // Useful for reflection. + } +} \ No newline at end of file diff --git a/jpms-check/build.gradle.kts b/jpms-check/build.gradle.kts index 84badd5..7eb6714 100644 --- a/jpms-check/build.gradle.kts +++ b/jpms-check/build.gradle.kts @@ -1,16 +1,14 @@ plugins { - `java-gradle-plugin` `maven-publish` - groovy + `groovy-gradle-plugin` id("com.gradle.plugin-publish") } -dependencies { -} - gradlePlugin { - val dependencyExportPlugin by plugins.creating { - id = "net.woggioni.plugins.jpms-check" - implementationClass = "net.woggioni.plugins.jpms.check.JPMSCheckPlugin" + plugins { + create("JPMSCheckPlugin") { + id = "net.woggioni.plugins.jpms-check" + implementationClass = "net.woggioni.plugins.jpms.check.JPMSCheckPlugin" + } } } \ No newline at end of file diff --git a/jpms-check/src/main/groovy/net/woggioni/plugins/jpms/check/JPMSCheckPlugin.groovy b/jpms-check/src/main/groovy/net/woggioni/plugins/jpms/check/JPMSCheckPlugin.groovy index 86e23e3..eea9dfd 100644 --- a/jpms-check/src/main/groovy/net/woggioni/plugins/jpms/check/JPMSCheckPlugin.groovy +++ b/jpms-check/src/main/groovy/net/woggioni/plugins/jpms/check/JPMSCheckPlugin.groovy @@ -2,6 +2,7 @@ package net.woggioni.plugins.jpms.check import groovy.json.JsonBuilder import groovy.transform.Canonical +import groovy.transform.CompileStatic import groovy.xml.MarkupBuilder import org.gradle.api.GradleException import org.gradle.api.Plugin @@ -20,6 +21,7 @@ import java.util.stream.Stream class JPMSCheckPlugin implements Plugin { @Canonical + @CompileStatic private class CheckResult { ResolvedArtifactResult dep String automaticModuleName @@ -34,10 +36,10 @@ class JPMSCheckPlugin implements Plugin { boolean equals(Object other) { if(other == null) { return false - } else if(other.class != CheckResult.class) { - return false + } else if(other.class == CheckResult.class) { + return dep?.id?.componentIdentifier == ((CheckResult) other).dep?.id?.componentIdentifier } else { - return dep?.id?.componentIdentifier == other.dep?.id?.componentIdentifier + return false } } @@ -47,10 +49,11 @@ class JPMSCheckPlugin implements Plugin { } } + @CompileStatic private Stream computeResults(Stream artifacts) { return artifacts.filter { ResolvedArtifactResult res -> res.file.exists() && res.file.name.endsWith(".jar") - }.map { resolvedArtifact -> + }.map { resolvedArtifact -> JarFile jarFile = new JarFile(resolvedArtifact.file).with { if (it.isMultiRelease()) { new JarFile( @@ -85,7 +88,8 @@ class JPMSCheckPlugin implements Plugin { builder.html { head { meta name: "viewport", content: "width=device-width, initial-scale=1" - getClass().classLoader.getResourceAsStream('net/woggioni/plugins/jpms/check/github-markdown.css').withReader { Reader reader -> + InputStream resourceStream = getClass().classLoader.getResourceAsStream('net/woggioni/plugins/jpms/check/github-markdown.css') + resourceStream.withReader { Reader reader -> style reader.text } body { @@ -151,6 +155,7 @@ class JPMSCheckPlugin implements Plugin { } @Override + @CompileStatic void apply(Project project) { project.tasks.register("jpms-check") {task -> boolean recursive = project.properties["jpms-check.recursive"]?.with(Boolean.&parseBoolean) ?: false @@ -170,23 +175,27 @@ class JPMSCheckPlugin implements Plugin { throw new IllegalArgumentException("Unsupported output format: $outputFormat") } } - doLast { - Set results = (recursive ? project.subprojects.stream() : Stream.of(project)).flatMap { - Configuration requestedConfiguration = project.configurations.find { Configuration cfg -> + task.doLast { + Stream projects = Stream.of(project) + if(recursive) { + projects = Stream.concat(projects, project.subprojects.stream()) + } + Set results = projects.flatMap { + Configuration requestedConfiguration = (project.configurations.find { Configuration cfg -> cfg.canBeResolved && cfg.name == cfgName - } ?: ({ + } ?: { def resolvableConfigurations = "[" + project.configurations .grep { Configuration cfg -> cfg.canBeResolved } .collect { "'${it.name}'" } .join(",") + "]" throw new GradleException("Configuration '$cfgName' doesn't exist or cannot be resolved, " + "resolvable configurations in this project are " + resolvableConfigurations) - } as Configuration) + }) as Configuration computeResults(requestedConfiguration.incoming.artifacts.artifacts.stream()) }.collect(Collectors.toSet()) Files.createDirectories(outputFile.parent) Files.newBufferedWriter(outputFile).withWriter { - Stream resultStream = results.stream().sorted(Comparator.comparing { CheckResult res -> + Stream resultStream = results.stream().sorted(Comparator.comparing { CheckResult res -> res.dep.id.componentIdentifier.displayName }) switch(outputFormat) { diff --git a/multi-release-jar/build.gradle.kts b/multi-release-jar/build.gradle.kts new file mode 100644 index 0000000..4ec348c --- /dev/null +++ b/multi-release-jar/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + `maven-publish` + `groovy-gradle-plugin` + id("com.gradle.plugin-publish") +} + +gradlePlugin { + plugins { + create("MultiVersionJarPlugin") { + id = "net.woggioni.plugins.multi-version-jar" + implementationClass = "net.woggioni.plugins.multi.release.jar.MultiVersionJarPlugin" + } + create("MultiReleaseJarPlugin") { + id = "net.woggioni.plugins.multi-release-jar" + implementationClass = "net.woggioni.plugins.multi.release.jar.MultiReleaseJarPlugin" + } + } +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} diff --git a/multi-release-jar/src/main/groovy/net/woggioni/plugins/multi/release/jar/MultiReleaseJarPlugin.groovy b/multi-release-jar/src/main/groovy/net/woggioni/plugins/multi/release/jar/MultiReleaseJarPlugin.groovy new file mode 100644 index 0000000..cb716f9 --- /dev/null +++ b/multi-release-jar/src/main/groovy/net/woggioni/plugins/multi/release/jar/MultiReleaseJarPlugin.groovy @@ -0,0 +1,75 @@ +package net.woggioni.plugins.multi.release.jar + +import org.gradle.api.JavaVersion +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.attributes.java.TargetJvmVersion +import org.gradle.api.file.FileCollection +import org.gradle.api.file.SourceDirectorySet +import org.gradle.api.plugins.Convention +import org.gradle.api.plugins.JavaBasePlugin +import org.gradle.api.plugins.JavaPluginConvention +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.TaskProvider +import org.gradle.api.tasks.compile.JavaCompile +import org.gradle.internal.impldep.org.apache.commons.compress.compressors.z.ZCompressorInputStream +import org.gradle.jvm.tasks.Jar + +class MultiReleaseJarPlugin implements Plugin { + @Override + void apply(Project project) { + project.pluginManager.apply(JavaBasePlugin) + if(JavaVersion.current() > JavaVersion.VERSION_1_8) { + SourceSet mainSourceSet = (project.sourceSets.main as SourceSet) + JavaCompile compileJavaTask = project.tasks.named("compileJava", JavaCompile).get() + compileJavaTask.configure { + options.release.set(JavaVersion.VERSION_1_8.majorVersion.toInteger()) + } + Jar jarTask = project.tasks.named("jar", Jar).get() + jarTask.configure { + manifest.attributes('Multi-Release': 'true') + } + ArrayList compileOutputs = new ArrayList<>() + compileOutputs << compileJavaTask.outputs.files + ArrayList sourcePaths = new ArrayList<>() + sourcePaths << mainSourceSet.java.sourceDirectories + Arrays.stream(JavaVersion.values()).filter { + it > JavaVersion.VERSION_1_8 && it <= JavaVersion.current() + }.forEach {javaVersion -> + SourceDirectorySet sourceDirectorySet = + project.objects.sourceDirectorySet("java${javaVersion.majorVersion}", javaVersion.toString()) + sourceDirectorySet.with { + srcDir(new File(project.projectDir, "src/main/${sourceDirectorySet.name}")) + destinationDirectory.set(new File(project.buildDir, "classes/${sourceDirectorySet.name}")) + sourcePaths << sourceDirectories + } + TaskProvider compileTask = project.tasks.register("compileJava${javaVersion.majorVersion}", JavaCompile, { + options.release.set(javaVersion.majorVersion.toInteger()) + classpath = compileOutputs.stream().reduce { fc1, fc2 -> fc1 + fc2 }.get() + it.doFirst { + options.compilerArgs << "--module-path" << mainSourceSet.compileClasspath.asPath + } + source = sourceDirectorySet + destinationDirectory.set(sourceDirectorySet.destinationDirectory) + options.annotationProcessorPath = mainSourceSet.annotationProcessorPath + modularity.inferModulePath = false + options.sourcepath = sourcePaths.stream().reduce { fc1, fc2 -> fc1 + fc2 }.get() + }) + compileOutputs << compileJavaTask.outputs.files + sourceDirectorySet.compiledBy(compileTask, { it.getDestinationDirectory()}) + jarTask.configure { Jar it -> + from(compileTask.get().outputs.files) { + into("META-INF/versions/${javaVersion.majorVersion}") + } + } + } + ["apiElements", "runtimeElements"].forEach {String name -> + Configuration conf = project.configurations.getByName(name) + conf.attributes { + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, compileJavaTask.options.release.get()) + } + } + } + } +} diff --git a/multi-release-jar/src/main/groovy/net/woggioni/plugins/multi/release/jar/MultiVersionJarPlugin.groovy b/multi-release-jar/src/main/groovy/net/woggioni/plugins/multi/release/jar/MultiVersionJarPlugin.groovy new file mode 100644 index 0000000..d8fb926 --- /dev/null +++ b/multi-release-jar/src/main/groovy/net/woggioni/plugins/multi/release/jar/MultiVersionJarPlugin.groovy @@ -0,0 +1,79 @@ +package net.woggioni.plugins.multi.release.jar + +import org.gradle.api.JavaVersion +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.attributes.java.TargetJvmVersion +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.file.SourceDirectorySet +import org.gradle.api.plugins.JavaBasePlugin +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.compile.JavaCompile +import org.gradle.jvm.tasks.Jar + +class MultiVersionJarPlugin implements Plugin { + + @Override + void apply(Project project) { + project.apply(to: JavaBasePlugin) + if(JavaVersion.current() > JavaVersion.VERSION_1_8) { + SourceSet mainSourceSet = (project.sourceSets.main as SourceSet) + SourceDirectorySet javaSet = mainSourceSet.java + File java8ClassesDir = project.buildDir.toPath().resolve("classes/java8").toFile() + File java11ClassesDir = project.buildDir.toPath().resolve("classes/java11").toFile() + JavaCompile compileJava8Task = project.tasks.register("compileJava8", JavaCompile, { + exclude("module-info.java") + options.release = JavaVersion.VERSION_1_8.majorVersion.toInteger() + classpath = mainSourceSet.compileClasspath + source = javaSet + destinationDirectory = java8ClassesDir + options.annotationProcessorPath = mainSourceSet.annotationProcessorPath + modularity.inferModulePath = false + }).get() + + JavaCompile compileModuleInfoTask = project.tasks.register("compileModuleInfo", JavaCompile, { + include("module-info.java") + options.release = JavaVersion.VERSION_11.majorVersion.toInteger() + classpath = mainSourceSet.compileClasspath + source = (project.sourceSets.main as SourceSet).java + destinationDirectory = java11ClassesDir + options.annotationProcessorPath = mainSourceSet.annotationProcessorPath + modularity.inferModulePath = true + }).get() + + Provider jarTaskProvider = project.tasks.named("jar", Jar) + Provider multiVersionJarTaskProvider = project.tasks.register("multiVersionJar", Jar) { + Jar jarTask = jarTaskProvider.get() + from(compileJava8Task.outputs.files) + from(compileModuleInfoTask.outputs.files) + archiveBaseName = jarTask.archiveBaseName + destinationDirectory = jarTask.destinationDirectory + archiveExtension = jarTask.archiveExtension + manifest = jarTask.manifest + } + + jarTaskProvider.configure { + actions = [] + Jar multiVersionJarTask = multiVersionJarTaskProvider.get() + from(multiVersionJarTask.outputs.files) + (it.archiveFile as RegularFileProperty).set(multiVersionJarTask.archiveFile) + } + ["apiElements", "runtimeElements"].forEach {String name -> + Configuration conf = project.configurations.getByName(name) + conf.attributes { + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8) + } + } + } + project.tasks.named("compileJava", JavaCompile) { + if(JavaVersion.current() > JavaVersion.VERSION_1_8) { + modularity.inferModulePath = true + } else { + exclude("module-info.java") + } + } + + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 229ef12..c90f1b5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,12 +1,11 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user manual at https://docs.gradle.org/6.1.1/userguide/multi_project_builds.html - */ +pluginManagement { + plugins { + id("org.jetbrains.kotlin.jvm") version "1.3.72" apply false + id("com.gradle.plugin-publish") version "0.10.1" apply false + } +} rootProject.name = "my-gradle-plugins" include("dependency-export") -include("jpms-check") \ No newline at end of file +include("jpms-check") +include("multi-release-jar")