diff options
Diffstat (limited to 'framework/src/maven/apache-maven-3.3.3/maven-core/src/main/java/org/apache/maven/DefaultMaven.java')
-rw-r--r-- | framework/src/maven/apache-maven-3.3.3/maven-core/src/main/java/org/apache/maven/DefaultMaven.java | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/framework/src/maven/apache-maven-3.3.3/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/framework/src/maven/apache-maven-3.3.3/maven-core/src/main/java/org/apache/maven/DefaultMaven.java new file mode 100644 index 00000000..94e75e02 --- /dev/null +++ b/framework/src/maven/apache-maven-3.3.3/maven-core/src/main/java/org/apache/maven/DefaultMaven.java @@ -0,0 +1,521 @@ +package org.apache.maven; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +import org.apache.maven.artifact.ArtifactUtils; +import org.apache.maven.execution.DefaultMavenExecutionResult; +import org.apache.maven.execution.ExecutionEvent; +import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.execution.MavenExecutionResult; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.ProjectDependencyGraph; +import org.apache.maven.graph.GraphBuilder; +import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory; +import org.apache.maven.lifecycle.internal.ExecutionEventCatapult; +import org.apache.maven.lifecycle.internal.LifecycleStarter; +import org.apache.maven.model.building.ModelProblem; +import org.apache.maven.model.building.Result; +import org.apache.maven.plugin.LegacySupport; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectBuilder; +import org.apache.maven.repository.LocalRepositoryNotAccessibleException; +import org.apache.maven.session.scope.internal.SessionScope; +import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.logging.Logger; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.util.repository.ChainedWorkspaceReader; + +import com.google.common.collect.Iterables; + +/** + * @author Jason van Zyl + */ +@Component( role = Maven.class ) +public class DefaultMaven + implements Maven +{ + + @Requirement + private Logger logger; + + @Requirement + protected ProjectBuilder projectBuilder; + + @Requirement + private LifecycleStarter lifecycleStarter; + + @Requirement + protected PlexusContainer container; + + @Requirement + private ExecutionEventCatapult eventCatapult; + + @Requirement + private LegacySupport legacySupport; + + @Requirement + private SessionScope sessionScope; + + @Requirement + private DefaultRepositorySystemSessionFactory repositorySessionFactory; + + @Requirement( hint = GraphBuilder.HINT ) + private GraphBuilder graphBuilder; + + @Override + public MavenExecutionResult execute( MavenExecutionRequest request ) + { + MavenExecutionResult result; + + try + { + result = doExecute( request ); + } + catch ( OutOfMemoryError e ) + { + result = addExceptionToResult( new DefaultMavenExecutionResult(), e ); + } + catch ( RuntimeException e ) + { + //TODO Hack to make the cycle detection the same for the new graph builder + if ( e.getCause() instanceof ProjectCycleException ) + { + result = addExceptionToResult( new DefaultMavenExecutionResult(), e.getCause() ); + } + else + { + result = addExceptionToResult( new DefaultMavenExecutionResult(), + new InternalErrorException( "Internal error: " + e, e ) ); + } + } + finally + { + legacySupport.setSession( null ); + } + + return result; + } + + // + // 1) Setup initial properties. + // + // 2) Validate local repository directory is accessible. + // + // 3) Create RepositorySystemSession. + // + // 4) Create MavenSession. + // + // 5) Execute AbstractLifecycleParticipant.afterSessionStart(session) + // + // 6) Get reactor projects looking for general POM errors + // + // 7) Create ProjectDependencyGraph using trimming which takes into account --projects and reactor mode. + // This ensures that the projects passed into the ReactorReader are only those specified. + // + // 8) Create ReactorReader with the getProjectMap( projects ). NOTE that getProjectMap(projects) is the code that + // checks for duplicate projects definitions in the build. Ideally this type of duplicate checking should be + // part of getting the reactor projects in 6). The duplicate checking is conflated with getProjectMap(projects). + // + // 9) Execute AbstractLifecycleParticipant.afterProjectsRead(session) + // + // 10) Create ProjectDependencyGraph without trimming (as trimming was done in 7). A new topological sort is + // required after the execution of 9) as the AbstractLifecycleParticipants are free to mutate the MavenProject + // instances, which may change dependencies which can, in turn, affect the build order. + // + // 11) Execute LifecycleStarter.start() + // + @SuppressWarnings( "checkstyle:methodlength" ) + private MavenExecutionResult doExecute( MavenExecutionRequest request ) + { + request.setStartTime( new Date() ); + + MavenExecutionResult result = new DefaultMavenExecutionResult(); + + try + { + validateLocalRepository( request ); + } + catch ( LocalRepositoryNotAccessibleException e ) + { + return addExceptionToResult( result, e ); + } + + // + // We enter the session scope right after the MavenSession creation and before any of the + // AbstractLifecycleParticipant lookups + // so that @SessionScoped components can be @Injected into AbstractLifecycleParticipants. + // + sessionScope.enter(); + try + { + DefaultRepositorySystemSession repoSession = + (DefaultRepositorySystemSession) newRepositorySession( request ); + MavenSession session = new MavenSession( container, repoSession, request, result ); + + sessionScope.seed( MavenSession.class, session ); + + legacySupport.setSession( session ); + + return doExecute( request, session, result, repoSession ); + } + finally + { + sessionScope.exit(); + } + } + + private MavenExecutionResult doExecute( MavenExecutionRequest request, MavenSession session, + MavenExecutionResult result, DefaultRepositorySystemSession repoSession ) + { + try + { + for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( Collections + .<MavenProject>emptyList() ) ) + { + listener.afterSessionStart( session ); + } + } + catch ( MavenExecutionException e ) + { + return addExceptionToResult( result, e ); + } + + eventCatapult.fire( ExecutionEvent.Type.ProjectDiscoveryStarted, session, null ); + + Result<? extends ProjectDependencyGraph> graphResult = buildGraph( session, result ); + + if ( graphResult.hasErrors() ) + { + return addExceptionToResult( result, + Iterables.toArray( graphResult.getProblems(), ModelProblem.class )[0] + .getException() ); + } + + try + { + session.setProjectMap( getProjectMap( session.getProjects() ) ); + } + catch ( DuplicateProjectException e ) + { + return addExceptionToResult( result, e ); + } + + WorkspaceReader reactorWorkspace; + try + { + reactorWorkspace = container.lookup( WorkspaceReader.class, ReactorReader.HINT ); + } + catch ( ComponentLookupException e ) + { + return addExceptionToResult( result, e ); + } + + // + // Desired order of precedence for local artifact repositories + // + // Reactor + // Workspace + // User Local Repository + // + repoSession.setWorkspaceReader( ChainedWorkspaceReader.newInstance( reactorWorkspace, + repoSession.getWorkspaceReader() ) ); + + repoSession.setReadOnly(); + + ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); + try + { + for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( session.getProjects() ) ) + { + Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() ); + + listener.afterProjectsRead( session ); + } + } + catch ( MavenExecutionException e ) + { + return addExceptionToResult( result, e ); + } + finally + { + Thread.currentThread().setContextClassLoader( originalClassLoader ); + } + + // + // The projects need to be topologically after the participants have run their afterProjectsRead(session) + // because the participant is free to change the dependencies of a project which can potentially change the + // topological order of the projects, and therefore can potentially change the build order. + // + // Note that participants may affect the topological order of the projects but it is + // not expected that a participant will add or remove projects from the session. + // + + graphResult = buildGraph( session, result ); + + if ( graphResult.hasErrors() ) + { + return addExceptionToResult( result, + Iterables.toArray( graphResult.getProblems(), ModelProblem.class )[0] + .getException() ); + } + + try + { + if ( result.hasExceptions() ) + { + return result; + } + + result.setTopologicallySortedProjects( session.getProjects() ); + + result.setProject( session.getTopLevelProject() ); + + lifecycleStarter.execute( session ); + + validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() ); + + if ( session.getResult().hasExceptions() ) + { + return addExceptionToResult( result, session.getResult().getExceptions().get( 0 ) ); + } + } + finally + { + try + { + afterSessionEnd( session.getProjects(), session ); + } + catch ( MavenExecutionException e ) + { + return addExceptionToResult( result, e ); + } + } + + return result; + } + + private void afterSessionEnd( Collection<MavenProject> projects, MavenSession session ) + throws MavenExecutionException + { + ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); + try + { + for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( projects ) ) + { + Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() ); + + listener.afterSessionEnd( session ); + } + } + finally + { + Thread.currentThread().setContextClassLoader( originalClassLoader ); + } + } + + public RepositorySystemSession newRepositorySession( MavenExecutionRequest request ) + { + return repositorySessionFactory.newRepositorySession( request ); + } + + private void validateLocalRepository( MavenExecutionRequest request ) + throws LocalRepositoryNotAccessibleException + { + File localRepoDir = request.getLocalRepositoryPath(); + + logger.debug( "Using local repository at " + localRepoDir ); + + localRepoDir.mkdirs(); + + if ( !localRepoDir.isDirectory() ) + { + throw new LocalRepositoryNotAccessibleException( "Could not create local repository at " + localRepoDir ); + } + } + + private Collection<AbstractMavenLifecycleParticipant> getLifecycleParticipants( Collection<MavenProject> projects ) + { + Collection<AbstractMavenLifecycleParticipant> lifecycleListeners = + new LinkedHashSet<AbstractMavenLifecycleParticipant>(); + + ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); + try + { + try + { + lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) ); + } + catch ( ComponentLookupException e ) + { + // this is just silly, lookupList should return an empty list! + logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() ); + } + + Collection<ClassLoader> scannedRealms = new HashSet<ClassLoader>(); + + for ( MavenProject project : projects ) + { + ClassLoader projectRealm = project.getClassRealm(); + + if ( projectRealm != null && scannedRealms.add( projectRealm ) ) + { + Thread.currentThread().setContextClassLoader( projectRealm ); + + try + { + lifecycleListeners.addAll( container.lookupList( AbstractMavenLifecycleParticipant.class ) ); + } + catch ( ComponentLookupException e ) + { + // this is just silly, lookupList should return an empty list! + logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() ); + } + } + } + } + finally + { + Thread.currentThread().setContextClassLoader( originalClassLoader ); + } + + return lifecycleListeners; + } + + private MavenExecutionResult addExceptionToResult( MavenExecutionResult result, Throwable e ) + { + if ( !result.getExceptions().contains( e ) ) + { + result.addException( e ); + } + + return result; + } + + private void validateActivatedProfiles( List<MavenProject> projects, List<String> activeProfileIds ) + { + Collection<String> notActivatedProfileIds = new LinkedHashSet<String>( activeProfileIds ); + + for ( MavenProject project : projects ) + { + for ( List<String> profileIds : project.getInjectedProfileIds().values() ) + { + notActivatedProfileIds.removeAll( profileIds ); + } + } + + for ( String notActivatedProfileId : notActivatedProfileIds ) + { + logger.warn( "The requested profile \"" + notActivatedProfileId + + "\" could not be activated because it does not exist." ); + } + } + + private Map<String, MavenProject> getProjectMap( Collection<MavenProject> projects ) + throws DuplicateProjectException + { + Map<String, MavenProject> index = new LinkedHashMap<String, MavenProject>(); + Map<String, List<File>> collisions = new LinkedHashMap<String, List<File>>(); + + for ( MavenProject project : projects ) + { + String projectId = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() ); + + MavenProject collision = index.get( projectId ); + + if ( collision == null ) + { + index.put( projectId, project ); + } + else + { + List<File> pomFiles = collisions.get( projectId ); + + if ( pomFiles == null ) + { + pomFiles = new ArrayList<File>( Arrays.asList( collision.getFile(), project.getFile() ) ); + collisions.put( projectId, pomFiles ); + } + else + { + pomFiles.add( project.getFile() ); + } + } + } + + if ( !collisions.isEmpty() ) + { + throw new DuplicateProjectException( "Two or more projects in the reactor" + + " have the same identifier, please make sure that <groupId>:<artifactId>:<version>" + + " is unique for each project: " + collisions, collisions ); + } + + return index; + } + + private Result<? extends ProjectDependencyGraph> buildGraph( MavenSession session, MavenExecutionResult result ) + { + Result<? extends ProjectDependencyGraph> graphResult = graphBuilder.build( session ); + for ( ModelProblem problem : graphResult.getProblems() ) + { + if ( problem.getSeverity() == ModelProblem.Severity.WARNING ) + { + logger.warn( problem.toString() ); + } + else + { + logger.error( problem.toString() ); + } + } + + if ( !graphResult.hasErrors() ) + { + ProjectDependencyGraph projectDependencyGraph = graphResult.get(); + session.setProjects( projectDependencyGraph.getSortedProjects() ); + session.setAllProjects( projectDependencyGraph.getSortedProjects() ); + session.setProjectDependencyGraph( projectDependencyGraph ); + } + + return graphResult; + } + + @Deprecated + // 5 January 2014 + protected Logger getLogger() + { + return logger; + } +} |