Merge branch 'pr-1489'

This commit is contained in:
Andreas Dangel
2018-12-08 20:13:23 +01:00
3 changed files with 79 additions and 12 deletions

View File

@ -38,6 +38,7 @@ This means, you can use CPD to find duplicated code in your Kotlin projects.
* [#1341](https://github.com/pmd/pmd/issues/1341): \[doc] Documentation Error with Regex Properties
* [#1468](https://github.com/pmd/pmd/issues/1468): \[doc] Missing escaping leads to XSS
* [#1471](https://github.com/pmd/pmd/issues/1471): \[core] XMLRenderer: ProcessingErrors from exceptions without a message missing
* [#1477](https://github.com/pmd/pmd/issues/1477): \[core] Analysis cache fails with wildcard classpath entries
* java
* [#1460](https://github.com/pmd/pmd/issues/1460): \[java] Intermittent PMD failure : PMD processing errors while no violations reported
* java-bestpractices

View File

@ -26,6 +26,7 @@ import java.util.logging.Logger;
import java.util.zip.Adler32;
import java.util.zip.CheckedInputStream;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import net.sourceforge.pmd.PMDVersion;
@ -153,28 +154,48 @@ public abstract class AbstractAnalysisCache implements AnalysisCache {
ruleMapper.initialize(ruleSets);
}
private static boolean isClassPathWildcard(String entry) {
return entry.endsWith("/*") || entry.endsWith("\\*");
}
private URL[] getClassPathEntries() {
final String classpath = System.getProperty("java.class.path");
final String[] classpathEntries = classpath.split(File.pathSeparator);
final List<URL> entries = new ArrayList<>();
final SimpleFileVisitor<Path> fileVisitor = new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(final Path file,
final BasicFileAttributes attrs) throws IOException {
if (!attrs.isSymbolicLink()) { // Broken link that can't be followed
entries.add(file.toUri().toURL());
}
return FileVisitResult.CONTINUE;
}
};
final SimpleFileVisitor<Path> jarFileVisitor = new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(final Path file,
final BasicFileAttributes attrs) throws IOException {
String extension = FilenameUtils.getExtension(file.toString());
if ("jar".equalsIgnoreCase(extension)) {
fileVisitor.visitFile(file, attrs);
}
return FileVisitResult.CONTINUE;
}
};
try {
for (final String entry : classpathEntries) {
final File f = new File(entry);
if (f.isFile()) {
if (isClassPathWildcard(entry)) {
Files.walkFileTree(new File(entry.substring(0, entry.length() - 1)).toPath(),
EnumSet.of(FileVisitOption.FOLLOW_LINKS), 1, jarFileVisitor);
} else if (f.isFile()) {
entries.add(f.toURI().toURL());
} else {
Files.walkFileTree(f.toPath(), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(final Path file,
final BasicFileAttributes attrs) throws IOException {
if (!attrs.isSymbolicLink()) { // Broken link that can't be followed
entries.add(file.toUri().toURL());
}
return FileVisitResult.CONTINUE;
}
});
fileVisitor);
}
}
} catch (final IOException e) {

View File

@ -16,6 +16,7 @@ import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
@ -254,7 +255,51 @@ public class FileAnalysisCacheTest {
assertFalse("Cache believes cache is up to date when a classpath file changed",
reloadedCache.isUpToDate(sourceFile));
}
@Test
public void testWildcardClasspath() throws MalformedURLException, IOException {
final RuleSets rs = mock(RuleSets.class);
final ClassLoader cl = mock(ClassLoader.class);
setupCacheWithFiles(newCacheFile, rs, cl, sourceFile);
// Prepare two jar files
final File classpathJar1 = tempFolder.newFile("mylib1.jar");
Files.write(classpathJar1.toPath(), "content of mylib1.jar".getBytes(StandardCharsets.UTF_8));
final File classpathJar2 = tempFolder.newFile("mylib2.jar");
Files.write(classpathJar2.toPath(), "content of mylib2.jar".getBytes(StandardCharsets.UTF_8));
System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + tempFolder.getRoot().getAbsolutePath() + "/*");
final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile);
reloadedCache.checkValidity(rs, cl);
assertFalse("Cache believes cache is up to date when the classpath changed",
reloadedCache.isUpToDate(sourceFile));
}
@Test
public void testWildcardClasspathContentsChangeInvalidatesCache() throws MalformedURLException, IOException {
final RuleSets rs = mock(RuleSets.class);
final ClassLoader cl = mock(ClassLoader.class);
// Prepare two jar files
final File classpathJar1 = tempFolder.newFile("mylib1.jar");
Files.write(classpathJar1.toPath(), "content of mylib1.jar".getBytes(StandardCharsets.UTF_8));
final File classpathJar2 = tempFolder.newFile("mylib2.jar");
Files.write(classpathJar2.toPath(), "content of mylib2.jar".getBytes(StandardCharsets.UTF_8));
System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + tempFolder.getRoot().getAbsolutePath() + "/*");
setupCacheWithFiles(newCacheFile, rs, cl, sourceFile);
// Change one file's contents
Files.write(Paths.get(classpathJar2.getAbsolutePath()), "some other text".getBytes(StandardCharsets.UTF_8));
final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile);
reloadedCache.checkValidity(rs, cl);
assertFalse("Cache believes cache is up to date when the classpath changed",
reloadedCache.isUpToDate(sourceFile));
}
@Test
public void testUnknownFileIsNotUpToDate() throws IOException {
final FileAnalysisCache cache = new FileAnalysisCache(newCacheFile);