1 package org.apache.maven.plugin.gpg;
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-gpg-plugin:1.4", 0 );
70 append( sb, "", 0 );
71
72 append( sb, "Maven GPG Plugin", 0 );
73 append( sb, "Signs the project artifacts with GnuPG.", 1 );
74 append( sb, "", 0 );
75
76 if ( goal == null || goal.length() <= 0 )
77 {
78 append( sb, "This plugin has 3 goals:", 0 );
79 append( sb, "", 0 );
80 }
81
82 if ( goal == null || goal.length() <= 0 || "help".equals( goal ) )
83 {
84 append( sb, "gpg:help", 0 );
85 append( sb, "Display help information on maven-gpg-plugin.\nCall\n\u00a0\u00a0mvn\u00a0gpg: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 || "sign".equals( goal ) )
115 {
116 append( sb, "gpg:sign", 0 );
117 append( sb, "Sign project artifact, the POM, and attached artifacts with GnuPG for deployment.", 1 );
118 append( sb, "", 0 );
119 if ( detail )
120 {
121 append( sb, "Available parameters:", 1 );
122 append( sb, "", 0 );
123
124 append( sb, "ascDirectory (Default: ${project.build.directory}/gpg)", 2 );
125 append( sb, "The directory where to store signature files.", 3 );
126 append( sb, "", 0 );
127
128 append( sb, "defaultKeyring (Default: true)", 2 );
129 append( sb, "Whether to add the default keyrings from gpg\'s home directory to the list of used keyrings.", 3 );
130 append( sb, "Expression: ${gpg.defaultKeyring}", 3 );
131 append( sb, "", 0 );
132
133 append( sb, "excludes", 2 );
134 append( sb, "A list of files to exclude from being signed. Can contain Ant-style wildcards and double wildcards. The default excludes are **/*.md5 **/*.sha1 **/*.asc.", 3 );
135 append( sb, "", 0 );
136
137 append( sb, "executable", 2 );
138 append( sb, "The path to the GnuPG executable to use for artifact signing. Defaults to either \'gpg\' or \'gpg.exe\' depending on the operating system.", 3 );
139 append( sb, "Expression: ${gpg.executable}", 3 );
140 append( sb, "", 0 );
141
142 append( sb, "homedir", 2 );
143 append( sb, "The directory from which gpg will load keyrings. If not specified, gpg will use the value configured for its installation, e.g. ~/.gnupg or %APPDATA%/gnupg.", 3 );
144 append( sb, "Expression: ${gpg.homedir}", 3 );
145 append( sb, "", 0 );
146
147 append( sb, "keyname", 2 );
148 append( sb, "The \'name\' of the key to sign with. Passed to gpg as --local-user.", 3 );
149 append( sb, "Expression: ${gpg.keyname}", 3 );
150 append( sb, "", 0 );
151
152 append( sb, "passphrase", 2 );
153 append( sb, "The passphrase to use when signing.", 3 );
154 append( sb, "Expression: ${gpg.passphrase}", 3 );
155 append( sb, "", 0 );
156
157 append( sb, "publicKeyring", 2 );
158 append( sb, "The path to a public keyring to add to the list of keyrings. By default, only the pubring.gpg from gpg\'s home directory is considered. Use this option (and defaultKeyring if required) to use a different public key. Note: Relative paths are resolved against gpg\'s home directory, not the project base directory.", 3 );
159 append( sb, "Expression: ${gpg.publicKeyring}", 3 );
160 append( sb, "", 0 );
161
162 append( sb, "secretKeyring", 2 );
163 append( sb, "The path to a secret keyring to add to the list of keyrings. By default, only the secring.gpg from gpg\'s home directory is considered. Use this option (in combination with publicKeyring and defaultKeyring if required) to use a different secret key. Note: Relative paths are resolved against gpg\'s home directory, not the project base directory.", 3 );
164 append( sb, "Expression: ${gpg.secretKeyring}", 3 );
165 append( sb, "", 0 );
166
167 append( sb, "skip (Default: false)", 2 );
168 append( sb, "Skip doing the gpg signing.", 3 );
169 append( sb, "Expression: ${gpg.skip}", 3 );
170 append( sb, "", 0 );
171
172 append( sb, "useAgent (Default: false)", 2 );
173 append( sb, "Passes --use-agent or --no-use-agent to gpg. If using an agent, the passphrase is optional as the agent will provide it. For gpg2, specify true as --no-use-agent was removed in gpg2 and doesn\'t ask for a passphrase anymore.", 3 );
174 append( sb, "Expression: ${gpg.useagent}", 3 );
175 append( sb, "", 0 );
176 }
177 }
178
179 if ( goal == null || goal.length() <= 0 || "sign-and-deploy-file".equals( goal ) )
180 {
181 append( sb, "gpg:sign-and-deploy-file", 0 );
182 append( sb, "Signs artifacts and installs the artifact in the remote repository.", 1 );
183 append( sb, "", 0 );
184 if ( detail )
185 {
186 append( sb, "Available parameters:", 1 );
187 append( sb, "", 0 );
188
189 append( sb, "artifactId", 2 );
190 append( sb, "ArtifactId of the artifact to be deployed. Retrieved from POM file if specified.", 3 );
191 append( sb, "Expression: ${artifactId}", 3 );
192 append( sb, "", 0 );
193
194 append( sb, "ascDirectory", 2 );
195 append( sb, "The directory where to store signature files.", 3 );
196 append( sb, "Expression: ${gpg.ascDirectory}", 3 );
197 append( sb, "", 0 );
198
199 append( sb, "classifier", 2 );
200 append( sb, "Add classifier to the artifact", 3 );
201 append( sb, "Expression: ${classifier}", 3 );
202 append( sb, "", 0 );
203
204 append( sb, "classifiers", 2 );
205 append( sb, "A comma separated list of classifiers for each of the extra side artifacts to deploy. If there is a mis-match in the number of entries in files or types, then an error will be raised.", 3 );
206 append( sb, "Expression: ${classifiers}", 3 );
207 append( sb, "", 0 );
208
209 append( sb, "defaultKeyring (Default: true)", 2 );
210 append( sb, "Whether to add the default keyrings from gpg\'s home directory to the list of used keyrings.", 3 );
211 append( sb, "Expression: ${gpg.defaultKeyring}", 3 );
212 append( sb, "", 0 );
213
214 append( sb, "description", 2 );
215 append( sb, "Description passed to a generated POM file (in case of generatePom=true).", 3 );
216 append( sb, "Expression: ${generatePom.description}", 3 );
217 append( sb, "", 0 );
218
219 append( sb, "executable", 2 );
220 append( sb, "The path to the GnuPG executable to use for artifact signing. Defaults to either \'gpg\' or \'gpg.exe\' depending on the operating system.", 3 );
221 append( sb, "Expression: ${gpg.executable}", 3 );
222 append( sb, "", 0 );
223
224 append( sb, "file", 2 );
225 append( sb, "File to be deployed.", 3 );
226 append( sb, "Required: Yes", 3 );
227 append( sb, "Expression: ${file}", 3 );
228 append( sb, "", 0 );
229
230 append( sb, "files", 2 );
231 append( sb, "A comma separated list of files for each of the extra side artifacts to deploy. If there is a mis-match in the number of entries in types or classifiers, then an error will be raised.", 3 );
232 append( sb, "Expression: ${files}", 3 );
233 append( sb, "", 0 );
234
235 append( sb, "generatePom (Default: true)", 2 );
236 append( sb, "Upload a POM for this artifact. Will generate a default POM if none is supplied with the pomFile argument.", 3 );
237 append( sb, "Expression: ${generatePom}", 3 );
238 append( sb, "", 0 );
239
240 append( sb, "groupId", 2 );
241 append( sb, "GroupId of the artifact to be deployed. Retrieved from POM file if specified.", 3 );
242 append( sb, "Expression: ${groupId}", 3 );
243 append( sb, "", 0 );
244
245 append( sb, "homedir", 2 );
246 append( sb, "The directory from which gpg will load keyrings. If not specified, gpg will use the value configured for its installation, e.g. ~/.gnupg or %APPDATA%/gnupg.", 3 );
247 append( sb, "Expression: ${gpg.homedir}", 3 );
248 append( sb, "", 0 );
249
250 append( sb, "javadoc", 2 );
251 append( sb, "The bundled API docs for the artifact.", 3 );
252 append( sb, "Expression: ${javadoc}", 3 );
253 append( sb, "", 0 );
254
255 append( sb, "keyname", 2 );
256 append( sb, "The \'name\' of the key to sign with. Passed to gpg as --local-user.", 3 );
257 append( sb, "Expression: ${gpg.keyname}", 3 );
258 append( sb, "", 0 );
259
260 append( sb, "packaging", 2 );
261 append( sb, "Type of the artifact to be deployed. Retrieved from POM file if specified. Defaults to file extension if not specified via command line or POM.", 3 );
262 append( sb, "Expression: ${packaging}", 3 );
263 append( sb, "", 0 );
264
265 append( sb, "passphrase", 2 );
266 append( sb, "The passphrase to use when signing.", 3 );
267 append( sb, "Expression: ${gpg.passphrase}", 3 );
268 append( sb, "", 0 );
269
270 append( sb, "pomFile", 2 );
271 append( sb, "Location of an existing POM file to be deployed alongside the main artifact, given by the ${file} parameter.", 3 );
272 append( sb, "Expression: ${pomFile}", 3 );
273 append( sb, "", 0 );
274
275 append( sb, "publicKeyring", 2 );
276 append( sb, "The path to a public keyring to add to the list of keyrings. By default, only the pubring.gpg from gpg\'s home directory is considered. Use this option (and defaultKeyring if required) to use a different public key. Note: Relative paths are resolved against gpg\'s home directory, not the project base directory.", 3 );
277 append( sb, "Expression: ${gpg.publicKeyring}", 3 );
278 append( sb, "", 0 );
279
280 append( sb, "repositoryId (Default: remote-repository)", 2 );
281 append( sb, "Server Id to map on the <id> under <server> section of settings.xml. In most cases, this parameter will be required for authentication.", 3 );
282 append( sb, "Required: Yes", 3 );
283 append( sb, "Expression: ${repositoryId}", 3 );
284 append( sb, "", 0 );
285
286 append( sb, "repositoryLayout (Default: default)", 2 );
287 append( sb, "The type of remote repository layout to deploy to. Try legacy for a Maven 1.x-style repository layout.", 3 );
288 append( sb, "Expression: ${repositoryLayout}", 3 );
289 append( sb, "", 0 );
290
291 append( sb, "retryFailedDeploymentCount (Default: 1)", 2 );
292 append( sb, "Parameter used to control how many times a failed deployment will be retried before giving up and failing. If a value outside the range 1-10 is specified it will be pulled to the nearest value within the range 1-10.", 3 );
293 append( sb, "Expression: ${retryFailedDeploymentCount}", 3 );
294 append( sb, "", 0 );
295
296 append( sb, "secretKeyring", 2 );
297 append( sb, "The path to a secret keyring to add to the list of keyrings. By default, only the secring.gpg from gpg\'s home directory is considered. Use this option (in combination with publicKeyring and defaultKeyring if required) to use a different secret key. Note: Relative paths are resolved against gpg\'s home directory, not the project base directory.", 3 );
298 append( sb, "Expression: ${gpg.secretKeyring}", 3 );
299 append( sb, "", 0 );
300
301 append( sb, "sources", 2 );
302 append( sb, "The bundled sources for the artifact.", 3 );
303 append( sb, "Expression: ${sources}", 3 );
304 append( sb, "", 0 );
305
306 append( sb, "types", 2 );
307 append( sb, "A comma separated list of types for each of the extra side artifacts to deploy. If there is a mis-match in the number of entries in files or classifiers, then an error will be raised.", 3 );
308 append( sb, "Expression: ${types}", 3 );
309 append( sb, "", 0 );
310
311 append( sb, "uniqueVersion (Default: true)", 2 );
312 append( sb, "Whether to deploy snapshots with a unique version or not.", 3 );
313 append( sb, "Expression: ${uniqueVersion}", 3 );
314 append( sb, "", 0 );
315
316 append( sb, "updateReleaseInfo (Default: false)", 2 );
317 append( sb, "Parameter used to update the metadata to make the artifact as release.", 3 );
318 append( sb, "Expression: ${updateReleaseInfo}", 3 );
319 append( sb, "", 0 );
320
321 append( sb, "url", 2 );
322 append( sb, "URL where the artifact will be deployed.\nie ( file:///C:/m2-repo or scp://host.com/path/to/repo )", 3 );
323 append( sb, "Required: Yes", 3 );
324 append( sb, "Expression: ${url}", 3 );
325 append( sb, "", 0 );
326
327 append( sb, "useAgent (Default: false)", 2 );
328 append( sb, "Passes --use-agent or --no-use-agent to gpg. If using an agent, the passphrase is optional as the agent will provide it. For gpg2, specify true as --no-use-agent was removed in gpg2 and doesn\'t ask for a passphrase anymore.", 3 );
329 append( sb, "Expression: ${gpg.useagent}", 3 );
330 append( sb, "", 0 );
331
332 append( sb, "version", 2 );
333 append( sb, "Version of the artifact to be deployed. Retrieved from POM file if specified.", 3 );
334 append( sb, "Expression: ${version}", 3 );
335 append( sb, "", 0 );
336 }
337 }
338
339 if ( getLog().isInfoEnabled() )
340 {
341 getLog().info( sb.toString() );
342 }
343 }
344
345
346
347
348
349
350
351
352
353
354 private static String repeat( String str, int repeat )
355 {
356 StringBuffer buffer = new StringBuffer( repeat * str.length() );
357
358 for ( int i = 0; i < repeat; i++ )
359 {
360 buffer.append( str );
361 }
362
363 return buffer.toString();
364 }
365
366
367
368
369
370
371
372
373
374 private void append( StringBuffer sb, String description, int indent )
375 {
376 for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); )
377 {
378 sb.append( it.next().toString() ).append( '\n' );
379 }
380 }
381
382
383
384
385
386
387
388
389
390
391
392 private static List toLines( String text, int indent, int indentSize, int lineLength )
393 {
394 List<String> lines = new ArrayList<String>();
395
396 String ind = repeat( "\t", indent );
397 String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
398 for ( int i = 0; i < plainLines.length; i++ )
399 {
400 toLines( lines, ind + plainLines[i], indentSize, lineLength );
401 }
402
403 return lines;
404 }
405
406
407
408
409
410
411
412
413
414 private static void toLines( List<String> lines, String line, int indentSize, int lineLength )
415 {
416 int lineIndent = getIndentLevel( line );
417 StringBuffer buf = new StringBuffer( 256 );
418 String[] tokens = line.split( " +" );
419 for ( int i = 0; i < tokens.length; i++ )
420 {
421 String token = tokens[i];
422 if ( i > 0 )
423 {
424 if ( buf.length() + token.length() >= lineLength )
425 {
426 lines.add( buf.toString() );
427 buf.setLength( 0 );
428 buf.append( repeat( " ", lineIndent * indentSize ) );
429 }
430 else
431 {
432 buf.append( ' ' );
433 }
434 }
435 for ( int j = 0; j < token.length(); j++ )
436 {
437 char c = token.charAt( j );
438 if ( c == '\t' )
439 {
440 buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
441 }
442 else if ( c == '\u00A0' )
443 {
444 buf.append( ' ' );
445 }
446 else
447 {
448 buf.append( c );
449 }
450 }
451 }
452 lines.add( buf.toString() );
453 }
454
455
456
457
458
459
460
461 private static int getIndentLevel( String line )
462 {
463 int level = 0;
464 for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
465 {
466 level++;
467 }
468 for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
469 {
470 if ( line.charAt( i ) == '\t' )
471 {
472 level++;
473 break;
474 }
475 }
476 return level;
477 }
478 }