diff --git a/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy b/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy index 20ba24c9..1fc3bed3 100644 --- a/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy +++ b/src/functionalTest/groovy/com/github/spotbugs/snom/StandardFunctionalTest.groovy @@ -452,6 +452,48 @@ public class FooTest { !result.output.contains("Trying to add already registered factory") } + def "can apply plugin using useAuxclasspathFile flag"() { + given: + buildFile << """ +spotbugs { + useAuxclasspathFile = true +} +dependencies { + implementation 'com.google.guava:guava:19.0' +}""" + + File sourceDir = rootDir.toPath().resolve(Paths.get("src", "main", "java")).toFile() + sourceDir.mkdirs() + File sourceFile = new File(sourceDir, "MyFoo.java") + sourceFile << """ +public class MyFoo { + public static void main(String... args) { + java.util.Map items = com.google.common.collect.ImmutableMap.of("coin", 3, "glass", 4, "pencil", 1); + + items.entrySet() + .stream() + .forEach(System.out::println); + } +} +""" + + + when: + BuildResult result = + GradleRunner.create() + .withProjectDir(rootDir) + .withArguments("spotbugsMain", '--debug') + .withPluginClasspath() + .forwardOutput() + .withGradleVersion(version) + .build() + + then: + result.task(":spotbugsMain").outcome == TaskOutcome.SUCCESS + result.output.contains("Using auxclasspath file") + result.output.contains("/build/spotbugs/spotbugs-auxclasspath") + } + @Unroll def 'shows report path when failures are found (Worker API? #isWorkerApi)'() { given: diff --git a/src/main/groovy/com/github/spotbugs/snom/SpotBugsExtension.groovy b/src/main/groovy/com/github/spotbugs/snom/SpotBugsExtension.groovy index 4ac59cd4..13887c55 100644 --- a/src/main/groovy/com/github/spotbugs/snom/SpotBugsExtension.groovy +++ b/src/main/groovy/com/github/spotbugs/snom/SpotBugsExtension.groovy @@ -144,6 +144,9 @@ class SpotBugsExtension { @NonNull final Property toolVersion + @NonNull + final Property useAuxclasspathFile; + @Inject SpotBugsExtension(Project project, ObjectFactory objects) { ignoreFailures = objects.property(Boolean).convention(false); @@ -173,6 +176,7 @@ class SpotBugsExtension { extraArgs = objects.listProperty(String); maxHeapSize = objects.property(String); toolVersion = objects.property(String) + useAuxclasspathFile = objects.property(Boolean).convention(false) } void setReportLevel(@Nullable String name) { diff --git a/src/main/groovy/com/github/spotbugs/snom/SpotBugsTask.groovy b/src/main/groovy/com/github/spotbugs/snom/SpotBugsTask.groovy index 7ed6046e..51fc3a29 100644 --- a/src/main/groovy/com/github/spotbugs/snom/SpotBugsTask.groovy +++ b/src/main/groovy/com/github/spotbugs/snom/SpotBugsTask.groovy @@ -229,6 +229,15 @@ class SpotBugsTask extends DefaultTask implements VerificationTask { @PathSensitive(PathSensitivity.RELATIVE) FileCollection auxClassPaths; + /** + * Property to enable auxclasspathFromFile and prevent Argument List Too Long issues in java processes. + * Default value is {@code false}. + */ + @Input + @Optional + @NonNull + final Property useAuxclasspathFile + private FileCollection classes; void setClasses(FileCollection fileCollection) { @@ -291,6 +300,7 @@ class SpotBugsTask extends DefaultTask implements VerificationTask { jvmArgs = objects.listProperty(String); extraArgs = objects.listProperty(String); maxHeapSize = objects.property(String); + useAuxclasspathFile = objects.property(Boolean) } /** @@ -316,6 +326,7 @@ class SpotBugsTask extends DefaultTask implements VerificationTask { jvmArgs.convention(extension.jvmArgs) extraArgs.convention(extension.extraArgs) maxHeapSize.convention(extension.maxHeapSize) + useAuxclasspathFile.convention(extension.useAuxclasspathFile) } @TaskAction diff --git a/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunner.java b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunner.java index cd4453d3..113b3d9a 100644 --- a/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunner.java +++ b/src/main/groovy/com/github/spotbugs/snom/internal/SpotBugsRunner.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Collection; @@ -49,8 +51,15 @@ protected List buildArguments(SpotBugsTask task) { args.add("-sortByClass"); args.add("-timestampNow"); if (!task.getAuxClassPaths().isEmpty()) { - args.add("-auxclasspath"); - args.add(join(task.getAuxClassPaths().getFiles())); + if (task.getUseAuxclasspathFile().get()) { + args.add("-auxclasspathFromFile"); + String auxClasspathFile = createFileForAuxClasspath(task); + log.debug("Using auxclasspath file: {}", auxClasspathFile); + args.add(auxClasspathFile); + } else { + args.add("-auxclasspath"); + args.add(join(task.getAuxClassPaths().getFiles())); + } } if (!task.getSourceDirs().isEmpty()) { args.add("-sourcepath"); @@ -108,6 +117,27 @@ protected List buildArguments(SpotBugsTask task) { return args; } + private String createFileForAuxClasspath(SpotBugsTask task) { + String auxClasspath = + task.getAuxClassPaths().getFiles().stream() + .map(File::getAbsolutePath) + .collect(Collectors.joining("\n")); + try { + Path auxClasspathFile = + Paths.get( + task.getProject().getBuildDir().getAbsolutePath(), + "spotbugs", + "spotbugs-auxclasspath"); + Files.createDirectories(auxClasspathFile.getParent()); + Files.createFile(auxClasspathFile); + Files.write(auxClasspathFile, auxClasspath.getBytes(), StandardOpenOption.TRUNCATE_EXISTING); + return auxClasspathFile.normalize().toString(); + } catch (Exception e) { + // oops + throw new GradleException("Could not create auxiliary classpath file for SpotBugsTask"); + } + } + private File generateFile(FileCollection files) { try { File file = File.createTempFile("spotbugs-gradle-plugin", ".txt");