001 package org.apache.maven; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import java.io.File; 023 import java.io.IOException; 024 import java.io.InputStream; 025 import java.text.SimpleDateFormat; 026 import java.util.ArrayList; 027 import java.util.Arrays; 028 import java.util.Collection; 029 import java.util.Collections; 030 import java.util.Date; 031 import java.util.HashSet; 032 import java.util.LinkedHashMap; 033 import java.util.LinkedHashSet; 034 import java.util.List; 035 import java.util.Map; 036 import java.util.Properties; 037 038 import org.apache.maven.artifact.ArtifactUtils; 039 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; 040 import org.apache.maven.eventspy.internal.EventSpyDispatcher; 041 import org.apache.maven.execution.DefaultMavenExecutionResult; 042 import org.apache.maven.execution.ExecutionEvent; 043 import org.apache.maven.execution.MavenExecutionRequest; 044 import org.apache.maven.execution.MavenExecutionRequestPopulationException; 045 import org.apache.maven.execution.MavenExecutionRequestPopulator; 046 import org.apache.maven.execution.MavenExecutionResult; 047 import org.apache.maven.execution.MavenSession; 048 import org.apache.maven.execution.ProjectDependencyGraph; 049 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult; 050 import org.apache.maven.lifecycle.internal.LifecycleStarter; 051 import org.apache.maven.model.building.ModelProblem; 052 import org.apache.maven.model.building.ModelProblemUtils; 053 import org.apache.maven.model.building.ModelSource; 054 import org.apache.maven.model.building.UrlModelSource; 055 import org.apache.maven.plugin.LegacySupport; 056 import org.apache.maven.project.DuplicateProjectException; 057 import org.apache.maven.project.MavenProject; 058 import org.apache.maven.project.ProjectBuilder; 059 import org.apache.maven.project.ProjectBuildingException; 060 import org.apache.maven.project.ProjectBuildingRequest; 061 import org.apache.maven.project.ProjectBuildingResult; 062 import org.apache.maven.project.ProjectSorter; 063 import org.apache.maven.repository.DelegatingLocalArtifactRepository; 064 import org.apache.maven.repository.LocalRepositoryNotAccessibleException; 065 import org.apache.maven.repository.internal.MavenRepositorySystemUtils; 066 import org.apache.maven.settings.Mirror; 067 import org.apache.maven.settings.Proxy; 068 import org.apache.maven.settings.Server; 069 import org.apache.maven.settings.building.SettingsProblem; 070 import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest; 071 import org.apache.maven.settings.crypto.SettingsDecrypter; 072 import org.apache.maven.settings.crypto.SettingsDecryptionResult; 073 import org.codehaus.plexus.PlexusContainer; 074 import org.codehaus.plexus.component.annotations.Component; 075 import org.codehaus.plexus.component.annotations.Requirement; 076 import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 077 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; 078 import org.codehaus.plexus.logging.Logger; 079 import org.codehaus.plexus.util.IOUtil; 080 import org.codehaus.plexus.util.StringUtils; 081 import org.codehaus.plexus.util.dag.CycleDetectedException; 082 import org.codehaus.plexus.util.xml.Xpp3Dom; 083 import org.eclipse.aether.ConfigurationProperties; 084 import org.eclipse.aether.DefaultRepositorySystemSession; 085 import org.eclipse.aether.RepositorySystem; 086 import org.eclipse.aether.RepositorySystemSession; 087 import org.eclipse.aether.repository.LocalRepository; 088 import org.eclipse.aether.repository.NoLocalRepositoryManagerException; 089 import org.eclipse.aether.repository.RepositoryPolicy; 090 import org.eclipse.aether.repository.WorkspaceReader; 091 import org.eclipse.aether.resolution.ResolutionErrorPolicy; 092 import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; 093 import org.eclipse.aether.util.repository.AuthenticationBuilder; 094 import org.eclipse.aether.util.repository.ChainedWorkspaceReader; 095 import org.eclipse.aether.util.repository.DefaultAuthenticationSelector; 096 import org.eclipse.aether.util.repository.DefaultMirrorSelector; 097 import org.eclipse.aether.util.repository.DefaultProxySelector; 098 import org.eclipse.aether.util.repository.SimpleResolutionErrorPolicy; 099 100 /** 101 * @author Jason van Zyl 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 //TODO: Need a general way to inject standard properties 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 //TODO: optimize for the single project or no project 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 // Desired order of precedence for local artifact repositories 249 // 250 // Reactor 251 // Workspace 252 // User Local Repository 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 // this is just silly, lookupList should return an empty list! 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 // this is just silly, lookupList should return an empty list! 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 // We have no POM file. 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 // [groupId]:artifactId 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 // relative path, e.g. "sub", "../sub" or "." 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 }