View Javadoc

    1   /**
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.cli;
    5
    6   import java.util.Properties;
    7
    8   import net.sourceforge.pmd.PMD;
    9   import net.sourceforge.pmd.lang.Language;
    10  import net.sourceforge.pmd.PropertyDescriptor;
    11  import net.sourceforge.pmd.lang.LanguageVersion;
    12  import net.sourceforge.pmd.renderers.Renderer;
    13  import net.sourceforge.pmd.renderers.RendererFactory;
    14
    15  import com.beust.jcommander.JCommander;
    16  import com.beust.jcommander.ParameterException;
    17
    18  /**
    19   * @author Romain Pelisse <belaran@gmail.com>
    20   *
    21   */
    22  public class PMDCommandLineInterface {
    23
    24  	private static JCommander jcommander = null;
    25  	public static final String PROG_NAME = "pmd";
    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  	public static final int ERROR_STATUS = 1;
    31
    32  	public static PMDParameters extractParameters(PMDParameters arguments, String[] args, String progName) {
    33  		jcommander = new JCommander(arguments);
    34  		jcommander.setProgramName(progName);
    35
    36  		try {
    37  			jcommander.parse(args);
    38  			if (arguments.isHelp()) {
    39  				jcommander.usage();
    40  				System.out.println(buildUsageText());
    41  				setStatusCodeOrExit(0);
    42  			}
    43  		} catch (ParameterException e) {
    44  			jcommander.usage();
    45  			System.out.println(buildUsageText());
    46  			System.out.println(e.getMessage());
    47  			setStatusCodeOrExit(ERROR_STATUS);
    48  		}
    49  		return arguments;
    50  	}
    51
    52  	public static String buildUsageText() {
    53  		final String launchCmd = "java -jar " + jarName();
    54
    55  		StringBuilder usage = new StringBuilder();
    56
    57  		String allCommandsDescription = null;
    58  		if ( jcommander != null && jcommander.getCommands() != null ) {
    59  			for ( String command : jcommander.getCommands().keySet() )
    60  				allCommandsDescription += jcommander.getCommandDescription(command) + PMD.EOL;
    61  		}
    62
    63  		// TODO: Externalize that to a file available within the classpath ? - with a poor's man templating ?
    64  		String fullText = PMD.EOL
    65  		+ "Mandatory arguments:"																+ PMD.EOL
    66  		+ "1) A java source code filename or directory"											+ PMD.EOL
    67  		+ "2) A report format "																	+ PMD.EOL
    68  		+ "3) A ruleset filename or a comma-delimited string of ruleset filenames"				+ PMD.EOL
    69  		+ PMD.EOL
    70  		+ "For example: "																		+ PMD.EOL
    71  		+ "c:\\> " + launchCmd + " -d c:\\my\\source\\code -f html -R java-unusedcode"			+ PMD.EOL
    72  		+ PMD.EOL;
    73
    74  		fullText += supportedVersions() + PMD.EOL;
    75
    76  		if ( allCommandsDescription != null ) {
    77  			fullText += "Optional arguments that may be put before or after the mandatory arguments: "		+ PMD.EOL
    78  					+ allCommandsDescription							 									+ PMD.EOL;
    79  		}
    80
    81  		fullText += "Available report formats and their configuration properties are:"					+ PMD.EOL
    82  		+ getReports()																			+ PMD.EOL
    83  		+ getExamples(launchCmd) + PMD.EOL
    84  		+ PMD.EOL + PMD.EOL;
    85
    86  		return fullText += usage.toString();
    87  	}
    88
    89  	private static String getExamples(String launchCmd) {
    90  		return getWindowsExample(launchCmd) + getUnixExample(launchCmd);
    91  	}
    92
    93  	private static String getWindowsExample(String launchCmd) {
    94  		final String WINDOWS_PROMPT = "c:\\> ";
    95  		final String WINDOWS_PATH_TO_CODE = "c:\\my\\source\\code";
    96
    97  		return "For example on windows: "															+ PMD.EOL
    98  		+ WINDOWS_PROMPT + launchCmd + " -dir" + WINDOWS_PATH_TO_CODE + "-format text -R java-unusedcode,java-imports -version 1.5 -language java -debug" + PMD.EOL
    99  		+ WINDOWS_PROMPT + launchCmd + " -dir" + WINDOWS_PATH_TO_CODE + "-f xml -rulesets java-basic,java-design -encoding UTF-8"					+ PMD.EOL
    100 		+ WINDOWS_PROMPT + launchCmd + " -d" + WINDOWS_PATH_TO_CODE + "-rulesets java-typeresolution -auxclasspath commons-collections.jar;derby.jar" + PMD.EOL
    101 		+ WINDOWS_PROMPT + launchCmd + " -d" + WINDOWS_PATH_TO_CODE + "-f html -R java-typeresolution -auxclasspath file:///C:/my/classpathfile" + PMD.EOL
    102 		+ PMD.EOL;
    103 	}
    104
    105 	private static String getUnixExample(String launchCmd) {
    106 		final String UNIX_PROMPT = "$ ";
    107 		return "For example on *nix: "				+ PMD.EOL
    108 		+ UNIX_PROMPT + launchCmd + " -dir /home/workspace/src/main/java/code -f html -rulesets java-basic,java-design"				+ PMD.EOL
    109 		+ UNIX_PROMPT + launchCmd + " -d ./src/main/java/code -f xslt -R java-basic,java-design -property xsltFilename=my-own.xsl" + PMD.EOL
    110 		+ UNIX_PROMPT + launchCmd + " -d ./src/main/java/code -f html -R java-typeresolution -auxclasspath commons-collections.jar:derby.jar"
    111 		+ PMD.EOL;
    112 	}
    113
    114 	private static String supportedVersions() {
    115 		return "Languages and version suported:" + PMD.EOL +
    116 				Language.commaSeparatedTerseNames(Language.findWithRuleSupport()) + PMD.EOL +
    117 				"Note that some language are not supported by PMD - only by CPD" + PMD.EOL;
    118 	}
    119
    120 	/**
    121 	 * For testing purpose only...
    122 	 *
    123 	 * @param args
    124 	 */
    125 	public static void main(String[] args) {
    126 		System.out.println(PMDCommandLineInterface.buildUsageText());
    127 	}
    128
    129 	public static String jarName() {
    130 		return "pmd-" + PMD.VERSION + ".jar";
    131 	}
    132
    133 	private static String getReports() {
    134 		StringBuilder buf = new StringBuilder();
    135 		for (String reportName : RendererFactory.REPORT_FORMAT_TO_RENDERER.keySet()) {
    136 			Renderer renderer = RendererFactory.createRenderer(reportName, new Properties());
    137 			buf.append("   ").append(reportName).append(": ");
    138 			if (!reportName.equals(renderer.getName())) {
    139 				buf.append(" Deprecated alias for '" + renderer.getName()).append(PMD.EOL);
    140 				continue;
    141 			}
    142 			buf.append(renderer.getDescription()).append(PMD.EOL);
    143
    144 			for (PropertyDescriptor<?> property : renderer.getPropertyDescriptors()) {
    145 			    buf.append("        ").append(property.name()).append(" - ");
    146 			    buf.append(property.description());
    147 			    Object deflt = property.defaultValue();
    148 			    if (deflt != null) buf.append("   default: ").append(deflt);
    149 			    buf.append(PMD.EOL);
    150                         }
    151
    152
    153 		}
    154 		return buf.toString();
    155 	}
    156
    157 	public static void run(String[] args) {
    158 		setStatusCodeOrExit(PMD.run(args));
    159     }
    160
    161 	public static void setStatusCodeOrExit(int status) {
    162 		if ( isExitAfterRunSet() )
    163 			System.exit(status);
    164 		else
    165 			setStatusCode(status);
    166 	}
    167
    168     private static boolean isExitAfterRunSet() {
    169     	return (System.getenv(NO_EXIT_AFTER_RUN) == null ? false : true);
    170     }
    171
    172     private static void setStatusCode(int statusCode) {
    173     	System.setProperty(STATUS_CODE_PROPERTY, Integer.toString(statusCode));
    174     }
    175
    176 }