forked from phoedos/pmd
[doc] Improve performance of rule doc generator
Now we walk PMD source tree only once to resolve the file names to rulesets and rules instead walking the whole tree again for each ruleset/rule.
This commit is contained in:
@ -30,6 +30,11 @@ public final class GenerateRuleDocsCmd {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws RuleSetNotFoundException {
|
||||
if (args.length != 1) {
|
||||
System.err.println("One argument is required: The base directory of the module pmd-doc.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
Path output = FileSystems.getDefault().getPath(args[0]).resolve("..").toAbsolutePath().normalize();
|
||||
System.out.println("Generating docs into " + output);
|
||||
|
@ -75,6 +75,12 @@ public class RuleDocGenerator {
|
||||
private final Path root;
|
||||
private final FileWriter writer;
|
||||
|
||||
/** Caches rule class name to java source file mapping. */
|
||||
private final Map<String, String> allRules = new HashMap<>();
|
||||
/** Caches ruleset to ruleset xml file mapping. */
|
||||
private final Map<String, String> allRulesets = new HashMap<>();
|
||||
|
||||
|
||||
public RuleDocGenerator(FileWriter writer, Path root) {
|
||||
this.writer = Objects.requireNonNull(writer, "A file writer must be provided");
|
||||
this.root = Objects.requireNonNull(root, "Root directory must be provided");
|
||||
@ -91,6 +97,7 @@ public class RuleDocGenerator {
|
||||
try {
|
||||
sortedRulesets = sortRulesets(registeredRulesets);
|
||||
sortedAdditionalRulesets = sortRulesets(resolveAdditionalRulesets(additionalRulesets));
|
||||
determineRuleClassSourceFiles(sortedRulesets);
|
||||
generateLanguageIndex(sortedRulesets, sortedAdditionalRulesets);
|
||||
generateRuleSetIndex(sortedRulesets);
|
||||
|
||||
@ -345,7 +352,7 @@ public class RuleDocGenerator {
|
||||
String permalink = RULESET_INDEX_PERMALINK_PATTERN
|
||||
.replace("${language.tersename}", languageTersename)
|
||||
.replace("${ruleset.name}", rulesetFilename);
|
||||
String ruleSetSourceFilepath = "../" + getRuleSetSourceFilepath(ruleset);
|
||||
String ruleSetSourceFilepath = "../" + allRulesets.get(ruleset.getFileName());
|
||||
|
||||
List<String> lines = new LinkedList<>();
|
||||
lines.add("---");
|
||||
@ -415,7 +422,7 @@ public class RuleDocGenerator {
|
||||
} else {
|
||||
lines.add("**This rule is defined by the following Java class:** "
|
||||
+ "[" + rule.getRuleClass() + "]("
|
||||
+ GITHUB_SOURCE_LINK + getRuleClassSourceFilepath(rule.getRuleClass())
|
||||
+ GITHUB_SOURCE_LINK + allRules.get(rule.getRuleClass())
|
||||
+ ")");
|
||||
}
|
||||
lines.add("");
|
||||
@ -607,63 +614,67 @@ public class RuleDocGenerator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the source file of the given ruleset. This provides the information
|
||||
* for the "editme" link.
|
||||
* Walks through the root directory once to get all rule source file path names and ruleset names.
|
||||
* This provides the information for the "editme" links.
|
||||
*
|
||||
* @param ruleset the ruleset to search for.
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @param sortedRulesets all the rulesets and rules
|
||||
*/
|
||||
private String getRuleSetSourceFilepath(RuleSet ruleset) throws IOException {
|
||||
final String rulesetFilename = FilenameUtils.normalize(StringUtils.chomp(ruleset.getFileName()));
|
||||
final List<Path> foundPathResult = new LinkedList<>();
|
||||
|
||||
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
String path = file.toString();
|
||||
if (path.contains("src") && path.endsWith(rulesetFilename)) {
|
||||
foundPathResult.add(file);
|
||||
return FileVisitResult.TERMINATE;
|
||||
private void determineRuleClassSourceFiles(Map<Language, List<RuleSet>> sortedRulesets) {
|
||||
// first collect all the classes, we need to resolve and the rulesets
|
||||
for (List<RuleSet> rulesets : sortedRulesets.values()) {
|
||||
for (RuleSet ruleset : rulesets) {
|
||||
String rulesetFilename = FilenameUtils.normalize(StringUtils.chomp(ruleset.getFileName()));
|
||||
allRulesets.put(ruleset.getFileName(), rulesetFilename);
|
||||
for (Rule rule : ruleset.getRules()) {
|
||||
String ruleClass = rule.getRuleClass();
|
||||
String relativeSourceFilename = ruleClass.replaceAll("\\.", Matcher.quoteReplacement(File.separator))
|
||||
+ ".java";
|
||||
allRules.put(ruleClass, relativeSourceFilename);
|
||||
}
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
});
|
||||
|
||||
if (!foundPathResult.isEmpty()) {
|
||||
Path foundPath = foundPathResult.get(0);
|
||||
foundPath = root.relativize(foundPath);
|
||||
// Note: the path is normalized to unix path separators, so that the editme link
|
||||
// uses forward slashes
|
||||
return FilenameUtils.normalize(foundPath.toString(), true);
|
||||
}
|
||||
|
||||
return StringUtils.chomp(ruleset.getFileName());
|
||||
}
|
||||
// then go and search the actual files
|
||||
try {
|
||||
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
String path = file.toString();
|
||||
|
||||
private String getRuleClassSourceFilepath(String ruleClass) throws IOException {
|
||||
final String relativeSourceFilename = ruleClass.replaceAll("\\.", Matcher.quoteReplacement(File.separator))
|
||||
+ ".java";
|
||||
final List<Path> foundPathResult = new LinkedList<>();
|
||||
if (path.contains("src")) {
|
||||
String foundRuleClass = null;
|
||||
for (Map.Entry<String, String> entry : allRules.entrySet()) {
|
||||
if (path.endsWith(entry.getValue())) {
|
||||
foundRuleClass = entry.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundRuleClass != null) {
|
||||
Path foundPath = root.relativize(file);
|
||||
// Note: the path is normalized to unix path separators, so that the editme link
|
||||
// uses forward slashes
|
||||
allRules.put(foundRuleClass, FilenameUtils.normalize(foundPath.toString(), true));
|
||||
}
|
||||
|
||||
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
String path = file.toString();
|
||||
if (path.contains("src") && path.endsWith(relativeSourceFilename)) {
|
||||
foundPathResult.add(file);
|
||||
return FileVisitResult.TERMINATE;
|
||||
String foundRuleset = null;
|
||||
for (Map.Entry<String, String> entry : allRulesets.entrySet()) {
|
||||
if (path.endsWith(entry.getValue())) {
|
||||
foundRuleset = entry.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundRuleset != null) {
|
||||
Path foundPath = root.relativize(file);
|
||||
// Note: the path is normalized to unix path separators, so that the editme link
|
||||
// uses forward slashes
|
||||
allRulesets.put(foundRuleset, FilenameUtils.normalize(foundPath.toString(), true));
|
||||
}
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
});
|
||||
|
||||
if (!foundPathResult.isEmpty()) {
|
||||
Path foundPath = foundPathResult.get(0);
|
||||
foundPath = root.relativize(foundPath);
|
||||
return FilenameUtils.normalize(foundPath.toString(), true);
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return FilenameUtils.normalize(relativeSourceFilename, true);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user