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