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