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.execution.DefaultMavenExecutionResult;
37 import org.apache.maven.execution.ExecutionEvent;
38 import org.apache.maven.execution.MavenExecutionRequest;
39 import org.apache.maven.execution.MavenExecutionRequestPopulationException;
40 import org.apache.maven.execution.MavenExecutionRequestPopulator;
41 import org.apache.maven.execution.MavenExecutionResult;
42 import org.apache.maven.execution.MavenSession;
43 import org.apache.maven.execution.ProjectDependencyGraph;
44 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
45 import org.apache.maven.lifecycle.internal.LifecycleStarter;
46 import org.apache.maven.model.building.ModelProblem;
47 import org.apache.maven.model.building.ModelProblemUtils;
48 import org.apache.maven.model.building.ModelSource;
49 import org.apache.maven.model.building.UrlModelSource;
50 import org.apache.maven.plugin.LegacySupport;
51 import org.apache.maven.project.DuplicateProjectException;
52 import org.apache.maven.project.MavenProject;
53 import org.apache.maven.project.ProjectBuilder;
54 import org.apache.maven.project.ProjectBuildingException;
55 import org.apache.maven.project.ProjectBuildingRequest;
56 import org.apache.maven.project.ProjectBuildingResult;
57 import org.apache.maven.project.ProjectSorter;
58 import org.apache.maven.repository.DelegatingLocalArtifactRepository;
59 import org.apache.maven.repository.LocalRepositoryNotAccessibleException;
60 import org.apache.maven.settings.Mirror;
61 import org.apache.maven.settings.Proxy;
62 import org.apache.maven.settings.Server;
63 import org.apache.maven.settings.building.SettingsProblem;
64 import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
65 import org.apache.maven.settings.crypto.SettingsDecrypter;
66 import org.apache.maven.settings.crypto.SettingsDecryptionResult;
67 import org.codehaus.plexus.PlexusContainer;
68 import org.codehaus.plexus.component.annotations.Component;
69 import org.codehaus.plexus.component.annotations.Requirement;
70 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
71 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
72 import org.codehaus.plexus.logging.Logger;
73 import org.codehaus.plexus.util.IOUtil;
74 import org.codehaus.plexus.util.StringUtils;
75 import org.codehaus.plexus.util.dag.CycleDetectedException;
76 import org.codehaus.plexus.util.xml.Xpp3Dom;
77 import org.sonatype.aether.ConfigurationProperties;
78 import org.sonatype.aether.RepositoryEvent;
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 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 = processResult( new DefaultMavenExecutionResult(), e );
158 }
159 catch ( MavenExecutionRequestPopulationException e )
160 {
161 result = processResult( new DefaultMavenExecutionResult(), e );
162 }
163 catch ( RuntimeException e )
164 {
165 result =
166 processResult( 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 @SuppressWarnings({"ThrowableInstanceNeverThrown", "ThrowableResultOfMethodCallIgnored"})
178 private MavenExecutionResult doExecute( MavenExecutionRequest request )
179 {
180
181 if ( request.getStartTime() != null )
182 {
183 request.getSystemProperties().put( "${build.timestamp}", 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 processResult( 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 processResult( 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 processResult( 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 processResult( result, e );
261 }
262
263 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
264 try
265 {
266 for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( projects ) )
267 {
268 Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() );
269
270 listener.afterProjectsRead( session );
271 }
272 }
273 catch ( MavenExecutionException e )
274 {
275 return processResult( result, e );
276 }
277 finally
278 {
279 Thread.currentThread().setContextClassLoader( originalClassLoader );
280 }
281
282 try
283 {
284 ProjectSorter projectSorter = new ProjectSorter( session.getProjects() );
285
286 ProjectDependencyGraph projectDependencyGraph = createDependencyGraph( projectSorter, request );
287
288 session.setProjects( projectDependencyGraph.getSortedProjects() );
289
290 session.setProjectDependencyGraph( projectDependencyGraph );
291 }
292 catch ( CycleDetectedException e )
293 {
294 String message = "The projects in the reactor contain a cyclic reference: " + e.getMessage();
295
296 ProjectCycleException error = new ProjectCycleException( message, e );
297
298 return processResult( result, error );
299 }
300 catch ( DuplicateProjectException e )
301 {
302 return processResult( result, e );
303 }
304 catch ( MavenExecutionException e )
305 {
306 return processResult( result, e );
307 }
308
309 result.setTopologicallySortedProjects( session.getProjects() );
310
311 if ( result.hasExceptions() )
312 {
313 return result;
314 }
315
316 lifecycleStarter.execute( session );
317
318 validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() );
319
320 if ( session.getResult().hasExceptions() )
321 {
322 return processResult( result, session.getResult().getExceptions().get( 0 ) );
323 }
324
325 return result;
326 }
327
328 public RepositorySystemSession newRepositorySession( MavenExecutionRequest request )
329 {
330 DefaultRepositorySystemSession session = new DefaultRepositorySystemSession();
331
332 session.setCache( request.getRepositoryCache() );
333
334 session.setIgnoreInvalidArtifactDescriptor( true ).setIgnoreMissingArtifactDescriptor( true );
335
336 Map<Object, Object> configProps = new LinkedHashMap<Object, Object>();
337 configProps.put( ConfigurationProperties.USER_AGENT, getUserAgent() );
338 configProps.put( ConfigurationProperties.INTERACTIVE, Boolean.valueOf( request.isInteractiveMode() ) );
339 configProps.putAll( request.getSystemProperties() );
340 configProps.putAll( request.getUserProperties() );
341
342 session.setOffline( request.isOffline() );
343 session.setChecksumPolicy( request.getGlobalChecksumPolicy() );
344 session.setUpdatePolicy( request.isUpdateSnapshots() ? RepositoryPolicy.UPDATE_POLICY_ALWAYS : null );
345
346 session.setNotFoundCachingEnabled( request.isCacheNotFound() );
347 session.setTransferErrorCachingEnabled( request.isCacheTransferError() );
348
349 session.setArtifactTypeRegistry( RepositoryUtils.newArtifactTypeRegistry( artifactHandlerManager ) );
350
351 LocalRepository localRepo = new LocalRepository( request.getLocalRepository().getBasedir() );
352 session.setLocalRepositoryManager( repoSystem.newLocalRepositoryManager( localRepo ) );
353
354 if ( request.getWorkspaceReader() != null )
355 {
356 session.setWorkspaceReader( request.getWorkspaceReader() );
357 }
358 else
359 {
360 session.setWorkspaceReader( workspaceRepository );
361 }
362
363 DefaultSettingsDecryptionRequest decrypt = new DefaultSettingsDecryptionRequest();
364 decrypt.setProxies( request.getProxies() );
365 decrypt.setServers( request.getServers() );
366 SettingsDecryptionResult decrypted = settingsDecrypter.decrypt( decrypt );
367
368 if ( logger.isDebugEnabled() )
369 {
370 for ( SettingsProblem problem : decrypted.getProblems() )
371 {
372 logger.debug( problem.getMessage(), problem.getException() );
373 }
374 }
375
376 DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
377 for ( Mirror mirror : request.getMirrors() )
378 {
379 mirrorSelector.add( mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, mirror.getMirrorOf(),
380 mirror.getMirrorOfLayouts() );
381 }
382 session.setMirrorSelector( mirrorSelector );
383
384 DefaultProxySelector proxySelector = new DefaultProxySelector();
385 for ( Proxy proxy : decrypted.getProxies() )
386 {
387 Authentication proxyAuth = new Authentication( proxy.getUsername(), proxy.getPassword() );
388 proxySelector.add( new org.sonatype.aether.repository.Proxy( proxy.getProtocol(), proxy.getHost(), proxy.getPort(),
389 proxyAuth ), proxy.getNonProxyHosts() );
390 }
391 session.setProxySelector( proxySelector );
392
393 DefaultAuthenticationSelector authSelector = new DefaultAuthenticationSelector();
394 for ( Server server : decrypted.getServers() )
395 {
396 Authentication auth =
397 new Authentication( server.getUsername(), server.getPassword(), server.getPrivateKey(),
398 server.getPassphrase() );
399 authSelector.add( server.getId(), auth );
400
401 if ( server.getConfiguration() != null )
402 {
403 Xpp3Dom dom = (Xpp3Dom) server.getConfiguration();
404 for ( int i = dom.getChildCount() - 1; i >= 0; i-- )
405 {
406 Xpp3Dom child = dom.getChild( i );
407 if ( "wagonProvider".equals( child.getName() ) )
408 {
409 dom.removeChild( i );
410 }
411 }
412
413 XmlPlexusConfiguration config = new XmlPlexusConfiguration( dom );
414 configProps.put( "aether.connector.wagon.config." + server.getId(), config );
415 }
416
417 configProps.put( "aether.connector.perms.fileMode." + server.getId(), server.getFilePermissions() );
418 configProps.put( "aether.connector.perms.dirMode." + server.getId(), server.getDirectoryPermissions() );
419 }
420 session.setAuthenticationSelector( authSelector );
421
422 DependencyTraverser depTraverser = new FatArtifactTraverser();
423 session.setDependencyTraverser( depTraverser );
424
425 DependencyManager depManager = new ClassicDependencyManager();
426 session.setDependencyManager( depManager );
427
428 DependencySelector depFilter =
429 new AndDependencySelector( new ScopeDependencySelector( "test", "provided" ), new OptionalDependencySelector(),
430 new ExclusionDependencySelector() );
431 session.setDependencySelector( depFilter );
432
433 DependencyGraphTransformer transformer =
434 new ChainedDependencyGraphTransformer( new ConflictMarker(), new JavaEffectiveScopeCalculator(),
435 new NearestVersionConflictResolver(),
436 new JavaDependencyContextRefiner() );
437 session.setDependencyGraphTransformer( transformer );
438
439 session.setTransferListener( request.getTransferListener() );
440
441 session.setRepositoryListener( new LoggingRepositoryListener( logger ) );
442
443 session.setUserProps( request.getUserProperties() );
444 session.setSystemProps( request.getSystemProperties() );
445 session.setConfigProps( configProps );
446
447 return session;
448 }
449
450 private String getUserAgent()
451 {
452 StringBuilder buffer = new StringBuilder( 128 );
453
454 buffer.append( "Apache-Maven/" ).append( getMavenVersion() );
455 buffer.append( " (" );
456 buffer.append( "Java " ).append( System.getProperty( "java.version" ) );
457 buffer.append( "; " );
458 buffer.append( System.getProperty( "os.name" ) ).append( " " ).append( System.getProperty( "os.version" ) );
459 buffer.append( ")" );
460
461 return buffer.toString();
462 }
463
464 private String getMavenVersion()
465 {
466 Properties props = new Properties();
467
468 InputStream is = getClass().getResourceAsStream( "/META-INF/maven/org.apache.maven/maven-core/pom.properties" );
469 if ( is != null )
470 {
471 try
472 {
473 props.load( is );
474 }
475 catch ( IOException e )
476 {
477 logger.debug( "Failed to read Maven version", e );
478 }
479 IOUtil.close( is );
480 }
481
482 return props.getProperty( "version", "unknown-version" );
483 }
484
485 @SuppressWarnings({"ResultOfMethodCallIgnored"})
486 private void validateLocalRepository( MavenExecutionRequest request )
487 throws LocalRepositoryNotAccessibleException
488 {
489 File localRepoDir = request.getLocalRepositoryPath();
490
491 logger.debug( "Using local repository at " + localRepoDir );
492
493 localRepoDir.mkdirs();
494
495 if ( !localRepoDir.isDirectory() )
496 {
497 throw new LocalRepositoryNotAccessibleException( "Could not create local repository at " + localRepoDir );
498 }
499 }
500
501 private Collection<AbstractMavenLifecycleParticipant> getLifecycleParticipants( Collection<MavenProject> projects )
502 {
503 Collection<AbstractMavenLifecycleParticipant> lifecycleListeners =
504 new LinkedHashSet<AbstractMavenLifecycleParticipant>();
505
506 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
507 try
508 {
509 try
510 {
511 lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
512 }
513 catch ( ComponentLookupException e )
514 {
515
516 logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
517 }
518
519 Collection<ClassLoader> scannedRealms = new HashSet<ClassLoader>();
520
521 for ( MavenProject project : projects )
522 {
523 ClassLoader projectRealm = project.getClassRealm();
524
525 if ( projectRealm != null && scannedRealms.add( projectRealm ) )
526 {
527 Thread.currentThread().setContextClassLoader( projectRealm );
528
529 try
530 {
531 lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) );
532 }
533 catch ( ComponentLookupException e )
534 {
535
536 logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() );
537 }
538 }
539 }
540 }
541 finally
542 {
543 Thread.currentThread().setContextClassLoader( originalClassLoader );
544 }
545
546 return lifecycleListeners;
547 }
548
549 private MavenExecutionResult processResult( MavenExecutionResult result, Throwable e )
550 {
551 if ( !result.getExceptions().contains( e ) )
552 {
553 result.addException( e );
554 }
555
556 return result;
557 }
558
559 private List<MavenProject> getProjectsForMavenReactor( MavenExecutionRequest request )
560 throws ProjectBuildingException
561 {
562 List<MavenProject> projects = new ArrayList<MavenProject>();
563
564
565
566 if ( request.getPom() == null )
567 {
568 ModelSource modelSource = new UrlModelSource( getClass().getResource( "project/standalone.xml" ) );
569 MavenProject project =
570 projectBuilder.build( modelSource, request.getProjectBuildingRequest() ).getProject();
571 project.setExecutionRoot( true );
572 projects.add( project );
573 request.setProjectPresent( false );
574 return projects;
575 }
576
577 List<File> files = Arrays.asList( request.getPom().getAbsoluteFile() );
578 collectProjects( projects, files, request );
579 return projects;
580 }
581
582 private Map<String, MavenProject> getProjectMap( List<MavenProject> projects )
583 throws org.apache.maven.DuplicateProjectException
584 {
585 Map<String, MavenProject> index = new LinkedHashMap<String, MavenProject>();
586 Map<String, List<File>> collisions = new LinkedHashMap<String, List<File>>();
587
588 for ( MavenProject project : projects )
589 {
590 String projectId = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
591
592 MavenProject collision = index.get( projectId );
593
594 if ( collision == null )
595 {
596 index.put( projectId, project );
597 }
598 else
599 {
600 List<File> pomFiles = collisions.get( projectId );
601
602 if ( pomFiles == null )
603 {
604 pomFiles = new ArrayList<File>( Arrays.asList( collision.getFile(), project.getFile() ) );
605 collisions.put( projectId, pomFiles );
606 }
607 else
608 {
609 pomFiles.add( project.getFile() );
610 }
611 }
612 }
613
614 if ( !collisions.isEmpty() )
615 {
616 throw new org.apache.maven.DuplicateProjectException( "Two or more projects in the reactor"
617 + " have the same identifier, please make sure that <groupId>:<artifactId>:<version>"
618 + " is unique for each project: " + collisions, collisions );
619 }
620
621 return index;
622 }
623
624 private void collectProjects( List<MavenProject> projects, List<File> files, MavenExecutionRequest request )
625 throws ProjectBuildingException
626 {
627 ProjectBuildingRequest projectBuildingRequest = request.getProjectBuildingRequest();
628
629 List<ProjectBuildingResult> results = projectBuilder.build( files, request.isRecursive(), projectBuildingRequest );
630
631 boolean problems = false;
632
633 for ( ProjectBuildingResult result : results )
634 {
635 projects.add( result.getProject() );
636
637 if ( !result.getProblems().isEmpty() && logger.isWarnEnabled() )
638 {
639 logger.warn( "" );
640 logger.warn( "Some problems were encountered while building the effective model for "
641 + result.getProject().getId() );
642
643 for ( ModelProblem problem : result.getProblems() )
644 {
645 String location = ModelProblemUtils.formatLocation( problem, result.getProjectId() );
646 logger.warn( problem.getMessage() + ( StringUtils.isNotEmpty( location ) ? " @ " + location : "" ) );
647 }
648
649 problems = true;
650 }
651 }
652
653 if ( problems )
654 {
655 logger.warn( "" );
656 logger.warn( "It is highly recommended to fix these problems"
657 + " because they threaten the stability of your build." );
658 logger.warn( "" );
659 logger.warn( "For this reason, future Maven versions might no"
660 + " longer support building such malformed projects." );
661 logger.warn( "" );
662 }
663 }
664
665 private void validateActivatedProfiles( List<MavenProject> projects, List<String> activeProfileIds )
666 {
667 Collection<String> notActivatedProfileIds = new LinkedHashSet<String>( activeProfileIds );
668
669 for ( MavenProject project : projects )
670 {
671 for ( List<String> profileIds : project.getInjectedProfileIds().values() )
672 {
673 notActivatedProfileIds.removeAll( profileIds );
674 }
675 }
676
677 for ( String notActivatedProfileId : notActivatedProfileIds )
678 {
679 logger.warn( "The requested profile \"" + notActivatedProfileId
680 + "\" could not be activated because it does not exist." );
681 }
682 }
683
684 protected Logger getLogger()
685 {
686 return logger;
687 }
688
689 private ProjectDependencyGraph createDependencyGraph( ProjectSorter sorter, MavenExecutionRequest request )
690 throws MavenExecutionException
691 {
692 ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( sorter );
693
694 Collection<MavenProject> activeProjects = sorter.getSortedProjects();
695
696 File reactorDirectory;
697 if ( request.getBaseDirectory() != null )
698 {
699 reactorDirectory = new File( request.getBaseDirectory() );
700 }
701 else
702 {
703 reactorDirectory = null;
704 }
705
706 if ( !request.getSelectedProjects().isEmpty() )
707 {
708 List<MavenProject> selectedProjects = new ArrayList<MavenProject>( request.getSelectedProjects().size() );
709
710 for ( String selectedProject : request.getSelectedProjects() )
711 {
712 MavenProject project = null;
713
714 for ( MavenProject activeProject : activeProjects )
715 {
716 if ( isMatchingProject( activeProject, selectedProject, reactorDirectory ) )
717 {
718 project = activeProject;
719 break;
720 }
721 }
722
723 if ( project != null )
724 {
725 selectedProjects.add( project );
726 }
727 else
728 {
729 throw new MavenExecutionException( "Could not find the selected project in the reactor: "
730 + selectedProject, request.getPom() );
731 }
732 }
733
734 activeProjects = selectedProjects;
735
736 boolean makeUpstream = false;
737 boolean makeDownstream = false;
738
739 if ( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( request.getMakeBehavior() ) )
740 {
741 makeUpstream = true;
742 }
743 else if ( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals( request.getMakeBehavior() ) )
744 {
745 makeDownstream = true;
746 }
747 else if ( MavenExecutionRequest.REACTOR_MAKE_BOTH.equals( request.getMakeBehavior() ) )
748 {
749 makeUpstream = true;
750 makeDownstream = true;
751 }
752 else if ( StringUtils.isNotEmpty( request.getMakeBehavior() ) )
753 {
754 throw new MavenExecutionException( "Invalid reactor make behavior: " + request.getMakeBehavior(),
755 request.getPom() );
756 }
757
758 if ( makeUpstream || makeDownstream )
759 {
760 activeProjects = new LinkedHashSet<MavenProject>( selectedProjects );
761
762 for ( MavenProject selectedProject : selectedProjects )
763 {
764 if ( makeUpstream )
765 {
766 activeProjects.addAll( graph.getUpstreamProjects( selectedProject, true ) );
767 }
768 if ( makeDownstream )
769 {
770 activeProjects.addAll( graph.getDownstreamProjects( selectedProject, true ) );
771 }
772 }
773 }
774 }
775
776 if ( StringUtils.isNotEmpty( request.getResumeFrom() ) )
777 {
778 String selectedProject = request.getResumeFrom();
779
780 List<MavenProject> projects = new ArrayList<MavenProject>( activeProjects.size() );
781
782 boolean resumed = false;
783
784 for ( MavenProject project : activeProjects )
785 {
786 if ( !resumed && isMatchingProject( project, selectedProject, reactorDirectory ) )
787 {
788 resumed = true;
789 }
790
791 if ( resumed )
792 {
793 projects.add( project );
794 }
795 }
796
797 if ( !resumed )
798 {
799 throw new MavenExecutionException( "Could not find project to resume reactor build from: "
800 + selectedProject + " vs " + activeProjects, request.getPom() );
801 }
802
803 activeProjects = projects;
804 }
805
806 if ( activeProjects.size() != sorter.getSortedProjects().size() )
807 {
808 graph = new FilteredProjectDependencyGraph( graph, activeProjects );
809 }
810
811 return graph;
812 }
813
814 private boolean isMatchingProject( MavenProject project, String selector, File reactorDirectory )
815 {
816
817 if ( selector.indexOf( ':' ) >= 0 )
818 {
819 String id = ':' + project.getArtifactId();
820
821 if ( id.equals( selector ) )
822 {
823 return true;
824 }
825
826 id = project.getGroupId() + id;
827
828 if ( id.equals( selector ) )
829 {
830 return true;
831 }
832 }
833
834
835 else if ( reactorDirectory != null )
836 {
837 File selectedProject = new File( new File( reactorDirectory, selector ).toURI().normalize() );
838
839 if ( selectedProject.isFile() )
840 {
841 return selectedProject.equals( project.getFile() );
842 }
843 else if ( selectedProject.isDirectory() )
844 {
845 return selectedProject.equals( project.getBasedir() );
846 }
847 }
848
849 return false;
850 }
851
852 }