1 | |
package org.apache.maven.plugin.jar; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
import org.apache.commons.lang.SystemUtils; |
23 | |
import org.apache.maven.plugin.AbstractMojo; |
24 | |
import org.apache.maven.plugin.MojoExecutionException; |
25 | |
import org.apache.maven.plugin.logging.Log; |
26 | |
import org.apache.maven.project.MavenProject; |
27 | |
import org.apache.maven.project.MavenProjectHelper; |
28 | |
import org.apache.maven.artifact.handler.ArtifactHandler; |
29 | |
import org.codehaus.plexus.util.StringUtils; |
30 | |
import org.codehaus.plexus.util.cli.CommandLineException; |
31 | |
import org.codehaus.plexus.util.cli.CommandLineUtils; |
32 | |
import org.codehaus.plexus.util.cli.Commandline; |
33 | |
import org.codehaus.plexus.util.cli.StreamConsumer; |
34 | |
|
35 | |
import java.io.File; |
36 | |
import java.io.InputStream; |
37 | |
import java.util.ArrayList; |
38 | |
import java.util.Iterator; |
39 | |
import java.util.List; |
40 | |
import java.util.StringTokenizer; |
41 | |
|
42 | |
|
43 | |
|
44 | |
|
45 | |
|
46 | |
|
47 | |
|
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | 12 | public class JarSignMojo |
55 | |
extends AbstractMojo |
56 | |
{ |
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
private boolean skip; |
64 | |
|
65 | |
|
66 | |
|
67 | |
|
68 | |
|
69 | |
|
70 | |
|
71 | |
private File workingDirectory; |
72 | |
|
73 | |
|
74 | |
|
75 | |
|
76 | |
|
77 | |
|
78 | |
|
79 | |
|
80 | |
private File basedir; |
81 | |
|
82 | |
|
83 | |
|
84 | |
|
85 | |
|
86 | |
|
87 | |
|
88 | |
private String finalName; |
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
|
94 | |
|
95 | |
private File jarPath; |
96 | |
|
97 | |
|
98 | |
|
99 | |
|
100 | |
|
101 | |
|
102 | |
private String keystore; |
103 | |
|
104 | |
|
105 | |
|
106 | |
|
107 | |
|
108 | |
|
109 | |
private String storepass; |
110 | |
|
111 | |
|
112 | |
|
113 | |
|
114 | |
|
115 | |
|
116 | |
private String keypass; |
117 | |
|
118 | |
|
119 | |
|
120 | |
|
121 | |
|
122 | |
|
123 | |
|
124 | |
private String sigfile; |
125 | |
|
126 | |
|
127 | |
|
128 | |
|
129 | |
|
130 | |
|
131 | |
|
132 | |
|
133 | |
private File signedjar; |
134 | |
|
135 | |
|
136 | |
|
137 | |
|
138 | |
|
139 | |
|
140 | |
|
141 | |
private String type; |
142 | |
|
143 | |
|
144 | |
|
145 | |
|
146 | |
|
147 | |
|
148 | |
|
149 | |
private String alias; |
150 | |
|
151 | |
|
152 | |
|
153 | |
|
154 | |
|
155 | |
|
156 | |
|
157 | |
|
158 | |
private boolean verify; |
159 | |
|
160 | |
|
161 | |
|
162 | |
|
163 | |
|
164 | |
|
165 | |
private boolean skipAttachSignedArtifact; |
166 | |
|
167 | |
|
168 | |
|
169 | |
|
170 | |
|
171 | |
|
172 | |
|
173 | |
private boolean verbose; |
174 | |
|
175 | |
|
176 | |
|
177 | |
|
178 | |
private MavenProjectHelper projectHelper; |
179 | |
|
180 | |
|
181 | |
|
182 | |
|
183 | |
|
184 | |
|
185 | |
|
186 | |
|
187 | |
private MavenProject project; |
188 | |
|
189 | |
|
190 | |
|
191 | |
|
192 | |
|
193 | |
|
194 | |
|
195 | |
private String classifier; |
196 | |
|
197 | |
public void execute() |
198 | |
throws MojoExecutionException |
199 | |
{ |
200 | 14 | if ( skip ) |
201 | |
{ |
202 | 0 | getLog().info( "Skipping JAR signing for file: " + getJarFile().getAbsolutePath() ); |
203 | 0 | return; |
204 | |
} |
205 | |
|
206 | 14 | if ( project != null ) |
207 | |
{ |
208 | 14 | ArtifactHandler artifactHandler = project.getArtifact().getArtifactHandler(); |
209 | 14 | if ( artifactHandler != null && !"java".equals( artifactHandler.getLanguage() ) ) |
210 | |
{ |
211 | 0 | getLog().debug( "Not executing jar:sign as the project is not a Java module" ); |
212 | 0 | return; |
213 | |
} |
214 | |
} |
215 | |
|
216 | |
|
217 | |
|
218 | 14 | JarSignVerifyMojo verifyMojo = createJarSignVerifyMojo(); |
219 | |
|
220 | 14 | verifyMojo.setWorkingDir( workingDirectory ); |
221 | |
|
222 | 14 | verifyMojo.setBasedir( basedir ); |
223 | |
|
224 | 14 | File signedJarFile = signedjar != null ? signedjar : getJarFile(); |
225 | |
|
226 | 14 | verifyMojo.setVerbose( verbose ); |
227 | |
|
228 | 14 | verifyMojo.setJarPath( signedJarFile ); |
229 | |
|
230 | 14 | if ( signedJarFile.exists() ) |
231 | |
{ |
232 | 0 | verifyMojo.setErrorWhenNotSigned( false ); |
233 | 0 | verifyMojo.execute(); |
234 | |
} |
235 | |
|
236 | 14 | if ( verifyMojo.isSigned() ) |
237 | |
{ |
238 | 2 | getLog().info( "JAR " + signedJarFile.getAbsoluteFile() + " is already signed. Skipping." ); |
239 | 2 | return; |
240 | |
} |
241 | |
|
242 | 12 | signJar(); |
243 | |
|
244 | 8 | if ( this.verify ) |
245 | |
{ |
246 | 4 | verifyMojo.setErrorWhenNotSigned( true ); |
247 | 4 | verifyMojo.execute(); |
248 | |
} |
249 | 8 | } |
250 | |
|
251 | |
protected JarSignVerifyMojo createJarSignVerifyMojo() |
252 | |
{ |
253 | 0 | return new JarSignVerifyMojo(); |
254 | |
} |
255 | |
|
256 | |
|
257 | |
File getJarFile() |
258 | |
{ |
259 | 14 | if ( jarPath != null ) |
260 | |
{ |
261 | 0 | return jarPath; |
262 | |
} |
263 | |
else |
264 | |
{ |
265 | 14 | return AbstractJarMojo.getJarFile( basedir, finalName, null ); |
266 | |
} |
267 | |
} |
268 | |
|
269 | |
void signJar() |
270 | |
throws MojoExecutionException |
271 | |
{ |
272 | 12 | List arguments = new ArrayList(); |
273 | |
|
274 | 12 | Commandline commandLine = new Commandline(); |
275 | |
|
276 | 12 | commandLine.setExecutable( getJarsignerPath() ); |
277 | |
|
278 | 12 | addArgIf( arguments, verbose, "-verbose" ); |
279 | |
|
280 | |
|
281 | |
|
282 | |
|
283 | 12 | addArgIfNotEmpty( arguments, "-keystore", this.keystore ); |
284 | 12 | addArgIfNotEmpty( arguments, "-storepass", this.storepass ); |
285 | 12 | addArgIfNotEmpty( arguments, "-keypass", this.keypass ); |
286 | 12 | addArgIfNotEmpty( arguments, "-signedjar", this.signedjar ); |
287 | 12 | addArgIfNotEmpty( arguments, "-storetype", this.type ); |
288 | 12 | addArgIfNotEmpty( arguments, "-sigfile", this.sigfile ); |
289 | |
|
290 | 12 | arguments.add( getJarFile() ); |
291 | |
|
292 | 12 | addArgIf( arguments, alias != null, this.alias ); |
293 | |
|
294 | 12 | for ( Iterator it = arguments.iterator(); it.hasNext(); ) |
295 | |
{ |
296 | 90 | commandLine.createArgument().setValue( it.next().toString() ); |
297 | |
} |
298 | |
|
299 | 12 | commandLine.setWorkingDirectory( workingDirectory.getAbsolutePath() ); |
300 | |
|
301 | 12 | createParentDirIfNecessary( signedjar ); |
302 | |
|
303 | 12 | if ( signedjar == null ) |
304 | |
{ |
305 | 2 | getLog().debug( "Signing JAR in-place (overwritting original JAR)." ); |
306 | |
} |
307 | |
|
308 | 12 | if ( getLog().isDebugEnabled() ) |
309 | |
{ |
310 | 0 | getLog().debug( "Executing: " + purgePassword( commandLine ) ); |
311 | |
} |
312 | |
|
313 | |
|
314 | |
|
315 | 12 | final InputStream inputStream = new InputStream() |
316 | |
{ |
317 | 12 | public int read() |
318 | |
{ |
319 | 0 | return -1; |
320 | |
} |
321 | |
}; |
322 | 12 | StreamConsumer outConsumer = new StreamConsumer() |
323 | |
{ |
324 | 12 | public void consumeLine( String line ) |
325 | |
{ |
326 | 0 | getLog().info( line ); |
327 | 0 | } |
328 | |
}; |
329 | 12 | final StringBuffer errBuffer = new StringBuffer(); |
330 | 12 | StreamConsumer errConsumer = new StreamConsumer() |
331 | |
{ |
332 | 12 | public void consumeLine( String line ) |
333 | |
{ |
334 | 0 | errBuffer.append( line ); |
335 | 0 | getLog().warn( line ); |
336 | 0 | } |
337 | |
}; |
338 | |
|
339 | |
try |
340 | |
{ |
341 | 12 | int result = executeCommandLine( commandLine, inputStream, outConsumer, errConsumer ); |
342 | |
|
343 | 10 | if ( result != 0 ) |
344 | |
{ |
345 | 2 | throw new MojoExecutionException( "Result of " + purgePassword( commandLine ) + |
346 | |
" execution is: \'" + result + "\'." ); |
347 | |
} |
348 | |
} |
349 | 2 | catch ( CommandLineException e ) |
350 | |
{ |
351 | 2 | throw new MojoExecutionException( "command execution failed", e ); |
352 | 8 | } |
353 | |
|
354 | |
|
355 | 8 | if ( signedjar == null || skipAttachSignedArtifact ) |
356 | |
{ |
357 | 2 | return; |
358 | |
} |
359 | |
|
360 | 6 | if ( classifier != null ) |
361 | |
{ |
362 | 0 | projectHelper.attachArtifact( project, "jar", classifier, signedjar ); |
363 | |
} |
364 | |
else |
365 | |
{ |
366 | 6 | project.getArtifact().setFile( signedjar ); |
367 | |
} |
368 | 6 | } |
369 | |
|
370 | |
private String purgePassword( Commandline commandLine ) |
371 | |
{ |
372 | 2 | String out = commandLine.toString(); |
373 | 2 | if ( keypass != null && out.indexOf( keypass ) != -1 ) |
374 | |
{ |
375 | 2 | out = StringUtils.replace( out, keypass, "******" ); |
376 | |
} |
377 | 2 | return out; |
378 | |
} |
379 | |
|
380 | |
private void createParentDirIfNecessary( File file ) |
381 | |
{ |
382 | 12 | if ( file != null ) |
383 | |
{ |
384 | 10 | File fileDir = file.getParentFile(); |
385 | |
|
386 | 10 | if ( fileDir != null ) |
387 | |
{ |
388 | 10 | boolean mkdirs = fileDir.mkdirs(); |
389 | 10 | getLog().debug( "mdkirs: " + mkdirs + " " + fileDir ); |
390 | |
} |
391 | |
} |
392 | 12 | } |
393 | |
|
394 | |
|
395 | |
|
396 | |
|
397 | |
|
398 | |
|
399 | |
|
400 | |
|
401 | |
|
402 | |
private String getJarsignerPath() |
403 | |
{ |
404 | 12 | return getJDKCommandPath( "jarsigner", getLog() ); |
405 | |
} |
406 | |
|
407 | |
private static String getJDKCommandPath( String command, Log logger ) |
408 | |
{ |
409 | 12 | String path = getJDKCommandExe( command ).getAbsolutePath(); |
410 | 12 | logger.debug( command + " executable=[" + path + "]" ); |
411 | 12 | return path; |
412 | |
} |
413 | |
|
414 | |
private static File getJDKCommandExe( String command ) |
415 | |
{ |
416 | 12 | String fullCommand = command + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" ); |
417 | |
|
418 | |
File exe; |
419 | |
|
420 | |
|
421 | 12 | if ( SystemUtils.IS_OS_AIX ) |
422 | |
{ |
423 | 0 | exe = new File( SystemUtils.getJavaHome() + "/../sh", fullCommand ); |
424 | |
} |
425 | 12 | else if ( SystemUtils.IS_OS_MAC_OSX ) |
426 | |
{ |
427 | 0 | exe = new File( SystemUtils.getJavaHome() + "/bin", fullCommand ); |
428 | |
} |
429 | |
else |
430 | |
{ |
431 | 12 | exe = new File( SystemUtils.getJavaHome() + "/../bin", fullCommand ); |
432 | |
} |
433 | |
|
434 | 12 | return exe; |
435 | |
} |
436 | |
|
437 | |
|
438 | |
|
439 | |
|
440 | |
|
441 | |
|
442 | |
|
443 | |
|
444 | |
|
445 | |
|
446 | |
|
447 | |
private void addArgIf( List arguments, boolean b, String value ) |
448 | |
{ |
449 | 24 | if ( b ) |
450 | |
{ |
451 | 10 | arguments.add( value ); |
452 | |
} |
453 | 24 | } |
454 | |
|
455 | |
|
456 | |
|
457 | |
|
458 | |
|
459 | |
|
460 | |
|
461 | |
|
462 | |
|
463 | |
|
464 | |
|
465 | |
|
466 | |
private void addArgIfNotEmpty( List arguments, String key, Object value ) |
467 | |
{ |
468 | 72 | addArgIfNotEmpty( arguments, key, value, false ); |
469 | 72 | } |
470 | |
|
471 | |
|
472 | |
|
473 | |
|
474 | |
|
475 | |
|
476 | |
|
477 | |
|
478 | |
|
479 | |
|
480 | |
|
481 | |
|
482 | |
private void addArgIfNotEmpty( List arguments, String key, Object value, boolean repeatKey ) |
483 | |
{ |
484 | 72 | if ( value != null && !StringUtils.isEmpty( value.toString() ) ) |
485 | |
{ |
486 | 34 | arguments.add( key ); |
487 | |
|
488 | 34 | StringTokenizer token = new StringTokenizer( value.toString(), "," ); |
489 | 68 | while ( token.hasMoreTokens() ) |
490 | |
{ |
491 | 34 | String current = token.nextToken().trim(); |
492 | |
|
493 | 34 | if ( !StringUtils.isEmpty( current ) ) |
494 | |
{ |
495 | 34 | arguments.add( current ); |
496 | |
|
497 | 34 | if ( token.hasMoreTokens() && repeatKey ) |
498 | |
{ |
499 | 0 | arguments.add( key ); |
500 | |
} |
501 | |
} |
502 | 34 | } |
503 | |
} |
504 | 72 | } |
505 | |
|
506 | |
|
507 | |
|
508 | |
|
509 | |
|
510 | |
protected int executeCommandLine( Commandline commandLine, InputStream inputStream, StreamConsumer stream1, |
511 | |
StreamConsumer stream2 ) |
512 | |
throws CommandLineException |
513 | |
{ |
514 | 0 | return CommandLineUtils.executeCommandLine( commandLine, inputStream, stream1, stream2 ); |
515 | |
} |
516 | |
|
517 | |
public void setWorkingDir( File workingDir ) |
518 | |
{ |
519 | 12 | this.workingDirectory = workingDir; |
520 | 12 | } |
521 | |
|
522 | |
public void setBasedir( File basedir ) |
523 | |
{ |
524 | 12 | this.basedir = basedir; |
525 | 12 | } |
526 | |
|
527 | |
public void setKeystore( String keystore ) |
528 | |
{ |
529 | 12 | this.keystore = keystore; |
530 | 12 | } |
531 | |
|
532 | |
public void setKeypass( String keypass ) |
533 | |
{ |
534 | 12 | this.keypass = keypass; |
535 | 12 | } |
536 | |
|
537 | |
public void setSignedJar( File signedjar ) |
538 | |
{ |
539 | 14 | this.signedjar = signedjar; |
540 | 14 | } |
541 | |
|
542 | |
public void setAlias( String alias ) |
543 | |
{ |
544 | 14 | this.alias = alias; |
545 | 14 | } |
546 | |
|
547 | |
|
548 | |
|
549 | |
|
550 | |
|
551 | |
|
552 | |
|
553 | |
|
554 | |
|
555 | |
public void setJarPath( File jarPath ) |
556 | |
{ |
557 | 0 | this.jarPath = jarPath; |
558 | 0 | } |
559 | |
|
560 | |
public void setStorepass( String storepass ) |
561 | |
{ |
562 | 0 | this.storepass = storepass; |
563 | 0 | } |
564 | |
|
565 | |
public void setSigFile( String sigfile ) |
566 | |
{ |
567 | 0 | this.sigfile = sigfile; |
568 | 0 | } |
569 | |
|
570 | |
public void setType( String type ) |
571 | |
{ |
572 | 0 | this.type = type; |
573 | 0 | } |
574 | |
|
575 | |
public void setVerbose( boolean verbose ) |
576 | |
{ |
577 | 0 | this.verbose = verbose; |
578 | 0 | } |
579 | |
|
580 | |
public void setSkipAttachSignedArtifact( boolean skipAttachSignedArtifact ) |
581 | |
{ |
582 | 0 | this.skipAttachSignedArtifact = skipAttachSignedArtifact; |
583 | 0 | } |
584 | |
|
585 | |
public void setProject( MavenProject project ) |
586 | |
{ |
587 | 12 | this.project = project; |
588 | 12 | } |
589 | |
|
590 | |
public void setVerify( boolean verify ) |
591 | |
{ |
592 | 4 | this.verify = verify; |
593 | 4 | } |
594 | |
} |