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