1 package org.apache.maven.plugin.assembly.archive.phase;
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.assembly.AssemblerConfigurationSource;
24 import org.apache.maven.plugin.assembly.InvalidAssemblerConfigurationException;
25 import org.apache.maven.plugin.assembly.archive.ArchiveCreationException;
26 import org.apache.maven.plugin.assembly.archive.task.AddArtifactTask;
27 import org.apache.maven.plugin.assembly.archive.task.AddDependencySetsTask;
28 import org.apache.maven.plugin.assembly.archive.task.AddFileSetsTask;
29 import org.apache.maven.plugin.assembly.artifact.DependencyResolutionException;
30 import org.apache.maven.plugin.assembly.artifact.DependencyResolver;
31 import org.apache.maven.plugin.assembly.format.AssemblyFormattingException;
32 import org.apache.maven.plugin.assembly.functions.MavenProjects;
33 import org.apache.maven.plugin.assembly.functions.ModuleSetConsumer;
34 import org.apache.maven.plugin.assembly.model.Assemblies;
35 import org.apache.maven.plugin.assembly.model.Assembly;
36 import org.apache.maven.plugin.assembly.model.DependencySet;
37 import org.apache.maven.plugin.assembly.model.FileSet;
38 import org.apache.maven.plugin.assembly.model.ModuleBinaries;
39 import org.apache.maven.plugin.assembly.model.ModuleSet;
40 import org.apache.maven.plugin.assembly.model.ModuleSources;
41 import org.apache.maven.plugin.assembly.utils.AssemblyFormatUtils;
42 import org.apache.maven.plugin.assembly.utils.FilterUtils;
43 import org.apache.maven.plugin.assembly.utils.ProjectUtils;
44 import org.apache.maven.plugin.assembly.utils.TypeConversionUtils;
45 import org.apache.maven.project.MavenProject;
46 import org.apache.maven.project.MavenProjectBuilder;
47 import org.codehaus.plexus.archiver.Archiver;
48 import org.codehaus.plexus.archiver.manager.ArchiverManager;
49 import org.codehaus.plexus.component.annotations.Component;
50 import org.codehaus.plexus.component.annotations.Requirement;
51 import org.codehaus.plexus.interpolation.fixed.FixedStringSearchInterpolator;
52 import org.codehaus.plexus.logging.AbstractLogEnabled;
53 import org.codehaus.plexus.logging.Logger;
54
55 import javax.annotation.Nonnull;
56 import java.io.File;
57 import java.io.IOException;
58 import java.util.ArrayList;
59 import java.util.Collections;
60 import java.util.HashMap;
61 import java.util.LinkedHashSet;
62 import java.util.List;
63 import java.util.Map;
64 import java.util.Set;
65
66 import static org.apache.maven.plugin.assembly.functions.MavenProjects.addTo;
67 import static org.apache.maven.plugin.assembly.functions.MavenProjects.log;
68 import static org.apache.maven.plugin.assembly.utils.AssemblyFormatUtils.artifactProjectInterpolator;
69 import static org.apache.maven.plugin.assembly.utils.AssemblyFormatUtils.moduleProjectInterpolator;
70
71
72
73
74
75
76 @Component( role = AssemblyArchiverPhase.class, hint = "module-sets" )
77 public class ModuleSetAssemblyPhase
78 extends AbstractLogEnabled
79 implements AssemblyArchiverPhase, PhaseOrder
80 {
81
82
83
84
85
86
87 private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
88
89 @Requirement
90 private MavenProjectBuilder projectBuilder;
91
92 @Requirement
93 private ArchiverManager archiverManager;
94
95 @Requirement
96 private DependencyResolver dependencyResolver;
97
98
99
100
101 public ModuleSetAssemblyPhase()
102 {
103
104 }
105
106
107
108
109
110 public ModuleSetAssemblyPhase( final MavenProjectBuilder projectBuilder, DependencyResolver dependencyResolver,
111 final Logger logger )
112 {
113 this.projectBuilder = projectBuilder;
114 this.dependencyResolver = dependencyResolver;
115 enableLogging( logger );
116 }
117
118
119
120
121 public void execute( final Assembly assembly, final Archiver archiver,
122 final AssemblerConfigurationSource configSource )
123 throws ArchiveCreationException, AssemblyFormattingException, InvalidAssemblerConfigurationException,
124 DependencyResolutionException
125 {
126 Assemblies.forEachModuleSet( assembly, new ModuleSetConsumer()
127 {
128 public void accept( ModuleSet resolvedModule )
129 throws ArchiveCreationException, AssemblyFormattingException, InvalidAssemblerConfigurationException,
130 DependencyResolutionException
131 {
132 validate( resolvedModule, configSource );
133
134 final Set<MavenProject> moduleProjects = getModuleProjects( resolvedModule, configSource, getLogger() );
135
136 final ModuleSources sources = resolvedModule.getSources();
137 addModuleSourceFileSets( sources, moduleProjects, archiver, configSource );
138
139 final ModuleBinaries binaries = resolvedModule.getBinaries();
140 addModuleBinaries( assembly, resolvedModule, binaries, moduleProjects, archiver, configSource );
141 }
142 } );
143 }
144
145 private void validate( final ModuleSet moduleSet, final AssemblerConfigurationSource configSource )
146 {
147 if ( ( moduleSet.getSources() == null ) && ( moduleSet.getBinaries() == null ) )
148 {
149 getLogger().warn( "Encountered ModuleSet with no sources or binaries specified. Skipping." );
150 }
151
152 if ( moduleSet.isUseAllReactorProjects() && !moduleSet.isIncludeSubModules() )
153 {
154 getLogger().warn( "includeSubModules == false is incompatible with useAllReactorProjects. Ignoring."
155 + "\n\nTo refactor, remove the <includeSubModules/> flag, and use the <includes/> "
156 + "and <excludes/> sections to fine-tune the modules included." );
157 }
158
159 final List<MavenProject> projects = configSource.getReactorProjects();
160 if ( projects != null && projects.size() > 1 && projects.indexOf( configSource.getProject() ) == 0
161 && moduleSet.getBinaries() != null )
162 {
163 getLogger().warn( "[DEPRECATION] moduleSet/binaries section detected in root-project assembly."
164 + "\n\nMODULE BINARIES MAY NOT BE AVAILABLE FOR THIS ASSEMBLY!"
165 + "\n\n To refactor, move this assembly into a child project and use the flag "
166 + "<useAllReactorProjects>true</useAllReactorProjects> in each moduleSet." );
167 }
168
169 if ( moduleSet.getSources() != null )
170 {
171 final ModuleSources sources = moduleSet.getSources();
172 if ( isDeprecatedModuleSourcesConfigPresent( sources ) )
173 {
174 getLogger().warn( "[DEPRECATION] Use of <moduleSources/> as a file-set is deprecated. "
175 + "Please use the <fileSets/> sub-element of <moduleSources/> instead." );
176 }
177 else if ( !sources.isUseDefaultExcludes() )
178 {
179 getLogger().warn( "[DEPRECATION] Use of directoryMode, fileMode, or useDefaultExcludes "
180 + "elements directly within <moduleSources/> are all deprecated. "
181 + "Please use the <fileSets/> sub-element of <moduleSources/> instead." );
182 }
183 }
184 }
185
186 void addModuleBinaries( final Assembly assembly, ModuleSet moduleSet, final ModuleBinaries binaries,
187 final Set<MavenProject> projects, final Archiver archiver,
188 final AssemblerConfigurationSource configSource )
189 throws ArchiveCreationException, AssemblyFormattingException, InvalidAssemblerConfigurationException,
190 DependencyResolutionException
191 {
192 if ( binaries == null )
193 {
194 return;
195 }
196
197 final Set<MavenProject> moduleProjects = new LinkedHashSet<MavenProject>();
198
199 MavenProjects.select( projects, "pom", log( getLogger() ), addTo( moduleProjects ) );
200
201 final String classifier = binaries.getAttachmentClassifier();
202
203 final Map<MavenProject, Artifact> chosenModuleArtifacts = new HashMap<MavenProject, Artifact>();
204
205 for ( final MavenProject project : moduleProjects )
206 {
207 Artifact artifact;
208
209 if ( classifier == null )
210 {
211 getLogger().debug( "Processing binary artifact for module project: " + project.getId() );
212
213 artifact = project.getArtifact();
214 }
215 else
216 {
217 getLogger().debug(
218 "Processing binary attachment: " + classifier + " for module project: " + project.getId() );
219
220 artifact = MavenProjects.findArtifactByClassifier( project, classifier );
221
222 if ( artifact == null )
223 {
224 throw new InvalidAssemblerConfigurationException(
225 "Cannot find attachment with classifier: " + classifier + " in module project: "
226 + project.getId() + ". Please exclude this module from the module-set." );
227 }
228 }
229
230 chosenModuleArtifacts.put( project, artifact );
231 addModuleArtifact( artifact, project, archiver, configSource, binaries );
232 }
233
234 final List<DependencySet> depSets = getDependencySets( binaries );
235
236 if ( depSets != null )
237 {
238 Map<DependencySet, Set<Artifact>> dependencySetSetMap =
239 dependencyResolver.resolveDependencySets( assembly, moduleSet, configSource, depSets );
240
241 for ( final DependencySet ds : depSets )
242 {
243
244 ds.setUseProjectArtifact( false );
245 }
246
247
248
249 List<MavenProject> validateModuleVersions = validateModuleVersions( moduleProjects );
250 if ( !validateModuleVersions.isEmpty() )
251 {
252
253 StringBuilder sb =
254 new StringBuilder().append( "The current modules seemed to be having different versions." );
255 sb.append( LINE_SEPARATOR );
256 for ( MavenProject mavenProject : validateModuleVersions )
257 {
258 sb.append( " --> " );
259 sb.append( mavenProject.getId() );
260 sb.append( LINE_SEPARATOR );
261 }
262 getLogger().warn( sb.toString() );
263 }
264
265 for ( final MavenProject moduleProject : moduleProjects )
266 {
267 getLogger().debug( "Processing binary dependencies for module project: " + moduleProject.getId() );
268
269 for ( Map.Entry<DependencySet, Set<Artifact>> dependencySetSetEntry : dependencySetSetMap.entrySet() )
270 {
271 final AddDependencySetsTask task =
272 new AddDependencySetsTask( Collections.singletonList( dependencySetSetEntry.getKey() ),
273 dependencySetSetEntry.getValue(), moduleProject, projectBuilder,
274 getLogger() );
275
276 task.setModuleProject( moduleProject );
277 task.setModuleArtifact( chosenModuleArtifacts.get( moduleProject ) );
278 task.setDefaultOutputDirectory( binaries.getOutputDirectory() );
279 task.setDefaultOutputFileNameMapping( binaries.getOutputFileNameMapping() );
280
281 task.execute( archiver, configSource );
282
283 }
284 }
285 }
286 }
287
288 private List<MavenProject> validateModuleVersions( Set<MavenProject> moduleProjects )
289 {
290 List<MavenProject> result = new ArrayList<MavenProject>();
291
292 if ( moduleProjects != null && !moduleProjects.isEmpty() )
293 {
294 String version = moduleProjects.iterator().next().getVersion();
295 getLogger().debug( "First version:" + version );
296 for ( MavenProject mavenProject : moduleProjects )
297 {
298 getLogger().debug( " -> checking " + mavenProject.getId() );
299 if ( !version.equals( mavenProject.getVersion() ) )
300 {
301 result.add( mavenProject );
302 }
303 }
304 }
305 return result;
306 }
307
308 public static List<DependencySet> getDependencySets( final ModuleBinaries binaries )
309 {
310 List<DependencySet> depSets = binaries.getDependencySets();
311
312 if ( ( ( depSets == null ) || depSets.isEmpty() ) && binaries.isIncludeDependencies() )
313 {
314 final DependencySet impliedDependencySet = new DependencySet();
315
316 impliedDependencySet.setOutputDirectory( binaries.getOutputDirectory() );
317
318 impliedDependencySet.setFileMode( binaries.getFileMode() );
319 impliedDependencySet.setDirectoryMode( binaries.getDirectoryMode() );
320 impliedDependencySet.setExcludes( binaries.getExcludes() );
321 impliedDependencySet.setIncludes( binaries.getIncludes() );
322 impliedDependencySet.setUnpack( binaries.isUnpack() );
323
324
325 depSets = Collections.singletonList( impliedDependencySet );
326 }
327
328 return depSets;
329 }
330
331 void addModuleArtifact( final Artifact artifact, final MavenProject project, final Archiver archiver,
332 final AssemblerConfigurationSource configSource, final ModuleBinaries binaries )
333 throws ArchiveCreationException, AssemblyFormattingException
334 {
335 if ( artifact.getFile() == null )
336 {
337 throw new ArchiveCreationException(
338 "Artifact: " + artifact.getId() + " (included by module) does not have an artifact with a file. "
339 + "Please ensure the package phase is run before the assembly is generated." );
340 }
341
342 final AddArtifactTask task = new AddArtifactTask( artifact, getLogger(), null );
343
344 task.setFileNameMapping( binaries.getOutputFileNameMapping() );
345 task.setOutputDirectory( binaries.getOutputDirectory() );
346 task.setProject( project );
347 task.setModuleProject( project );
348 task.setModuleArtifact( artifact );
349
350 final int dirMode = TypeConversionUtils.modeToInt( binaries.getDirectoryMode(), getLogger() );
351 if ( dirMode != -1 )
352 {
353 task.setDirectoryMode( dirMode );
354 }
355
356 final int fileMode = TypeConversionUtils.modeToInt( binaries.getFileMode(), getLogger() );
357 if ( fileMode != -1 )
358 {
359 task.setFileMode( fileMode );
360 }
361
362 task.setUnpack( binaries.isUnpack() );
363
364 if ( binaries.isUnpack() && binaries.getUnpackOptions() != null )
365 {
366 task.setIncludes( binaries.getUnpackOptions().getIncludes() );
367 task.setExcludes( binaries.getUnpackOptions().getExcludes() );
368 }
369
370 task.execute( archiver, configSource );
371 }
372
373 void addModuleSourceFileSets( final ModuleSources sources, final Set<MavenProject> moduleProjects,
374 final Archiver archiver, final AssemblerConfigurationSource configSource )
375 throws ArchiveCreationException, AssemblyFormattingException
376 {
377 if ( sources == null )
378 {
379 return;
380 }
381
382 final List<FileSet> fileSets = new ArrayList<FileSet>();
383
384 if ( isDeprecatedModuleSourcesConfigPresent( sources ) )
385 {
386 final FileSet fs = new FileSet();
387 fs.setOutputDirectory( sources.getOutputDirectory() );
388 fs.setIncludes( sources.getIncludes() );
389 fs.setExcludes( sources.getExcludes() );
390 fs.setUseDefaultExcludes( sources.isUseDefaultExcludes() );
391
392 fileSets.add( fs );
393 }
394
395 List<FileSet> subFileSets = sources.getFileSets();
396
397 if ( ( subFileSets == null ) || subFileSets.isEmpty() )
398 {
399 final FileSet fs = new FileSet();
400 fs.setDirectory( "src" );
401
402 subFileSets = Collections.singletonList( fs );
403 }
404
405 fileSets.addAll( subFileSets );
406
407 for ( final MavenProject moduleProject : moduleProjects )
408 {
409 getLogger().info( "Processing sources for module project: " + moduleProject.getId() );
410
411 final List<FileSet> moduleFileSets = new ArrayList<FileSet>();
412
413 for ( final FileSet fileSet : fileSets )
414 {
415 moduleFileSets.add( createFileSet( fileSet, sources, moduleProject, configSource ) );
416 }
417
418 final AddFileSetsTask task = new AddFileSetsTask( moduleFileSets );
419
420 task.setProject( moduleProject );
421 task.setModuleProject( moduleProject );
422 task.setLogger( getLogger() );
423
424 task.execute( archiver, configSource );
425 }
426 }
427
428
429
430
431 boolean isDeprecatedModuleSourcesConfigPresent( @Nonnull final ModuleSources sources )
432 {
433 boolean result = false;
434
435 if ( sources.getOutputDirectory() != null )
436 {
437 result = true;
438 }
439 else if ( ( sources.getIncludes() != null ) && !sources.getIncludes().isEmpty() )
440 {
441 result = true;
442 }
443 else if ( ( sources.getExcludes() != null ) && !sources.getExcludes().isEmpty() )
444 {
445 result = true;
446 }
447
448 return result;
449 }
450
451 @Nonnull
452 FileSet createFileSet( @Nonnull final FileSet fileSet, @Nonnull final ModuleSources sources,
453 @Nonnull final MavenProject moduleProject,
454 @Nonnull final AssemblerConfigurationSource configSource )
455 throws AssemblyFormattingException
456 {
457 final FileSet fs = new FileSet();
458
459 String sourcePath = fileSet.getDirectory();
460
461 final File moduleBasedir = moduleProject.getBasedir();
462
463 if ( sourcePath != null )
464 {
465 final File sourceDir = new File( sourcePath );
466
467 if ( !sourceDir.isAbsolute() )
468 {
469 sourcePath = new File( moduleBasedir, sourcePath ).getAbsolutePath();
470 }
471 }
472 else
473 {
474 sourcePath = moduleBasedir.getAbsolutePath();
475 }
476
477 fs.setDirectory( sourcePath );
478 fs.setDirectoryMode( fileSet.getDirectoryMode() );
479
480 final List<String> excludes = new ArrayList<String>();
481
482 final List<String> originalExcludes = fileSet.getExcludes();
483 if ( ( originalExcludes != null ) && !originalExcludes.isEmpty() )
484 {
485 excludes.addAll( originalExcludes );
486 }
487
488 if ( sources.isExcludeSubModuleDirectories() )
489 {
490 @SuppressWarnings( "unchecked" ) final List<String> modules = moduleProject.getModules();
491 for ( final String moduleSubPath : modules )
492 {
493 excludes.add( moduleSubPath + "/**" );
494 }
495 }
496
497 fs.setExcludes( excludes );
498 fs.setFiltered( fileSet.isFiltered() );
499 fs.setFileMode( fileSet.getFileMode() );
500 fs.setIncludes( fileSet.getIncludes() );
501 fs.setLineEnding( fileSet.getLineEnding() );
502
503 FixedStringSearchInterpolator moduleProjectInterpolator = moduleProjectInterpolator( moduleProject );
504 FixedStringSearchInterpolator artifactProjectInterpolator = artifactProjectInterpolator( moduleProject );
505 String destPathPrefix = "";
506 if ( sources.isIncludeModuleDirectory() )
507 {
508 destPathPrefix = AssemblyFormatUtils.evaluateFileNameMapping( sources.getOutputDirectoryMapping(),
509 moduleProject.getArtifact(),
510 configSource.getProject(),
511 moduleProject.getArtifact(), configSource,
512 moduleProjectInterpolator,
513 artifactProjectInterpolator );
514
515 if ( !destPathPrefix.endsWith( "/" ) )
516 {
517 destPathPrefix += "/";
518 }
519 }
520
521 String destPath = fileSet.getOutputDirectory();
522
523 if ( destPath == null )
524 {
525 destPath = destPathPrefix;
526 }
527 else
528 {
529 destPath = destPathPrefix + destPath;
530 }
531
532 destPath = AssemblyFormatUtils.getOutputDirectory( destPath, configSource.getFinalName(), configSource,
533 moduleProjectInterpolator, artifactProjectInterpolator );
534
535 fs.setOutputDirectory( destPath );
536
537 getLogger().debug( "module source directory is: " + sourcePath );
538 getLogger().debug( "module dest directory is: " + destPath + " (assembly basedir may be prepended)" );
539
540 return fs;
541 }
542
543 @Nonnull
544 public static Set<MavenProject> getModuleProjects( final ModuleSet moduleSet,
545 final AssemblerConfigurationSource configSource,
546 final Logger logger )
547 throws ArchiveCreationException
548 {
549 MavenProject project = configSource.getProject();
550 Set<MavenProject> moduleProjects = null;
551
552 if ( moduleSet.isUseAllReactorProjects() )
553 {
554 if ( !moduleSet.isIncludeSubModules() )
555 {
556 moduleProjects = new LinkedHashSet<MavenProject>( configSource.getReactorProjects() );
557 }
558
559 project = configSource.getReactorProjects().get( 0 );
560 }
561
562 if ( moduleProjects == null )
563 {
564 try
565 {
566 moduleProjects = ProjectUtils.getProjectModules( project, configSource.getReactorProjects(),
567 moduleSet.isIncludeSubModules(), logger );
568 }
569 catch ( final IOException e )
570 {
571 throw new ArchiveCreationException(
572 "Error retrieving module-set for project: " + project.getId() + ": " + e.getMessage(), e );
573 }
574 }
575
576 return FilterUtils.filterProjects( moduleProjects, moduleSet.getIncludes(), moduleSet.getExcludes(), true,
577 logger );
578 }
579
580
581 public int order()
582 {
583
584 return 30;
585
586 }
587 }