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