From 5ded20c22e5d77cb3dd63d74e6670f0cf9568f51 Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Wed, 19 Jul 2017 16:10:44 +0200 Subject: [PATCH 1/2] Initial commit to remove warning in Gradle 4: - classesDir -> classesDirs - deprecated classesDir - make plugin-init.groovy detect correct behaviour using hasProperty() --- .../gradle/CheckForbiddenApis.java | 50 +++++++++++++------ .../forbiddenapis/gradle/plugin-init.groovy | 9 ++-- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java b/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java index f8c4bdd3..5a4867a3 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java +++ b/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java @@ -27,6 +27,7 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.EnumSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Set; @@ -43,7 +44,7 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.OutputDirectories; import org.gradle.api.tasks.ParallelizableTask; import org.gradle.api.tasks.SkipWhenEmpty; import org.gradle.api.tasks.TaskAction; @@ -109,23 +110,43 @@ public class CheckForbiddenApis extends DefaultTask implements PatternFilterable private final CheckForbiddenApisExtension data = new CheckForbiddenApisExtension(); private final PatternSet patternSet = new PatternSet().include("**/*.class"); - private File classesDir; + private FileCollection classesDirs; private FileCollection classpath; private String targetCompatibility; + /** + * Directories with the class files to check. + * Defaults to current sourseSet's output directory (Gradle 2/3) or output directories (Gradle 4.0+). + */ + @OutputDirectories + // no @InputDirectories, we use separate getter for a list of all input files + public FileCollection getClassesDirs() { + return classesDirs; + } + + /** @see #getClassesDirs */ + public void setClassesDirs(FileCollection classesDirs) { + this.classesDirs = classesDirs; + } + /** * Directory with the class files to check. * Defaults to current sourseSet's output directory. + * @deprecated use {@link #getClassesDirs()} instead */ - @OutputDirectory - // no @InputDirectory, we use separate getter for a list of all input files + @Deprecated public File getClassesDir() { - return classesDir; + final FileCollection col = getClassesDirs(); + return (col == null) ? null : col.getSingleFile(); } - /** @see #getClassesDir */ + /** Sets the directory where to look for classes. Overwrites any value set by {@link #setClassesDirs()}! + * @deprecated use {@link #setClassesDirs()} instead + * @see #getClassesDir + */ + @Deprecated public void setClassesDir(File classesDir) { - this.classesDir = classesDir; + setClassesDirs(getProject().files(classesDir)); } /** Returns the pattern set to match against class files in {@link #getClassesDir()}. */ @@ -453,16 +474,16 @@ public CheckForbiddenApis include(@SuppressWarnings("rawtypes") Closure arg0) { @InputFiles @SkipWhenEmpty public FileTree getClassFiles() { - return getProject().files(getClassesDir()).getAsFileTree().matching(getPatternSet()); + return getClassesDirs().getAsFileTree().matching(getPatternSet()); } /** Executes the forbidden apis task. */ @TaskAction public void checkForbidden() throws ForbiddenApiException { - final File classesDir = getClassesDir(); + final FileCollection classesDirs = getClassesDirs(); final FileCollection classpath = getClasspath(); - if (classesDir == null || classpath == null) { - throw new InvalidUserDataException("Missing 'classesDir' or 'classpath' property."); + if (classesDirs == null || classpath == null) { + throw new InvalidUserDataException("Missing 'classesDirs' or 'classpath' property."); } final Logger log = new Logger() { @@ -482,14 +503,15 @@ public void info(String msg) { } }; - final Set cpElements = classpath.getFiles(); - final URL[] urls = new URL[cpElements.size() + 1]; + 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(); } - urls[i++] = classesDir.toURI().toURL(); assert i == urls.length; } catch (MalformedURLException mfue) { throw new InvalidUserDataException("Failed to build classpath URLs.", mfue); diff --git a/src/main/resources/de/thetaphi/forbiddenapis/gradle/plugin-init.groovy b/src/main/resources/de/thetaphi/forbiddenapis/gradle/plugin-init.groovy index 2f575575..a5fdd250 100644 --- a/src/main/resources/de/thetaphi/forbiddenapis/gradle/plugin-init.groovy +++ b/src/main/resources/de/thetaphi/forbiddenapis/gradle/plugin-init.groovy @@ -45,19 +45,20 @@ def extensionProps = CheckForbiddenApisExtension.class.declaredFields.findAll{ f // Define our tasks (one for each SourceSet): def forbiddenTasks = project.sourceSets.collect{ sourceSet -> + def getClassesDirs = { sourceSet.output.hasProperty('classesDirs') ? sourceSet.output.classesDirs : project.files(sourceSet.output.classesDir) } project.tasks.create(sourceSet.getTaskName(FORBIDDEN_APIS_TASK_NAME, null), CheckForbiddenApis.class) { description = "Runs forbidden-apis checks on '${sourceSet.name}' classes."; conventionMapping.with{ extensionProps.each{ key -> map(key, { extension[key] }); } - classesDir = { sourceSet.output.classesDir } + classesDirs = { getClassesDirs() } classpath = { sourceSet.compileClasspath } targetCompatibility = { project.targetCompatibility?.toString() } } - // add dependency to compile task after evaluation, if the classesDir is from our SourceSet: - project.afterEvaluate{ - if (classesDir == sourceSet.output.classesDir) { + // add dependency to compile task after evaluation, if the classesDirs collection has overlaps with our SourceSet: + project.afterEvaluate{ + if (!classesDirs.minus(getClassesDirs()).isEmpty()) { dependsOn(sourceSet.output); } } From 7e9fd787673d7d81997272aae07f143a128b1ec8 Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Wed, 19 Jul 2017 20:24:44 +0200 Subject: [PATCH 2/2] Add a deprecation warning and update some docs. Also add null checks. --- .../forbiddenapis/gradle/CheckForbiddenApis.java | 15 +++++++++++---- src/test/gradle/build.gradle | 3 ++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java b/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java index 5a4867a3..c0970ade 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java +++ b/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java @@ -126,13 +126,16 @@ public FileCollection getClassesDirs() { /** @see #getClassesDirs */ public void setClassesDirs(FileCollection classesDirs) { + if (classesDirs == null) throw new NullPointerException("classesDirs"); this.classesDirs = classesDirs; } /** * Directory with the class files to check. - * Defaults to current sourseSet's output directory. - * @deprecated use {@link #getClassesDirs()} instead + * Defaults to current sourseSet's output directory (Gradle 2/3 only). + * @deprecated use {@link #getClassesDirs()} instead. If there are more than one + * {@code classesDir} set by {@link #setClassesDirs(FileCollection)}, this getter may + * throw an exception! */ @Deprecated public File getClassesDir() { @@ -140,12 +143,15 @@ public File getClassesDir() { return (col == null) ? null : col.getSingleFile(); } - /** Sets the directory where to look for classes. Overwrites any value set by {@link #setClassesDirs()}! - * @deprecated use {@link #setClassesDirs()} instead + /** Sets the directory where to look for classes. Overwrites any value set by {@link #setClassesDirs(FileCollection)}! + * @deprecated use {@link #setClassesDirs(FileCollection)} instead. * @see #getClassesDir */ @Deprecated public void setClassesDir(File classesDir) { + if (classesDir == null) throw new NullPointerException("classesDir"); + getLogger().warn("The 'classesDir' property on the '{}' task is deprecated. Use 'classesDirs' of type FileCollection instead!", + getName()); setClassesDirs(getProject().files(classesDir)); } @@ -170,6 +176,7 @@ public FileCollection getClasspath() { /** @see #getClasspath */ public void setClasspath(FileCollection classpath) { + if (classpath == null) throw new NullPointerException("classpath"); this.classpath = classpath; } diff --git a/src/test/gradle/build.gradle b/src/test/gradle/build.gradle index 397e526f..41e0bd7c 100644 --- a/src/test/gradle/build.gradle +++ b/src/test/gradle/build.gradle @@ -37,12 +37,13 @@ forbiddenApis { } forbiddenApisMain { - classesDir = new File(forbiddenRootDir, 'build/main') + classesDirs = files(new File(forbiddenRootDir, 'build/main')) classpath = files(forbiddenClasspath.tokenize(File.pathSeparator)) bundledSignatures += 'jdk-system-out' } forbiddenApisTest { + // use classesDir here to check backwards compatibility!: classesDir = new File(forbiddenRootDir, 'build/test') classpath = files(forbiddenTestClasspath.tokenize(File.pathSeparator)) }