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