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