1 package org.apache.maven.plugin.dependency;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.artifact.Artifact;
23 import org.apache.maven.plugin.MojoExecutionException;
24 import org.apache.maven.plugin.dependency.utils.DependencyUtil;
25 import org.apache.maven.plugins.annotations.Component;
26 import org.apache.maven.plugins.annotations.LifecyclePhase;
27 import org.apache.maven.plugins.annotations.Mojo;
28 import org.apache.maven.plugins.annotations.Parameter;
29 import org.apache.maven.plugins.annotations.ResolutionScope;
30 import org.apache.maven.project.MavenProjectHelper;
31 import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
32 import org.codehaus.plexus.util.IOUtil;
33 import org.codehaus.plexus.util.StringUtils;
34
35 import java.io.BufferedReader;
36 import java.io.BufferedWriter;
37 import java.io.File;
38 import java.io.FileReader;
39 import java.io.FileWriter;
40 import java.io.IOException;
41 import java.io.Writer;
42 import java.util.ArrayList;
43 import java.util.Comparator;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Set;
47 import java.util.regex.Matcher;
48 import java.util.regex.Pattern;
49
50
51
52
53
54
55
56
57 @Mojo( name = "build-classpath", requiresDependencyResolution = ResolutionScope.TEST,
58 defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true )
59 public class BuildClasspathMojo
60 extends AbstractDependencyFilterMojo
61 implements Comparator<Artifact>
62 {
63
64
65
66
67 @Parameter( property = "mdep.stripVersion", defaultValue = "false" )
68 private boolean stripVersion = false;
69
70
71
72
73
74 @Parameter( property = "mdep.prefix" )
75 private String prefix;
76
77
78
79
80
81
82
83
84 @Parameter( property = "mdep.cpFile" )
85 private File cpFile;
86
87
88
89
90 @Parameter( property = "mdep.outputProperty" )
91 private String outputProperty;
92
93
94
95
96 @Parameter( property = "mdep.outputFile" )
97 private File outputFile;
98
99
100
101
102 @Parameter( property = "mdep.regenerateFile", defaultValue = "false" )
103 private boolean regenerateFile;
104
105
106
107
108
109
110
111
112 @Parameter( property = "mdep.fileSeparator", defaultValue = "" )
113 private String fileSeparator;
114
115
116
117
118
119
120
121
122
123 @Parameter( property = "mdep.pathSeparator", defaultValue = "" )
124 private String pathSeparator;
125
126
127
128
129
130
131
132 @Parameter( property = "mdep.localRepoProperty", defaultValue = "" )
133 private String localRepoProperty;
134
135
136
137
138
139
140 @Parameter( defaultValue = "false" )
141 boolean attach;
142
143
144
145
146
147
148 @Parameter( property = "mdep.outputFilterFile", defaultValue = "false" )
149 boolean outputFilterFile;
150
151
152
153
154
155
156 @Parameter( property = "mdep.useBaseVersion", defaultValue = "true" )
157 protected boolean useBaseVersion = true;
158
159
160
161
162 @Component
163 private MavenProjectHelper projectHelper;
164
165 boolean isFileSepSet = true;
166
167 boolean isPathSepSet = true;
168
169
170
171
172
173
174
175
176 protected void doExecute()
177 throws MojoExecutionException
178 {
179
180 if ( cpFile != null )
181 {
182 getLog().warn( "The parameter cpFile is deprecated. Use outputFile instead." );
183 this.outputFile = cpFile;
184 }
185
186
187 isFileSepSet = StringUtils.isNotEmpty( fileSeparator );
188 isPathSepSet = StringUtils.isNotEmpty( pathSeparator );
189
190
191 if ( attach && StringUtils.isEmpty( localRepoProperty ) )
192 {
193 localRepoProperty = "${M2_REPO}";
194 }
195
196 Set<Artifact> artifacts = getResolvedDependencies( true );
197
198 if ( artifacts == null || artifacts.isEmpty() )
199 {
200 getLog().info( "No dependencies found." );
201 }
202
203 List<Artifact> artList = new ArrayList<Artifact>( artifacts );
204
205 StringBuilder sb = new StringBuilder();
206 Iterator<Artifact> i = artList.iterator();
207
208 if ( i.hasNext() )
209 {
210 appendArtifactPath( i.next(), sb );
211
212 while ( i.hasNext() )
213 {
214 sb.append( isPathSepSet ? this.pathSeparator : File.pathSeparator );
215 appendArtifactPath( (Artifact) i.next(), sb );
216 }
217 }
218
219 String cpString = sb.toString();
220
221
222
223 if ( isFileSepSet )
224 {
225
226 final String pattern = Pattern.quote( File.separator );
227 final String replacement = Matcher.quoteReplacement( fileSeparator );
228 cpString = cpString.replaceAll( pattern, replacement );
229 }
230
231
232 if ( outputFilterFile )
233 {
234 cpString = "classpath=" + cpString;
235 }
236
237 if ( outputProperty != null )
238 {
239 project.getProperties().setProperty( outputProperty, cpString );
240 if ( getLog().isDebugEnabled() )
241 {
242 getLog().debug( outputProperty + " = " + cpString );
243 }
244 }
245 else if ( outputFile == null )
246 {
247 getLog().info( "Dependencies classpath:\n" + cpString );
248 }
249 else
250 {
251 if ( regenerateFile || !isUpdToDate( cpString ) )
252 {
253 storeClasspathFile( cpString, outputFile );
254 }
255 else
256 {
257 this.getLog().info( "Skipped writing classpath file '" + outputFile + "'. No changes found." );
258 }
259 }
260 if ( attach )
261 {
262 attachFile( cpString );
263 }
264 }
265
266 protected void attachFile( String cpString )
267 throws MojoExecutionException
268 {
269 File attachedFile = new File( project.getBuild().getDirectory(), "classpath" );
270 storeClasspathFile( cpString, attachedFile );
271
272 projectHelper.attachArtifact( project, attachedFile, "classpath" );
273 }
274
275
276
277
278
279
280
281 protected void appendArtifactPath( Artifact art, StringBuilder sb )
282 {
283 if ( prefix == null )
284 {
285 String file = art.getFile().getPath();
286
287 if ( StringUtils.isNotEmpty( localRepoProperty ) )
288 {
289 file = StringUtils.replace( file, getLocal().getBasedir(), localRepoProperty );
290 }
291 sb.append( file );
292 }
293 else
294 {
295
296 sb.append( prefix );
297 sb.append( File.separator );
298 sb.append( DependencyUtil.getFormattedFileName( art, this.stripVersion, this.prependGroupId, this.useBaseVersion ) );
299 }
300 }
301
302
303
304
305
306
307
308
309 private boolean isUpdToDate( String cpString )
310 {
311 try
312 {
313 String oldCp = readClasspathFile();
314 return ( cpString == oldCp || ( cpString != null && cpString.equals( oldCp ) ) );
315 }
316 catch ( Exception ex )
317 {
318 this.getLog().warn(
319 "Error while reading old classpath file '" + outputFile + "' for up-to-date check: " + ex );
320
321 return false;
322 }
323 }
324
325
326
327
328
329
330
331 private void storeClasspathFile( String cpString, File out )
332 throws MojoExecutionException
333 {
334
335 out.getParentFile().mkdirs();
336
337 Writer w = null;
338 try
339 {
340 w = new BufferedWriter( new FileWriter( out ) );
341 w.write( cpString );
342 getLog().info( "Wrote classpath file '" + out + "'." );
343 }
344 catch ( IOException ex )
345 {
346 throw new MojoExecutionException( "Error while writting to classpath file '" + out + "': " + ex.toString(),
347 ex );
348 }
349 finally
350 {
351 IOUtil.close( w );
352 }
353 }
354
355
356
357
358
359
360
361
362 protected String readClasspathFile()
363 throws IOException
364 {
365 if ( outputFile == null )
366 {
367 throw new IllegalArgumentException(
368 "The outputFile parameter cannot be null if the file is intended to be read." );
369 }
370
371 if ( !outputFile.isFile() )
372 {
373 return null;
374 }
375 StringBuilder sb = new StringBuilder();
376 BufferedReader r = null;
377
378 try
379 {
380 r = new BufferedReader( new FileReader( outputFile ) );
381 String l;
382 while ( ( l = r.readLine() ) != null )
383 {
384 sb.append( l );
385 }
386
387 return sb.toString();
388 }
389 finally
390 {
391 IOUtil.close( r );
392 }
393 }
394
395
396
397
398
399
400
401
402
403
404 public int compare( Artifact art1, Artifact art2 )
405 {
406 if ( art1 == art2 )
407 {
408 return 0;
409 }
410 else if ( art1 == null )
411 {
412 return -1;
413 }
414 else if ( art2 == null )
415 {
416 return +1;
417 }
418
419 String s1 = art1.getGroupId() + art1.getArtifactId() + art1.getVersion();
420 String s2 = art2.getGroupId() + art2.getArtifactId() + art2.getVersion();
421
422 return s1.compareTo( s2 );
423 }
424
425 protected ArtifactsFilter getMarkedArtifactFilter()
426 {
427 return null;
428 }
429
430
431
432
433 public File getCpFile()
434 {
435 return this.outputFile;
436 }
437
438
439
440
441 public void setCpFile( File theCpFile )
442 {
443 this.outputFile = theCpFile;
444 }
445
446
447
448
449 public String getOutputProperty()
450 {
451 return this.outputProperty;
452 }
453
454
455
456
457 public void setOutputProperty( String theOutputProperty )
458 {
459 this.outputProperty = theOutputProperty;
460 }
461
462
463
464
465 public String getFileSeparator()
466 {
467 return this.fileSeparator;
468 }
469
470
471
472
473 public void setFileSeparator( String theFileSeparator )
474 {
475 this.fileSeparator = theFileSeparator;
476 }
477
478
479
480
481 public String getPathSeparator()
482 {
483 return this.pathSeparator;
484 }
485
486
487
488
489 public void setPathSeparator( String thePathSeparator )
490 {
491 this.pathSeparator = thePathSeparator;
492 }
493
494
495
496
497 public String getPrefix()
498 {
499 return this.prefix;
500 }
501
502
503
504
505 public void setPrefix( String thePrefix )
506 {
507 this.prefix = thePrefix;
508 }
509
510
511
512
513 public boolean isRegenerateFile()
514 {
515 return this.regenerateFile;
516 }
517
518
519
520
521 public void setRegenerateFile( boolean theRegenerateFile )
522 {
523 this.regenerateFile = theRegenerateFile;
524 }
525
526
527
528
529 public boolean isStripVersion()
530 {
531 return this.stripVersion;
532 }
533
534
535
536
537 public void setStripVersion( boolean theStripVersion )
538 {
539 this.stripVersion = theStripVersion;
540 }
541
542 public String getLocalRepoProperty()
543 {
544 return localRepoProperty;
545 }
546
547 public void setLocalRepoProperty( String localRepoProperty )
548 {
549 this.localRepoProperty = localRepoProperty;
550 }
551
552 public boolean isFileSepSet()
553 {
554 return isFileSepSet;
555 }
556
557 public void setFileSepSet( boolean isFileSepSet )
558 {
559 this.isFileSepSet = isFileSepSet;
560 }
561
562 public boolean isPathSepSet()
563 {
564 return isPathSepSet;
565 }
566
567 public void setPathSepSet( boolean isPathSepSet )
568 {
569 this.isPathSepSet = isPathSepSet;
570 }
571 }