diff --git a/docs/pages/pmd/userdocs/cli_reference.md b/docs/pages/pmd/userdocs/cli_reference.md index a43c809081..743f5c3a15 100644 --- a/docs/pages/pmd/userdocs/cli_reference.md +++ b/docs/pages/pmd/userdocs/cli_reference.md @@ -40,7 +40,9 @@ The tool comes with a rather extensive help text, simply running with `-help`! {% include custom/cli_option_row.html options="-auxclasspath" option_arg="cp" description="Specifies the classpath for libraries used by the source code. - This is used to resolve types in source files. Alternatively, a `file://` URL + This is used to resolve types in source files. The platform specific path delimiter + (\":\" on Linux, \";\" on Windows) is used to separate the entries. + Alternatively, a single `file:` URL to a text file containing path elements on consecutive lines can be specified." languages="Java" %} diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 2947d9f354..531522fbac 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -67,6 +67,8 @@ The command line version of PMD continues to use **scala 2.13**. * [#2554](https://github.com/pmd/pmd/issues/2554): \[apex] Exception applying rule UnusedLocalVariable on trigger * c# * [#2551](https://github.com/pmd/pmd/issues/2551): \[c#] CPD suppression with comments doesn't work +* java + * [#2549](https://github.com/pmd/pmd/issues/2549): \[java] Auxclasspath in PMD CLI does not support relative file path * java-codestyle * [#2545](https://github.com/pmd/pmd/issues/2545): \[java] UseDiamondOperator false negatives * [#2573](https://github.com/pmd/pmd/pull/2573): \[java] DefaultPackage: Allow package default JUnit 5 Test methods diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java index 218a40923d..b68cb336a3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java @@ -92,7 +92,11 @@ public class PMDParameters { private String language = null; @Parameter(names = "-auxclasspath", - description = "Specifies the classpath for libraries used by the source code. This is used by the type resolution. Alternatively, a 'file://' URL to a text file containing path elements on consecutive lines can be specified.") + description = "Specifies the classpath for libraries used by the source code. " + + "This is used by the type resolution. The platform specific path delimiter " + + "(\":\" on Linux, \";\" on Windows) is used to separate the entries. " + + "Alternatively, a single 'file:' URL to a text file containing path elements on consecutive lines " + + "can be specified.") private String auxclasspath; @Parameter(names = { "-failOnViolation", "--failOnViolation" }, arity = 1, diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/ClasspathClassLoader.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/ClasspathClassLoader.java index e9b31a13cb..6c8148e274 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/ClasspathClassLoader.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/ClasspathClassLoader.java @@ -62,7 +62,7 @@ public class ClasspathClassLoader extends URLClassLoader { throw new IllegalArgumentException("classpath argument cannot be null"); } final List urls = new ArrayList<>(); - if (classpath.startsWith("file://")) { + if (classpath.startsWith("file:")) { // Treat as file URL addFileURLs(urls, new URL(classpath)); } else { @@ -87,7 +87,7 @@ public class ClasspathClassLoader extends URLClassLoader { while ((line = in.readLine()) != null) { LOG.log(Level.FINE, "Read classpath entry line: <{0}>", line); line = line.trim(); - if (line.length() > 0) { + if (line.length() > 0 && line.charAt(0) != '#') { LOG.log(Level.FINE, "Adding classpath entry: <{0}>", line); urls.add(createURLFromPath(line)); } @@ -97,7 +97,7 @@ public class ClasspathClassLoader extends URLClassLoader { private static URL createURLFromPath(String path) throws MalformedURLException { File file = new File(path); - return file.getAbsoluteFile().toURI().toURL(); + return file.getAbsoluteFile().toURI().normalize().toURL(); } @Override diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/ConfigurationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/ConfigurationTest.java index f1251cd25e..b88e95d8a9 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/ConfigurationTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/ConfigurationTest.java @@ -12,10 +12,13 @@ import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Properties; +import org.junit.Assert; import org.junit.Test; import net.sourceforge.pmd.cache.FileAnalysisCache; @@ -59,6 +62,50 @@ public class ConfigurationTest { configuration.getClassLoader()); } + @Test + public void auxClasspathWithRelativeFileEmpty() throws IOException { + String relativeFilePath = "src/test/resources/net/sourceforge/pmd/cli/auxclasspath-empty.cp"; + PMDConfiguration configuration = new PMDConfiguration(); + configuration.prependClasspath("file:" + relativeFilePath); + URL[] urls = ((ClasspathClassLoader) configuration.getClassLoader()).getURLs(); + Assert.assertEquals(0, urls.length); + } + + @Test + public void auxClasspathWithRelativeFileEmpty2() throws IOException { + String relativeFilePath = "./src/test/resources/net/sourceforge/pmd/cli/auxclasspath-empty.cp"; + PMDConfiguration configuration = new PMDConfiguration(); + configuration.prependClasspath("file:" + relativeFilePath); + URL[] urls = ((ClasspathClassLoader) configuration.getClassLoader()).getURLs(); + Assert.assertEquals(0, urls.length); + } + + @Test + public void auxClasspathWithRelativeFile() throws IOException, URISyntaxException { + final String FILE_SCHEME = "file"; + + String currentWorkingDirectory = new File("").getAbsoluteFile().toURI().getPath(); + String relativeFilePath = "src/test/resources/net/sourceforge/pmd/cli/auxclasspath.cp"; + PMDConfiguration configuration = new PMDConfiguration(); + configuration.prependClasspath("file:" + relativeFilePath); + URL[] urls = ((ClasspathClassLoader) configuration.getClassLoader()).getURLs(); + URI[] uris = new URI[urls.length]; + for (int i = 0; i < urls.length; i++) { + uris[i] = urls[i].toURI(); + } + URI[] expectedUris = new URI[] { + new URI(FILE_SCHEME, null, currentWorkingDirectory + "lib1.jar", null), + new URI(FILE_SCHEME, null, currentWorkingDirectory + "other/directory/lib2.jar", null), + new URI(FILE_SCHEME, null, new File("/home/jondoe/libs/lib3.jar").getAbsoluteFile().toURI().getPath(), null), + new URI(FILE_SCHEME, null, currentWorkingDirectory + "classes", null), + new URI(FILE_SCHEME, null, currentWorkingDirectory + "classes2", null), + new URI(FILE_SCHEME, null, new File("/home/jondoe/classes").getAbsoluteFile().toURI().getPath(), null), + new URI(FILE_SCHEME, null, currentWorkingDirectory, null), + new URI(FILE_SCHEME, null, currentWorkingDirectory + "relative source dir/bar", null), + }; + Assert.assertArrayEquals(expectedUris, uris); + } + @Test public void testRuleSets() { PMDConfiguration configuration = new PMDConfiguration(); diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/cli/auxclasspath-empty.cp b/pmd-core/src/test/resources/net/sourceforge/pmd/cli/auxclasspath-empty.cp new file mode 100644 index 0000000000..39eeac6911 --- /dev/null +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/cli/auxclasspath-empty.cp @@ -0,0 +1,4 @@ +# this file is deliberately empty +# comments start with # + +# empty lines are ignored diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/cli/auxclasspath.cp b/pmd-core/src/test/resources/net/sourceforge/pmd/cli/auxclasspath.cp new file mode 100644 index 0000000000..852cdf0bce --- /dev/null +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/cli/auxclasspath.cp @@ -0,0 +1,13 @@ +# relative paths here should be resolved relative to the current working directory - not relative to this file +lib1.jar +other/directory/lib2.jar +# absolute paths work as well +/home/jondoe/libs/lib3.jar +# also directories are possible +classes +classes2/ +/home/jondoe/classes +# relative current directory +. +# a test with a space in the uri +relative source dir/bar