From 1269a860bb5644d49db044facf68b56c03f7788d Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Mon, 13 Mar 2023 00:23:41 +0100 Subject: [PATCH] Remove plugin-init.groovy in resources and compile the plugin code with groovyc (#221) --- build.xml | 18 +++- ivy.xml | 7 +- .../gradle/ForbiddenApisPlugin.groovy | 93 +++++++++++++++++++ .../gradle/CheckForbiddenApisExtension.java | 2 +- ...ugin.java => ForbiddenApisPluginBase.java} | 72 +------------- .../forbiddenapis/gradle/plugin-init.groovy | 77 --------------- 6 files changed, 118 insertions(+), 151 deletions(-) create mode 100644 src/main/groovy/de/thetaphi/forbiddenapis/gradle/ForbiddenApisPlugin.groovy rename src/main/java/de/thetaphi/forbiddenapis/gradle/{ForbiddenApisPlugin.java => ForbiddenApisPluginBase.java} (52%) delete mode 100644 src/main/resources/de/thetaphi/forbiddenapis/gradle/plugin-init.groovy diff --git a/build.xml b/build.xml index 20f7368..251b38e 100644 --- a/build.xml +++ b/build.xml @@ -220,7 +220,13 @@ - + + + + + + + @@ -255,6 +261,7 @@ + @@ -282,8 +289,15 @@ - + + + + + + + diff --git a/ivy.xml b/ivy.xml index 054485f..435c349 100644 --- a/ivy.xml +++ b/ivy.xml @@ -22,8 +22,9 @@ ]> - + + @@ -35,10 +36,10 @@ - + - + diff --git a/src/main/groovy/de/thetaphi/forbiddenapis/gradle/ForbiddenApisPlugin.groovy b/src/main/groovy/de/thetaphi/forbiddenapis/gradle/ForbiddenApisPlugin.groovy new file mode 100644 index 0000000..abc8185 --- /dev/null +++ b/src/main/groovy/de/thetaphi/forbiddenapis/gradle/ForbiddenApisPlugin.groovy @@ -0,0 +1,93 @@ +/* + * (C) Copyright Uwe Schindler (Generics Policeman) and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.thetaphi.forbiddenapis.gradle; + +import org.gradle.api.GradleException; +import org.gradle.api.Project; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.plugins.JavaBasePlugin; +import org.gradle.util.GradleVersion; + +/** + * Forbiddenapis Gradle Plugin (requires at least Gradle v3.2) + * @since 2.0 + */ +public class ForbiddenApisPlugin extends ForbiddenApisPluginBase { + + @Override + public void apply(Project project) { + if (GradleVersion.current().compareTo(MIN_GRADLE_VERSION) < 0) { + throw new GradleException("Forbiddenapis plugin requires at least " + MIN_GRADLE_VERSION + ", running version is " + GradleVersion.current()); + } + + project.plugins.apply(JavaBasePlugin.class); + + // create Extension for defaults: + def extension = project.extensions.create(FORBIDDEN_APIS_EXTENSION_NAME, CheckForbiddenApisExtension.class, project); + + // Create a convenience task for all checks (this does not conflict with extension, as it has higher priority in DSL): + def forbiddenTask = TASK_AVOIDANCE_AVAILABLE ? project.tasks.register(FORBIDDEN_APIS_TASK_NAME) : project.tasks.create(FORBIDDEN_APIS_TASK_NAME) + forbiddenTask.configure { + description = "Runs forbidden-apis checks."; + group = JavaBasePlugin.VERIFICATION_GROUP; + } + + // Gradle is buggy with it's JavaVersion enum: We use majorVersion property before Java 11 (6,7,8,9,10) and for later we use toString() to be future-proof: + Closure targetCompatibilityGetter = { (project.targetCompatibility?.hasProperty('java11Compatible') && project.targetCompatibility?.java11Compatible) ? + project.targetCompatibility.toString() : project.targetCompatibility?.majorVersion }; + + // Define our tasks (one for each SourceSet): + project.sourceSets.all{ sourceSet -> + String sourceSetTaskName = sourceSet.getTaskName(FORBIDDEN_APIS_TASK_NAME, null); + def sourceSetTask = TASK_AVOIDANCE_AVAILABLE ? project.tasks.register(sourceSetTaskName, CheckForbiddenApis.class) : + project.tasks.create(sourceSetTaskName, CheckForbiddenApis.class); + def templateClassesDirs = project.files(); + def templateClasspath = project.files(); + sourceSetTask.configure { + description = "Runs forbidden-apis checks on '${sourceSet.name}' classes."; + dependsOn(sourceSet.output); + outputs.upToDateWhen { true } + def taskData = internalTaskData() + conventionMapping.with{ + FORBIDDEN_APIS_EXTENSION_PROPS.each{ key -> + map(key, { + def item = taskData[key] + if (item instanceof ConfigurableFileCollection) { + return item.from(extension[key]) + } else if (item instanceof Collection) { + item.addAll(extension[key]) + return item + } + return extension[key] + }) + } + classesDirs = { templateClassesDirs.from(sourceSet.output.hasProperty('classesDirs') ? sourceSet.output.classesDirs : sourceSet.output.classesDir) } + classpath = { templateClasspath.from(sourceSet.compileClasspath) } + targetCompatibility = targetCompatibilityGetter + } + } + forbiddenTask.configure { + dependsOn(sourceSetTask) + } + } + + // Add our task as dependency to chain + def checkTask = TASK_AVOIDANCE_AVAILABLE ? project.tasks.named(JavaBasePlugin.CHECK_TASK_NAME) : project.tasks.getByName(JavaBasePlugin.CHECK_TASK_NAME); + checkTask.configure { it.dependsOn(forbiddenTask) }; + } + +} diff --git a/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApisExtension.java b/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApisExtension.java index 775fbe8..6b92fa3 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApisExtension.java +++ b/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApisExtension.java @@ -47,6 +47,6 @@ public CheckForbiddenApisExtension(Project project) { failOnUnresolvableSignatures = true, ignoreFailures = false, ignoreSignaturesOfMissingClasses = false, - disableClassloadingCache = ForbiddenApisPlugin.DEFAULT_DISABLE_CLASSLOADING_CACHE; + disableClassloadingCache = ForbiddenApisPluginBase.DEFAULT_DISABLE_CLASSLOADING_CACHE; } diff --git a/src/main/java/de/thetaphi/forbiddenapis/gradle/ForbiddenApisPlugin.java b/src/main/java/de/thetaphi/forbiddenapis/gradle/ForbiddenApisPluginBase.java similarity index 52% rename from src/main/java/de/thetaphi/forbiddenapis/gradle/ForbiddenApisPlugin.java rename to src/main/java/de/thetaphi/forbiddenapis/gradle/ForbiddenApisPluginBase.java index f2bee43..b3ea476 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/gradle/ForbiddenApisPlugin.java +++ b/src/main/java/de/thetaphi/forbiddenapis/gradle/ForbiddenApisPluginBase.java @@ -16,36 +16,21 @@ package de.thetaphi.forbiddenapis.gradle; -import groovy.lang.GroovyClassLoader; -import groovy.lang.GroovyCodeSource; -import groovy.util.DelegatingScript; - import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.codehaus.groovy.control.CompilerConfiguration; -import org.codehaus.groovy.control.customizers.ImportCustomizer; -import org.gradle.api.GradleException; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; import org.gradle.util.GradleVersion; -/** - * Forbiddenapis Gradle Plugin (requires at least Gradle v3.2) - * @since 2.0 - */ -public class ForbiddenApisPlugin implements Plugin { +abstract class ForbiddenApisPluginBase implements Plugin { - private static final Logger LOG = Logging.getLogger(ForbiddenApisPlugin.class); + private static final Logger LOG = Logging.getLogger(ForbiddenApisPluginBase.class); /** Name of the base task that depends on one for every SourceSet. */ public static final String FORBIDDEN_APIS_TASK_NAME = "forbiddenApis"; @@ -69,45 +54,12 @@ public class ForbiddenApisPlugin implements Plugin { /** True, if this version of Gradle supports task avoidance API (>=v4.9). */ public static final boolean TASK_AVOIDANCE_AVAILABLE = GradleVersion.current().compareTo(GradleVersion.version("4.9")) >= 0; - /** All properties that our ForbiddenApisExtension provides. Used by plugin init script to create convention mapping. */ - public static final List FORBIDDEN_APIS_EXTENSION_PROPS = determineExtensionProps(); + /** All properties that our ForbiddenApisExtension provides. Used to create convention mapping. */ + protected static final List FORBIDDEN_APIS_EXTENSION_PROPS = determineExtensionProps(); /** Java Package that contains the Gradle Daemon (needed to detect it on startup). */ private static final String GRADLE_DAEMON_PACKAGE = "org.gradle.launcher.daemon."; - /** Resource with Groovy script that initializes the plugin. */ - private static final String PLUGIN_INIT_SCRIPT = "plugin-init.groovy"; - - /** Compiled class instance of the plugin init script, an instance is executed per {@link #apply(Project)} */ - private static final Class COMPILED_SCRIPT = loadScript(); - - private static Class loadScript() { - final ImportCustomizer importCustomizer = new ImportCustomizer().addStarImports(ForbiddenApisPlugin.class.getPackage().getName()); - final CompilerConfiguration configuration = new CompilerConfiguration().addCompilationCustomizers(importCustomizer); - configuration.setScriptBaseClass(DelegatingScript.class.getName()); - configuration.setSourceEncoding(StandardCharsets.UTF_8.name()); - final URL scriptUrl = ForbiddenApisPlugin.class.getResource(PLUGIN_INIT_SCRIPT); - if (scriptUrl == null) { - throw new RuntimeException("Cannot find resource with script: " + PLUGIN_INIT_SCRIPT); - } - return AccessController.doPrivileged(new PrivilegedAction>() { - @Override - public Class run() { - try { - // We don't close the classloader, as we may need it later when loading other classes from inside script: - @SuppressWarnings("resource") final GroovyClassLoader loader = - new GroovyClassLoader(ForbiddenApisPlugin.class.getClassLoader(), configuration); - final GroovyCodeSource csrc = new GroovyCodeSource(scriptUrl); - @SuppressWarnings("unchecked") final Class clazz = - loader.parseClass(csrc, false).asSubclass(DelegatingScript.class); - return clazz; - } catch (Exception e) { - throw new RuntimeException("Cannot compile Groovy script: " + PLUGIN_INIT_SCRIPT, e); - } - } - }); - } - private static List determineExtensionProps() { final List props = new ArrayList<>(); for (final Field f : CheckForbiddenApisExtension.class.getDeclaredFields()) { @@ -140,20 +92,4 @@ private static boolean detectAndLogGradleDaemon() { return daemon; } - @Override - public void apply(Project project) { - if (GradleVersion.current().compareTo(MIN_GRADLE_VERSION) < 0) { - throw new GradleException("Forbiddenapis plugin requires at least " + MIN_GRADLE_VERSION + ", running version is " + GradleVersion.current()); - } - final DelegatingScript script; - try { - script = COMPILED_SCRIPT.newInstance(); - } catch (Exception e) { - throw new GradleException("Cannot instantiate Groovy script to apply forbiddenapis plugin.", e); - } - script.setDelegate(this); - script.setProperty("project", project); - script.run(); - } - } diff --git a/src/main/resources/de/thetaphi/forbiddenapis/gradle/plugin-init.groovy b/src/main/resources/de/thetaphi/forbiddenapis/gradle/plugin-init.groovy deleted file mode 100644 index 0c54635..0000000 --- a/src/main/resources/de/thetaphi/forbiddenapis/gradle/plugin-init.groovy +++ /dev/null @@ -1,77 +0,0 @@ -/* - * (C) Copyright Uwe Schindler (Generics Policeman) and others. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** Initializes the plugin and binds it to project lifecycle. */ - -package de.thetaphi.forbiddenapis.gradle; - -import org.gradle.api.plugins.JavaBasePlugin; -import org.gradle.api.file.ConfigurableFileCollection; - -project.plugins.apply(JavaBasePlugin.class); - -// create Extension for defaults: -def extension = project.extensions.create(FORBIDDEN_APIS_EXTENSION_NAME, CheckForbiddenApisExtension.class, project); - -// Create a convenience task for all checks (this does not conflict with extension, as it has higher priority in DSL): -def forbiddenTask = TASK_AVOIDANCE_AVAILABLE ? project.tasks.register(FORBIDDEN_APIS_TASK_NAME) : project.tasks.create(FORBIDDEN_APIS_TASK_NAME) -forbiddenTask.configure { - description = "Runs forbidden-apis checks."; - group = JavaBasePlugin.VERIFICATION_GROUP; -} - -// Gradle is buggy with it's JavaVersion enum: We use majorVersion property before Java 11 (6,7,8,9,10) and for later we use toString() to be future-proof: -Closure targetCompatibilityGetter = { (project.targetCompatibility?.hasProperty('java11Compatible') && project.targetCompatibility?.java11Compatible) ? - project.targetCompatibility.toString() : project.targetCompatibility?.majorVersion }; - -// Define our tasks (one for each SourceSet): -project.sourceSets.all{ sourceSet -> - String sourceSetTaskName = sourceSet.getTaskName(FORBIDDEN_APIS_TASK_NAME, null); - def sourceSetTask = TASK_AVOIDANCE_AVAILABLE ? project.tasks.register(sourceSetTaskName, CheckForbiddenApis.class) : - project.tasks.create(sourceSetTaskName, CheckForbiddenApis.class); - def templateClassesDirs = project.files(); - def templateClasspath = project.files(); - sourceSetTask.configure { - description = "Runs forbidden-apis checks on '${sourceSet.name}' classes."; - dependsOn(sourceSet.output); - outputs.upToDateWhen { true } - def taskData = internalTaskData() - conventionMapping.with{ - FORBIDDEN_APIS_EXTENSION_PROPS.each{ key -> - map(key, { - def item = taskData[key] - if (item instanceof ConfigurableFileCollection) { - return item.from(extension[key]) - } else if (item instanceof Collection) { - item.addAll(extension[key]) - return item - } - return extension[key] - }) - } - classesDirs = { templateClassesDirs.from(sourceSet.output.hasProperty('classesDirs') ? sourceSet.output.classesDirs : sourceSet.output.classesDir) } - classpath = { templateClasspath.from(sourceSet.compileClasspath) } - targetCompatibility = targetCompatibilityGetter - } - } - forbiddenTask.configure { - dependsOn(sourceSetTask) - } -} - -// Add our task as dependency to chain -def checkTask = TASK_AVOIDANCE_AVAILABLE ? project.tasks.named(JavaBasePlugin.CHECK_TASK_NAME) : project.tasks.getByName(JavaBasePlugin.CHECK_TASK_NAME); -checkTask.configure { it.dependsOn(forbiddenTask) };