diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/CheckForbiddenApisTask.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/CheckForbiddenApisTask.java index e158dd7c755c..194d0361980e 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/CheckForbiddenApisTask.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/CheckForbiddenApisTask.java @@ -8,25 +8,568 @@ package org.elasticsearch.gradle.internal.precommit; -import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis; +import de.thetaphi.forbiddenapis.Checker; +import de.thetaphi.forbiddenapis.Constants; +import de.thetaphi.forbiddenapis.Logger; +import de.thetaphi.forbiddenapis.ParseException; +import groovy.lang.Closure; +import org.gradle.api.DefaultTask; +import org.gradle.api.GradleException; +import org.gradle.api.InvalidUserDataException; +import org.gradle.api.Transformer; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileTree; +import org.gradle.api.file.FileTreeElement; +import org.gradle.api.file.ProjectLayout; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.logging.Logging; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.SetProperty; +import org.gradle.api.specs.Spec; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.CompileClasspath; import org.gradle.api.tasks.IgnoreEmptyDirectories; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.api.tasks.SkipWhenEmpty; +import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.VerificationTask; +import org.gradle.api.tasks.util.PatternFilterable; +import org.gradle.api.tasks.util.PatternSet; +import org.gradle.workers.WorkAction; +import org.gradle.workers.WorkParameters; +import org.gradle.workers.WorkQueue; +import org.gradle.workers.WorkerExecutor; +import org.jetbrains.annotations.NotNull; -/** - * This implementation is used to fix gradle 8 compatibility of - * the CheckForbiddenApis task which is built with gradle 4 support - * in mind. - * */ -public class CheckForbiddenApisTask extends CheckForbiddenApis { +import java.io.File; +import java.io.IOException; +import java.lang.annotation.RetentionPolicy; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; + +import javax.inject.Inject; + +import static de.thetaphi.forbiddenapis.Checker.Option.DISABLE_CLASSLOADING_CACHE; +import static de.thetaphi.forbiddenapis.Checker.Option.FAIL_ON_MISSING_CLASSES; +import static de.thetaphi.forbiddenapis.Checker.Option.FAIL_ON_UNRESOLVABLE_SIGNATURES; +import static de.thetaphi.forbiddenapis.Checker.Option.FAIL_ON_VIOLATION; + +@CacheableTask +public abstract class CheckForbiddenApisTask extends DefaultTask implements PatternFilterable, VerificationTask, Constants { + + public static final Set BUNDLED_SIGNATURE_DEFAULTS = Set.of("jdk-unsafe", "jdk-non-portable", "jdk-system-out"); + + private static final String NL = System.getProperty("line.separator", "\n"); + private final PatternSet patternSet = new PatternSet().include("**/*.class"); + private FileCollection classesDirs; + private FileCollection classpath; + private String targetCompatibility; + + private FileCollection signaturesFiles; + + private final ObjectFactory objectFactory; + private ProjectLayout projectLayout; + + private List signatures = new ArrayList<>(); + + private File resourcesDir; + + private boolean ignoreFailures = false; + + @Input + @Optional + abstract SetProperty getBundledSignatures(); /** - * Add additional annotation to make this input gradle 8 compliant. - * Otherwise we see a deprecation warning here starting with gradle 7.4 - * */ - @Override - @IgnoreEmptyDirectories - public FileTree getClassFiles() { - return super.getClassFiles(); + * List of a custom Java annotations (full class names) that are used in the checked + * code to suppress errors. Those annotations must have at least + * {@link RetentionPolicy#CLASS}. They can be applied to classes, their methods, + * or fields. By default, {@code @de.thetaphi.forbiddenapis.SuppressForbidden} + * can always be used, but needs the {@code forbidden-apis.jar} file in classpath + * of compiled project, which may not be wanted. + * Instead of a full class name, a glob pattern may be used (e.g., + * {@code **.SuppressForbidden}). + */ + @Input + @Optional + abstract SetProperty getSuppressAnnotations(); + + @Inject + public CheckForbiddenApisTask(ObjectFactory factory, ProjectLayout projectLayout) { + signaturesFiles = factory.fileCollection(); + this.objectFactory = factory; + this.projectLayout = projectLayout; } + + @OutputFile + public File getSuccessMarker() { + return new File(projectLayout.getBuildDirectory().getAsFile().get(), "markers/" + this.getName()); + } + + /** + * Directories with the class files to check. + * Defaults to current sourseSet's output directory (Gradle 3) or output directories (Gradle 4.0+). + */ + @Internal + public FileCollection getClassesDirs() { + return classesDirs; + } + + /** @see #getClassesDirs() */ + public void setClassesDirs(FileCollection classesDirs) { + Objects.requireNonNull(classesDirs, "classesDirs"); + this.classesDirs = classesDirs; + } + + /** Returns the pattern set to match against class files in {@link #getClassesDirs()}. */ + @Internal + public PatternSet getPatternSet() { + return patternSet; + } + + /** @see #getPatternSet() */ + public void setPatternSet(PatternSet patternSet) { + patternSet.copyFrom(patternSet); + } + + /** + * A {@link FileCollection} used to configure the classpath. + * Defaults to current sourseSet's compile classpath. + */ + @CompileClasspath + public FileCollection getClasspath() { + return classpath; + } + + /** @see #getClasspath */ + public void setClasspath(FileCollection classpath) { + Objects.requireNonNull(classpath, "classpath"); + this.classpath = classpath; + } + + /** + * A {@link FileCollection} containing all files, which contain signatures and comments for forbidden API calls. + * The signatures are resolved against {@link #getClasspath()}. + */ + @InputFiles + @Optional + @PathSensitive(PathSensitivity.RELATIVE) + public FileCollection getSignaturesFiles() { + return signaturesFiles; + } + + @InputDirectory + @PathSensitive(PathSensitivity.RELATIVE) + public File getResourcesDir() { + return resourcesDir; + } + + public void setResourcesDir(File resourcesDir) { + this.resourcesDir = resourcesDir; + } + + /** @see #getSignaturesFiles */ + public void setSignaturesFiles(FileCollection signaturesFiles) { + this.signaturesFiles = signaturesFiles; + } + + public void modifyBundledSignatures(Transformer, Set> transformer) { + getBundledSignatures().set(transformer.transform(getBundledSignatures().get())); + } + + public void replaceSignatureFiles(String... signatureFiles) { + List resources = new ArrayList<>(signatureFiles.length); + for (Object name : signatureFiles) { + resources.add(new File(resourcesDir, "forbidden/" + name + ".txt")); + } + setSignaturesFiles(objectFactory.fileCollection().from(resources)); + } + + public void addSignatureFiles(String... signatureFiles) { + List resources = new ArrayList<>(signatureFiles.length); + for (Object name : signatureFiles) { + resources.add(new File(resourcesDir, "forbidden/" + name + ".txt")); + } + setSignaturesFiles(objectFactory.fileCollection().from(getSignaturesFiles()).from(resources)); + + } + + /** + * Gives multiple API signatures that are joined with newlines and + * parsed like a single {@link #getSignaturesFiles()}. + * The signatures are resolved against {@link #getClasspath()}. + */ + @Input + @Optional + public List getSignatures() { + return signatures; + } + + /** @see #getSignatures */ + public void setSignatures(List signatures) { + this.signatures = signatures; + } + + /** + * {@inheritDoc} + *

+ * This setting is to conform with {@link VerificationTask} interface. + * Default is {@code false}. + */ + @Override + @Input + public boolean getIgnoreFailures() { + return ignoreFailures; + } + + @Override + public void setIgnoreFailures(boolean ignoreFailures) { + this.ignoreFailures = ignoreFailures; + } + + /** + * The default compiler target version used to expand references to bundled JDK signatures. + * E.g., if you use "jdk-deprecated", it will expand to this version. + * This setting should be identical to the target version used in the compiler task. + * Defaults to {@code project.targetCompatibility}. + */ + @Input + @Optional + public String getTargetCompatibility() { + return targetCompatibility; + } + + /** @see #getTargetCompatibility */ + public void setTargetCompatibility(String targetCompatibility) { + this.targetCompatibility = targetCompatibility; + } + + // PatternFilterable implementation: + + /** + * {@inheritDoc} + *

+ * Set of patterns matching all class files to be parsed from the classesDirectory. + * Can be changed to e.g. exclude several files (using excludes). + * The default is a single include with pattern '**/*.class' + */ + @Override + @Internal + public Set getIncludes() { + return getPatternSet().getIncludes(); + } + + @Override + public CheckForbiddenApisTask setIncludes(Iterable includes) { + getPatternSet().setIncludes(includes); + return this; + } + + /** + * {@inheritDoc} + *

+ * Set of patterns matching class files to be excluded from checking. + */ + @Override + @Internal + public Set getExcludes() { + return getPatternSet().getExcludes(); + } + + @Override + public CheckForbiddenApisTask setExcludes(Iterable excludes) { + getPatternSet().setExcludes(excludes); + return this; + } + + @Override + public CheckForbiddenApisTask exclude(String... arg0) { + getPatternSet().exclude(arg0); + return this; + } + + @Override + public CheckForbiddenApisTask exclude(Iterable arg0) { + getPatternSet().exclude(arg0); + return this; + } + + @Override + public CheckForbiddenApisTask exclude(Spec arg0) { + getPatternSet().exclude(arg0); + return this; + } + + @Override + public CheckForbiddenApisTask exclude(@SuppressWarnings("rawtypes") Closure arg0) { + getPatternSet().exclude(arg0); + return this; + } + + @Override + public CheckForbiddenApisTask include(String... arg0) { + getPatternSet().include(arg0); + return this; + } + + @Override + public CheckForbiddenApisTask include(Iterable arg0) { + getPatternSet().include(arg0); + return this; + } + + @Override + public CheckForbiddenApisTask include(Spec arg0) { + getPatternSet().include(arg0); + return this; + } + + @Override + public CheckForbiddenApisTask include(@SuppressWarnings("rawtypes") Closure arg0) { + getPatternSet().include(arg0); + return this; + } + + /** Returns the classes to check. */ + @InputFiles + @SkipWhenEmpty + @IgnoreEmptyDirectories + @PathSensitive(PathSensitivity.RELATIVE) + public FileTree getClassFiles() { + return getClassesDirs().getAsFileTree().matching(getPatternSet()); + } + + @Inject + public abstract WorkerExecutor getWorkerExecutor(); + + /** Executes the forbidden apis task. */ + @TaskAction + public void checkForbidden() { + WorkQueue workQueue = getWorkerExecutor().noIsolation(); + workQueue.submit(ForbiddenApisCheckWorkAction.class, parameters -> { + parameters.getClasspath().setFrom(getClasspath()); + parameters.getClassDirectories().setFrom(getClassesDirs()); + parameters.getClassFiles().from(getClassFiles().getFiles()); + parameters.getSuppressAnnotations().set(getSuppressAnnotations()); + parameters.getBundledSignatures().set(getBundledSignatures()); + parameters.getSignatures().set(getSignatures()); + parameters.getTargetCompatibility().set(getTargetCompatibility()); + parameters.getIgnoreFailures().set(getIgnoreFailures()); + parameters.getSuccessMarker().set(getSuccessMarker()); + }); + } + + abstract static class ForbiddenApisCheckWorkAction implements WorkAction { + + private final org.gradle.api.logging.Logger logger = Logging.getLogger(getClass()); + + @Inject + public ForbiddenApisCheckWorkAction() {} + + private boolean checkIsUnsupportedJDK(Checker checker) { + if (checker.isSupportedJDK == false) { + final String msg = String.format( + Locale.ENGLISH, + "Your Java runtime (%s %s) is not supported by the forbiddenapis plugin. Please run the checks with a supported JDK!", + System.getProperty("java.runtime.name"), + System.getProperty("java.runtime.version") + ); + logger.warn(msg); + return true; + } + return false; + } + + @Override + public void execute() { + + final URLClassLoader urlLoader = createClassLoader(getParameters().getClasspath(), getParameters().getClassDirectories()); + try { + final Checker checker = createChecker(urlLoader); + if (checkIsUnsupportedJDK(checker)) { + return; + } + + final Set suppressAnnotations = getParameters().getSuppressAnnotations().get(); + for (String a : suppressAnnotations) { + checker.addSuppressAnnotation(a); + } + + try { + final Set bundledSignatures = getParameters().getBundledSignatures().get(); + if (bundledSignatures.isEmpty() == false) { + final String bundledSigsJavaVersion = getParameters().getTargetCompatibility().get(); + if (bundledSigsJavaVersion == null) { + logger.warn( + "The 'targetCompatibility' project or task property is missing. " + + "Trying to read bundled JDK signatures without compiler target. " + + "You have to explicitly specify the version in the resource name." + ); + } + for (String bs : bundledSignatures) { + checker.addBundledSignatures(bs, bundledSigsJavaVersion); + } + } + + final FileCollection signaturesFiles = getParameters().getSignaturesFiles(); + if (signaturesFiles != null) for (final File f : signaturesFiles) { + checker.parseSignaturesFile(f); + } + final List signatures = getParameters().getSignatures().get(); + if ((signatures != null) && !signatures.isEmpty()) { + final StringBuilder sb = new StringBuilder(); + for (String line : signatures) { + sb.append(line).append(NL); + } + checker.parseSignaturesString(sb.toString()); + } + } catch (IOException ioe) { + throw new GradleException("IO problem while reading files with API signatures.", ioe); + } catch (ParseException pe) { + throw new InvalidUserDataException("Parsing signatures failed: " + pe.getMessage(), pe); + } + + if (checker.hasNoSignatures()) { + if (checker.noSignaturesFilesParsed()) { + throw new InvalidUserDataException( + "No signatures were added to task; use properties 'signatures', 'bundledSignatures', 'signaturesURLs', and/or 'signaturesFiles' to define those!" + ); + } else { + logger.info("Skipping execution because no API signatures are available."); + return; + } + } + + try { + checker.addClassesToCheck(getParameters().getClassFiles()); + } catch (IOException ioe) { + throw new GradleException("Failed to load one of the given class files.", ioe); + } + checker.run(); + writeMarker(getParameters().getSuccessMarker().getAsFile().get()); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + // Close the classloader to free resources: + try { + if (urlLoader != null) urlLoader.close(); + } catch (IOException ioe) { + // getLogger().warn("Cannot close classloader: ".concat(ioe.toString())); + } + } + } + + private void writeMarker(File successMarker) throws IOException { + Files.write(successMarker.toPath(), new byte[] {}, StandardOpenOption.CREATE); + } + + private URLClassLoader createClassLoader(FileCollection classpath, FileCollection classesDirs) { + if (classesDirs == null || classpath == null) { + throw new InvalidUserDataException("Missing 'classesDirs' or 'classpath' property."); + } + + final Set cpElements = new LinkedHashSet<>(); + cpElements.addAll(classpath.getFiles()); + cpElements.addAll(classesDirs.getFiles()); + final URL[] urls = new URL[cpElements.size()]; + try { + int i = 0; + for (final File cpElement : cpElements) { + urls[i++] = cpElement.toURI().toURL(); + } + assert i == urls.length; + } catch (MalformedURLException mfue) { + throw new InvalidUserDataException("Failed to build classpath URLs.", mfue); + } + + return URLClassLoader.newInstance(urls, ClassLoader.getSystemClassLoader()); + } + + @NotNull + private Checker createChecker(URLClassLoader urlLoader) { + final EnumSet options = EnumSet.noneOf(Checker.Option.class); + options.add(FAIL_ON_MISSING_CLASSES); + if (getParameters().getIgnoreFailures().get() == false) { + options.add(FAIL_ON_VIOLATION); + } + options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES); + options.add(DISABLE_CLASSLOADING_CACHE); + final Checker checker = new Checker(new GradleForbiddenApiLogger(logger), urlLoader, options); + return checker; + } + + private static class GradleForbiddenApiLogger implements Logger { + + private final org.gradle.api.logging.Logger delegate; + + GradleForbiddenApiLogger(org.gradle.api.logging.Logger delegate) { + this.delegate = delegate; + } + + @Override + public void error(String msg) { + delegate.error(msg); + } + + @Override + public void warn(String msg) { + delegate.warn(msg); + } + + @Override + public void info(String msg) { + delegate.info(msg); + } + + @Override + public void debug(String msg) { + delegate.debug(msg); + } + }; + } + + interface Parameters extends WorkParameters { + ConfigurableFileCollection getClassDirectories(); + + ConfigurableFileCollection getClassFiles(); + + ConfigurableFileCollection getClasspath(); + + SetProperty getSuppressAnnotations(); + + RegularFileProperty getSuccessMarker(); + + ConfigurableFileCollection getSignaturesFiles(); + + SetProperty getBundledSignatures(); + + Property getTargetCompatibility(); + + Property getIgnoreFailures(); + + ListProperty getSignatures(); + + } + } diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/DependencyLicensesTask.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/DependencyLicensesTask.java index 71de2626d5fc..092230a2b12e 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/DependencyLicensesTask.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/DependencyLicensesTask.java @@ -88,8 +88,6 @@ public class DependencyLicensesTask extends DefaultTask { private final Logger logger = Logging.getLogger(getClass()); - private static final String SHA_EXTENSION = ".sha1"; - // TODO: we should be able to default this to eg compile deps, but we need to move the licenses // check from distribution to core (ie this should only be run on java projects) /** diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/ForbiddenApisPrecommitPlugin.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/ForbiddenApisPrecommitPlugin.java index 96fb11214902..e24dd5ab2094 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/ForbiddenApisPrecommitPlugin.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/ForbiddenApisPrecommitPlugin.java @@ -8,50 +8,37 @@ package org.elasticsearch.gradle.internal.precommit; -import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApisExtension; -import groovy.lang.Closure; - import org.elasticsearch.gradle.internal.ExportElasticsearchBuildResourcesTask; import org.elasticsearch.gradle.internal.conventions.precommit.PrecommitPlugin; import org.elasticsearch.gradle.internal.info.BuildParams; import org.gradle.api.Project; import org.gradle.api.Task; -import org.gradle.api.plugins.ExtraPropertiesExtension; import org.gradle.api.plugins.JavaBasePlugin; -import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.specs.Specs; import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.TaskProvider; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; +import java.io.File; import java.util.Set; -import static de.thetaphi.forbiddenapis.gradle.ForbiddenApisPlugin.FORBIDDEN_APIS_EXTENSION_NAME; import static de.thetaphi.forbiddenapis.gradle.ForbiddenApisPlugin.FORBIDDEN_APIS_TASK_NAME; +import static org.elasticsearch.gradle.internal.precommit.CheckForbiddenApisTask.BUNDLED_SIGNATURE_DEFAULTS; public class ForbiddenApisPrecommitPlugin extends PrecommitPlugin { + @Override public TaskProvider createTask(Project project) { project.getPluginManager().apply(JavaBasePlugin.class); - // create Extension for defaults: - var checkForbiddenApisExtension = project.getExtensions() - .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): var forbiddenTask = project.getTasks() .register(FORBIDDEN_APIS_TASK_NAME, task -> { task.setDescription("Runs forbidden-apis checks."); }); - JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class); - // Define our tasks (one for each SourceSet): - TaskProvider resourcesTask = project.getTasks() .register("forbiddenApisResources", ExportElasticsearchBuildResourcesTask.class); - Path resourcesDir = project.getBuildDir().toPath().resolve("forbidden-apis-config"); + File resourcesDir = project.getLayout().getBuildDirectory().dir("forbidden-apis-config").get().getAsFile(); resourcesTask.configure(t -> { - t.setOutputDir(resourcesDir.toFile()); + t.setOutputDir(resourcesDir); t.copy("forbidden/jdk-signatures.txt"); t.copy("forbidden/jdk-deprecated.txt"); t.copy("forbidden/es-all-signatures.txt"); @@ -65,60 +52,36 @@ public class ForbiddenApisPrecommitPlugin extends PrecommitPlugin { String sourceSetTaskName = sourceSet.getTaskName(FORBIDDEN_APIS_TASK_NAME, null); var sourceSetTask = project.getTasks().register(sourceSetTaskName, CheckForbiddenApisTask.class, t -> { t.setDescription("Runs forbidden-apis checks on '${sourceSet.name}' classes."); + t.setResourcesDir(resourcesDir); t.getOutputs().upToDateWhen(Specs.SATISFIES_ALL); t.setClassesDirs(sourceSet.getOutput().getClassesDirs()); t.dependsOn(resourcesTask); - t.setClasspath(sourceSet.getRuntimeClasspath().plus(sourceSet.getCompileClasspath()).plus(sourceSet.getOutput())); + t.setClasspath(sourceSet.getRuntimeClasspath().plus(sourceSet.getCompileClasspath())); t.setTargetCompatibility(BuildParams.getMinimumRuntimeVersion().getMajorVersion()); - t.setBundledSignatures(Set.of("jdk-unsafe", "jdk-non-portable", "jdk-system-out")); + t.getBundledSignatures().set(BUNDLED_SIGNATURE_DEFAULTS); t.setSignaturesFiles( project.files( - resourcesDir.resolve("forbidden/jdk-signatures.txt"), - resourcesDir.resolve("forbidden/es-all-signatures.txt"), - resourcesDir.resolve("forbidden/jdk-deprecated.txt") + resourcesDir.toPath().resolve("forbidden/jdk-signatures.txt"), + resourcesDir.toPath().resolve("forbidden/es-all-signatures.txt"), + resourcesDir.toPath().resolve("forbidden/jdk-deprecated.txt") ) ); - t.setSuppressAnnotations(Set.of("**.SuppressForbidden")); + t.getSuppressAnnotations().set(Set.of("**.SuppressForbidden")); if (t.getName().endsWith("Test")) { t.setSignaturesFiles( t.getSignaturesFiles() .plus( project.files( - resourcesDir.resolve("forbidden/es-test-signatures.txt"), - resourcesDir.resolve("forbidden/http-signatures.txt") + resourcesDir.toPath().resolve("forbidden/es-test-signatures.txt"), + resourcesDir.toPath().resolve("forbidden/http-signatures.txt") ) ) ); } else { t.setSignaturesFiles( - t.getSignaturesFiles().plus(project.files(resourcesDir.resolve("forbidden/es-server-signatures.txt"))) + t.getSignaturesFiles().plus(project.files(resourcesDir.toPath().resolve("forbidden/es-server-signatures.txt"))) ); } - ExtraPropertiesExtension ext = t.getExtensions().getExtraProperties(); - ext.set("replaceSignatureFiles", new Closure(t) { - @Override - public Void call(Object... names) { - List resources = new ArrayList<>(names.length); - for (Object name : names) { - resources.add(resourcesDir.resolve("forbidden/" + name + ".txt")); - } - t.setSignaturesFiles(project.files(resources)); - return null; - } - - }); - ext.set("addSignatureFiles", new Closure(t) { - @Override - public Void call(Object... names) { - List resources = new ArrayList<>(names.length); - for (Object name : names) { - resources.add(resourcesDir.resolve("forbidden/" + name + ".txt")); - } - t.setSignaturesFiles(t.getSignaturesFiles().plus(project.files(resources))); - return null; - } - }); - }); forbiddenTask.configure(t -> t.dependsOn(sourceSetTask)); }); diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/LoggerUsageTask.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/LoggerUsageTask.java index 0059913ad086..559d7536c310 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/LoggerUsageTask.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/LoggerUsageTask.java @@ -52,7 +52,7 @@ public abstract class LoggerUsageTask extends PrecommitTask { } @Inject - abstract public WorkerExecutor getWorkerExecutor(); + public abstract WorkerExecutor getWorkerExecutor(); @TaskAction public void runLoggerUsageTask() { diff --git a/client/rest/build.gradle b/client/rest/build.gradle index 85d38b007e63..6006fae1c2d8 100644 --- a/client/rest/build.gradle +++ b/client/rest/build.gradle @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis +import org.elasticsearch.gradle.internal.precommit.CheckForbiddenApisTask import org.elasticsearch.gradle.VersionProperties import org.elasticsearch.gradle.internal.conventions.precommit.LicenseHeadersTask @@ -60,7 +60,7 @@ tasks.named("processResources").configure { ] } -tasks.withType(CheckForbiddenApis).configureEach { +tasks.withType(CheckForbiddenApisTask).configureEach { //client does not depend on server, so only jdk and http signatures should be checked replaceSignatureFiles('jdk-signatures', 'http-signatures') } @@ -71,8 +71,11 @@ tasks.named("forbiddenPatterns").configure { tasks.named('forbiddenApisTest').configure { //we are using jdk-internal instead of jdk-non-portable to allow for com.sun.net.httpserver.* usage - bundledSignatures -= 'jdk-non-portable' - bundledSignatures += 'jdk-internal' + modifyBundledSignatures { signatures -> + signatures -= 'jdk-non-portable' + signatures += 'jdk-internal' + signatures + } } // JarHell is part of es server, which we don't want to pull in diff --git a/client/sniffer/build.gradle b/client/sniffer/build.gradle index 546e81445bb8..901917c7b25f 100644 --- a/client/sniffer/build.gradle +++ b/client/sniffer/build.gradle @@ -57,8 +57,12 @@ tasks.named('forbiddenApisMain').configure { tasks.named('forbiddenApisTest').configure { //we are using jdk-internal instead of jdk-non-portable to allow for com.sun.net.httpserver.* usage - bundledSignatures -= 'jdk-non-portable' - bundledSignatures += 'jdk-internal' + modifyBundledSignatures { bundledSignatures -> + bundledSignatures -= 'jdk-non-portable' + bundledSignatures += 'jdk-internal' + bundledSignatures + } + //client does not depend on server, so only jdk signatures should be checked replaceSignatureFiles 'jdk-signatures' } diff --git a/client/test/build.gradle b/client/test/build.gradle index 18eb16883ab1..9ee222b036cd 100644 --- a/client/test/build.gradle +++ b/client/test/build.gradle @@ -40,8 +40,11 @@ tasks.named('forbiddenApisMain').configure { tasks.named('forbiddenApisTest').configure { //we are using jdk-internal instead of jdk-non-portable to allow for com.sun.net.httpserver.* usage - bundledSignatures -= 'jdk-non-portable' - bundledSignatures += 'jdk-internal' + modifyBundledSignatures { bundledSignatures -> + bundledSignatures -= 'jdk-non-portable' + bundledSignatures += 'jdk-internal' + bundledSignatures + } //client does not depend on core, so only jdk signatures should be checked replaceSignatureFiles 'jdk-signatures' } diff --git a/distribution/tools/server-cli/build.gradle b/distribution/tools/server-cli/build.gradle index 3ab5e6e86f5b..623f9d40cd49 100644 --- a/distribution/tools/server-cli/build.gradle +++ b/distribution/tools/server-cli/build.gradle @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis +import org.elasticsearch.gradle.internal.precommit.CheckForbiddenApisTask apply plugin: 'elasticsearch.build' @@ -20,7 +20,7 @@ tasks.named("test").configure { systemProperty "tests.security.manager", "false" } -tasks.withType(CheckForbiddenApis).configureEach { +tasks.withType(CheckForbiddenApisTask).configureEach { replaceSignatureFiles 'jdk-signatures' } diff --git a/x-pack/plugin/security/build.gradle b/x-pack/plugin/security/build.gradle index 0b7de9a0996e..509d4d5012f5 100644 --- a/x-pack/plugin/security/build.gradle +++ b/x-pack/plugin/security/build.gradle @@ -186,8 +186,11 @@ tasks.named('forbiddenApisMain').configure { tasks.named('forbiddenApisTest').configure { //we are using jdk-internal instead of jdk-non-portable to allow for com.sun.net.httpserver.* usage - bundledSignatures -= 'jdk-non-portable' - bundledSignatures += 'jdk-internal' + modifyBundledSignatures { bundledSignatures -> + bundledSignatures -= 'jdk-non-portable' + bundledSignatures += 'jdk-internal' + bundledSignatures + } } // classes are missing, e.g. com.ibm.icu.lang.UCharacter diff --git a/x-pack/plugin/security/cli/build.gradle b/x-pack/plugin/security/cli/build.gradle index 72c3abec8d3d..3e98dfe60ea2 100644 --- a/x-pack/plugin/security/cli/build.gradle +++ b/x-pack/plugin/security/cli/build.gradle @@ -1,4 +1,4 @@ -import de.thetaphi.forbiddenapis.gradle.CheckForbiddenApis +import org.elasticsearch.gradle.internal.precommit.CheckForbiddenApisTask import org.elasticsearch.gradle.internal.info.BuildParams apply plugin: 'elasticsearch.build' @@ -52,7 +52,10 @@ if (BuildParams.inFipsJvm) { } // Forbiden APIs non-portable checks fail because bouncy castle classes being used from the FIPS JDK since those are // not part of the Java specification - all of this is as designed, so we have to relax this check for FIPS. - tasks.withType(CheckForbiddenApis).configureEach { - bundledSignatures -= "jdk-non-portable" + tasks.withType(CheckForbiddenApisTask).configureEach { + modifyBundledSignatures { bundledSignatures -> + bundledSignatures -= "jdk-non-portable" + bundledSignatures + } } } diff --git a/x-pack/plugin/sql/sql-client/build.gradle b/x-pack/plugin/sql/sql-client/build.gradle index ac6600b09427..4a20e00666ea 100644 --- a/x-pack/plugin/sql/sql-client/build.gradle +++ b/x-pack/plugin/sql/sql-client/build.gradle @@ -23,8 +23,11 @@ tasks.named('forbiddenApisMain').configure { } tasks.named('forbiddenApisTest').configure { - bundledSignatures -= 'jdk-non-portable' - bundledSignatures += 'jdk-internal' + modifyBundledSignatures { bundledSignatures -> + bundledSignatures -= 'jdk-non-portable' + bundledSignatures += 'jdk-internal' + bundledSignatures + } } tasks.named("forbiddenPatterns").configure {