1 package org.apache.maven;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.text.SimpleDateFormat;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Date;
27 import java.util.HashSet;
28 import java.util.LinkedHashMap;
29 import java.util.LinkedHashSet;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Properties;
33
34 import org.apache.maven.artifact.ArtifactUtils;
35 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
36 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
37 import org.apache.maven.execution.DefaultMavenExecutionResult;
38 import org.apache.maven.execution.ExecutionEvent;
39 import org.apache.maven.execution.MavenExecutionRequest;
40 import org.apache.maven.execution.MavenExecutionRequestPopulationException;
41 import org.apache.maven.execution.MavenExecutionRequestPopulator;
42 import org.apache.maven.execution.MavenExecutionResult;
43 import org.apache.maven.execution.MavenSession;
44 import org.apache.maven.execution.ProjectDependencyGraph;
45 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
46 import org.apache.maven.lifecycle.internal.LifecycleStarter;
47 import org.apache.maven.model.building.ModelProblem;
48 import org.apache.maven.model.building.ModelProblemUtils;
49 import org.apache.maven.model.building.ModelSource;
50 import org.apache.maven.model.building.UrlModelSource;
51 import org.apache.maven.plugin.LegacySupport;
52 import org.apache.maven.project.DuplicateProjectException;
53 import org.apache.maven.project.MavenProject;
54 import org.apache.maven.project.ProjectBuilder;
55 import org.apache.maven.project.ProjectBuildingException;
56 import org.apache.maven.project.ProjectBuildingRequest;
57 import org.apache.maven.project.ProjectBuildingResult;
58 import org.apache.maven.project.ProjectSorter;
59 import org.apache.maven.repository.DelegatingLocalArtifactRepository;
60 import org.apache.maven.repository.LocalRepositoryNotAccessibleException;
61 import org.apache.maven.settings.Mirror;
62 import org.apache.maven.settings.Proxy;
63 import org.apache.maven.settings.Server;
64 import org.apache.maven.settings.building.SettingsProblem;
65 import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
66 import org.apache.maven.settings.crypto.SettingsDecrypter;
67 import org.apache.maven.settings.crypto.SettingsDecryptionResult;
68 import org.codehaus.plexus.PlexusContainer;
69 import org.codehaus.plexus.component.annotations.Component;
70 import org.codehaus.plexus.component.annotations.Requirement;
71 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
72 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
73 import org.codehaus.plexus.logging.Logger;
74 import org.codehaus.plexus.util.IOUtil;
75 import org.codehaus.plexus.util.StringUtils;
76 import org.codehaus.plexus.util.dag.CycleDetectedException;
77 import org.codehaus.plexus.util.xml.Xpp3Dom;
78 import org.sonatype.aether.ConfigurationProperties;
79 import org.sonatype.aether.RepositorySystem;
80 import org.sonatype.aether.RepositorySystemSession;
81 import org.sonatype.aether.collection.DependencyGraphTransformer;
82 import org.sonatype.aether.collection.DependencyManager;
83 import org.sonatype.aether.collection.DependencySelector;
84 import org.sonatype.aether.collection.DependencyTraverser;
85 import org.sonatype.aether.repository.Authentication;
86 import org.sonatype.aether.repository.LocalRepository;
87 import org.sonatype.aether.repository.RepositoryPolicy;
88 import org.sonatype.aether.repository.WorkspaceReader;
89 import org.sonatype.aether.util.DefaultRepositorySystemSession;
90 import org.sonatype.aether.util.graph.manager.ClassicDependencyManager;
91 import org.sonatype.aether.util.graph.selector.AndDependencySelector;
92 import org.sonatype.aether.util.graph.selector.ExclusionDependencySelector;
93 import org.sonatype.aether.util.graph.selector.OptionalDependencySelector;
94 import org.sonatype.aether.util.graph.selector.ScopeDependencySelector;
95 import org.sonatype.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
96 import org.sonatype.aether.util.graph.transformer.NearestVersionConflictResolver;
97 import org.sonatype.aether.util.graph.transformer.ConflictMarker;
98 import org.sonatype.aether.util.graph.transformer.JavaDependencyContextRefiner;
99 import org.sonatype.aether.util.graph.transformer.JavaEffectiveScopeCalculator;
100 import org.sonatype.aether.util.graph.traverser.FatArtifactTraverser;
101 import org.sonatype.aether.util.repository.ChainedWorkspaceReader;
102 import org.sonatype.aether.util.repository.DefaultAuthenticationSelector;
103 import org.sonatype.aether.util.repository.DefaultMirrorSelector;
104 import org.sonatype.aether.util.repository.DefaultProxySelector;
105
106
107
108
109 @Component(role = Maven.class)
110 public class DefaultMaven
111 implements Maven
112 {
113
114 @Requirement
115 private Logger logger;
116
117 @Requirement
118 protected ProjectBuilder projectBuilder;
119
120 @Requirement
121 private LifecycleStarter lifecycleStarter;
122
123 @Requirement
124 protected PlexusContainer container;
125
126 @Requirement
127 MavenExecutionRequestPopulator populator;
128
129 @Requirement
130 private ExecutionEventCatapult eventCatapult;
131
132 @Requirement
133 private ArtifactHandlerManager artifactHandlerManager;
134
135 @Requirement( optional = true, hint = "ide" )
136 private WorkspaceReader workspaceRepository;
137
138 @Requirement
139 private RepositorySystem repoSystem;
140
141 @Requirement
142 private SettingsDecrypter settingsDecrypter;
143
144 @Requirement
145 private LegacySupport legacySupport;
146
147 @Requirement
148 private EventSpyDispatcher eventSpyDispatcher;
149
150 public MavenExecutionResult execute( MavenExecutionRequest request )
151 {
152 MavenExecutionResult result;
153
154 try
155 {
156 result = doExecute( populator.populateDefaults( request ) );
157 }
158 catch ( OutOfMemoryError e )
159 {
160 result = processResult( new DefaultMavenExecutionResult(), e );
161 }
162 catch ( MavenExecutionRequestPopulationException e )
163 {
164 result = processResult( new DefaultMavenExecutionResult(), e );
165 }
166 catch ( RuntimeException e )
167 {
168 result =
169 processResult( new DefaultMavenExecutionResult(),
170 new InternalErrorException( "Internal error: " + e, e ) );
171 }
172 finally
173 {
174 legacySupport.setSession( null );
175 }
176
177 return result;
178 }
179
180 @SuppressWarnings({"ThrowableInstanceNeverThrown", "ThrowableResultOfMethodCallIgnored"})
181 private MavenExecutionResult doExecute( MavenExecutionRequest request )
182 {
183
184 if ( request.getStartTime() != null )
185 {
186 request.getSystemProperties().put( "${build.timestamp}",
187 new SimpleDateFormat( "yyyyMMdd-hhmm" ).format( request.getStartTime() ) );
188 }
189
190 request.setStartTime( new Date() );
191
192 MavenExecutionResult result = new DefaultMavenExecutionResult();
193
194 try
195 {
196 validateLocalRepository( request );
197 }
198 catch ( LocalRepositoryNotAccessibleException e )
199 {
200 return processResult( result, e );
201 }
202
203 DelegatingLocalArtifactRepository delegatingLocalArtifactRepository =
204 new DelegatingLocalArtifactRepository( request.getLocalRepository() );
205
206 request.setLocalRepository( delegatingLocalArtifactRepository );
207
208 DefaultRepositorySystemSession repoSession = (DefaultRepositorySystemSession) newRepositorySession( request );
209
210 MavenSession session = new MavenSession( container, repoSession, request, result );
211 legacySupport.setSession( session );
212
213 try
214 {
215 for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( Collections.<MavenProject> emptyList() ) )
216 {
217 listener.afterSessionStart( session );
218 }
219 }
220 catch ( MavenExecutionException e )
221 {
222 return processResult( result, e );
223 }
224
225 eventCatapult.fire( ExecutionEvent.Type.ProjectDiscoveryStarted, session, null );
226
227 request.getProjectBuildingRequest().setRepositorySession( session.getRepositorySession() );
228
229
230
231 List<MavenProject> projects;
232 try
233 {
234 projects = getProjectsForMavenReactor( request );
235 }
236 catch ( ProjectBuildingException e )
237 {
238 return processResult( result, e );
239 }
240
241 session.setProjects( projects );
242
243 result.setTopologicallySortedProjects( session.getProjects() );
244
245 result.setProject( session.getTopLevelProject() );
246
247 try
248 {
249 Map<String, MavenProject> projectMap;
250 projectMap = getProjectMap( session.getProjects() );
251
252
253
254
255
256
257 ReactorReader reactorRepository = new ReactorReader( projectMap );
258
259 repoSession.setWorkspaceReader( ChainedWorkspaceReader.newInstance( reactorRepository,
260 repoSession.getWorkspaceReader() ) );
261 }
262 catch ( org.apache.maven.DuplicateProjectException e )
263 {
264 return processResult( result, e );
265 }
266
267 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
268 try
269 {
270 for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( projects ) )
271 {
272 Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() );
273
274 listener.afterProjectsRead( session );
275 }
276 }
277 catch ( MavenExecutionException e )
278 {
279 return processResult( result, e );
280 }
281 finally
282 {
283 Thread.currentThread().setContextClassLoader( originalClassLoader );
284 }
285
286 try
287 {
288 ProjectSorter projectSorter = new ProjectSorter( session.getProjects() );
289
290 ProjectDependencyGraph projectDependencyGraph = createDependencyGraph( projectSorter, request );
291
292 session.setProjects( projectDependencyGraph.getSortedProjects() );
293
294 session.setProjectDependencyGraph( projectDependencyGraph );
295 }
296 catch ( CycleDetectedException e )
297 {
298 String message = "The projects in the reactor contain a cyclic reference: " + e.getMessage();
299
300 ProjectCycleException error = new ProjectCycleException( message, e );
301
302 return processResult( result, error );
303 }
304 catch ( DuplicateProjectException e )
305 {
306 return processResult( result, e );
307 }
308 catch ( MavenExecutionException e )
309 {
310 return processResult( result, e );
311 }
312
313 result.setTopologicallySortedProjects( session.getProjects() );
314
315 if ( result.hasExceptions() )
316 {
317 return result;
318 }
319
320 lifecycleStarter.execute( session );
321
322 validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() );
323
324 if ( session.getResult().hasExceptions() )
325 {
326 return processResult( result, session.getResult().getExceptions().get( 0 ) );
327 }
328
329 return result;
330 }
331
332 public RepositorySystemSession newRepositorySession( MavenExecutionRequest request )
333 {
334 DefaultRepositorySystemSession session = new DefaultRepositorySystemSession();
335
336 session.setCache( request.getRepositoryCache() );
337
338 session.setIgnoreInvalidArtifactDescriptor( true ).setIgnoreMissingArtifactDescriptor( true );
339
340 Map<Object, Object> configProps = new LinkedHashMap<Object, Object>();
341 configProps.put( ConfigurationProperties.USER_AGENT, getUserAgent() );
342 configProps.put( ConfigurationProperties.INTERACTIVE, Boolean.valueOf( request.isInteractiveMode() ) );
343 configProps.putAll( request.getSystemProperties() );
344 configProps.putAll( request.getUserProperties() );
345
346 session.setOffline( request.isOffline() );
347 session.setChecksumPolicy( request.getGlobalChecksumPolicy() );
348 if ( request.isNoSnapshotUpdates() )
349 {
350 session.setUpdatePolicy( RepositoryPolicy.UPDATE_POLICY_NEVER );
351 }
352 else if ( request.isUpdateSnapshots() )
353 {
354 session.setUpdatePolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS );
355 }
356 else
357 {
358 session.setUpdatePolicy( null );
359 }
360
361 session.setNotFoundCachingEnabled( request.isCacheNotFound() );
362 session.setTransferErrorCachingEnabled( request.isCacheTransferError() );
363
364 session.setArtifactTypeRegistry( RepositoryUtils.newArtifactTypeRegistry( artifactHandlerManager ) );
365
366 LocalRepository localRepo = new LocalRepository( request.getLocalRepository().getBasedir() );
367 session.setLocalRepositoryManager( repoSystem.newLocalRepositoryManager( localRepo ) );
368
369 if ( request.getWorkspaceReader() != null )
370 {
371 session.setWorkspaceReader( request.getWorkspaceReader() );
372 }
373 else
374 {
375 session.setWorkspaceReader( workspaceRepository );
376 }
377
378 DefaultSettingsDecryptionRequest decrypt = new DefaultSettingsDecryptionRequest();
379 decrypt.setProxies( request.getProxies() );
380 decrypt.setServers( request.getServers() );
381 SettingsDecryptionResult decrypted = settingsDecrypter.decrypt( decrypt );
382
383 if ( logger.isDebugEnabled() )
384 {
385 for ( SettingsProblem problem : decrypted.getProblems() )
386 {
387 logger.debug( problem.getMessage(), problem.getException() );
388 }
389 }
390
391 DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
392 for ( Mirror mirror : request.getMirrors() )
393 {
394 mirrorSelector.add( mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, mirror.getMirrorOf(),
395 mirror.getMirrorOfLayouts() );
396 }
397 session.setMirrorSelector( mirrorSelector );
398
399 DefaultProxySelector proxySelector = new DefaultProxySelector();
400 for ( Proxy proxy : decrypted.getProxies() )
401 {
402 Authentication proxyAuth = new Authentication( proxy.getUsername(), proxy.getPassword() );
403 proxySelector.add( new org.sonatype.aether.repository.Proxy( proxy.getProtocol(), proxy.getHost(), proxy.getPort(),
404 proxyAuth ), proxy.getNonProxyHosts() );
405 }
406 session.setProxySelector( proxySelector );
407
408 DefaultAuthenticationSelector authSelector = new DefaultAuthenticationSelector();
409 for ( Server server : decrypted.getServers() )
410 {
411 Authentication auth =
412 new Authentication( server.getUsername(), server.getPassword(), server.getPrivateKey(),
413 server.getPassphrase() );
414 authSelector.add( server.getId(), auth );
415
416 if ( server.getConfiguration() != null )
417 {
418 Xpp3Dom dom = (Xpp3Dom) server.getConfiguration();
419 for ( int i = dom.getChildCount() - 1; i >= 0; i-- )
420 {
421 Xpp3Dom child = dom.getChild( i );
422 if ( "wagonProvider".equals( child.getName() ) )
423 {
424 dom.removeChild( i );
425 }
426 }
427
428 XmlPlexusConfiguration config = new XmlPlexusConfiguration( dom );
429 configProps.put( "aether.connector.wagon.config." + server.getId(), config );
430 }
431
432 configProps.put( "aether.connector.perms.fileMode." + server.getId(), server.getFilePermissions() );
433 configProps.put( "aether.connector.perms.dirMode." + server.getId(), server.getDirectoryPermissions() );
434 }
435 session.setAuthenticationSelector( authSelector );
436
437 DependencyTraverser depTraverser = new FatArtifactTraverser();
438 session.setDependencyTraverser( depTraverser );
439
440 DependencyManager depManager = new ClassicDependencyManager();
441 session.setDependencyManager( depManager );
442
443 DependencySelector depFilter =
444 new AndDependencySelector( new ScopeDependencySelector( "test", "provided" ), new OptionalDependencySelector(),
445 new ExclusionDependencySelector() );
446 session.setDependencySelector( depFilter );
447
448 DependencyGraphTransformer transformer =
449 new ChainedDependencyGraphTransformer( new ConflictMarker(), new JavaEffectiveScopeCalculator(),
450 new NearestVersionConflictResolver(),
451 new JavaDependencyContextRefiner() );
452 session.setDependencyGraphTransformer( transformer );
453
454 session.setTransferListener( request.getTransferListener() );
455
456 session.setRepositoryListener( eventSpyDispatcher.chainListener( new LoggingRepositoryListener( logger ) ) );
457
458 session.setUserProps( request.getUserProperties() );
459 session.setSystemProps( request.getSystemProperties() );
460 session.setConfigProps( configProps );
461
462 return session;
463 }
464
465 private String getUserAgent()
466 {
467 return "Apache-Maven/" + getMavenVersion()
468 + " (Java " + System.getProperty( "java.version" ) + "; "
469 + System.getProperty( "os.name" ) + " " + System.getProperty( "os.version" ) + ")";
470 }
471
472 private String getMavenVersion()
473 {
474 Properties props = new Properties();
475
476 InputStream is = getClass().getResourceAsStream( "/META-INF/maven/org.apache.maven/maven-core/pom.properties" );
477 if ( is != null )
478 {
479 try
480 {
481 props.load( is );
482 }
483 catch ( IOException e )
484 {
485 logger.debug( "Failed to read Maven version", e );
486 }
487 IOUtil.close( is );
488 }
489
490 return props.getProperty( "version", "unknown-version" );
491 }
492
493 private void validateLocalRepository( MavenExecutionRequest request )
494 throws LocalRepositoryNotAccessibleException
495 {
496 File localRepoDir = request.getLocalRepositoryPath();
497
498 logger.debug( "Using local repository at " + localRepoDir );
499
500 localRepoDir.mkdirs();
501
502 if ( !localRepoDir.isDirectory() )
503 {
504 throw new LocalRepositoryNotAccessibleException( "Could not create local repository at " + localRepoDir );
505 }
506 }
507
508 private Collection<AbstractMavenLifecycleParticipant> getLifecycleParticipants( Collection<MavenProject> projects )
509 {
510 Collection<AbstractMavenLifecycleParticipant> lifecycleListeners =
511 new LinkedHashSet<AbstractMavenLifecycleParticipant>();
512
513 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
514 try
515 {
516 try
517 {
518 lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
519 }
520 catch ( ComponentLookupException e )
521 {
522
523 logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
524 }
525
526 Collection<ClassLoader> scannedRealms = new HashSet<ClassLoader>();
527
528 for ( MavenProject project : projects )
529 {
530 ClassLoader projectRealm = project.getClassRealm();
531
532 if ( projectRealm != null && scannedRealms.add( projectRealm ) )
533 {
534 Thread.currentThread().setContextClassLoader( projectRealm );
535
536 try
537 {
538 lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
539 }
540 catch ( ComponentLookupException e )
541 {
542
543 logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
544 }
545 }
546 }
547 }
548 finally
549 {
550 Thread.currentThread().setContextClassLoader( originalClassLoader );
551 }
552
553 return lifecycleListeners;
554 }
555
556 private MavenExecutionResult processResult( MavenExecutionResult result, Throwable e )
557 {
558 if ( !result.getExceptions().contains( e ) )
559 {
560 result.addException( e );
561 }
562
563 return result;
564 }
565
566 private List<MavenProject> getProjectsForMavenReactor( MavenExecutionRequest request )
567 throws ProjectBuildingException
568 {
569 List<MavenProject> projects = new ArrayList<MavenProject>();
570
571
572
573 if ( request.getPom() == null )
574 {
575 ModelSource modelSource = new UrlModelSource( DefaultMaven.class.getResource( "project/standalone.xml" ) );
576 MavenProject project =
577 projectBuilder.build( modelSource, request.getProjectBuildingRequest() ).getProject();
578 project.setExecutionRoot( true );
579 projects.add( project );
580 request.setProjectPresent( false );
581 return projects;
582 }
583
584 List<File> files = Arrays.asList( request.getPom().getAbsoluteFile() );
585 collectProjects( projects, files, request );
586 return projects;
587 }
588
589 private Map<String, MavenProject> getProjectMap( List<MavenProject> projects )
590 throws org.apache.maven.DuplicateProjectException
591 {
592 Map<String, MavenProject> index = new LinkedHashMap<String, MavenProject>();
593 Map<String, List<File>> collisions = new LinkedHashMap<String, List<File>>();
594
595 for ( MavenProject project : projects )
596 {
597 String projectId = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
598
599 MavenProject collision = index.get( projectId );
600
601 if ( collision == null )
602 {
603 index.put( projectId, project );
604 }
605 else
606 {
607 List<File> pomFiles = collisions.get( projectId );
608
609 if ( pomFiles == null )
610 {
611 pomFiles = new ArrayList<File>( Arrays.asList( collision.getFile(), project.getFile() ) );
612 collisions.put( projectId, pomFiles );
613 }
614 else
615 {
616 pomFiles.add( project.getFile() );
617 }
618 }
619 }
620
621 if ( !collisions.isEmpty() )
622 {
623 throw new org.apache.maven.DuplicateProjectException( "Two or more projects in the reactor"
624 + " have the same identifier, please make sure that <groupId>:<artifactId>:<version>"
625 + " is unique for each project: " + collisions, collisions );
626 }
627
628 return index;
629 }
630
631 private void collectProjects( List<MavenProject> projects, List<File> files, MavenExecutionRequest request )
632 throws ProjectBuildingException
633 {
634 ProjectBuildingRequest projectBuildingRequest = request.getProjectBuildingRequest();
635
636 List<ProjectBuildingResult> results = projectBuilder.build( files, request.isRecursive(), projectBuildingRequest );
637
638 boolean problems = false;
639
640 for ( ProjectBuildingResult result : results )
641 {
642 projects.add( result.getProject() );
643
644 if ( !result.getProblems().isEmpty() && logger.isWarnEnabled() )
645 {
646 logger.warn( "" );
647 logger.warn( "Some problems were encountered while building the effective model for "
648 + result.getProject().getId() );
649
650 for ( ModelProblem problem : result.getProblems() )
651 {
652 String location = ModelProblemUtils.formatLocation( problem, result.getProjectId() );
653 logger.warn( problem.getMessage() + ( StringUtils.isNotEmpty( location ) ? " @ " + location : "" ) );
654 }
655
656 problems = true;
657 }
658 }
659
660 if ( problems )
661 {
662 logger.warn( "" );
663 logger.warn( "It is highly recommended to fix these problems"
664 + " because they threaten the stability of your build." );
665 logger.warn( "" );
666 logger.warn( "For this reason, future Maven versions might no"
667 + " longer support building such malformed projects." );
668 logger.warn( "" );
669 }
670 }
671
672 private void validateActivatedProfiles( List<MavenProject> projects, List<String> activeProfileIds )
673 {
674 Collection<String> notActivatedProfileIds = new LinkedHashSet<String>( activeProfileIds );
675
676 for ( MavenProject project : projects )
677 {
678 for ( List<String> profileIds : project.getInjectedProfileIds().values() )
679 {
680 notActivatedProfileIds.removeAll( profileIds );
681 }
682 }
683
684 for ( String notActivatedProfileId : notActivatedProfileIds )
685 {
686 logger.warn( "The requested profile \"" + notActivatedProfileId
687 + "\" could not be activated because it does not exist." );
688 }
689 }
690
691 protected Logger getLogger()
692 {
693 return logger;
694 }
695
696 private ProjectDependencyGraph createDependencyGraph( ProjectSorter sorter, MavenExecutionRequest request )
697 throws MavenExecutionException
698 {
699 ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( sorter );
700
701 List<MavenProject> activeProjects = sorter.getSortedProjects();
702
703 activeProjects = trimSelectedProjects( activeProjects, graph, request );
704 activeProjects = trimResumedProjects( activeProjects, request );
705
706 if ( activeProjects.size() != sorter.getSortedProjects().size() )
707 {
708 graph = new FilteredProjectDependencyGraph( graph, activeProjects );
709 }
710
711 return graph;
712 }
713
714 private List<MavenProject> trimSelectedProjects( List<MavenProject> projects, ProjectDependencyGraph graph,
715 MavenExecutionRequest request )
716 throws MavenExecutionException
717 {
718 List<MavenProject> result = projects;
719
720 if ( !request.getSelectedProjects().isEmpty() )
721 {
722 File reactorDirectory = null;
723 if ( request.getBaseDirectory() != null )
724 {
725 reactorDirectory = new File( request.getBaseDirectory() );
726 }
727
728 Collection<MavenProject> selectedProjects = new LinkedHashSet<MavenProject>( projects.size() );
729
730 for ( String selector : request.getSelectedProjects() )
731 {
732 MavenProject selectedProject = null;
733
734 for ( MavenProject project : projects )
735 {
736 if ( isMatchingProject( project, selector, reactorDirectory ) )
737 {
738 selectedProject = project;
739 break;
740 }
741 }
742
743 if ( selectedProject != null )
744 {
745 selectedProjects.add( selectedProject );
746 }
747 else
748 {
749 throw new MavenExecutionException( "Could not find the selected project in the reactor: "
750 + selector, request.getPom() );
751 }
752 }
753
754 boolean makeUpstream = false;
755 boolean makeDownstream = false;
756
757 if ( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( request.getMakeBehavior() ) )
758 {
759 makeUpstream = true;
760 }
761 else if ( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals( request.getMakeBehavior() ) )
762 {
763 makeDownstream = true;
764 }
765 else if ( MavenExecutionRequest.REACTOR_MAKE_BOTH.equals( request.getMakeBehavior() ) )
766 {
767 makeUpstream = true;
768 makeDownstream = true;
769 }
770 else if ( StringUtils.isNotEmpty( request.getMakeBehavior() ) )
771 {
772 throw new MavenExecutionException( "Invalid reactor make behavior: " + request.getMakeBehavior(),
773 request.getPom() );
774 }
775
776 if ( makeUpstream || makeDownstream )
777 {
778 for ( MavenProject selectedProject : new ArrayList<MavenProject>( selectedProjects ) )
779 {
780 if ( makeUpstream )
781 {
782 selectedProjects.addAll( graph.getUpstreamProjects( selectedProject, true ) );
783 }
784 if ( makeDownstream )
785 {
786 selectedProjects.addAll( graph.getDownstreamProjects( selectedProject, true ) );
787 }
788 }
789 }
790
791 result = new ArrayList<MavenProject>( selectedProjects.size() );
792
793 for ( MavenProject project : projects )
794 {
795 if ( selectedProjects.contains( project ) )
796 {
797 result.add( project );
798 }
799 }
800 }
801
802 return result;
803 }
804
805 private List<MavenProject> trimResumedProjects( List<MavenProject> projects, MavenExecutionRequest request )
806 throws MavenExecutionException
807 {
808 List<MavenProject> result = projects;
809
810 if ( StringUtils.isNotEmpty( request.getResumeFrom() ) )
811 {
812 File reactorDirectory = null;
813 if ( request.getBaseDirectory() != null )
814 {
815 reactorDirectory = new File( request.getBaseDirectory() );
816 }
817
818 String selector = request.getResumeFrom();
819
820 result = new ArrayList<MavenProject>( projects.size() );
821
822 boolean resumed = false;
823
824 for ( MavenProject project : projects )
825 {
826 if ( !resumed && isMatchingProject( project, selector, reactorDirectory ) )
827 {
828 resumed = true;
829 }
830
831 if ( resumed )
832 {
833 result.add( project );
834 }
835 }
836
837 if ( !resumed )
838 {
839 throw new MavenExecutionException( "Could not find project to resume reactor build from: " + selector
840 + " vs " + projects, request.getPom() );
841 }
842 }
843
844 return result;
845 }
846
847 private boolean isMatchingProject( MavenProject project, String selector, File reactorDirectory )
848 {
849
850 if ( selector.indexOf( ':' ) >= 0 )
851 {
852 String id = ':' + project.getArtifactId();
853
854 if ( id.equals( selector ) )
855 {
856 return true;
857 }
858
859 id = project.getGroupId() + id;
860
861 if ( id.equals( selector ) )
862 {
863 return true;
864 }
865 }
866
867
868 else if ( reactorDirectory != null )
869 {
870 File selectedProject = new File( new File( reactorDirectory, selector ).toURI().normalize() );
871
872 if ( selectedProject.isFile() )
873 {
874 return selectedProject.equals( project.getFile() );
875 }
876 else if ( selectedProject.isDirectory() )
877 {
878 return selectedProject.equals( project.getBasedir() );
879 }
880 }
881
882 return false;
883 }
884
885 }