View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.cli;
5   
6   import java.io.IOException;
7   import java.util.ArrayList;
8   import java.util.List;
9   import java.util.Properties;
10  
11  import net.sourceforge.pmd.PMDConfiguration;
12  import net.sourceforge.pmd.RulePriority;
13  import net.sourceforge.pmd.lang.LanguageRegistry;
14  import net.sourceforge.pmd.lang.LanguageVersion;
15  
16  import com.beust.jcommander.IStringConverter;
17  import com.beust.jcommander.Parameter;
18  import com.beust.jcommander.ParameterException;
19  import com.beust.jcommander.validators.PositiveInteger;
20  
21  public class PMDParameters {
22  
23      @Parameter(names = { "-rulesets", "-R" }, description = "Comma separated list of ruleset names to use.", required = true)
24      private String rulesets;
25  
26      @Parameter(names = { "-uri", "-u" }, description = "Database URI for sources.", required = false)
27      private String uri;
28  
29      @Parameter(names = { "-dir", "-d" }, description = "Root directory for sources.", required = false)
30      private String sourceDir;
31  
32      @Parameter(names = { "-format", "-f" }, description = "Report format type.")
33      private String format = "text"; // Enhance to support other usage
34  
35      @Parameter(names = { "-debug", "-verbose", "-D", "-V" }, description = "Debug mode.")
36      private boolean debug = false;
37  
38      @Parameter(names = { "-help", "-h", "-H" }, description = "Display help on usage.", help = true)
39      private boolean help = false;
40  
41      @Parameter(names = { "-encoding", "-e" }, description = "Specifies the character set encoding of the source code files PMD is reading (i.e., UTF-8).")
42      private String encoding = "UTF-8";
43  
44      @Parameter(names = { "-threads", "-t" }, description = "Sets the number of threads used by PMD.", validateWith = PositiveInteger.class)
45      private Integer threads = 1;
46  
47      @Parameter(names = { "-benchmark", "-b" }, description = "Benchmark mode - output a benchmark report upon completion; default to System.err.")
48      private boolean benchmark = false;
49  
50      @Parameter(names = { "-stress", "-S" }, description = "Performs a stress test.")
51      private boolean stress = false;
52  
53      @Parameter(names = "-shortnames", description = "Prints shortened filenames in the report.")
54      private boolean shortnames = false;
55  
56      @Parameter(names = "-showsuppressed", description = "Report should show suppressed rule violations.")
57      private boolean showsuppressed = false;
58  
59      @Parameter(names = "-suppressmarker", description = "Specifies the string that marks the a line which PMD should ignore; default is NOPMD.")
60      private String suppressmarker = "NOPMD";
61  
62      @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)
63      private RulePriority minimumPriority = RulePriority.LOW;
64  
65      @Parameter(names = { "-property", "-P" }, description = "{name}={value}: Define a property for the report format.",
66              converter = PropertyConverter.class)
67      private List<Properties> properties = new ArrayList<>();
68  
69      @Parameter(names = { "-reportfile", "-r" }, description = "Sends report output to a file; default to System.out.")
70      private String reportfile = null;
71  
72      @Parameter(names = { "-version", "-v" }, description = "Specify version of a language PMD should use.")
73      private String version = null;
74  
75      @Parameter(names = { "-language", "-l" }, description = "Specify a language PMD should use.")
76      private String language = null;
77  
78      @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.")
79      private String auxclasspath;
80  
81      @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.")
82      private boolean failOnViolation = true;
83  
84      // this has to be a public static class, so that JCommander can use it!
85      public static class PropertyConverter implements IStringConverter<Properties> {
86  
87          private static final char SEPARATOR = '=';
88  
89          public Properties convert(String value) {
90              int indexOfSeparator = value.indexOf(SEPARATOR);
91              if (indexOfSeparator < 0) {
92                  throw new ParameterException(
93                          "Property name must be separated with an = sign from it value: name=value.");
94              }
95              String propertyName = value.substring(0, indexOfSeparator);
96              String propertyValue = value.substring(indexOfSeparator + 1);
97              Properties properties = new Properties();
98              properties.put(propertyName, propertyValue);
99              return properties;
100         }
101     }
102 
103     // this has to be a public static class, so that JCommander can use it!
104     public static class RulePriorityConverter implements IStringConverter<RulePriority> {
105 
106         public int validate(String value) throws ParameterException {
107             int minPriorityValue = Integer.parseInt(value);
108             if (minPriorityValue < 1 || minPriorityValue > 5) {
109                 throw new ParameterException("Priority values can only be integer value, between 1 and 5," + value
110                         + " is not valid");
111             }
112             return minPriorityValue;
113         }
114 
115         public RulePriority convert(String value) {
116             return RulePriority.valueOf(validate(value));
117         }
118     }
119 
120     public static PMDConfiguration transformParametersIntoConfiguration(PMDParameters params) {
121         if (null == params.getSourceDir() && null == params.getUri()) {
122             throw new IllegalArgumentException(
123                     "Please provide either source root directory (-dir or -d) or database URI (-uri or -u) parameter");
124         }
125         PMDConfiguration configuration = new PMDConfiguration();
126         configuration.setInputPaths(params.getSourceDir());
127         configuration.setInputUri(params.getUri());
128         configuration.setReportFormat(params.getFormat());
129         configuration.setBenchmark(params.isBenchmark());
130         configuration.setDebug(params.isDebug());
131         configuration.setMinimumPriority(params.getMinimumPriority());
132         configuration.setReportFile(params.getReportfile());
133         configuration.setReportProperties(params.getProperties());
134         configuration.setReportShortNames(params.isShortnames());
135         configuration.setRuleSets(params.getRulesets());
136         configuration.setShowSuppressedViolations(params.isShowsuppressed());
137         configuration.setSourceEncoding(params.getEncoding());
138         configuration.setStressTest(params.isStress());
139         configuration.setSuppressMarker(params.getSuppressmarker());
140         configuration.setThreads(params.getThreads());
141         configuration.setFailOnViolation(params.isFailOnViolation());
142 
143         LanguageVersion languageVersion = LanguageRegistry.findLanguageVersionByTerseName(params.getLanguage() + " " + params.getVersion());
144         if(languageVersion != null) {
145             configuration.getLanguageVersionDiscoverer().setDefaultLanguageVersion(languageVersion);
146         }
147         try {
148             configuration.prependClasspath(params.getAuxclasspath());
149         } catch (IOException e) {
150             throw new IllegalArgumentException("Invalid auxiliary classpath: " + e.getMessage(), e);
151         }
152         return configuration;
153     }
154 
155     public boolean isDebug() {
156         return debug;
157     }
158 
159     public boolean isHelp() {
160         return help;
161     }
162 
163     public String getEncoding() {
164         return encoding;
165     }
166 
167     public Integer getThreads() {
168         return threads;
169     }
170 
171     public boolean isBenchmark() {
172         return benchmark;
173     }
174 
175     public boolean isStress() {
176         return stress;
177     }
178 
179     public boolean isShortnames() {
180         return shortnames;
181     }
182 
183     public boolean isShowsuppressed() {
184         return showsuppressed;
185     }
186 
187     public String getSuppressmarker() {
188         return suppressmarker;
189     }
190 
191     public RulePriority getMinimumPriority() {
192         return minimumPriority;
193     }
194 
195     public Properties getProperties() {
196         Properties result = new Properties();
197         for (Properties p : properties) {
198             result.putAll(p);
199         }
200         return result;
201     }
202 
203     public String getReportfile() {
204         return reportfile;
205     }
206 
207     public String getVersion() {
208         return version != null ? version : LanguageRegistry.getDefaultLanguage().getDefaultVersion().getVersion();
209     }
210 
211     public String getLanguage() {
212         return language != null ? language : LanguageRegistry.getDefaultLanguage().getTerseName();
213     }
214 
215     public String getAuxclasspath() {
216         return auxclasspath;
217     }
218 
219     public String getRulesets() {
220         return rulesets;
221     }
222 
223     public String getSourceDir() {
224         return sourceDir;
225     }
226 
227     public String getFormat() {
228         return format;
229     }
230 
231     public boolean isFailOnViolation() {
232         return failOnViolation;
233     }
234 
235     /**
236      * @return the uri alternative to source directory.
237      */
238     public String getUri() {
239         return uri;
240     }
241 
242     /**
243      * @param uri the uri specifying the source directory.
244      */
245     public void setUri(String uri) {
246         this.uri = uri;
247     }
248 
249 }