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