1
2
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
73
74 CPDConfiguration.setSystemProperties(arguments);
75 CPD cpd = new CPD(arguments);
76
77
78 if ( null != arguments.getFiles() && ! arguments.getFiles().isEmpty() )
79 {
80 addSourcesFilesToCPD(arguments.getFiles(), arguments.filenameFilter(), cpd, !arguments.isNonRecursive());
81 }
82
83
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
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 }