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