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