1 package org.apache.maven.plugin.jar;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6
7 import org.apache.maven.plugin.AbstractMojo;
8 import org.apache.maven.plugin.MojoExecutionException;
9
10
11
12
13
14
15
16
17
18
19 @SuppressWarnings( "all" )
20 public class HelpMojo
21 extends AbstractMojo
22 {
23
24
25
26
27
28 private boolean detail;
29
30
31
32
33
34
35 private java.lang.String goal;
36
37
38
39
40
41
42 private int lineLength;
43
44
45
46
47
48
49 private int indentSize;
50
51
52
53 public void execute()
54 throws MojoExecutionException
55 {
56 if ( lineLength <= 0 )
57 {
58 getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." );
59 lineLength = 80;
60 }
61 if ( indentSize <= 0 )
62 {
63 getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." );
64 indentSize = 2;
65 }
66
67 StringBuffer sb = new StringBuffer();
68
69 append( sb, "org.apache.maven.plugins:maven-jar-plugin:2.4", 0 );
70 append( sb, "", 0 );
71
72 append( sb, "Maven JAR Plugin", 0 );
73 append( sb, "Builds a Java Archive (JAR) file from the compiled project classes and resources.", 1 );
74 append( sb, "", 0 );
75
76 if ( goal == null || goal.length() <= 0 )
77 {
78 append( sb, "This plugin has 5 goals:", 0 );
79 append( sb, "", 0 );
80 }
81
82 if ( goal == null || goal.length() <= 0 || "help".equals( goal ) )
83 {
84 append( sb, "jar:help", 0 );
85 append( sb, "Display help information on maven-jar-plugin.\nCall\n\u00a0\u00a0mvn\u00a0jar:help\u00a0-Ddetail=true\u00a0-Dgoal=<goal-name>\nto display parameter details.", 1 );
86 append( sb, "", 0 );
87 if ( detail )
88 {
89 append( sb, "Available parameters:", 1 );
90 append( sb, "", 0 );
91
92 append( sb, "detail (Default: false)", 2 );
93 append( sb, "If true, display all settable properties for each goal.", 3 );
94 append( sb, "Expression: ${detail}", 3 );
95 append( sb, "", 0 );
96
97 append( sb, "goal", 2 );
98 append( sb, "The name of the goal for which to show help. If unspecified, all goals will be displayed.", 3 );
99 append( sb, "Expression: ${goal}", 3 );
100 append( sb, "", 0 );
101
102 append( sb, "indentSize (Default: 2)", 2 );
103 append( sb, "The number of spaces per indentation level, should be positive.", 3 );
104 append( sb, "Expression: ${indentSize}", 3 );
105 append( sb, "", 0 );
106
107 append( sb, "lineLength (Default: 80)", 2 );
108 append( sb, "The maximum length of a display line, should be positive.", 3 );
109 append( sb, "Expression: ${lineLength}", 3 );
110 append( sb, "", 0 );
111 }
112 }
113
114 if ( goal == null || goal.length() <= 0 || "jar".equals( goal ) )
115 {
116 append( sb, "jar:jar", 0 );
117 append( sb, "Build a JAR from the current project.", 1 );
118 append( sb, "", 0 );
119 if ( detail )
120 {
121 append( sb, "Available parameters:", 1 );
122 append( sb, "", 0 );
123
124 append( sb, "archive", 2 );
125 append( sb, "The archive configuration to use. See Maven Archiver Reference.", 3 );
126 append( sb, "", 0 );
127
128 append( sb, "classesDirectory (Default: ${project.build.outputDirectory})", 2 );
129 append( sb, "Directory containing the classes and resource files that should be packaged into the JAR.", 3 );
130 append( sb, "Required: Yes", 3 );
131 append( sb, "", 0 );
132
133 append( sb, "classifier", 2 );
134 append( sb, "Classifier to add to the artifact generated. If given, the artifact will be attached. If this is not given,it will merely be written to the output directory according to the finalName.", 3 );
135 append( sb, "", 0 );
136
137 append( sb, "excludes", 2 );
138 append( sb, "List of files to exclude. Specified as fileset patterns which are relative to the input directory whose contents is being packaged into the JAR.", 3 );
139 append( sb, "", 0 );
140
141 append( sb, "finalName (Default: ${project.build.finalName})", 2 );
142 append( sb, "Name of the generated JAR.", 3 );
143 append( sb, "Required: Yes", 3 );
144 append( sb, "Expression: ${jar.finalName}", 3 );
145 append( sb, "", 0 );
146
147 append( sb, "forceCreation (Default: false)", 2 );
148 append( sb, "Whether creating the archive should be forced.", 3 );
149 append( sb, "Expression: ${jar.forceCreation}", 3 );
150 append( sb, "", 0 );
151
152 append( sb, "includes", 2 );
153 append( sb, "List of files to include. Specified as fileset patterns which are relative to the input directory whose contents is being packaged into the JAR.", 3 );
154 append( sb, "", 0 );
155
156 append( sb, "outputDirectory (Default: ${project.build.directory})", 2 );
157 append( sb, "Directory containing the generated JAR.", 3 );
158 append( sb, "Required: Yes", 3 );
159 append( sb, "", 0 );
160
161 append( sb, "skipIfEmpty (Default: false)", 2 );
162 append( sb, "Skip creating empty archives", 3 );
163 append( sb, "Expression: ${jar.skipIfEmpty}", 3 );
164 append( sb, "", 0 );
165
166 append( sb, "useDefaultManifestFile (Default: false)", 2 );
167 append( sb, "Set this to true to enable the use of the defaultManifestFile.", 3 );
168 append( sb, "Expression: ${jar.useDefaultManifestFile}", 3 );
169 append( sb, "", 0 );
170 }
171 }
172
173 if ( goal == null || goal.length() <= 0 || "sign".equals( goal ) )
174 {
175 append( sb, "jar:sign", 0 );
176 append( sb, "Deprecated. As of version 2.3, this goal is no longer supported in favor of the dedicated maven-jarsigner-plugin.", 1 );
177 if ( detail )
178 {
179 append( sb, "", 0 );
180 append( sb, "Signs a JAR using jarsigner.", 1 );
181 }
182 append( sb, "", 0 );
183 if ( detail )
184 {
185 append( sb, "Available parameters:", 1 );
186 append( sb, "", 0 );
187
188 append( sb, "alias", 2 );
189 append( sb, "See options.", 3 );
190 append( sb, "Required: Yes", 3 );
191 append( sb, "Expression: ${alias}", 3 );
192 append( sb, "", 0 );
193
194 append( sb, "classifier", 2 );
195 append( sb, "Classifier to use for the generated artifact. If not specified, the generated artifact becomes the primary artifact.", 3 );
196 append( sb, "Expression: ${classifier}", 3 );
197 append( sb, "", 0 );
198
199 append( sb, "finalName", 2 );
200 append( sb, "Name of the generated JAR (without classifier and extension).", 3 );
201 append( sb, "Required: Yes", 3 );
202 append( sb, "Expression: ${project.build.finalName}", 3 );
203 append( sb, "", 0 );
204
205 append( sb, "jarPath (Default: ${project.build.directory}/${project.build.finalName}.${project.packaging})", 2 );
206 append( sb, "Path of the jar to sign. When specified, the finalName is ignored.", 3 );
207 append( sb, "", 0 );
208
209 append( sb, "keypass", 2 );
210 append( sb, "See options.", 3 );
211 append( sb, "Expression: ${keypass}", 3 );
212 append( sb, "", 0 );
213
214 append( sb, "keystore", 2 );
215 append( sb, "See options.", 3 );
216 append( sb, "Expression: ${keystore}", 3 );
217 append( sb, "", 0 );
218
219 append( sb, "sigfile", 2 );
220 append( sb, "See options.", 3 );
221 append( sb, "Expression: ${sigfile}", 3 );
222 append( sb, "", 0 );
223
224 append( sb, "signedjar", 2 );
225 append( sb, "See options. Not specifying this argument will sign the jar in-place (your original jar is going to be overwritten).", 3 );
226 append( sb, "Expression: ${signedjar}", 3 );
227 append( sb, "", 0 );
228
229 append( sb, "skip (Default: false)", 2 );
230 append( sb, "Set this to true to disable signing. Useful to speed up build process in development environment.", 3 );
231 append( sb, "Expression: ${maven.jar.sign.skip}", 3 );
232 append( sb, "", 0 );
233
234 append( sb, "storepass", 2 );
235 append( sb, "See options.", 3 );
236 append( sb, "Expression: ${storepass}", 3 );
237 append( sb, "", 0 );
238
239 append( sb, "type", 2 );
240 append( sb, "See options. The corresponding option in the command line is -storetype.", 3 );
241 append( sb, "Expression: ${type}", 3 );
242 append( sb, "", 0 );
243
244 append( sb, "verbose (Default: false)", 2 );
245 append( sb, "Enable verbose. See options.", 3 );
246 append( sb, "Expression: ${verbose}", 3 );
247 append( sb, "", 0 );
248
249 append( sb, "verify (Default: false)", 2 );
250 append( sb, "Automatically verify a jar after signing it. See options.", 3 );
251 append( sb, "Expression: ${verify}", 3 );
252 append( sb, "", 0 );
253
254 append( sb, "workingDirectory (Default: ${basedir})", 2 );
255 append( sb, "The working directory in which the jarsigner executable will be run.", 3 );
256 append( sb, "Required: Yes", 3 );
257 append( sb, "Expression: ${workingdir}", 3 );
258 append( sb, "", 0 );
259 }
260 }
261
262 if ( goal == null || goal.length() <= 0 || "sign-verify".equals( goal ) )
263 {
264 append( sb, "jar:sign-verify", 0 );
265 append( sb, "Deprecated. As of version 2.3, this goal is no longer supported in favor of the dedicated maven-jarsigner-plugin.", 1 );
266 if ( detail )
267 {
268 append( sb, "", 0 );
269 append( sb, "Checks the signature of a signed jar using jarsigner.", 1 );
270 }
271 append( sb, "", 0 );
272 if ( detail )
273 {
274 append( sb, "Available parameters:", 1 );
275 append( sb, "", 0 );
276
277 append( sb, "checkCerts (Default: false)", 2 );
278 append( sb, "Check certificates. Requires setVerbose(). See options.", 3 );
279 append( sb, "Expression: ${checkcerts}", 3 );
280 append( sb, "", 0 );
281
282 append( sb, "errorWhenNotSigned (Default: true)", 2 );
283 append( sb, "When true this will make the execute() operation fail, throwing an exception, when verifying a non signed jar. Primarily to keep backwards compatibility with existing code, and allow reusing the bean in unattended operations when set to false.", 3 );
284 append( sb, "Expression: ${errorWhenNotSigned}", 3 );
285 append( sb, "", 0 );
286
287 append( sb, "finalName", 2 );
288 append( sb, "Name of the generated JAR (without classifier and extension).", 3 );
289 append( sb, "Required: Yes", 3 );
290 append( sb, "Expression: ${project.build.finalName}", 3 );
291 append( sb, "", 0 );
292
293 append( sb, "jarPath", 2 );
294 append( sb, "Path of the signed jar. When specified, the finalName is ignored.", 3 );
295 append( sb, "Expression: ${jarpath}", 3 );
296 append( sb, "", 0 );
297
298 append( sb, "verbose (Default: false)", 2 );
299 append( sb, "Enable verbose See options.", 3 );
300 append( sb, "Expression: ${verbose}", 3 );
301 append( sb, "", 0 );
302
303 append( sb, "workingDirectory (Default: ${basedir})", 2 );
304 append( sb, "The working directory in which the jarsigner executable will be run.", 3 );
305 append( sb, "Required: Yes", 3 );
306 append( sb, "Expression: ${workingdir}", 3 );
307 append( sb, "", 0 );
308 }
309 }
310
311 if ( goal == null || goal.length() <= 0 || "test-jar".equals( goal ) )
312 {
313 append( sb, "jar:test-jar", 0 );
314 append( sb, "Build a JAR of the test classes for the current project.", 1 );
315 append( sb, "", 0 );
316 if ( detail )
317 {
318 append( sb, "Available parameters:", 1 );
319 append( sb, "", 0 );
320
321 append( sb, "archive", 2 );
322 append( sb, "The archive configuration to use. See Maven Archiver Reference.", 3 );
323 append( sb, "", 0 );
324
325 append( sb, "excludes", 2 );
326 append( sb, "List of files to exclude. Specified as fileset patterns which are relative to the input directory whose contents is being packaged into the JAR.", 3 );
327 append( sb, "", 0 );
328
329 append( sb, "finalName (Default: ${project.build.finalName})", 2 );
330 append( sb, "Name of the generated JAR.", 3 );
331 append( sb, "Required: Yes", 3 );
332 append( sb, "Expression: ${jar.finalName}", 3 );
333 append( sb, "", 0 );
334
335 append( sb, "forceCreation (Default: false)", 2 );
336 append( sb, "Whether creating the archive should be forced.", 3 );
337 append( sb, "Expression: ${jar.forceCreation}", 3 );
338 append( sb, "", 0 );
339
340 append( sb, "includes", 2 );
341 append( sb, "List of files to include. Specified as fileset patterns which are relative to the input directory whose contents is being packaged into the JAR.", 3 );
342 append( sb, "", 0 );
343
344 append( sb, "outputDirectory (Default: ${project.build.directory})", 2 );
345 append( sb, "Directory containing the generated JAR.", 3 );
346 append( sb, "Required: Yes", 3 );
347 append( sb, "", 0 );
348
349 append( sb, "skip", 2 );
350 append( sb, "Set this to true to bypass unit tests entirely. Its use is NOT RECOMMENDED, but quite convenient on occasion.", 3 );
351 append( sb, "Expression: ${maven.test.skip}", 3 );
352 append( sb, "", 0 );
353
354 append( sb, "skipIfEmpty (Default: false)", 2 );
355 append( sb, "Skip creating empty archives", 3 );
356 append( sb, "Expression: ${jar.skipIfEmpty}", 3 );
357 append( sb, "", 0 );
358
359 append( sb, "testClassesDirectory (Default: ${project.build.testOutputDirectory})", 2 );
360 append( sb, "Directory containing the test classes and resource files that should be packaged into the JAR.", 3 );
361 append( sb, "Required: Yes", 3 );
362 append( sb, "", 0 );
363
364 append( sb, "useDefaultManifestFile (Default: false)", 2 );
365 append( sb, "Set this to true to enable the use of the defaultManifestFile.", 3 );
366 append( sb, "Expression: ${jar.useDefaultManifestFile}", 3 );
367 append( sb, "", 0 );
368 }
369 }
370
371 if ( getLog().isInfoEnabled() )
372 {
373 getLog().info( sb.toString() );
374 }
375 }
376
377
378
379
380
381
382
383
384
385
386 private static String repeat( String str, int repeat )
387 {
388 StringBuffer buffer = new StringBuffer( repeat * str.length() );
389
390 for ( int i = 0; i < repeat; i++ )
391 {
392 buffer.append( str );
393 }
394
395 return buffer.toString();
396 }
397
398
399
400
401
402
403
404
405
406 private void append( StringBuffer sb, String description, int indent )
407 {
408 for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); )
409 {
410 sb.append( it.next().toString() ).append( '\n' );
411 }
412 }
413
414
415
416
417
418
419
420
421
422
423
424 private static List toLines( String text, int indent, int indentSize, int lineLength )
425 {
426 List<String> lines = new ArrayList<String>();
427
428 String ind = repeat( "\t", indent );
429 String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
430 for ( int i = 0; i < plainLines.length; i++ )
431 {
432 toLines( lines, ind + plainLines[i], indentSize, lineLength );
433 }
434
435 return lines;
436 }
437
438
439
440
441
442
443
444
445
446 private static void toLines( List<String> lines, String line, int indentSize, int lineLength )
447 {
448 int lineIndent = getIndentLevel( line );
449 StringBuffer buf = new StringBuffer( 256 );
450 String[] tokens = line.split( " +" );
451 for ( int i = 0; i < tokens.length; i++ )
452 {
453 String token = tokens[i];
454 if ( i > 0 )
455 {
456 if ( buf.length() + token.length() >= lineLength )
457 {
458 lines.add( buf.toString() );
459 buf.setLength( 0 );
460 buf.append( repeat( " ", lineIndent * indentSize ) );
461 }
462 else
463 {
464 buf.append( ' ' );
465 }
466 }
467 for ( int j = 0; j < token.length(); j++ )
468 {
469 char c = token.charAt( j );
470 if ( c == '\t' )
471 {
472 buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
473 }
474 else if ( c == '\u00A0' )
475 {
476 buf.append( ' ' );
477 }
478 else
479 {
480 buf.append( c );
481 }
482 }
483 }
484 lines.add( buf.toString() );
485 }
486
487
488
489
490
491
492
493 private static int getIndentLevel( String line )
494 {
495 int level = 0;
496 for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
497 {
498 level++;
499 }
500 for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
501 {
502 if ( line.charAt( i ) == '\t' )
503 {
504 level++;
505 break;
506 }
507 }
508 return level;
509 }
510 }