/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.util.FileUtil;
import net.sourceforge.pmd.util.database.DBURI;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
public class CPDCommandLineInterface {
private static final Logger LOGGER = Logger.getLogger(CPDCommandLineInterface.class.getName());
private static final int DUPLICATE_CODE_FOUND = 4;
private static final int ERROR_STATUS = 1;
public static final String NO_EXIT_AFTER_RUN = "net.sourceforge.pmd.cli.noExit";
public static final String STATUS_CODE_PROPERTY = "net.sourceforge.pmd.cli.status";
private static final String PROGRAM_NAME = "cpd";
private CPDCommandLineInterface() { }
public static void setStatusCodeOrExit(int status) {
if (isExitAfterRunSet()) {
System.exit(status);
} else {
setStatusCode(status);
}
}
private static boolean isExitAfterRunSet() {
String noExit = System.getenv(NO_EXIT_AFTER_RUN);
if (noExit == null) {
noExit = System.getProperty(NO_EXIT_AFTER_RUN);
}
return (noExit == null ? true : false);
}
private static void setStatusCode(int statusCode) {
System.setProperty(STATUS_CODE_PROPERTY, Integer.toString(statusCode));
}
public static void main(String[] args) {
CPDConfiguration arguments = new CPDConfiguration();
JCommander jcommander = new JCommander(arguments);
jcommander.setProgramName(PROGRAM_NAME);
try {
jcommander.parse(args);
if (arguments.isHelp()) {
jcommander.usage();
System.out.println(buildUsageText());
setStatusCodeOrExit(ERROR_STATUS);
return;
}
} catch (ParameterException e) {
jcommander.usage();
System.out.println(buildUsageText());
System.err.println(" " + e.getMessage());
setStatusCodeOrExit(ERROR_STATUS);
return;
}
arguments.postContruct();
// Pass extra parameters as System properties to allow language
// implementation to retrieve their associate values...
CPDConfiguration.setSystemProperties(arguments);
CPD cpd = new CPD(arguments);
try {
addSourceFilesToCPD(cpd, arguments);
cpd.go();
System.out.println(arguments.getRenderer().render(cpd.getMatches()));
if (cpd.getMatches().hasNext()) {
if (arguments.isFailOnViolation()) {
setStatusCodeOrExit(DUPLICATE_CODE_FOUND);
} else {
setStatusCodeOrExit(0);
}
} else {
setStatusCodeOrExit(0);
}
} catch (RuntimeException e) {
e.printStackTrace();
setStatusCodeOrExit(ERROR_STATUS);
}
}
public static void addSourceFilesToCPD(CPD cpd, CPDConfiguration arguments) {
// Add files
if (null != arguments.getFiles() && !arguments.getFiles().isEmpty()) {
addSourcesFilesToCPD(arguments.getFiles(), cpd, !arguments.isNonRecursive());
}
// Add Database URIS
if (null != arguments.getURI() && !"".equals(arguments.getURI())) {
addSourceURIToCPD(arguments.getURI(), cpd);
}
if (null != arguments.getFileListPath() && !"".equals(arguments.getFileListPath())) {
addFilesFromFilelist(arguments.getFileListPath(), cpd, !arguments.isNonRecursive());
}
}
private static void addSourcesFilesToCPD(List<File> files, CPD cpd, boolean recursive) {
try {
for (File file : files) {
if (!file.exists()) {
throw new FileNotFoundException("Couldn't find directory/file '" + file + "'");
} else if (file.isDirectory()) {
if (recursive) {
cpd.addRecursively(file);
} else {
cpd.addAllInDirectory(file);
}
} else {
cpd.add(file);
}
}
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
private static void addFilesFromFilelist(String inputFilePath, CPD cpd, boolean recursive) {
File file = new File(inputFilePath);
List<File> files = new ArrayList<>();
try {
if (!file.exists()) {
throw new FileNotFoundException("Couldn't find directory/file '" + inputFilePath + "'");
} else {
String filePaths = FileUtil.readFilelist(new File(inputFilePath));
for (String param : filePaths.split(",")) {
File fileToAdd = new File(param);
if (!fileToAdd.exists()) {
throw new FileNotFoundException("Couldn't find directory/file '" + param + "'");
}
files.add(fileToAdd);
}
addSourcesFilesToCPD(files, cpd, recursive);
}
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
private static void addSourceURIToCPD(String uri, CPD cpd) {
try {
LOGGER.fine(String.format("Attempting DBURI=%s", uri));
DBURI dburi = new DBURI(uri);
LOGGER.fine(String.format("Initialised DBURI=%s", dburi));
LOGGER.fine(
String.format("Adding DBURI=%s with DBType=%s", dburi.toString(), dburi.getDbType().toString()));
cpd.add(dburi);
} catch (IOException e) {
throw new IllegalStateException("uri=" + uri, e);
} catch (URISyntaxException ex) {
throw new IllegalStateException("uri=" + uri, ex);
} catch (Exception ex) {
throw new IllegalStateException("uri=" + uri, ex);
}
}
public static String buildUsageText() {
String helpText = " For example on Windows:" + PMD.EOL;
helpText += " C:\\>" + "pmd-bin-" + PMD.VERSION + "\\bin\\cpd.bat"
+ " --minimum-tokens 100 --files c:\\jdk18\\src\\java" + PMD.EOL;
helpText += PMD.EOL;
helpText += " For example on *nix:" + PMD.EOL;
helpText += " $ " + "pmd-bin-" + PMD.VERSION + "/bin/run.sh cpd"
+ " --minimum-tokens 100 --files /path/to/java/code" + PMD.EOL;
helpText += PMD.EOL;
helpText += " Supported languages: " + Arrays.toString(LanguageFactory.supportedLanguages) + PMD.EOL;
helpText += " Formats: " + Arrays.toString(CPDConfiguration.getRenderers()) + PMD.EOL;
return helpText;
}
}