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