1
2
3
4 package net.sourceforge.pmd.cpd;
5
6 import java.io.File;
7 import java.io.FilenameFilter;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Properties;
11 import java.util.Set;
12
13 import net.sourceforge.pmd.AbstractConfiguration;
14 import net.sourceforge.pmd.util.FileFinder;
15
16 import com.beust.jcommander.IStringConverter;
17 import com.beust.jcommander.Parameter;
18 import java.io.Reader;
19
20
21
22
23
24
25 public class CPDConfiguration extends AbstractConfiguration {
26
27 public final static String DEFAULT_LANGUAGE = "java";
28
29 public final static String DEFAULT_RENDERER = "text";
30
31 @Parameter(names = "--language", description = "Sources code language. Default value is "
32 + DEFAULT_LANGUAGE, required = false, converter = LanguageConverter.class)
33 private Language language;
34
35 @Parameter(names = "--minimum-tokens", description = "The minimum token length which should be reported as a duplicate.", required = true)
36 private int minimumTileSize;
37
38 @Parameter(names = "--skip-duplicate-files", description = "Ignore multiple copies of files of the same name and length in comparison", required = false)
39 private boolean skipDuplicates;
40
41 @Parameter(names = "--format", description = "Report format. Default value is "
42 + DEFAULT_RENDERER, required = false)
43 private String rendererName;
44
45
46
47
48
49 private Renderer renderer;
50
51 @Parameter(names = "--encoding", description = "Characterset to use when processing files", required = false)
52 private String encoding;
53
54 @Parameter(names = "--ignore-literals", description = "Ignore number values and string contents when comparing text", required = false)
55 private boolean ignoreLiterals;
56
57 @Parameter(names = "--ignore-identifiers", description = "Ignore constant and variable names when comparing text", required = false)
58 private boolean ignoreIdentifiers;
59
60 @Parameter(names = "--ignore-annotations", description = "Ignore language annotations when comparing text", required = false)
61 private boolean ignoreAnnotations;
62
63 @Parameter(names = "--skip-lexical-errors", description = "Skip files which can't be tokenized due to invalid characters instead of aborting CPD", required = false)
64 private boolean skipLexicalErrors = false;
65
66 @Parameter(names = "--files", variableArity = true, description = "List of files and directories to process", required = false)
67 private List<String> files;
68
69 @Parameter(names = "--exclude", variableArity = true, description = "Files to be excluded from CPD check", required = false)
70 private List<String> excludes;
71
72 @Parameter(names = "--non-recursive", description = "Don't scan subdirectiories", required = false)
73 private boolean nonRecursive;
74
75 @Parameter(names = "--uri", description = "URI to process", required = false)
76 private String uri;
77
78 @Parameter(names = { "--help", "-h" }, description = "Print help text", required = false, help = true)
79 private boolean help;
80
81
82 public static class LanguageConverter implements IStringConverter<Language> {
83
84
85 public Language convert(String languageString) {
86 if (languageString == null || "".equals(languageString)) {
87 languageString = DEFAULT_LANGUAGE;
88 }
89 return new LanguageFactory().createLanguage(languageString);
90 }
91 }
92
93 public CPDConfiguration()
94 {
95 }
96
97 @Deprecated
98 public CPDConfiguration(int minimumTileSize, Language language, String encoding)
99 {
100 setMinimumTileSize(minimumTileSize);
101 setLanguage(language);
102 setEncoding(encoding);
103 }
104
105
106 public void setEncoding(String encoding) {
107 this.encoding = encoding;
108 }
109
110 public SourceCode sourceCodeFor(File file) {
111 return new SourceCode(new SourceCode.FileCodeLoader(file,
112 getSourceEncoding()));
113 }
114
115 public SourceCode sourceCodeFor(Reader reader, String sourceCodeName ) {
116 return new SourceCode(new SourceCode.ReaderCodeLoader(reader, sourceCodeName ));
117 }
118
119 public void postContruct() {
120 if (getEncoding() != null) {
121 super.setSourceEncoding(getEncoding());
122 if (!getEncoding().equals(System.getProperty("file.encoding")))
123 System.setProperty("file.encoding", getEncoding());
124 }
125 if ( this.getLanguage() == null )
126 this.setLanguage(CPDConfiguration.getLanguageFromString(DEFAULT_LANGUAGE));
127 if (this.getRendererName() == null )
128 this.setRendererName(DEFAULT_RENDERER);
129 if ( this.getRenderer() == null )
130 this.setRenderer(getRendererFromString(getRendererName()));
131 }
132
133 public static Renderer getRendererFromString(String name ) {
134 if (name.equalsIgnoreCase(DEFAULT_RENDERER) || name.equals("")) {
135 return new SimpleRenderer();
136 } else if ("xml".equals(name)) {
137 return new XMLRenderer();
138 } else if ("csv".equals(name)) {
139 return new CSVRenderer();
140 } else if ("vs".equals(name)) {
141 return new VSRenderer();
142 }
143 try {
144 return (Renderer) Class.forName(name).newInstance();
145 } catch (Exception e) {
146 System.out.println("Can't find class '" + name
147 + "', defaulting to SimpleRenderer.");
148 }
149 return new SimpleRenderer();
150 }
151
152 public static Language getLanguageFromString(String languageString) {
153 return new LanguageFactory().createLanguage(languageString);
154 }
155
156 public static void setSystemProperties(CPDConfiguration configuration) {
157 Properties properties = System.getProperties();
158 if (configuration.isIgnoreLiterals()) {
159 properties.setProperty(JavaTokenizer.IGNORE_LITERALS, "true");
160 } else {
161 properties.remove(JavaTokenizer.IGNORE_LITERALS);
162 }
163 if (configuration.isIgnoreIdentifiers()) {
164 properties.setProperty(JavaTokenizer.IGNORE_IDENTIFIERS, "true");
165 } else {
166 properties.remove(JavaTokenizer.IGNORE_IDENTIFIERS);
167 }
168 if (configuration.isIgnoreAnnotations()) {
169 properties.setProperty(JavaTokenizer.IGNORE_ANNOTATIONS, "true");
170 } else {
171 properties.remove(JavaTokenizer.IGNORE_ANNOTATIONS);
172 }
173 System.setProperties(properties);
174 configuration.getLanguage().setProperties(properties);
175 }
176
177 public Language getLanguage() {
178 return language;
179 }
180
181 public void setLanguage(Language language) {
182 this.language = language;
183 }
184
185 public int getMinimumTileSize() {
186 return minimumTileSize;
187 }
188
189 public void setMinimumTileSize(int minimumTileSize) {
190 this.minimumTileSize = minimumTileSize;
191 }
192
193 public boolean isSkipDuplicates() {
194 return skipDuplicates;
195 }
196
197 public void setSkipDuplicates(boolean skipDuplicates) {
198 this.skipDuplicates = skipDuplicates;
199 }
200
201 public String getRendererName() {
202 return rendererName;
203 }
204
205 public void setRendererName(String rendererName) {
206 this.rendererName = rendererName;
207 }
208
209 public Renderer getRenderer() {
210 return renderer;
211 }
212
213 public Tokenizer tokenizer() {
214 if ( language == null )
215 throw new IllegalStateException("Language is null.");
216 return language.getTokenizer();
217 }
218
219 public FilenameFilter filenameFilter() {
220 if (language == null)
221 throw new IllegalStateException("Language is null.");
222
223 final FilenameFilter languageFilter = language.getFileFilter();
224 final Set<String> exclusions = new HashSet<String>();
225
226 if (excludes != null) {
227 FileFinder finder = new FileFinder();
228 for (String excludedFile : excludes) {
229 File exFile = new File(excludedFile);
230 if (exFile.isDirectory()) {
231 List<File> files = finder.findFilesFrom(excludedFile, languageFilter, true);
232 for (File f : files) {
233 exclusions.add(f.getAbsolutePath());
234 }
235 } else {
236 exclusions.add(exFile.getAbsolutePath());
237 }
238 }
239 }
240
241 FilenameFilter filter = new FilenameFilter() {
242 public boolean accept(File dir, String name) {
243 File f = new File(dir, name);
244 if (exclusions.contains(f.getAbsolutePath())) {
245 System.err.println("Excluding " + f.getAbsolutePath());
246 return false;
247 }
248 return languageFilter.accept(dir, name);
249 }
250 };
251 return filter;
252 }
253
254 public void setRenderer(Renderer renderer) {
255 this.renderer = renderer;
256 }
257
258 public boolean isIgnoreLiterals() {
259 return ignoreLiterals;
260 }
261
262 public void setIgnoreLiterals(boolean ignoreLiterals) {
263 this.ignoreLiterals = ignoreLiterals;
264 }
265
266 public boolean isIgnoreIdentifiers() {
267 return ignoreIdentifiers;
268 }
269
270 public void setIgnoreIdentifiers(boolean ignoreIdentifiers) {
271 this.ignoreIdentifiers = ignoreIdentifiers;
272 }
273
274 public boolean isIgnoreAnnotations() {
275 return ignoreAnnotations;
276 }
277
278 public void setIgnoreAnnotations(boolean ignoreAnnotations) {
279 this.ignoreAnnotations = ignoreAnnotations;
280 }
281
282 public boolean isSkipLexicalErrors() {
283 return skipLexicalErrors;
284 }
285
286 public void setSkipLexicalErrors(boolean skipLexicalErrors) {
287 this.skipLexicalErrors = skipLexicalErrors;
288 }
289
290 public List<String> getFiles() {
291 return files;
292 }
293
294 public void setFiles(List<String> files) {
295 this.files = files;
296 }
297
298 public String getURI() {
299 return uri;
300 }
301
302 public void setURI(String uri) {
303 this.uri = uri;
304 }
305
306 public List<String> getExcludes() {
307 return excludes;
308 }
309
310 public void setExcludes(List<String> excludes) {
311 this.excludes = excludes;
312 }
313
314 public boolean isNonRecursive() {
315 return nonRecursive;
316 }
317
318 public void setNonRecursive(boolean nonRecursive) {
319 this.nonRecursive = nonRecursive;
320 }
321
322 public boolean isHelp() {
323 return help;
324 }
325
326 public void setHelp(boolean help) {
327 this.help = help;
328 }
329
330 public String getEncoding() {
331 return encoding;
332 }
333 }