/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.cli; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.RulePriority; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; import com.beust.jcommander.IStringConverter; import com.beust.jcommander.Parameter; import com.beust.jcommander.ParameterException; import com.beust.jcommander.validators.PositiveInteger; public class PMDParameters { @Parameter(names = { "-rulesets", "-R" }, description = "Comma separated list of ruleset names to use.", required = true) private String rulesets; @Parameter(names = { "-uri", "-u" }, description = "Database URI for sources.", required = false) private String uri; @Parameter(names = { "-dir", "-d" }, description = "Root directory for sources.", required = false) private String sourceDir; @Parameter(names = { "-filelist" }, description = "Path to a file containing a list of files to analyze.", required = false) private String fileListPath; @Parameter(names = { "-format", "-f" }, description = "Report format type.") private String format = "text"; // Enhance to support other usage @Parameter(names = { "-debug", "-verbose", "-D", "-V" }, description = "Debug mode.") private boolean debug = false; @Parameter(names = { "-help", "-h", "-H" }, description = "Display help on usage.", help = true) private boolean help = false; @Parameter(names = { "-encoding", "-e" }, description = "Specifies the character set encoding of the source code files PMD is reading (i.e., UTF-8).") private String encoding = "UTF-8"; @Parameter(names = { "-threads", "-t" }, description = "Sets the number of threads used by PMD.", validateWith = PositiveInteger.class) private Integer threads = 1; @Parameter(names = { "-benchmark", "-b" }, description = "Benchmark mode - output a benchmark report upon completion; default to System.err.") private boolean benchmark = false; @Parameter(names = { "-stress", "-S" }, description = "Performs a stress test.") private boolean stress = false; @Parameter(names = "-shortnames", description = "Prints shortened filenames in the report.") private boolean shortnames = false; @Parameter(names = "-showsuppressed", description = "Report should show suppressed rule violations.") private boolean showsuppressed = false; @Parameter(names = "-suppressmarker", description = "Specifies the string that marks the a line which PMD should ignore; default is NOPMD.") private String suppressmarker = "NOPMD"; @Parameter(names = { "-minimumpriority", "-min" }, description = "Rule priority threshold; rules with lower priority than configured here won't be used. Default is '5' which is the lowest priority.", converter = RulePriorityConverter.class) private RulePriority minimumPriority = RulePriority.LOW; @Parameter(names = { "-property", "-P" }, description = "{name}={value}: Define a property for the report format.", converter = PropertyConverter.class) private List<Properties> properties = new ArrayList<>(); @Parameter(names = { "-reportfile", "-r" }, description = "Sends report output to a file; default to System.out.") private String reportfile = null; @Parameter(names = { "-version", "-v" }, description = "Specify version of a language PMD should use.") private String version = null; @Parameter(names = { "-language", "-l" }, description = "Specify a language PMD should use.") 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.") private String auxclasspath; @Parameter(names = { "-failOnViolation", "--failOnViolation" }, arity = 1, description = "By default PMD exits with status 4 if violations are found. Disable this option with '-failOnViolation false' to exit with 0 instead and just write the report.") private boolean failOnViolation = true; @Parameter(names = "-norulesetcompatibility", description = "Disable the ruleset compatibility filter. The filter is active by default and tries automatically 'fix' old ruleset files with old rule names") private boolean noRuleSetCompatibility = false; @Parameter(names = "-cache", description = "Specify the location of the cache file for incremental analysis.") private String cacheLocation = null; // this has to be a public static class, so that JCommander can use it! public static class PropertyConverter implements IStringConverter<Properties> { private static final char SEPARATOR = '='; @Override public Properties convert(String value) { int indexOfSeparator = value.indexOf(SEPARATOR); if (indexOfSeparator < 0) { throw new ParameterException( "Property name must be separated with an = sign from it value: name=value."); } String propertyName = value.substring(0, indexOfSeparator); String propertyValue = value.substring(indexOfSeparator + 1); Properties properties = new Properties(); properties.put(propertyName, propertyValue); return properties; } } // this has to be a public static class, so that JCommander can use it! public static class RulePriorityConverter implements IStringConverter<RulePriority> { public int validate(String value) throws ParameterException { int minPriorityValue = Integer.parseInt(value); if (minPriorityValue < 1 || minPriorityValue > 5) { throw new ParameterException( "Priority values can only be integer value, between 1 and 5," + value + " is not valid"); } return minPriorityValue; } @Override public RulePriority convert(String value) { return RulePriority.valueOf(validate(value)); } } public static PMDConfiguration transformParametersIntoConfiguration(PMDParameters params) { if (null == params.getSourceDir() && null == params.getUri() && null == params.getFileListPath()) { throw new IllegalArgumentException( "Please provide a parameter for source root directory (-dir or -d), database URI (-uri or -u), or file list path (-filelist)."); } PMDConfiguration configuration = new PMDConfiguration(); configuration.setInputPaths(params.getSourceDir()); configuration.setInputFilePath(params.getFileListPath()); configuration.setInputUri(params.getUri()); configuration.setReportFormat(params.getFormat()); configuration.setBenchmark(params.isBenchmark()); configuration.setDebug(params.isDebug()); configuration.setMinimumPriority(params.getMinimumPriority()); configuration.setReportFile(params.getReportfile()); configuration.setReportProperties(params.getProperties()); configuration.setReportShortNames(params.isShortnames()); configuration.setRuleSets(params.getRulesets()); configuration.setRuleSetFactoryCompatibilityEnabled(!params.noRuleSetCompatibility); configuration.setShowSuppressedViolations(params.isShowsuppressed()); configuration.setSourceEncoding(params.getEncoding()); configuration.setStressTest(params.isStress()); configuration.setSuppressMarker(params.getSuppressmarker()); configuration.setThreads(params.getThreads()); configuration.setFailOnViolation(params.isFailOnViolation()); configuration.setAnalysisCacheLocation(params.cacheLocation); LanguageVersion languageVersion = LanguageRegistry .findLanguageVersionByTerseName(params.getLanguage() + " " + params.getVersion()); if (languageVersion != null) { configuration.getLanguageVersionDiscoverer().setDefaultLanguageVersion(languageVersion); } try { configuration.prependClasspath(params.getAuxclasspath()); } catch (IOException e) { throw new IllegalArgumentException("Invalid auxiliary classpath: " + e.getMessage(), e); } return configuration; } public boolean isDebug() { return debug; } public boolean isHelp() { return help; } public String getEncoding() { return encoding; } public Integer getThreads() { return threads; } public boolean isBenchmark() { return benchmark; } public boolean isStress() { return stress; } public boolean isShortnames() { return shortnames; } public boolean isShowsuppressed() { return showsuppressed; } public String getSuppressmarker() { return suppressmarker; } public RulePriority getMinimumPriority() { return minimumPriority; } public Properties getProperties() { Properties result = new Properties(); for (Properties p : properties) { result.putAll(p); } return result; } public String getReportfile() { return reportfile; } public String getVersion() { if (version != null) { return version; } return LanguageRegistry.findLanguageByTerseName(getLanguage()).getDefaultVersion().getVersion(); } public String getLanguage() { return language != null ? language : LanguageRegistry.getDefaultLanguage().getTerseName(); } public String getAuxclasspath() { return auxclasspath; } public String getRulesets() { return rulesets; } public String getSourceDir() { return sourceDir; } public String getFileListPath() { return fileListPath; } public String getFormat() { return format; } public boolean isFailOnViolation() { return failOnViolation; } /** * @return the uri alternative to source directory. */ public String getUri() { return uri; } /** * @param uri * the uri specifying the source directory. */ public void setUri(String uri) { this.uri = uri; } }