MNG-5775 Make the project graph building code pluggable to allow for new/different implementations.
Project: http://git-wip-us.apache.org/repos/asf/maven/repo Commit: http://git-wip-us.apache.org/repos/asf/maven/commit/be3fb200 Tree: http://git-wip-us.apache.org/repos/asf/maven/tree/be3fb200 Diff: http://git-wip-us.apache.org/repos/asf/maven/diff/be3fb200 Branch: refs/heads/master Commit: be3fb200326208ca4b8c41ebf16d5ae6b8049792 Parents: 7997634 Author: Jason van Zyl <ja...@tesla.io> Authored: Wed Sep 3 11:48:28 2014 -0700 Committer: Jason van Zyl <ja...@tesla.io> Committed: Sun Mar 1 12:39:30 2015 -0800 ---------------------------------------------------------------------- .../DefaultArtifactDescriptorReader.java | 14 +- .../internal/MavenWorkspaceReader.java | 32 ++ .../java/org/apache/maven/DefaultMaven.java | 500 +++---------------- .../maven/DefaultProjectDependencyGraph.java | 134 ----- .../maven/FilteredProjectDependencyGraph.java | 111 ---- .../org/apache/maven/ProjectCycleException.java | 5 + .../java/org/apache/maven/ReactorReader.java | 13 +- .../apache/maven/execution/MavenSession.java | 9 +- .../apache/maven/graph/DefaultGraphBuilder.java | 487 ++++++++++++++++++ .../graph/DefaultProjectDependencyGraph.java | 134 +++++ .../graph/FilteredProjectDependencyGraph.java | 111 ++++ .../org/apache/maven/graph/GraphBuilder.java | 31 ++ .../project/DefaultModelBuildingListener.java | 2 +- .../org/apache/maven/project/MavenProject.java | 2 +- .../maven/project/ProjectModelResolver.java | 3 +- .../DefaultProjectDependencyGraphTest.java | 172 ------- .../DefaultProjectDependencyGraphTest.java | 172 +++++++ .../maven/lifecycle/LifecycleExecutorTest.java | 5 + maven-model-builder/pom.xml | 5 +- .../model/building/DefaultModelBuilder.java | 291 +++++++---- .../building/DefaultModelBuildingRequest.java | 32 ++ .../building/FilterModelBuildingRequest.java | 30 +- .../maven/model/building/ModelBuilder.java | 13 + .../model/building/ModelBuildingRequest.java | 22 +- .../org/apache/maven/model/building/Result.java | 255 ++++++++++ .../resolution/UnresolvableModelException.java | 16 + .../resolution/WorkspaceModelResolver.java | 33 ++ maven-model/src/main/mdo/maven.mdo | 8 +- 28 files changed, 1676 insertions(+), 966 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java ---------------------------------------------------------------------- diff --git a/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java b/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java index 0fea15a..a768de5 100644 --- a/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java +++ b/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java @@ -52,6 +52,7 @@ import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.impl.RepositoryEventDispatcher; import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.impl.VersionResolver; +import org.eclipse.aether.repository.WorkspaceReader; import org.eclipse.aether.repository.WorkspaceRepository; import org.eclipse.aether.resolution.ArtifactDescriptorException; import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; @@ -215,7 +216,6 @@ public class DefaultArtifactDescriptorReader ArtifactDescriptorResult result = new ArtifactDescriptorResult( request ); Model model = loadPom( session, request, result ); - if ( model != null ) { Map<String, Object> config = session.getConfigProperties(); @@ -303,6 +303,18 @@ public class DefaultArtifactDescriptorReader } Model model; + + // hack: don't rebuild model if it was already loaded during reactor resolution + final WorkspaceReader workspace = session.getWorkspaceReader(); + if ( workspace instanceof MavenWorkspaceReader ) + { + model = ( (MavenWorkspaceReader) workspace ).findModel( pomArtifact ); + if ( model != null ) + { + return model; + } + } + try { ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest(); http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java ---------------------------------------------------------------------- diff --git a/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java b/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java new file mode 100644 index 0000000..270cf58 --- /dev/null +++ b/maven-aether-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java @@ -0,0 +1,32 @@ +package org.apache.maven.repository.internal; + +/* + * 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 org.apache.maven.model.Model; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.WorkspaceReader; + +public interface MavenWorkspaceReader + extends WorkspaceReader +{ + + Model findModel( Artifact artifact ); + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/DefaultMaven.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java index 20d3758..3009301 100644 --- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java +++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java @@ -9,7 +9,7 @@ package org.apache.maven; * "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 + * 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 @@ -25,7 +25,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -39,20 +38,15 @@ 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.Plugin; import org.apache.maven.model.building.ModelProblem; -import org.apache.maven.model.building.ModelProblemUtils; -import org.apache.maven.model.building.ModelSource; -import org.apache.maven.model.building.UrlModelSource; +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.project.ProjectBuildingException; -import org.apache.maven.project.ProjectBuildingRequest; -import org.apache.maven.project.ProjectBuildingResult; import org.apache.maven.repository.LocalRepositoryNotAccessibleException; import org.apache.maven.session.scope.internal.SessionScope; import org.codehaus.plexus.PlexusContainer; @@ -60,13 +54,13 @@ 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.codehaus.plexus.util.StringUtils; -import org.codehaus.plexus.util.dag.CycleDetectedException; 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 */ @@ -99,6 +93,9 @@ public class DefaultMaven @Requirement private DefaultRepositorySystemSessionFactory repositorySessionFactory; + @Requirement( hint = GraphBuilder.HINT ) + private GraphBuilder graphBuilder; + @Override public MavenExecutionResult execute( MavenExecutionRequest request ) { @@ -114,9 +111,18 @@ public class DefaultMaven } catch ( RuntimeException e ) { - result = - addExceptionToResult( new DefaultMavenExecutionResult(), new InternalErrorException( "Internal error: " - + e, 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 { @@ -140,17 +146,17 @@ public class DefaultMaven // 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. + // 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). + // 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. + // 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() // @@ -171,7 +177,8 @@ public class DefaultMaven } // - // We enter the session scope right after the MavenSession creation and before any of the AbstractLifecycleParticipant lookups + // 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(); @@ -198,7 +205,8 @@ public class DefaultMaven { try { - for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( Collections.<MavenProject>emptyList() ) ) + for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( Collections + .<MavenProject>emptyList() ) ) { listener.afterSessionStart( session ); } @@ -210,36 +218,15 @@ public class DefaultMaven eventCatapult.fire( ExecutionEvent.Type.ProjectDiscoveryStarted, session, null ); - List<MavenProject> projects; - try - { - projects = getProjectsForMavenReactor( session ); - // - // Capture the full set of projects before any potential constraining is performed by --projects - // - session.setAllProjects( projects ); - } - catch ( ProjectBuildingException e ) - { - return addExceptionToResult( result, e ); - } - - validateProjects( projects ); - - // - // This creates the graph and trims the projects down based on the user request using something like: - // - // -pl project0,project2 eclipse:eclipse - // - ProjectDependencyGraph projectDependencyGraph = createProjectDependencyGraph( projects, request, result, true ); - - if ( result.hasExceptions() ) + Result<? extends ProjectDependencyGraph> graphResult = buildGraph( session, result ); + + if ( graphResult.hasErrors() ) { - return result; + return addExceptionToResult( result, + Iterables.toArray( graphResult.getProblems(), ModelProblem.class )[0] + .getException() ); } - session.setProjects( projectDependencyGraph.getSortedProjects() ); - try { session.setProjectMap( getProjectMap( session.getProjects() ) ); @@ -274,7 +261,7 @@ public class DefaultMaven ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); try { - for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( projects ) ) + for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( session.getProjects() ) ) { Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() ); @@ -298,7 +285,15 @@ public class DefaultMaven // 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. // - projectDependencyGraph = createProjectDependencyGraph( session.getProjects(), request, result, false ); + + graphResult = buildGraph( session, result ); + + if ( graphResult.hasErrors() ) + { + return addExceptionToResult( result, + Iterables.toArray( graphResult.getProblems(), ModelProblem.class )[0] + .getException() ); + } try { @@ -307,10 +302,6 @@ public class DefaultMaven return result; } - session.setProjects( projectDependencyGraph.getSortedProjects() ); - - session.setProjectDependencyGraph( projectDependencyGraph ); - result.setTopologicallySortedProjects( session.getProjects() ); result.setProject( session.getTopLevelProject() ); @@ -328,7 +319,7 @@ public class DefaultMaven { try { - afterSessionEnd( projects, session ); + afterSessionEnd( session.getProjects(), session ); } catch ( MavenExecutionException e ) { @@ -357,7 +348,7 @@ public class DefaultMaven Thread.currentThread().setContextClassLoader( originalClassLoader ); } } - + public RepositorySystemSession newRepositorySession( MavenExecutionRequest request ) { return repositorySessionFactory.newRepositorySession( request ); @@ -380,8 +371,7 @@ public class DefaultMaven private Collection<AbstractMavenLifecycleParticipant> getLifecycleParticipants( Collection<MavenProject> projects ) { - Collection<AbstractMavenLifecycleParticipant> lifecycleListeners = - new LinkedHashSet<AbstractMavenLifecycleParticipant>(); + Collection<AbstractMavenLifecycleParticipant> lifecycleListeners = new LinkedHashSet<AbstractMavenLifecycleParticipant>(); ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); try @@ -436,72 +426,22 @@ public class DefaultMaven return result; } - private List<MavenProject> getProjectsForMavenReactor( MavenSession session ) - throws ProjectBuildingException - { - MavenExecutionRequest request = session.getRequest(); - - request.getProjectBuildingRequest().setRepositorySession( session.getRepositorySession() ); - - List<MavenProject> projects = new ArrayList<MavenProject>(); - - // We have no POM file. - // - if ( request.getPom() == null ) - { - ModelSource modelSource = new UrlModelSource( DefaultMaven.class.getResource( "project/standalone.xml" ) ); - MavenProject project = - projectBuilder.build( modelSource, request.getProjectBuildingRequest() ).getProject(); - project.setExecutionRoot( true ); - projects.add( project ); - request.setProjectPresent( false ); - return projects; - } - - List<File> files = Arrays.asList( request.getPom().getAbsoluteFile() ); - collectProjects( projects, files, request ); - return projects; - } - - private void collectProjects( List<MavenProject> projects, List<File> files, MavenExecutionRequest request ) - throws ProjectBuildingException + private void validateActivatedProfiles( List<MavenProject> projects, List<String> activeProfileIds ) { - ProjectBuildingRequest projectBuildingRequest = request.getProjectBuildingRequest(); - - List<ProjectBuildingResult> results = - projectBuilder.build( files, request.isRecursive(), projectBuildingRequest ); - - boolean problems = false; + Collection<String> notActivatedProfileIds = new LinkedHashSet<String>( activeProfileIds ); - for ( ProjectBuildingResult result : results ) + for ( MavenProject project : projects ) { - projects.add( result.getProject() ); - - if ( !result.getProblems().isEmpty() && logger.isWarnEnabled() ) + for ( List<String> profileIds : project.getInjectedProfileIds().values() ) { - logger.warn( "" ); - logger.warn( "Some problems were encountered while building the effective model for " - + result.getProject().getId() ); - - for ( ModelProblem problem : result.getProblems() ) - { - String loc = ModelProblemUtils.formatLocation( problem, result.getProjectId() ); - logger.warn( problem.getMessage() + ( StringUtils.isNotEmpty( loc ) ? " @ " + loc : "" ) ); - } - - problems = true; + notActivatedProfileIds.removeAll( profileIds ); } } - if ( problems ) + for ( String notActivatedProfileId : notActivatedProfileIds ) { - logger.warn( "" ); - logger.warn( "It is highly recommended to fix these problems" - + " because they threaten the stability of your build." ); - logger.warn( "" ); - logger.warn( "For this reason, future Maven versions might no" - + " longer support building such malformed projects." ); - logger.warn( "" ); + logger.warn( "The requested profile \"" + notActivatedProfileId + + "\" could not be activated because it does not exist." ); } } @@ -547,330 +487,36 @@ public class DefaultMaven return index; } - private void validateProjects( List<MavenProject> projects ) + private Result<? extends ProjectDependencyGraph> buildGraph( MavenSession session, MavenExecutionResult result ) { - Map<String, MavenProject> projectsMap = new HashMap<String, MavenProject>(); - - for ( MavenProject p : projects ) + Result<? extends ProjectDependencyGraph> graphResult = graphBuilder.build( session ); + for ( ModelProblem problem : graphResult.getProblems() ) { - String projectKey = ArtifactUtils.key( p.getGroupId(), p.getArtifactId(), p.getVersion() ); - - projectsMap.put( projectKey, p ); - } - - for ( MavenProject project : projects ) - { - // MNG-1911 / MNG-5572: Building plugins with extensions cannot be part of reactor - for ( Plugin plugin : project.getBuildPlugins() ) + if ( problem.getSeverity() == ModelProblem.Severity.WARNING ) { - if ( plugin.isExtensions() ) - { - String pluginKey = - ArtifactUtils.key( plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion() ); - - if ( projectsMap.containsKey( pluginKey ) ) - { - logger.warn( project.getName() + " uses " + plugin.getKey() - + " as extensions, which is not possible within the same reactor build. " - + "This plugin was pulled from the local repository!" ); - } - } + logger.warn( problem.toString() ); } - } - } - - 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() ) + else { - notActivatedProfileIds.removeAll( profileIds ); + logger.error( problem.toString() ); } } - for ( String notActivatedProfileId : notActivatedProfileIds ) + if ( !graphResult.hasErrors() ) { - logger.warn( "The requested profile \"" + notActivatedProfileId - + "\" could not be activated because it does not exist." ); + ProjectDependencyGraph projectDependencyGraph = graphResult.get(); + session.setProjects( projectDependencyGraph.getSortedProjects() ); + session.setAllProjects( projectDependencyGraph.getSortedProjects() ); + session.setProjectDependencyGraph( projectDependencyGraph ); } + + return graphResult; } - - @Deprecated // 5 January 2014 + + @Deprecated + // 5 January 2014 protected Logger getLogger() { return logger; } - - private ProjectDependencyGraph createProjectDependencyGraph( Collection<MavenProject> projects, - MavenExecutionRequest request, - MavenExecutionResult result, boolean trimming ) - { - ProjectDependencyGraph projectDependencyGraph = null; - - try - { - projectDependencyGraph = new DefaultProjectDependencyGraph( projects ); - - if ( trimming ) - { - List<MavenProject> activeProjects = projectDependencyGraph.getSortedProjects(); - - activeProjects = trimSelectedProjects( activeProjects, projectDependencyGraph, request ); - activeProjects = trimExcludedProjects( activeProjects, request ); - activeProjects = trimResumedProjects( activeProjects, request ); - - if ( activeProjects.size() != projectDependencyGraph.getSortedProjects().size() ) - { - projectDependencyGraph = - new FilteredProjectDependencyGraph( projectDependencyGraph, activeProjects ); - } - } - } - catch ( CycleDetectedException e ) - { - String message = "The projects in the reactor contain a cyclic reference: " + e.getMessage(); - - ProjectCycleException error = new ProjectCycleException( message, e ); - - addExceptionToResult( result, error ); - } - catch ( org.apache.maven.project.DuplicateProjectException e ) - { - addExceptionToResult( result, e ); - } - catch ( MavenExecutionException e ) - { - addExceptionToResult( result, e ); - } - - return projectDependencyGraph; - } - - private List<MavenProject> trimSelectedProjects( List<MavenProject> projects, ProjectDependencyGraph graph, - MavenExecutionRequest request ) - throws MavenExecutionException - { - List<MavenProject> result = projects; - - if ( !request.getSelectedProjects().isEmpty() ) - { - File reactorDirectory = null; - if ( request.getBaseDirectory() != null ) - { - reactorDirectory = new File( request.getBaseDirectory() ); - } - - Collection<MavenProject> selectedProjects = new LinkedHashSet<MavenProject>( projects.size() ); - - for ( String selector : request.getSelectedProjects() ) - { - MavenProject selectedProject = null; - - for ( MavenProject project : projects ) - { - if ( isMatchingProject( project, selector, reactorDirectory ) ) - { - selectedProject = project; - break; - } - } - - if ( selectedProject != null ) - { - selectedProjects.add( selectedProject ); - } - else - { - throw new MavenExecutionException( "Could not find the selected project in the reactor: " - + selector, request.getPom() ); - } - } - - boolean makeUpstream = false; - boolean makeDownstream = false; - - if ( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( request.getMakeBehavior() ) ) - { - makeUpstream = true; - } - else if ( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals( request.getMakeBehavior() ) ) - { - makeDownstream = true; - } - else if ( MavenExecutionRequest.REACTOR_MAKE_BOTH.equals( request.getMakeBehavior() ) ) - { - makeUpstream = true; - makeDownstream = true; - } - else if ( StringUtils.isNotEmpty( request.getMakeBehavior() ) ) - { - throw new MavenExecutionException( "Invalid reactor make behavior: " + request.getMakeBehavior(), - request.getPom() ); - } - - if ( makeUpstream || makeDownstream ) - { - for ( MavenProject selectedProject : new ArrayList<MavenProject>( selectedProjects ) ) - { - if ( makeUpstream ) - { - selectedProjects.addAll( graph.getUpstreamProjects( selectedProject, true ) ); - } - if ( makeDownstream ) - { - selectedProjects.addAll( graph.getDownstreamProjects( selectedProject, true ) ); - } - } - } - - result = new ArrayList<MavenProject>( selectedProjects.size() ); - - for ( MavenProject project : projects ) - { - if ( selectedProjects.contains( project ) ) - { - result.add( project ); - } - } - } - - return result; - } - - private List<MavenProject> trimExcludedProjects( List<MavenProject> projects, MavenExecutionRequest request ) - throws MavenExecutionException - { - List<MavenProject> result = projects; - - if ( !request.getExcludedProjects().isEmpty() ) - { - File reactorDirectory = null; - - if ( request.getBaseDirectory() != null ) - { - reactorDirectory = new File( request.getBaseDirectory() ); - } - - Collection<MavenProject> excludedProjects = new LinkedHashSet<MavenProject>( projects.size() ); - - for ( String selector : request.getExcludedProjects() ) - { - MavenProject excludedProject = null; - - for ( MavenProject project : projects ) - { - if ( isMatchingProject( project, selector, reactorDirectory ) ) - { - excludedProject = project; - break; - } - } - - if ( excludedProject != null ) - { - excludedProjects.add( excludedProject ); - } - else - { - throw new MavenExecutionException( "Could not find the selected project in the reactor: " - + selector, request.getPom() ); - } - } - - result = new ArrayList<MavenProject>( projects.size() ); - for ( MavenProject project : projects ) - { - if ( !excludedProjects.contains( project ) ) - { - result.add( project ); - } - } - } - - return result; - } - - private List<MavenProject> trimResumedProjects( List<MavenProject> projects, MavenExecutionRequest request ) - throws MavenExecutionException - { - List<MavenProject> result = projects; - - if ( StringUtils.isNotEmpty( request.getResumeFrom() ) ) - { - File reactorDirectory = null; - if ( request.getBaseDirectory() != null ) - { - reactorDirectory = new File( request.getBaseDirectory() ); - } - - String selector = request.getResumeFrom(); - - result = new ArrayList<MavenProject>( projects.size() ); - - boolean resumed = false; - - for ( MavenProject project : projects ) - { - if ( !resumed && isMatchingProject( project, selector, reactorDirectory ) ) - { - resumed = true; - } - - if ( resumed ) - { - result.add( project ); - } - } - - if ( !resumed ) - { - throw new MavenExecutionException( "Could not find project to resume reactor build from: " + selector - + " vs " + projects, request.getPom() ); - } - } - - return result; - } - - private boolean isMatchingProject( MavenProject project, String selector, File reactorDirectory ) - { - // [groupId]:artifactId - if ( selector.indexOf( ':' ) >= 0 ) - { - String id = ':' + project.getArtifactId(); - - if ( id.equals( selector ) ) - { - return true; - } - - id = project.getGroupId() + id; - - if ( id.equals( selector ) ) - { - return true; - } - } - - // relative path, e.g. "sub", "../sub" or "." - else if ( reactorDirectory != null ) - { - File selectedProject = new File( new File( reactorDirectory, selector ).toURI().normalize() ); - - if ( selectedProject.isFile() ) - { - return selectedProject.equals( project.getFile() ); - } - else if ( selectedProject.isDirectory() ) - { - return selectedProject.equals( project.getBasedir() ); - } - } - - return false; - } - } http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/DefaultProjectDependencyGraph.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/DefaultProjectDependencyGraph.java b/maven-core/src/main/java/org/apache/maven/DefaultProjectDependencyGraph.java deleted file mode 100644 index 4074e58..0000000 --- a/maven-core/src/main/java/org/apache/maven/DefaultProjectDependencyGraph.java +++ /dev/null @@ -1,134 +0,0 @@ -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.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.apache.maven.execution.ProjectDependencyGraph; -import org.apache.maven.project.DuplicateProjectException; -import org.apache.maven.project.MavenProject; -import org.apache.maven.project.ProjectSorter; -import org.codehaus.plexus.util.dag.CycleDetectedException; - -/** - * Describes the inter-dependencies between projects in the reactor. - * - * @author Benjamin Bentmann - */ -class DefaultProjectDependencyGraph - implements ProjectDependencyGraph -{ - - private ProjectSorter sorter; - - /** - * Creates a new project dependency graph based on the specified projects. - * - * @param projects The projects to create the dependency graph with - * @throws DuplicateProjectException - * @throws CycleDetectedException - */ - public DefaultProjectDependencyGraph( Collection<MavenProject> projects ) - throws CycleDetectedException, DuplicateProjectException - { - this.sorter = new ProjectSorter( projects ); - } - - public List<MavenProject> getSortedProjects() - { - return new ArrayList<MavenProject>( sorter.getSortedProjects() ); - } - - public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive ) - { - if ( project == null ) - { - throw new IllegalArgumentException( "project missing" ); - } - - Set<String> projectIds = new HashSet<String>(); - - getDownstreamProjects( ProjectSorter.getId( project ), projectIds, transitive ); - - return getSortedProjects( projectIds ); - } - - private void getDownstreamProjects( String projectId, Set<String> projectIds, boolean transitive ) - { - for ( String id : sorter.getDependents( projectId ) ) - { - if ( projectIds.add( id ) && transitive ) - { - getDownstreamProjects( id, projectIds, transitive ); - } - } - } - - public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive ) - { - if ( project == null ) - { - throw new IllegalArgumentException( "project missing" ); - } - - Set<String> projectIds = new HashSet<String>(); - - getUpstreamProjects( ProjectSorter.getId( project ), projectIds, transitive ); - - return getSortedProjects( projectIds ); - } - - private void getUpstreamProjects( String projectId, Collection<String> projectIds, boolean transitive ) - { - for ( String id : sorter.getDependencies( projectId ) ) - { - if ( projectIds.add( id ) && transitive ) - { - getUpstreamProjects( id, projectIds, transitive ); - } - } - } - - private List<MavenProject> getSortedProjects( Set<String> projectIds ) - { - List<MavenProject> result = new ArrayList<MavenProject>( projectIds.size() ); - - for ( MavenProject mavenProject : sorter.getSortedProjects() ) - { - if ( projectIds.contains( ProjectSorter.getId( mavenProject ) ) ) - { - result.add( mavenProject ); - } - } - - return result; - } - - @Override - public String toString() - { - return sorter.getSortedProjects().toString(); - } - -} http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/FilteredProjectDependencyGraph.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/FilteredProjectDependencyGraph.java b/maven-core/src/main/java/org/apache/maven/FilteredProjectDependencyGraph.java deleted file mode 100644 index e5db6bd..0000000 --- a/maven-core/src/main/java/org/apache/maven/FilteredProjectDependencyGraph.java +++ /dev/null @@ -1,111 +0,0 @@ -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.util.ArrayList; -import java.util.Collection; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; - -import org.apache.maven.execution.ProjectDependencyGraph; -import org.apache.maven.project.MavenProject; - -/** - * Provides a sub view of another dependency graph. - * - * @author Benjamin Bentmann - */ -class FilteredProjectDependencyGraph - implements ProjectDependencyGraph -{ - - private ProjectDependencyGraph projectDependencyGraph; - - private Map<MavenProject, ?> whiteList; - - private List<MavenProject> sortedProjects; - - /** - * Creates a new project dependency graph from the specified graph. - * - * @param projectDependencyGraph The project dependency graph to create a sub view from, must not be {@code null}. - * @param whiteList The projects on which the dependency view should focus, must not be {@code null}. - */ - public FilteredProjectDependencyGraph( ProjectDependencyGraph projectDependencyGraph, - Collection<? extends MavenProject> whiteList ) - { - if ( projectDependencyGraph == null ) - { - throw new IllegalArgumentException( "project dependency graph missing" ); - } - - this.projectDependencyGraph = projectDependencyGraph; - - this.whiteList = new IdentityHashMap<MavenProject, Object>(); - - for ( MavenProject project : whiteList ) - { - this.whiteList.put( project, null ); - } - } - - public List<MavenProject> getSortedProjects() - { - if ( sortedProjects == null ) - { - sortedProjects = applyFilter( projectDependencyGraph.getSortedProjects() ); - } - - return new ArrayList<MavenProject>( sortedProjects ); - } - - public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive ) - { - return applyFilter( projectDependencyGraph.getDownstreamProjects( project, transitive ) ); - } - - public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive ) - { - return applyFilter( projectDependencyGraph.getUpstreamProjects( project, transitive ) ); - } - - private List<MavenProject> applyFilter( Collection<? extends MavenProject> projects ) - { - List<MavenProject> filtered = new ArrayList<MavenProject>( projects.size() ); - - for ( MavenProject project : projects ) - { - if ( whiteList.containsKey( project ) ) - { - filtered.add( project ); - } - } - - return filtered; - } - - @Override - public String toString() - { - return getSortedProjects().toString(); - } - -} http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java b/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java index cba4462..ecd8eca 100644 --- a/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java +++ b/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java @@ -27,6 +27,11 @@ import org.codehaus.plexus.util.dag.CycleDetectedException; public class ProjectCycleException extends BuildFailureException { + public ProjectCycleException( String message ) + { + super( message ); + } + public ProjectCycleException( String message, CycleDetectedException cause ) { super( message, cause ); http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/ReactorReader.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 3aca28d..252bdd0 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -34,9 +34,10 @@ import javax.inject.Named; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.Model; import org.apache.maven.project.MavenProject; +import org.apache.maven.repository.internal.MavenWorkspaceReader; import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.repository.WorkspaceReader; import org.eclipse.aether.repository.WorkspaceRepository; import org.eclipse.aether.util.artifact.ArtifactIdUtils; @@ -49,7 +50,7 @@ import org.eclipse.aether.util.artifact.ArtifactIdUtils; @Named( ReactorReader.HINT ) @SessionScoped class ReactorReader - implements WorkspaceReader + implements MavenWorkspaceReader { public static final String HINT = "reactor"; @@ -136,6 +137,14 @@ class ReactorReader return Collections.unmodifiableList( versions ); } + @Override + public Model findModel( Artifact artifact ) + { + String projectKey = ArtifactUtils.key( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() ); + MavenProject project = projectsByGAV.get( projectKey ); + return project == null ? null : project.getModel(); + } + // // Implementation // http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java b/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java index e463079..5fdbd07 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java +++ b/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java @@ -271,8 +271,10 @@ public class MavenSession { this.projectMap = projectMap; } - - public Map<String, MavenProject> getProjectMap() + + @Deprecated + /** @deprecated This appears to only be used in the ReactorReader and we can do any processing required there */ + public Map<String, MavenProject> getProjectMap() { return projectMap; } @@ -288,7 +290,7 @@ public class MavenSession { this.allProjects = allProjects; } - + /*if_not[MAVEN4]*/ // @@ -433,5 +435,4 @@ public class MavenSession } /*end[MAVEN4]*/ - } http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java new file mode 100644 index 0000000..0a602ba --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java @@ -0,0 +1,487 @@ +package org.apache.maven.graph; + +/* + * 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.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +import org.apache.maven.DefaultMaven; +import org.apache.maven.MavenExecutionException; +import org.apache.maven.ProjectCycleException; +import org.apache.maven.artifact.ArtifactUtils; +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.model.Plugin; +import org.apache.maven.model.building.DefaultModelProblem; +import org.apache.maven.model.building.ModelProblem; +import org.apache.maven.model.building.ModelProblemUtils; +import org.apache.maven.model.building.ModelSource; +import org.apache.maven.model.building.Result; +import org.apache.maven.model.building.UrlModelSource; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectBuilder; +import org.apache.maven.project.ProjectBuildingException; +import org.apache.maven.project.ProjectBuildingRequest; +import org.apache.maven.project.ProjectBuildingResult; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.logging.Logger; +import org.codehaus.plexus.util.StringUtils; +import org.codehaus.plexus.util.dag.CycleDetectedException; + +import com.google.common.collect.Lists; + +@Component( role = GraphBuilder.class, hint = GraphBuilder.HINT ) +public class DefaultGraphBuilder + implements GraphBuilder +{ + @Requirement + private Logger logger; + + @Requirement + protected ProjectBuilder projectBuilder; + + @Override + public Result<ProjectDependencyGraph> build( MavenSession session ) + { + if ( session.getProjectDependencyGraph() != null ) + { + return dependencyGraph( session, session.getProjects(), false ); + } + + List<MavenProject> projects = session.getProjects(); + + if ( projects == null ) + { + try + { + projects = getProjectsForMavenReactor( session ); + } + catch ( ProjectBuildingException e ) + { + return Result.error( Lists.newArrayList( new DefaultModelProblem( null, null, null, null, 0, 0, e ) ) ); + } + + validateProjects( projects ); + + return dependencyGraph( session, projects, true ); + } + else + { + return dependencyGraph( session, projects, false ); + } + } + + private Result<ProjectDependencyGraph> dependencyGraph( MavenSession session, List<MavenProject> projects, + boolean applyMakeBehaviour ) + { + MavenExecutionRequest request = session.getRequest(); + + ProjectDependencyGraph projectDependencyGraph = null; + + try + { + projectDependencyGraph = new DefaultProjectDependencyGraph( projects ); + + if ( applyMakeBehaviour ) + { + List<MavenProject> activeProjects = projectDependencyGraph.getSortedProjects(); + + activeProjects = trimSelectedProjects( activeProjects, projectDependencyGraph, request ); + activeProjects = trimExcludedProjects( activeProjects, request ); + activeProjects = trimResumedProjects( activeProjects, request ); + + if ( activeProjects.size() != projectDependencyGraph.getSortedProjects().size() ) + { + projectDependencyGraph = new FilteredProjectDependencyGraph( projectDependencyGraph, activeProjects ); + } + } + } + catch ( CycleDetectedException e ) + { + String message = "The projects in the reactor contain a cyclic reference: " + e.getMessage(); + ProjectCycleException error = new ProjectCycleException( message, e ); + return Result.error( Lists.newArrayList( new DefaultModelProblem( null, null, null, null, 0, 0, error ) ) ); + } + catch ( org.apache.maven.project.DuplicateProjectException e ) + { + return Result.error( Lists.newArrayList( new DefaultModelProblem( null, null, null, null, 0, 0, e ) ) ); + } + catch ( MavenExecutionException e ) + { + return Result.error( Lists.newArrayList( new DefaultModelProblem( null, null, null, null, 0, 0, e ) ) ); + } + + session.setProjects( projectDependencyGraph.getSortedProjects() ); + session.setProjectDependencyGraph( projectDependencyGraph ); + + return Result.success( projectDependencyGraph ); + } + + private List<MavenProject> trimSelectedProjects( List<MavenProject> projects, ProjectDependencyGraph graph, + MavenExecutionRequest request ) + throws MavenExecutionException + { + List<MavenProject> result = projects; + + if ( !request.getSelectedProjects().isEmpty() ) + { + File reactorDirectory = null; + if ( request.getBaseDirectory() != null ) + { + reactorDirectory = new File( request.getBaseDirectory() ); + } + + Collection<MavenProject> selectedProjects = new LinkedHashSet<MavenProject>( projects.size() ); + + for ( String selector : request.getSelectedProjects() ) + { + MavenProject selectedProject = null; + + for ( MavenProject project : projects ) + { + if ( isMatchingProject( project, selector, reactorDirectory ) ) + { + selectedProject = project; + break; + } + } + + if ( selectedProject != null ) + { + selectedProjects.add( selectedProject ); + } + else + { + throw new MavenExecutionException( "Could not find the selected project in the reactor: " + + selector, request.getPom() ); + } + } + + boolean makeUpstream = false; + boolean makeDownstream = false; + + if ( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( request.getMakeBehavior() ) ) + { + makeUpstream = true; + } + else if ( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals( request.getMakeBehavior() ) ) + { + makeDownstream = true; + } + else if ( MavenExecutionRequest.REACTOR_MAKE_BOTH.equals( request.getMakeBehavior() ) ) + { + makeUpstream = true; + makeDownstream = true; + } + else if ( StringUtils.isNotEmpty( request.getMakeBehavior() ) ) + { + throw new MavenExecutionException( "Invalid reactor make behavior: " + request.getMakeBehavior(), + request.getPom() ); + } + + if ( makeUpstream || makeDownstream ) + { + for ( MavenProject selectedProject : new ArrayList<MavenProject>( selectedProjects ) ) + { + if ( makeUpstream ) + { + selectedProjects.addAll( graph.getUpstreamProjects( selectedProject, true ) ); + } + if ( makeDownstream ) + { + selectedProjects.addAll( graph.getDownstreamProjects( selectedProject, true ) ); + } + } + } + + result = new ArrayList<MavenProject>( selectedProjects.size() ); + + for ( MavenProject project : projects ) + { + if ( selectedProjects.contains( project ) ) + { + result.add( project ); + } + } + } + + return result; + } + + private List<MavenProject> trimExcludedProjects( List<MavenProject> projects, MavenExecutionRequest request ) + throws MavenExecutionException + { + List<MavenProject> result = projects; + + if ( !request.getExcludedProjects().isEmpty() ) + { + File reactorDirectory = null; + + if ( request.getBaseDirectory() != null ) + { + reactorDirectory = new File( request.getBaseDirectory() ); + } + + Collection<MavenProject> excludedProjects = new LinkedHashSet<MavenProject>( projects.size() ); + + for ( String selector : request.getExcludedProjects() ) + { + MavenProject excludedProject = null; + + for ( MavenProject project : projects ) + { + if ( isMatchingProject( project, selector, reactorDirectory ) ) + { + excludedProject = project; + break; + } + } + + if ( excludedProject != null ) + { + excludedProjects.add( excludedProject ); + } + else + { + throw new MavenExecutionException( "Could not find the selected project in the reactor: " + + selector, request.getPom() ); + } + } + + result = new ArrayList<MavenProject>( projects.size() ); + for ( MavenProject project : projects ) + { + if ( !excludedProjects.contains( project ) ) + { + result.add( project ); + } + } + } + + return result; + } + + private List<MavenProject> trimResumedProjects( List<MavenProject> projects, MavenExecutionRequest request ) + throws MavenExecutionException + { + List<MavenProject> result = projects; + + if ( StringUtils.isNotEmpty( request.getResumeFrom() ) ) + { + File reactorDirectory = null; + if ( request.getBaseDirectory() != null ) + { + reactorDirectory = new File( request.getBaseDirectory() ); + } + + String selector = request.getResumeFrom(); + + result = new ArrayList<MavenProject>( projects.size() ); + + boolean resumed = false; + + for ( MavenProject project : projects ) + { + if ( !resumed && isMatchingProject( project, selector, reactorDirectory ) ) + { + resumed = true; + } + + if ( resumed ) + { + result.add( project ); + } + } + + if ( !resumed ) + { + throw new MavenExecutionException( "Could not find project to resume reactor build from: " + selector + + " vs " + projects, request.getPom() ); + } + } + + return result; + } + + private boolean isMatchingProject( MavenProject project, String selector, File reactorDirectory ) + { + // [groupId]:artifactId + if ( selector.indexOf( ':' ) >= 0 ) + { + String id = ':' + project.getArtifactId(); + + if ( id.equals( selector ) ) + { + return true; + } + + id = project.getGroupId() + id; + + if ( id.equals( selector ) ) + { + return true; + } + } + + // relative path, e.g. "sub", "../sub" or "." + else if ( reactorDirectory != null ) + { + File selectedProject = new File( new File( reactorDirectory, selector ).toURI().normalize() ); + + if ( selectedProject.isFile() ) + { + return selectedProject.equals( project.getFile() ); + } + else if ( selectedProject.isDirectory() ) + { + return selectedProject.equals( project.getBasedir() ); + } + } + + return false; + } + + private MavenExecutionResult addExceptionToResult( MavenExecutionResult result, Throwable e ) + { + if ( !result.getExceptions().contains( e ) ) + { + result.addException( e ); + } + + return result; + } + + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Project collection + // + // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + private List<MavenProject> getProjectsForMavenReactor( MavenSession session ) + throws ProjectBuildingException + { + MavenExecutionRequest request = session.getRequest(); + + request.getProjectBuildingRequest().setRepositorySession( session.getRepositorySession() ); + + List<MavenProject> projects = new ArrayList<MavenProject>(); + + // We have no POM file. + // + if ( request.getPom() == null ) + { + ModelSource modelSource = new UrlModelSource( DefaultMaven.class.getResource( "project/standalone.xml" ) ); + MavenProject project = projectBuilder.build( modelSource, request.getProjectBuildingRequest() ) + .getProject(); + project.setExecutionRoot( true ); + projects.add( project ); + request.setProjectPresent( false ); + return projects; + } + + List<File> files = Arrays.asList( request.getPom().getAbsoluteFile() ); + collectProjects( projects, files, request ); + return projects; + } + + private void collectProjects( List<MavenProject> projects, List<File> files, MavenExecutionRequest request ) + throws ProjectBuildingException + { + ProjectBuildingRequest projectBuildingRequest = request.getProjectBuildingRequest(); + + List<ProjectBuildingResult> results = projectBuilder.build( files, request.isRecursive(), + projectBuildingRequest ); + + boolean problems = false; + + for ( ProjectBuildingResult result : results ) + { + projects.add( result.getProject() ); + + if ( !result.getProblems().isEmpty() && logger.isWarnEnabled() ) + { + logger.warn( "" ); + logger.warn( "Some problems were encountered while building the effective model for " + + result.getProject().getId() ); + + for ( ModelProblem problem : result.getProblems() ) + { + String loc = ModelProblemUtils.formatLocation( problem, result.getProjectId() ); + logger.warn( problem.getMessage() + ( StringUtils.isNotEmpty( loc ) ? " @ " + loc : "" ) ); + } + + problems = true; + } + } + + if ( problems ) + { + logger.warn( "" ); + logger.warn( "It is highly recommended to fix these problems" + + " because they threaten the stability of your build." ); + logger.warn( "" ); + logger.warn( "For this reason, future Maven versions might no" + + " longer support building such malformed projects." ); + logger.warn( "" ); + } + } + + private void validateProjects( List<MavenProject> projects ) + { + Map<String, MavenProject> projectsMap = new HashMap<String, MavenProject>(); + + for ( MavenProject p : projects ) + { + String projectKey = ArtifactUtils.key( p.getGroupId(), p.getArtifactId(), p.getVersion() ); + + projectsMap.put( projectKey, p ); + } + + for ( MavenProject project : projects ) + { + // MNG-1911 / MNG-5572: Building plugins with extensions cannot be part of reactor + for ( Plugin plugin : project.getBuildPlugins() ) + { + if ( plugin.isExtensions() ) + { + String pluginKey = ArtifactUtils.key( plugin.getGroupId(), plugin.getArtifactId(), + plugin.getVersion() ); + + if ( projectsMap.containsKey( pluginKey ) ) + { + logger.warn( project.getName() + " uses " + plugin.getKey() + + " as extensions, which is not possible within the same reactor build. " + + "This plugin was pulled from the local repository!" ); + } + } + } + } + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java new file mode 100644 index 0000000..01fec33 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java @@ -0,0 +1,134 @@ +package org.apache.maven.graph; + +/* + * 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.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.maven.execution.ProjectDependencyGraph; +import org.apache.maven.project.DuplicateProjectException; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectSorter; +import org.codehaus.plexus.util.dag.CycleDetectedException; + +/** + * Describes the inter-dependencies between projects in the reactor. + * + * @author Benjamin Bentmann + */ +public class DefaultProjectDependencyGraph + implements ProjectDependencyGraph +{ + + private ProjectSorter sorter; + + /** + * Creates a new project dependency graph based on the specified projects. + * + * @param projects The projects to create the dependency graph with + * @throws DuplicateProjectException + * @throws CycleDetectedException + */ + public DefaultProjectDependencyGraph( Collection<MavenProject> projects ) + throws CycleDetectedException, DuplicateProjectException + { + this.sorter = new ProjectSorter( projects ); + } + + public List<MavenProject> getSortedProjects() + { + return new ArrayList<MavenProject>( sorter.getSortedProjects() ); + } + + public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive ) + { + if ( project == null ) + { + throw new IllegalArgumentException( "project missing" ); + } + + Set<String> projectIds = new HashSet<String>(); + + getDownstreamProjects( ProjectSorter.getId( project ), projectIds, transitive ); + + return getSortedProjects( projectIds ); + } + + private void getDownstreamProjects( String projectId, Set<String> projectIds, boolean transitive ) + { + for ( String id : sorter.getDependents( projectId ) ) + { + if ( projectIds.add( id ) && transitive ) + { + getDownstreamProjects( id, projectIds, transitive ); + } + } + } + + public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive ) + { + if ( project == null ) + { + throw new IllegalArgumentException( "project missing" ); + } + + Set<String> projectIds = new HashSet<String>(); + + getUpstreamProjects( ProjectSorter.getId( project ), projectIds, transitive ); + + return getSortedProjects( projectIds ); + } + + private void getUpstreamProjects( String projectId, Collection<String> projectIds, boolean transitive ) + { + for ( String id : sorter.getDependencies( projectId ) ) + { + if ( projectIds.add( id ) && transitive ) + { + getUpstreamProjects( id, projectIds, transitive ); + } + } + } + + private List<MavenProject> getSortedProjects( Set<String> projectIds ) + { + List<MavenProject> result = new ArrayList<MavenProject>( projectIds.size() ); + + for ( MavenProject mavenProject : sorter.getSortedProjects() ) + { + if ( projectIds.contains( ProjectSorter.getId( mavenProject ) ) ) + { + result.add( mavenProject ); + } + } + + return result; + } + + @Override + public String toString() + { + return sorter.getSortedProjects().toString(); + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java b/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java new file mode 100644 index 0000000..662bda4 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java @@ -0,0 +1,111 @@ +package org.apache.maven.graph; + +/* + * 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.util.ArrayList; +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.maven.execution.ProjectDependencyGraph; +import org.apache.maven.project.MavenProject; + +/** + * Provides a sub view of another dependency graph. + * + * @author Benjamin Bentmann + */ +class FilteredProjectDependencyGraph + implements ProjectDependencyGraph +{ + + private ProjectDependencyGraph projectDependencyGraph; + + private Map<MavenProject, ?> whiteList; + + private List<MavenProject> sortedProjects; + + /** + * Creates a new project dependency graph from the specified graph. + * + * @param projectDependencyGraph The project dependency graph to create a sub view from, must not be {@code null}. + * @param whiteList The projects on which the dependency view should focus, must not be {@code null}. + */ + public FilteredProjectDependencyGraph( ProjectDependencyGraph projectDependencyGraph, + Collection<? extends MavenProject> whiteList ) + { + if ( projectDependencyGraph == null ) + { + throw new IllegalArgumentException( "project dependency graph missing" ); + } + + this.projectDependencyGraph = projectDependencyGraph; + + this.whiteList = new IdentityHashMap<MavenProject, Object>(); + + for ( MavenProject project : whiteList ) + { + this.whiteList.put( project, null ); + } + } + + public List<MavenProject> getSortedProjects() + { + if ( sortedProjects == null ) + { + sortedProjects = applyFilter( projectDependencyGraph.getSortedProjects() ); + } + + return new ArrayList<MavenProject>( sortedProjects ); + } + + public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive ) + { + return applyFilter( projectDependencyGraph.getDownstreamProjects( project, transitive ) ); + } + + public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive ) + { + return applyFilter( projectDependencyGraph.getUpstreamProjects( project, transitive ) ); + } + + private List<MavenProject> applyFilter( Collection<? extends MavenProject> projects ) + { + List<MavenProject> filtered = new ArrayList<MavenProject>( projects.size() ); + + for ( MavenProject project : projects ) + { + if ( whiteList.containsKey( project ) ) + { + filtered.add( project ); + } + } + + return filtered; + } + + @Override + public String toString() + { + return getSortedProjects().toString(); + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java b/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java new file mode 100644 index 0000000..fb7c4f2 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java @@ -0,0 +1,31 @@ +package org.apache.maven.graph; + +/* + * 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 org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.ProjectDependencyGraph; +import org.apache.maven.model.building.Result; + +public interface GraphBuilder +{ + String HINT = "graphBuilder"; + + Result<? extends ProjectDependencyGraph> build( MavenSession session ); +} http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java b/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java index 262cf09..a536562 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java @@ -37,7 +37,7 @@ import org.apache.maven.plugin.version.PluginVersionResolutionException; * * @author Benjamin Bentmann */ -class DefaultModelBuildingListener +public class DefaultModelBuildingListener extends AbstractModelBuildingListener { http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/project/MavenProject.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java index 641ebda..a14aaa1 100644 --- a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java +++ b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java @@ -1171,7 +1171,7 @@ public class MavenProject return clone; } - protected void setModel( Model model ) + public void setModel( Model model ) { this.model = model; } http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java b/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java index c64dd73..77e7c49 100644 --- a/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java +++ b/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java @@ -28,6 +28,7 @@ import java.util.Set; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; + import org.apache.maven.model.Parent; import org.apache.maven.model.Repository; import org.apache.maven.model.building.FileModelSource; @@ -55,7 +56,7 @@ import org.eclipse.aether.resolution.VersionRangeResult; * * @author Benjamin Bentmann */ -class ProjectModelResolver +public class ProjectModelResolver implements ModelResolver { http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/test/java/org/apache/maven/DefaultProjectDependencyGraphTest.java ---------------------------------------------------------------------- diff --git a/maven-core/src/test/java/org/apache/maven/DefaultProjectDependencyGraphTest.java b/maven-core/src/test/java/org/apache/maven/DefaultProjectDependencyGraphTest.java deleted file mode 100644 index 668dafb..0000000 --- a/maven-core/src/test/java/org/apache/maven/DefaultProjectDependencyGraphTest.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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. - */ -package org.apache.maven; - -import junit.framework.TestCase; -import org.apache.maven.execution.ProjectDependencyGraph; -import org.apache.maven.model.Dependency; -import org.apache.maven.project.DuplicateProjectException; -import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.util.dag.CycleDetectedException; - -import java.util.Arrays; -import java.util.List; - -/** - * @author Kristian Rosenvold - */ -public class DefaultProjectDependencyGraphTest - extends TestCase -{ - - private final MavenProject aProject = createA(); - - private final MavenProject depender1 = createProject( Arrays.asList( toDependency( aProject ) ), "depender1" ); - - private final MavenProject depender2 = createProject( Arrays.asList( toDependency( aProject ) ), "depender2" ); - - private final MavenProject depender3 = createProject( Arrays.asList( toDependency( aProject ) ), "depender3" ); - - private final MavenProject depender4 = - createProject( Arrays.asList( toDependency( aProject ), toDependency( depender3 ) ), "depender4" ); - - private final MavenProject transitiveOnly = - createProject( Arrays.asList( toDependency( depender3 ) ), "depender5" ); - - public void testGetSortedProjects() - throws DuplicateProjectException, CycleDetectedException - { - ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( Arrays.asList( depender1, aProject ) ); - final List<MavenProject> sortedProjects = graph.getSortedProjects(); - assertEquals( aProject, sortedProjects.get( 0 ) ); - assertEquals( depender1, sortedProjects.get( 1 ) ); - } - - public void testVerifyExpectedParentStructure() - throws CycleDetectedException, DuplicateProjectException - { - // This test verifies the baseline structure used in susequent tests. If this fails, the rest will fail. - ProjectDependencyGraph graph = threeProjectsDependingOnASingle(); - final List<MavenProject> sortedProjects = graph.getSortedProjects(); - assertEquals( aProject, sortedProjects.get( 0 ) ); - assertEquals( depender1, sortedProjects.get( 1 ) ); - assertEquals( depender2, sortedProjects.get( 2 ) ); - assertEquals( depender3, sortedProjects.get( 3 ) ); - } - - public void testVerifyThatDownsteamProjectsComeInSortedOrder() - throws CycleDetectedException, DuplicateProjectException - { - final List<MavenProject> downstreamProjects = - threeProjectsDependingOnASingle().getDownstreamProjects( aProject, true ); - assertEquals( depender1, downstreamProjects.get( 0 ) ); - assertEquals( depender2, downstreamProjects.get( 1 ) ); - assertEquals( depender3, downstreamProjects.get( 2 ) ); - } - - public void testTransitivesInOrder() - throws CycleDetectedException, DuplicateProjectException - { - final ProjectDependencyGraph graph = - new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender4, depender2, depender3, aProject ) ); - - final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, true ); - assertEquals( depender1, downstreamProjects.get( 0 ) ); - assertEquals( depender3, downstreamProjects.get( 1 ) ); - assertEquals( depender4, downstreamProjects.get( 2 ) ); - assertEquals( depender2, downstreamProjects.get( 3 ) ); - } - - public void testNonTransitivesInOrder() - throws CycleDetectedException, DuplicateProjectException - { - final ProjectDependencyGraph graph = - new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender4, depender2, depender3, aProject ) ); - - final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, false ); - assertEquals( depender1, downstreamProjects.get( 0 ) ); - assertEquals( depender3, downstreamProjects.get( 1 ) ); - assertEquals( depender4, downstreamProjects.get( 2 ) ); - assertEquals( depender2, downstreamProjects.get( 3 ) ); - } - - public void testWithTranistiveOnly() - throws CycleDetectedException, DuplicateProjectException - { - final ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( - Arrays.asList( depender1, transitiveOnly, depender2, depender3, aProject ) ); - - final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, true ); - assertEquals( depender1, downstreamProjects.get( 0 ) ); - assertEquals( depender3, downstreamProjects.get( 1 ) ); - assertEquals( transitiveOnly, downstreamProjects.get( 2 ) ); - assertEquals( depender2, downstreamProjects.get( 3 ) ); - } - - public void testWithMissingTranistiveOnly() - throws CycleDetectedException, DuplicateProjectException - { - final ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( - Arrays.asList( depender1, transitiveOnly, depender2, depender3, aProject ) ); - - final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, false ); - assertEquals( depender1, downstreamProjects.get( 0 ) ); - assertEquals( depender3, downstreamProjects.get( 1 ) ); - assertEquals( depender2, downstreamProjects.get( 2 ) ); - } - - public void testGetUpstreamProjects() - throws CycleDetectedException, DuplicateProjectException - { - ProjectDependencyGraph graph = threeProjectsDependingOnASingle(); - final List<MavenProject> downstreamProjects = graph.getUpstreamProjects( depender1, true ); - assertEquals( aProject, downstreamProjects.get( 0 ) ); - } - - private ProjectDependencyGraph threeProjectsDependingOnASingle() - throws CycleDetectedException, DuplicateProjectException - { - return new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender2, depender3, aProject ) ); - } - - private static MavenProject createA() - { - MavenProject result = new MavenProject(); - result.setGroupId( "org.apache" ); - result.setArtifactId( "A" ); - result.setVersion( "1.2" ); - return result; - } - - static Dependency toDependency( MavenProject mavenProject ) - { - final Dependency dependency = new Dependency(); - dependency.setArtifactId( mavenProject.getArtifactId() ); - dependency.setGroupId( mavenProject.getGroupId() ); - dependency.setVersion( mavenProject.getVersion() ); - return dependency; - } - - private static MavenProject createProject( List<Dependency> dependencies, String artifactId ) - { - MavenProject result = new MavenProject(); - result.setGroupId( "org.apache" ); - result.setArtifactId( artifactId ); - result.setVersion( "1.2" ); - result.setDependencies( dependencies ); - return result; - } - -} \ No newline at end of file