View Javadoc

1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.cpd;
5   
6   import java.io.File;
7   import java.io.FileNotFoundException;
8   import java.io.IOException;
9   import java.util.HashMap;
10  import java.util.HashSet;
11  import java.util.Iterator;
12  import java.util.List;
13  import java.util.Map;
14  import java.util.Set;
15  
16  public class CPD {
17  
18      private Map source = new HashMap();
19      private CPDListener listener = new CPDNullListener();
20      private Tokens tokens = new Tokens();
21      private int minimumTileSize;
22      private MatchAlgorithm matchAlgorithm;
23      private Language language;
24      private boolean skipDuplicates;
25  
26      public CPD(int minimumTileSize, Language language) {
27          this.minimumTileSize = minimumTileSize;
28          this.language = language;
29      }
30  
31      public void skipDuplicates() {
32          this.skipDuplicates = true;
33      }
34  
35      public void setCpdListener(CPDListener cpdListener) {
36          this.listener = cpdListener;
37      }
38  
39      public void go() {
40          TokenEntry.clearImages();
41          matchAlgorithm = new MatchAlgorithm(source, tokens, minimumTileSize, listener);
42          matchAlgorithm.findMatches();
43      }
44  
45      public Iterator getMatches() {
46          return matchAlgorithm.matches();
47      }
48  
49      public void add(File file) throws IOException {
50          add(1, file);
51      }
52  
53      public void addAllInDirectory(String dir) throws IOException {
54          addDirectory(dir, false);
55      }
56  
57      public void addRecursively(String dir) throws IOException {
58          addDirectory(dir, true);
59      }
60  
61      public void add(List files) throws IOException {
62          for (Iterator i = files.iterator(); i.hasNext();) {
63              add(files.size(), (File) i.next());
64          }
65      }
66  
67      private void addDirectory(String dir, boolean recurse) throws IOException {
68          if (!(new File(dir)).exists()) {
69              throw new FileNotFoundException("Couldn't find directory " + dir);
70          }
71          FileFinder finder = new FileFinder();
72          // TODO - could use SourceFileSelector here
73          add(finder.findFilesFrom(dir, language.getFileFilter(), recurse));
74      }
75  
76      private Set current = new HashSet();
77  
78      private void add(int fileCount, File file) throws IOException {
79  
80          if (skipDuplicates) {
81              // TODO refactor this thing into a separate class
82              String signature = file.getName() + '_' + file.length();
83              if (current.contains(signature)) {
84                  System.out.println("Skipping " + file.getAbsolutePath() + " since it appears to be a duplicate file and --skip-duplicate-files is set");
85                  return;
86              }
87              current.add(signature);
88          }
89  
90          if (!file.getCanonicalPath().equals(file.getAbsolutePath())) {
91              System.out.println("Skipping " + file + " since it appears to be a symlink");
92              return;
93          }
94  
95          listener.addedFile(fileCount, file);
96          SourceCode sourceCode = new SourceCode(new SourceCode.FileCodeLoader(file));
97          language.getTokenizer().tokenize(sourceCode, tokens);
98          source.put(sourceCode.getFileName(), sourceCode);
99      }
100 
101     public static Renderer getRendererFromString(String name) {
102         if (name.equalsIgnoreCase("text") || name.equals("")) {
103             return new SimpleRenderer();
104         }
105         try {
106             return (Renderer) Class.forName(name).newInstance();
107         } catch (Exception e) {
108             System.out.println("Can't find class '" + name + "', defaulting to SimpleRenderer.");
109         }
110         return new SimpleRenderer();
111     }
112 
113     private static boolean findBooleanSwitch(String[] args, String name) {
114         for (int i = 0; i < args.length; i++) {
115             if (args[i].equals(name)) {
116                 return true;
117             }
118         }
119         return false;
120     }
121 
122     private static String findRequiredStringValue(String[] args, String name) {
123         for (int i = 0; i < args.length; i++) {
124             if (args[i].equals(name)) {
125                 return args[i + 1];
126             }
127         }
128         System.out.println("No " + name + " value passed in");
129         usage();
130         throw new RuntimeException();
131     }
132 
133     private static String findOptionalStringValue(String[] args, String name, String defaultValue) {
134         for (int i = 0; i < args.length; i++) {
135             if (args[i].equals(name)) {
136                 return args[i + 1];
137             }
138         }
139         return defaultValue;
140     }
141 
142     public static void main(String[] args) {
143         if (args.length == 0) {
144             usage();
145         }
146 
147         try {
148             boolean skipDuplicateFiles = findBooleanSwitch(args, "--skip-duplicate-files");
149             String pathToFiles = findRequiredStringValue(args, "--files");
150             String languageString = findOptionalStringValue(args, "--language", "java");
151             String formatString = findOptionalStringValue(args, "--format", "text");
152             int minimumTokens = Integer.parseInt(findRequiredStringValue(args, "--minimum-tokens"));
153             LanguageFactory f = new LanguageFactory();
154             Language language = f.createLanguage(languageString);
155             Renderer renderer = CPD.getRendererFromString(formatString);
156             CPD cpd = new CPD(minimumTokens, language);
157             if (skipDuplicateFiles) {
158                 cpd.skipDuplicates();
159             }
160             cpd.addRecursively(pathToFiles);
161             cpd.go();
162             System.out.println(renderer.render(cpd.getMatches()));
163         } catch (Exception e) {
164             e.printStackTrace();
165         }
166     }
167 
168     private static void usage() {
169         System.out.println("Usage:");
170         System.out.println(" java net.sourceforge.pmd.cpd.CPD --minimum-tokens xxx --files xxx [--language xxx] [--format (xml|text|csv)] [--skip-duplicate-files] ");
171         System.out.println("i.e: ");
172         System.out.println(" java net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files c://jdk14//src//java ");
173         System.out.println("or: ");
174         System.out.println(" java net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files /path/to/c/code --language c ");
175         System.out.println("or: ");
176         System.out.println(" java net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files /path/to/java/code --format xml");
177     }
178 
179 }