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 }