You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by si...@apache.org on 2008/09/04 01:36:04 UTC
svn commit: r691831 - in
/maven/components/branches/sisbell-maven-2.1-profile:
maven-core/src/main/java/org/apache/maven/
maven-core/src/main/java/org/apache/maven/execution/
maven-core/src/test/java/org/apache/maven/execution/
maven-project/src/main/a...
Author: sisbell
Date: Wed Sep 3 16:36:03 2008
New Revision: 691831
URL: http://svn.apache.org/viewvc?rev=691831&view=rev
Log:
Moved Project sorter out of maven-project. Only one class from a different package used it. Now its an inner class of ReactorManager.
Added:
maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/test/java/org/apache/maven/execution/ProjectSorterTest.java
Removed:
maven/components/branches/sisbell-maven-2.1-profile/maven-project/src/main/aspect/org/apache/maven/project/aspect/ProjectCollisionReporterAspect.aj
maven/components/branches/sisbell-maven-2.1-profile/maven-project/src/main/java/org/apache/maven/project/ProjectSorter.java
maven/components/branches/sisbell-maven-2.1-profile/maven-project/src/test/java/org/apache/maven/project/ProjectSorterTest.java
Modified:
maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java
maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java
Modified: maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java
URL: http://svn.apache.org/viewvc/maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java?rev=691831&r1=691830&r2=691831&view=diff
==============================================================================
--- maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java (original)
+++ maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java Wed Sep 3 16:36:03 2008
@@ -1,7 +1,6 @@
package org.apache.maven;
import org.apache.maven.execution.ReactorManager;
-import org.apache.maven.project.ProjectSorter;
import org.codehaus.plexus.util.dag.CycleDetectedException;
import java.util.List;
@@ -9,7 +8,7 @@
/**
* Exception which occurs when creating a new {@link ReactorManager} instance,
* due to failure to sort the current projects. The embedded {@link CycleDetectedException}
- * is thrown by the {@link ProjectSorter}, and context of this wrapped exception
+ * is thrown by the ProjectSorter and context of this wrapped exception
* includes the list of projects that contain the cycle, along with a friendly
* rendering of the cycle message indicating that it comes from the current projects list.
*
Modified: maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java
URL: http://svn.apache.org/viewvc/maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java?rev=691831&r1=691830&r2=691831&view=diff
==============================================================================
--- maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java (original)
+++ maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java Wed Sep 3 16:36:03 2008
@@ -24,14 +24,15 @@
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.project.DuplicateProjectException;
import org.apache.maven.project.MavenProject;
-import org.apache.maven.project.ProjectSorter;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.ReportPlugin;
+import org.apache.maven.model.Extension;
import org.codehaus.plexus.util.dag.CycleDetectedException;
+import org.codehaus.plexus.util.dag.DAG;
+import org.codehaus.plexus.util.dag.TopologicalSorter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
public class ReactorManager
{
@@ -188,4 +189,210 @@
{
return buildFailuresByProject.size() + buildSuccessesByProject.size() > 1;
}
+
+ protected static class ProjectSorter
+ {
+ private final DAG dag;
+
+ private final List sortedProjects;
+
+ private MavenProject topLevelProject;
+
+ /**
+ * Sort a list of projects.
+ * <ul>
+ * <li>collect all the vertices for the projects that we want to build.</li>
+ * <li>iterate through the deps of each project and if that dep is within
+ * the set of projects we want to build then add an edge, otherwise throw
+ * the edge away because that dependency is not within the set of projects
+ * we are trying to build. we assume a closed set.</li>
+ * <li>do a topo sort on the graph that remains.</li>
+ * </ul>
+ * @throws DuplicateProjectException if any projects are duplicated by id
+ */
+ // MAVENAPI FIXME: the DAG used is NOT only used to represent the dependency relation,
+ // but also for <parent>, <build><plugin>, <reports>. We need multiple DAG's
+ // since a DAG can only handle 1 type of relationship properly.
+ // Usecase: This is detected as a cycle:
+ // org.apache.maven:maven-plugin-api -(PARENT)->
+ // org.apache.maven:maven -(inherited REPORTING)->
+ // org.apache.maven.plugins:maven-checkstyle-plugin -(DEPENDENCY)->
+ // org.apache.maven:maven-plugin-api
+ // In this case, both the verify and the report goals are called
+ // in a different lifecycle. Though the compiler-plugin has a valid usecase, although
+ // that seems to work fine. We need to take versions and lifecycle into account.
+ public ProjectSorter( List projects )
+ throws CycleDetectedException, DuplicateProjectException
+ {
+ dag = new DAG();
+
+ Map projectMap = new HashMap();
+
+ for ( Iterator i = projects.iterator(); i.hasNext(); )
+ {
+ MavenProject project = (MavenProject) i.next();
+
+ String id = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
+
+ if ( dag.getVertex( id ) != null )
+ {
+ MavenProject conflictingProject = (MavenProject) projectMap.get( id );
+
+ throw new DuplicateProjectException( id,
+ conflictingProject.getFile(),
+ project.getFile(),
+ "Project '"
+ + id
+ + "' is duplicated in the reactor" );
+ }
+
+ dag.addVertex( id );
+
+ projectMap.put( id, project );
+ }
+
+ for ( Iterator i = projects.iterator(); i.hasNext(); )
+ {
+ MavenProject project = (MavenProject) i.next();
+
+ String id = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
+
+ for ( Iterator j = project.getDependencies().iterator(); j.hasNext(); )
+ {
+ Dependency dependency = (Dependency) j.next();
+
+ String dependencyId = ArtifactUtils
+ .versionlessKey( dependency.getGroupId(), dependency.getArtifactId() );
+
+ if ( dag.getVertex( dependencyId ) != null )
+ {
+ project.addProjectReference( (MavenProject) projectMap.get( dependencyId ) );
+
+ dag.addEdge( id, dependencyId );
+ }
+ }
+
+ MavenProject parent = project.getParent();
+ if ( parent != null )
+ {
+ String parentId = ArtifactUtils.versionlessKey( parent.getGroupId(), parent.getArtifactId() );
+ if ( dag.getVertex( parentId ) != null )
+ {
+ // Parent is added as an edge, but must not cause a cycle - so we remove any other edges it has in conflict
+ if ( dag.hasEdge( parentId, id ) )
+ {
+ dag.removeEdge( parentId, id );
+ }
+ dag.addEdge( id, parentId );
+ }
+ }
+
+ List buildPlugins = project.getBuildPlugins();
+ if ( buildPlugins != null )
+ {
+ for ( Iterator j = buildPlugins.iterator(); j.hasNext(); )
+ {
+ Plugin plugin = (Plugin) j.next();
+ String pluginId = ArtifactUtils.versionlessKey( plugin.getGroupId(), plugin.getArtifactId() );
+ if ( ( dag.getVertex( pluginId ) != null ) && !pluginId.equals( id ) )
+ {
+ addEdgeWithParentCheck( projectMap, pluginId, project, id );
+ }
+ }
+ }
+
+ List reportPlugins = project.getReportPlugins();
+ if ( reportPlugins != null )
+ {
+ for ( Iterator j = reportPlugins.iterator(); j.hasNext(); )
+ {
+ ReportPlugin plugin = (ReportPlugin) j.next();
+ String pluginId = ArtifactUtils.versionlessKey( plugin.getGroupId(), plugin.getArtifactId() );
+ if ( ( dag.getVertex( pluginId ) != null ) && !pluginId.equals( id ) )
+ {
+ addEdgeWithParentCheck( projectMap, pluginId, project, id );
+ }
+ }
+ }
+
+ for ( Iterator j = project.getBuildExtensions().iterator(); j.hasNext(); )
+ {
+ Extension extension = (Extension) j.next();
+ String extensionId = ArtifactUtils.versionlessKey( extension.getGroupId(), extension.getArtifactId() );
+ if ( dag.getVertex( extensionId ) != null )
+ {
+ addEdgeWithParentCheck( projectMap, extensionId, project, id );
+ }
+ }
+ }
+
+ List sortedProjects = new ArrayList();
+
+ for ( Iterator i = TopologicalSorter.sort( dag ).iterator(); i.hasNext(); )
+ {
+ String id = (String) i.next();
+
+ sortedProjects.add( projectMap.get( id ) );
+ }
+
+ this.sortedProjects = Collections.unmodifiableList( sortedProjects );
+ }
+
+ private void addEdgeWithParentCheck( Map projectMap, String projectRefId, MavenProject project, String id )
+ throws CycleDetectedException
+ {
+ MavenProject extProject = (MavenProject) projectMap.get( projectRefId );
+
+ if ( extProject == null )
+ {
+ return;
+ }
+
+ project.addProjectReference( extProject );
+
+ MavenProject extParent = extProject.getParent();
+ if ( extParent != null )
+ {
+ String parentId = ArtifactUtils.versionlessKey( extParent.getGroupId(), extParent.getArtifactId() );
+ // Don't add edge from parent to extension if a reverse edge already exists
+ if ( !dag.hasEdge( projectRefId, id ) || !parentId.equals( id ) )
+ {
+ dag.addEdge( id, projectRefId );
+ }
+ }
+ }
+
+ // TODO: !![jc; 28-jul-2005] check this; if we're using '-r' and there are aggregator tasks, this will result in weirdness.
+ public MavenProject getTopLevelProject()
+ {
+ if ( topLevelProject == null )
+ {
+ for ( Iterator i = sortedProjects.iterator(); i.hasNext() && ( topLevelProject == null ); )
+ {
+ MavenProject project = (MavenProject) i.next();
+ if ( project.isExecutionRoot() )
+ {
+ topLevelProject = project;
+ }
+ }
+ }
+
+ return topLevelProject;
+ }
+
+ public List getSortedProjects()
+ {
+ return sortedProjects;
+ }
+
+ public boolean hasMultipleProjects()
+ {
+ return sortedProjects.size() > 1;
+ }
+
+ private List getDependents( String id )
+ {
+ return dag.getParentLabels( id );
+ }
+ }
}
Added: maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/test/java/org/apache/maven/execution/ProjectSorterTest.java
URL: http://svn.apache.org/viewvc/maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/test/java/org/apache/maven/execution/ProjectSorterTest.java?rev=691831&view=auto
==============================================================================
--- maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/test/java/org/apache/maven/execution/ProjectSorterTest.java (added)
+++ maven/components/branches/sisbell-maven-2.1-profile/maven-core/src/test/java/org/apache/maven/execution/ProjectSorterTest.java Wed Sep 3 16:36:03 2008
@@ -0,0 +1,161 @@
+package org.apache.maven.execution;
+
+/*
+ * 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 junit.framework.TestCase;
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Extension;
+import org.apache.maven.model.Model;
+import org.apache.maven.project.DuplicateProjectException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.dag.CycleDetectedException;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Test sorting projects by dependencies.
+ *
+ * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ * @version $Id: ProjectSorterTest.java 513038 2007-02-28 22:54:19Z jvanzyl $
+ */
+public class ProjectSorterTest
+ extends TestCase
+{
+
+ public void testShouldNotFailWhenProjectReferencesNonExistentProject()
+ throws CycleDetectedException, DuplicateProjectException
+ {
+ MavenProject project = createProject( "group", "artifact", "1.0" );
+ Model model = project.getModel();
+
+ Build build = model.getBuild();
+
+ if ( build == null )
+ {
+ build = new Build();
+ model.setBuild( build );
+ }
+
+ Extension extension = new Extension();
+
+ extension.setArtifactId( "other-artifact" );
+ extension.setGroupId( "other.group" );
+ extension.setVersion( "1.0" );
+
+ build.addExtension( extension );
+
+ new ReactorManager.ProjectSorter( Collections.singletonList( project ) );
+ }
+
+ public void testMatchingArtifactIdsDifferentGroupIds()
+ throws CycleDetectedException, DuplicateProjectException
+ {
+ List projects = new ArrayList();
+ MavenProject project1 = createProject( "groupId1", "artifactId", "1.0" );
+ projects.add( project1 );
+ MavenProject project2 = createProject( "groupId2", "artifactId", "1.0" );
+ projects.add( project2 );
+ project1.getDependencies().add( createDependency( project2 ) );
+
+ projects = new ReactorManager.ProjectSorter( projects ).getSortedProjects();
+
+ assertEquals( project2, projects.get( 0 ) );
+ assertEquals( project1, projects.get( 1 ) );
+ }
+
+ public void testMatchingGroupIdsDifferentArtifactIds()
+ throws CycleDetectedException, DuplicateProjectException
+ {
+ List projects = new ArrayList();
+ MavenProject project1 = createProject( "groupId", "artifactId1", "1.0" );
+ projects.add( project1 );
+ MavenProject project2 = createProject( "groupId", "artifactId2", "1.0" );
+ projects.add( project2 );
+ project1.getDependencies().add( createDependency( project2 ) );
+
+ projects = new ReactorManager.ProjectSorter( projects ).getSortedProjects();
+
+ assertEquals( project2, projects.get( 0 ) );
+ assertEquals( project1, projects.get( 1 ) );
+ }
+
+ public void testMatchingIdsAndVersions()
+ throws CycleDetectedException
+ {
+ List projects = new ArrayList();
+ MavenProject project1 = createProject( "groupId", "artifactId", "1.0" );
+ projects.add( project1 );
+ MavenProject project2 = createProject( "groupId", "artifactId", "1.0" );
+ projects.add( project2 );
+
+ try
+ {
+ projects = new ReactorManager.ProjectSorter( projects ).getSortedProjects();
+ fail( "Duplicate projects should fail" );
+ }
+ catch ( DuplicateProjectException e )
+ {
+ // expected
+ assertTrue( true );
+ }
+ }
+
+ public void testMatchingIdsAndDifferentVersions()
+ throws CycleDetectedException
+ {
+ List projects = new ArrayList();
+ MavenProject project1 = createProject( "groupId", "artifactId", "1.0" );
+ projects.add( project1 );
+ MavenProject project2 = createProject( "groupId", "artifactId", "2.0" );
+ projects.add( project2 );
+
+ try
+ {
+ projects = new ReactorManager.ProjectSorter( projects ).getSortedProjects();
+ fail( "Duplicate projects should fail" );
+ }
+ catch ( DuplicateProjectException e )
+ {
+ // expected
+ assertTrue( true );
+ }
+ }
+
+ private Dependency createDependency( MavenProject project )
+ {
+ Dependency depdendency = new Dependency();
+ depdendency.setArtifactId( project.getArtifactId() );
+ depdendency.setGroupId( project.getGroupId() );
+ depdendency.setVersion( project.getVersion() );
+ return depdendency;
+ }
+
+ private static MavenProject createProject( String groupId, String artifactId, String version )
+ {
+ Model model = new Model();
+ model.setGroupId( groupId );
+ model.setArtifactId( artifactId );
+ model.setVersion( version );
+ return new MavenProject( model );
+ }
+}