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.FilenameFilter;
9   import java.io.IOException;
10  import java.net.URISyntaxException;
11  import java.util.Arrays;
12  import java.util.List;
13  import java.util.logging.Logger;
14  
15  import net.sourceforge.pmd.PMD;
16  import net.sourceforge.pmd.util.database.DBURI;
17  
18  import com.beust.jcommander.JCommander;
19  import com.beust.jcommander.ParameterException;
20  
21  public class CPDCommandLineInterface {
22      private final static Logger LOGGER = Logger.getLogger(CPDCommandLineInterface.class.getName());
23  
24  	private static final int DUPLICATE_CODE_FOUND = 4;
25  	private static final int ERROR_STATUS = 1;
26  
27  	public static final String NO_EXIT_AFTER_RUN = "net.sourceforge.pmd.cli.noExit";
28  	public static final String STATUS_CODE_PROPERTY = "net.sourceforge.pmd.cli.status";
29  
30  	private static final String PROGRAM_NAME = "cpd";
31  
32  	public static void setStatusCodeOrExit(int status) {
33  		if (isExitAfterRunSet()) {
34  			System.exit(status);
35  		} else {
36  			setStatusCode(status);
37  		}
38  	}
39  
40  	private static boolean isExitAfterRunSet() {
41  	    String noExit = System.getenv(NO_EXIT_AFTER_RUN);
42  	    if (noExit == null) {
43  	        noExit = System.getProperty(NO_EXIT_AFTER_RUN);
44  	    }
45  		return (noExit == null ? true : false);
46  	}
47  
48  	private static void setStatusCode(int statusCode) {
49  		System.setProperty(STATUS_CODE_PROPERTY, Integer.toString(statusCode));
50  	}
51  
52  	public static void main(String[] args) {
53  		CPDConfiguration arguments = new CPDConfiguration();
54  		JCommander jcommander = new JCommander(arguments);
55  		jcommander.setProgramName(PROGRAM_NAME);
56  
57  		try {
58  			jcommander.parse(args);
59  			if (arguments.isHelp()) {
60  				jcommander.usage();
61  				System.out.println(buildUsageText());
62  				setStatusCodeOrExit(ERROR_STATUS);
63  				return;
64  			}
65  		} catch (ParameterException e) {
66  			jcommander.usage();
67  			System.out.println(buildUsageText());
68  			System.err.println(" " + e.getMessage());
69  			setStatusCodeOrExit(ERROR_STATUS);
70  			return;
71  		}
72  		arguments.postContruct();
73  		// Pass extra parameters as System properties to allow language
74  		// implementation to retrieve their associate values...
75  		CPDConfiguration.setSystemProperties(arguments);
76  		CPD cpd = new CPD(arguments);
77  
78          try {
79              // Add files
80              if (null != arguments.getFiles() && !arguments.getFiles().isEmpty()) {
81                  addSourcesFilesToCPD(arguments.getFiles(), arguments.filenameFilter(), cpd, !arguments.isNonRecursive());
82              }
83  
84              // Add Database URIS
85              if (null != arguments.getURI() && !"".equals(arguments.getURI())) {
86                  addSourceURIToCPD(arguments.getURI(), cpd);
87              }
88  
89              cpd.go();
90              if (cpd.getMatches().hasNext()) {
91                  System.out.println(arguments.getRenderer().render(cpd.getMatches()));
92                  if (arguments.isFailOnViolation()) {
93                      setStatusCodeOrExit(DUPLICATE_CODE_FOUND);
94                  } else {
95                      setStatusCodeOrExit(0);
96                  }
97              } else {
98                  setStatusCodeOrExit(0);
99              }
100         } catch (RuntimeException e) {
101             e.printStackTrace();
102             setStatusCodeOrExit(ERROR_STATUS);
103         }
104     }
105 
106 	private static void addSourcesFilesToCPD(List<File> files, FilenameFilter filter, CPD cpd, boolean recursive) {
107 		try {
108 			for (File file : files) {
109 				if (!file.exists()) {
110 					throw new FileNotFoundException("Couldn't find directory/file '" + file + "'");
111 				} else if (file.isDirectory()) {
112 					if (recursive) {
113 						cpd.addRecursively(file);
114 					} else {
115 						cpd.addAllInDirectory(file);
116 					}
117 				} else {
118 					//Add a single file if it is accepted by the file filter
119 					File directory = file.getAbsoluteFile().getParentFile();
120 					String filename = file.getName();
121 
122 					if (filter.accept(directory, filename)) {
123 						cpd.add(file);
124 					}
125 				}
126 			}
127 		} catch (IOException e) {
128 			throw new IllegalStateException(e);
129 		}
130 	}
131 
132 	private static void addSourceURIToCPD(String uri, CPD cpd) {
133           try {
134                         LOGGER.fine(String.format("Attempting DBURI=%s" , uri));
135                             DBURI dburi = new DBURI(uri);
136                             LOGGER.fine(String.format("Initialised DBURI=%s"
137                                                  , dburi
138                                                  )
139                                       );
140                             LOGGER.fine(String.format("Adding DBURI=%s with DBType=%s"
141                                                  , dburi.toString() 
142                                                  , dburi.getDbType().toString()
143                                                  )
144                                       );
145                             cpd.add(dburi);
146               } catch (IOException e) {
147                       throw new IllegalStateException( "uri="+uri, e);
148               } catch (URISyntaxException ex) {
149                       throw new IllegalStateException( "uri="+uri, ex);
150               } catch (Exception ex) {
151                 throw new IllegalStateException( "uri="+uri, ex);
152               }
153 	}
154 
155     public static String buildUsageText() {
156         String helpText = " For example on Windows:" + PMD.EOL;
157 
158         helpText += " C:\\>" + "pmd-bin-" + PMD.VERSION + "\\bin\\cpd.bat"
159                 + " --minimum-tokens 100 --files c:\\jdk18\\src\\java" + PMD.EOL;
160         helpText += PMD.EOL;
161 
162         helpText += " For example on *nix:" + PMD.EOL;
163         helpText += " $ " + "pmd-bin-" + PMD.VERSION + "/bin/run.sh cpd"
164                 + " --minimum-tokens 100 --files /path/to/java/code" + PMD.EOL;
165         helpText += PMD.EOL;
166 
167         helpText += " Supported languages: " + Arrays.toString(LanguageFactory.supportedLanguages) + PMD.EOL;
168         helpText += " Formats: " + Arrays.toString(CPDConfiguration.getRenderers()) + PMD.EOL;
169         return helpText;
170     }
171 
172 }