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
74 public static final String LINE_SEPARATOR = System.getProperty("line.separator");
75
76 @Requirement
77 private MavenProjectBuilder projectBuilder;
78
79 @Requirement
80 private ArchiverManager archiverManager;
81
82 public ModuleSetAssemblyPhase()
83 {
84
85 }
86
87 public ModuleSetAssemblyPhase( final MavenProjectBuilder projectBuilder, final Logger logger )
88 {
89 this.projectBuilder = projectBuilder;
90 enableLogging( logger );
91 }
92
93
94
95
96 public void execute( final Assembly assembly, final Archiver archiver,
97 final AssemblerConfigurationSource configSource, final AssemblyContext context )
98 throws ArchiveCreationException, AssemblyFormattingException, InvalidAssemblerConfigurationException
99 {
100 final List<ModuleSet> moduleSets = assembly.getModuleSets();
101
102 for (final ModuleSet moduleSet : moduleSets) {
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 MavenProject project : moduleProjects) {
187 Artifact artifact = null;
188
189 if (classifier == null) {
190 getLogger().debug("Processing binary artifact for module project: " + project.getId());
191
192 artifact = project.getArtifact();
193 } else {
194 getLogger().debug("Processing binary attachment: " + classifier + " for module project: "
195 + project.getId());
196
197 @SuppressWarnings("unchecked")
198 final List<Artifact> attachments = project.getAttachedArtifacts();
199 if ((attachments != null) && !attachments.isEmpty()) {
200 for (final Artifact attachment : attachments) {
201 if (classifier.equals(attachment.getClassifier())) {
202 artifact = attachment;
203 break;
204 }
205 }
206 }
207
208 if (artifact == null) {
209 throw new InvalidAssemblerConfigurationException("Cannot find attachment with classifier: "
210 + classifier + " in module project: " + project.getId()
211 + ". Please exclude this module from the module-set.");
212 }
213 }
214
215 chosenModuleArtifacts.put(project, artifact);
216 addModuleArtifact(artifact, project, archiver, configSource, binaries);
217 }
218
219 final List<DependencySet> depSets = getDependencySets( binaries );
220
221 if ( depSets != null )
222 {
223 for (final DependencySet ds : depSets) {
224
225 ds.setUseProjectArtifact(false);
226 }
227
228
229
230 List<MavenProject> validateModuleVersions = validateModuleVersions( moduleProjects );
231 if (!validateModuleVersions.isEmpty()) {
232
233 StringBuilder sb = new StringBuilder().append( "The current modules seemed to be having different versions.");
234 sb.append (LINE_SEPARATOR);
235 for ( MavenProject mavenProject : validateModuleVersions )
236 {
237 sb.append( " --> " );
238 sb.append( mavenProject.getId() );
239 sb.append( LINE_SEPARATOR );
240 }
241 getLogger().warn( sb.toString() );
242 }
243
244 for (final MavenProject moduleProject : moduleProjects) {
245 getLogger().debug("Processing binary dependencies for module project: " + moduleProject.getId());
246
247 final AddDependencySetsTask task =
248 new AddDependencySetsTask(depSets, context.getResolvedArtifacts(), moduleProject, projectBuilder,
249 archiverManager, getLogger());
250
251 task.setModuleProject(moduleProject);
252 task.setModuleArtifact(chosenModuleArtifacts.get(moduleProject));
253 task.setDefaultOutputDirectory(binaries.getOutputDirectory());
254 task.setDefaultOutputFileNameMapping(binaries.getOutputFileNameMapping());
255
256 task.execute(archiver, configSource);
257 }
258 }
259 }
260
261 private List<MavenProject> validateModuleVersions (Set<MavenProject> moduleProjects) {
262 List<MavenProject> result = new ArrayList<MavenProject>();
263
264 if (moduleProjects != null && !moduleProjects.isEmpty()) {
265 String version = moduleProjects.iterator().next().getVersion();
266 getLogger().debug( "First version:" + version );
267 for ( MavenProject mavenProject : moduleProjects )
268 {
269 getLogger().debug( " -> checking " + mavenProject.getId() );
270 if ( !version.equals( mavenProject.getVersion() ) )
271 {
272 result.add( mavenProject );
273 }
274 }
275 }
276 return result;
277 }
278
279 public static List<DependencySet> getDependencySets( final ModuleBinaries binaries )
280 {
281 List<DependencySet> depSets = binaries.getDependencySets();
282
283 if ( ( ( depSets == null ) || depSets.isEmpty() ) && binaries.isIncludeDependencies() )
284 {
285 final DependencySet impliedDependencySet = new DependencySet();
286
287 impliedDependencySet.setOutputDirectory( binaries.getOutputDirectory() );
288 impliedDependencySet.setOutputFileNameMapping( binaries.getOutputFileNameMapping() );
289 impliedDependencySet.setFileMode( binaries.getFileMode() );
290 impliedDependencySet.setDirectoryMode( binaries.getDirectoryMode() );
291 impliedDependencySet.setExcludes( binaries.getExcludes() );
292 impliedDependencySet.setIncludes( binaries.getIncludes() );
293 impliedDependencySet.setUnpack( binaries.isUnpack() );
294
295
296 depSets = Collections.singletonList( impliedDependencySet );
297 }
298
299 return depSets;
300 }
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324 protected void addModuleArtifact( final Artifact artifact, final MavenProject project, final Archiver archiver,
325 final AssemblerConfigurationSource configSource, final ModuleBinaries binaries )
326 throws ArchiveCreationException, AssemblyFormattingException
327 {
328 if ( artifact.getFile() == null )
329 {
330 throw new ArchiveCreationException( "Artifact: " + artifact.getId()
331 + " (included by module) does not have an artifact with a file. "
332 + "Please ensure the package phase is run before the assembly is generated." );
333 }
334
335 final AddArtifactTask task = new AddArtifactTask( artifact, getLogger() );
336
337 task.setFileNameMapping( binaries.getOutputFileNameMapping() );
338 task.setOutputDirectory( binaries.getOutputDirectory() );
339 task.setProject( project );
340 task.setModuleProject( project );
341 task.setModuleArtifact( artifact );
342
343 final int dirMode = TypeConversionUtils.modeToInt( binaries.getDirectoryMode(), getLogger() );
344 if ( dirMode != -1 )
345 {
346 task.setDirectoryMode( dirMode );
347 }
348
349 final int fileMode = TypeConversionUtils.modeToInt( binaries.getFileMode(), getLogger() );
350 if ( fileMode != -1 )
351 {
352 task.setFileMode( fileMode );
353 }
354
355 task.setUnpack( binaries.isUnpack() );
356
357 if ( binaries.isUnpack() && binaries.getUnpackOptions() != null )
358 {
359 task.setIncludes( binaries.getUnpackOptions().getIncludes() );
360 task.setExcludes( binaries.getUnpackOptions().getExcludes() );
361 }
362
363 task.execute( archiver, configSource );
364 }
365
366 protected void addModuleSourceFileSets( final ModuleSources sources, final Set<MavenProject> moduleProjects,
367 final Archiver archiver, final AssemblerConfigurationSource configSource )
368 throws ArchiveCreationException, AssemblyFormattingException
369 {
370 if ( sources == null )
371 {
372 return;
373 }
374
375 final List<FileSet> fileSets = new ArrayList<FileSet>();
376
377 if ( isDeprecatedModuleSourcesConfigPresent( sources ) )
378 {
379 final FileSet fs = new FileSet();
380 fs.setOutputDirectory( sources.getOutputDirectory() );
381 fs.setIncludes( sources.getIncludes() );
382 fs.setExcludes( sources.getExcludes() );
383 fs.setUseDefaultExcludes( sources.isUseDefaultExcludes() );
384
385 fileSets.add( fs );
386 }
387
388 List<FileSet> subFileSets = sources.getFileSets();
389
390 if ( ( subFileSets == null ) || subFileSets.isEmpty() )
391 {
392 final FileSet fs = new FileSet();
393 fs.setDirectory( "src" );
394
395 subFileSets = Collections.singletonList( fs );
396 }
397
398 fileSets.addAll( subFileSets );
399
400 for (final MavenProject moduleProject : moduleProjects) {
401 getLogger().info("Processing sources for module project: " + moduleProject.getId());
402
403 final List<FileSet> moduleFileSets = new ArrayList<FileSet>();
404
405 for (final FileSet fileSet : fileSets) {
406 moduleFileSets.add(createFileSet(fileSet, sources, moduleProject, configSource));
407 }
408
409 final AddFileSetsTask task = new AddFileSetsTask(moduleFileSets);
410
411 task.setProject(moduleProject);
412 task.setModuleProject(moduleProject);
413 task.setLogger(getLogger());
414
415 task.execute(archiver, configSource);
416 }
417 }
418
419
420
421
422 protected boolean isDeprecatedModuleSourcesConfigPresent( final ModuleSources sources )
423 {
424 boolean result = false;
425
426 if ( sources.getOutputDirectory() != null )
427 {
428 result = true;
429 }
430 else if ( ( sources.getIncludes() != null ) && !sources.getIncludes().isEmpty() )
431 {
432 result = true;
433 }
434 else if ( ( sources.getExcludes() != null ) && !sources.getExcludes().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 String moduleSubPath : modules) {
482 excludes.add(moduleSubPath + "/**");
483 }
484 }
485
486 fs.setExcludes( excludes );
487 fs.setFiltered( fileSet.isFiltered() );
488 fs.setFileMode( fileSet.getFileMode() );
489 fs.setIncludes( fileSet.getIncludes() );
490 fs.setLineEnding( fileSet.getLineEnding() );
491
492 String destPathPrefix = "";
493 if ( sources.isIncludeModuleDirectory() )
494 {
495 destPathPrefix =
496 AssemblyFormatUtils.evaluateFileNameMapping( sources.getOutputDirectoryMapping(),
497 moduleProject.getArtifact(), configSource.getProject(),
498 moduleProject, moduleProject.getArtifact(), moduleProject,
499 configSource );
500
501 if ( !destPathPrefix.endsWith( "/" ) )
502 {
503 destPathPrefix += "/";
504 }
505 }
506
507 String destPath = fileSet.getOutputDirectory();
508
509 if ( destPath == null )
510 {
511 destPath = destPathPrefix;
512 }
513 else
514 {
515 destPath = destPathPrefix + destPath;
516 }
517
518 destPath =
519 AssemblyFormatUtils.getOutputDirectory( destPath, configSource.getProject(), moduleProject, moduleProject,
520 configSource.getFinalName(), configSource );
521
522 fs.setOutputDirectory( destPath );
523
524 getLogger().debug( "module source directory is: " + sourcePath );
525 getLogger().debug( "module dest directory is: " + destPath + " (assembly basedir may be prepended)" );
526
527 return fs;
528 }
529
530 public static Set<MavenProject> getModuleProjects( final ModuleSet moduleSet,
531 final AssemblerConfigurationSource configSource,
532 final Logger logger )
533 throws ArchiveCreationException
534 {
535 MavenProject project = configSource.getProject();
536 Set<MavenProject> moduleProjects = null;
537
538 if ( moduleSet.isUseAllReactorProjects() )
539 {
540 if ( !moduleSet.isIncludeSubModules() )
541 {
542 moduleProjects = new LinkedHashSet<MavenProject>( configSource.getReactorProjects() );
543 }
544
545 project = configSource.getReactorProjects().get( 0 );
546 }
547
548 if ( moduleProjects == null )
549 {
550 try
551 {
552 moduleProjects =
553 ProjectUtils.getProjectModules( project, configSource.getReactorProjects(),
554 moduleSet.isIncludeSubModules(), logger );
555 }
556 catch ( final IOException e )
557 {
558 throw new ArchiveCreationException( "Error retrieving module-set for project: " + project.getId()
559 + ": " + e.getMessage(), e );
560 }
561 }
562
563 FilterUtils.filterProjects( moduleProjects, moduleSet.getIncludes(), moduleSet.getExcludes(), true, logger );
564 return moduleProjects;
565 }
566
567 }