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