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.2", 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, "keyname", 2 );
240 append( sb, "The \'name\' of the key to sign with. Passed to gpg as --local-user.", 3 );
241 append( sb, "Expression: ${gpg.keyname}", 3 );
242 append( sb, "", 0 );
243
244 append( sb, "packaging", 2 );
245 append( sb, "Type of the artifact to be deployed. Retrieved from POM file if specified.", 3 );
246 append( sb, "Expression: ${packaging}", 3 );
247 append( sb, "", 0 );
248
249 append( sb, "passphrase", 2 );
250 append( sb, "The passphrase to use when signing.", 3 );
251 append( sb, "Expression: ${gpg.passphrase}", 3 );
252 append( sb, "", 0 );
253
254 append( sb, "pomFile", 2 );
255 append( sb, "Location of an existing POM file to be deployed alongside the main artifact, given by the ${file} parameter.", 3 );
256 append( sb, "Expression: ${pomFile}", 3 );
257 append( sb, "", 0 );
258
259 append( sb, "publicKeyring", 2 );
260 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 );
261 append( sb, "Expression: ${gpg.publicKeyring}", 3 );
262 append( sb, "", 0 );
263
264 append( sb, "repositoryId (Default: remote-repository)", 2 );
265 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 );
266 append( sb, "Required: Yes", 3 );
267 append( sb, "Expression: ${repositoryId}", 3 );
268 append( sb, "", 0 );
269
270 append( sb, "repositoryLayout (Default: default)", 2 );
271 append( sb, "The type of remote repository layout to deploy to. Try legacy for a Maven 1.x-style repository layout.", 3 );
272 append( sb, "Expression: ${repositoryLayout}", 3 );
273 append( sb, "", 0 );
274
275 append( sb, "secretKeyring", 2 );
276 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 );
277 append( sb, "Expression: ${gpg.secretKeyring}", 3 );
278 append( sb, "", 0 );
279
280 append( sb, "uniqueVersion (Default: true)", 2 );
281 append( sb, "Whether to deploy snapshots with a unique version or not.", 3 );
282 append( sb, "Expression: ${uniqueVersion}", 3 );
283 append( sb, "", 0 );
284
285 append( sb, "url", 2 );
286 append( sb, "URL where the artifact will be deployed.\nie ( file:///C:/m2-repo or scp://host.com/path/to/repo )", 3 );
287 append( sb, "Required: Yes", 3 );
288 append( sb, "Expression: ${url}", 3 );
289 append( sb, "", 0 );
290
291 append( sb, "useAgent (Default: false)", 2 );
292 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 );
293 append( sb, "Expression: ${gpg.useagent}", 3 );
294 append( sb, "", 0 );
295
296 append( sb, "version", 2 );
297 append( sb, "Version of the artifact to be deployed. Retrieved from POM file if specified.", 3 );
298 append( sb, "Expression: ${version}", 3 );
299 append( sb, "", 0 );
300 }
301 }
302
303 if ( getLog().isInfoEnabled() )
304 {
305 getLog().info( sb.toString() );
306 }
307 }
308
309
310
311
312
313
314
315
316
317
318 private static String repeat( String str, int repeat )
319 {
320 StringBuffer buffer = new StringBuffer( repeat * str.length() );
321
322 for ( int i = 0; i < repeat; i++ )
323 {
324 buffer.append( str );
325 }
326
327 return buffer.toString();
328 }
329
330
331
332
333
334
335
336
337
338 private void append( StringBuffer sb, String description, int indent )
339 {
340 for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); )
341 {
342 sb.append( it.next().toString() ).append( '\n' );
343 }
344 }
345
346
347
348
349
350
351
352
353
354
355
356 private static List toLines( String text, int indent, int indentSize, int lineLength )
357 {
358 List lines = new ArrayList();
359
360 String ind = repeat( "\t", indent );
361 String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
362 for ( int i = 0; i < plainLines.length; i++ )
363 {
364 toLines( lines, ind + plainLines[i], indentSize, lineLength );
365 }
366
367 return lines;
368 }
369
370
371
372
373
374
375
376
377
378 private static void toLines( List lines, String line, int indentSize, int lineLength )
379 {
380 int lineIndent = getIndentLevel( line );
381 StringBuffer buf = new StringBuffer( 256 );
382 String[] tokens = line.split( " +" );
383 for ( int i = 0; i < tokens.length; i++ )
384 {
385 String token = tokens[i];
386 if ( i > 0 )
387 {
388 if ( buf.length() + token.length() >= lineLength )
389 {
390 lines.add( buf.toString() );
391 buf.setLength( 0 );
392 buf.append( repeat( " ", lineIndent * indentSize ) );
393 }
394 else
395 {
396 buf.append( ' ' );
397 }
398 }
399 for ( int j = 0; j < token.length(); j++ )
400 {
401 char c = token.charAt( j );
402 if ( c == '\t' )
403 {
404 buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
405 }
406 else if ( c == '\u00A0' )
407 {
408 buf.append( ' ' );
409 }
410 else
411 {
412 buf.append( c );
413 }
414 }
415 }
416 lines.add( buf.toString() );
417 }
418
419
420
421
422
423
424
425 private static int getIndentLevel( String line )
426 {
427 int level = 0;
428 for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
429 {
430 level++;
431 }
432 for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
433 {
434 if ( line.charAt( i ) == '\t' )
435 {
436 level++;
437 break;
438 }
439 }
440 return level;
441 }
442 }