Author: dfabulich Date: Thu Aug 14 19:46:18 2008 New Revision: 686117 URL: http://svn.apache.org/viewvc?rev=686117&view=rev Log: Added maven-reactor-plugin
Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/ maven/sandbox/trunk/plugins/maven-reactor-plugin/pom.xml maven/sandbox/trunk/plugins/maven-reactor-plugin/src/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeDependentsMojo.java maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeMojo.java maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeMyChanges.java maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MissingProjectException.java maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/NonReactorException.java maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/RelativePather.java maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/ResumeMojo.java maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/SimpleInvoker.java maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/SuperProjectSorter.java maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/org/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/org/apache/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/org/apache/maven/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/org/apache/maven/plugin/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/org/apache/maven/plugin/reactor/ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/org/apache/maven/plugin/reactor/RelativePatherTest.java Modified: maven/sandbox/trunk/plugins/pom.xml Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/pom.xml URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/pom.xml?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/pom.xml (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/pom.xml Thu Aug 14 19:46:18 2008 @@ -0,0 +1,51 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-reactor-plugin</artifactId> + <packaging>maven-plugin</packaging> + <version>1.0-SNAPSHOT</version> + <name>maven-reactor-plugin</name> + <description>Build a subset of interdependent projects in a reactor</description> + <url>http://maven.apache.org</url> + <dependencies> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + <version>2.0.9</version> + </dependency> + <dependency> + <groupId>org.apache.maven.shared</groupId> + <artifactId>maven-invoker</artifactId> + <version>2.0.10-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-scm-plugin</artifactId> + <version>1.0</version> + </dependency> + <!-- DGF it's too painful to depend on all of the providers plus the API + plexus and track their versions ... --> + <!-- + <dependency> + <groupId>org.apache.maven.scm</groupId> + <artifactId>maven-scm-api</artifactId> + <version>1.0</version> + </dependency> + <dependency> + <groupId>org.apache.maven.scm</groupId> + <artifactId>maven-scm-manager-plexus</artifactId> + <version>1.0</version> + </dependency>--> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-project</artifactId> + <version>2.0.9</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.1</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeDependentsMojo.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeDependentsMojo.java?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeDependentsMojo.java (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeDependentsMojo.java Thu Aug 14 19:46:18 2008 @@ -0,0 +1,49 @@ +package org.apache.maven.plugin.reactor; + +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed 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.List; +import java.util.Set; + +import org.codehaus.plexus.util.dag.Vertex; + +/** + * Goal to build a project X and all of the reactor projects that depend on X + * + * @author <a href="mailto:[EMAIL PROTECTED]">Dan Fabulich</a> + * @goal makeDependents + * @aggregator + * @phase process-sources + */ +public class MakeDependentsMojo + extends MakeMojo +{ + // gather parents instead of children + protected Set gatherProjects( Vertex v, SuperProjectSorter ps, Set visited, Set out ) + { + visited.add(v); + out.add(ps.getProjectMap().get(v.getLabel())); + List parents = v.getParents(); + for (int i = 0; i < parents.size(); i++) { + Vertex parent = (Vertex) parents.get(i); + if (visited.contains(parent)) continue; + gatherProjects(parent, ps, visited, out); + } + return out; + } +} Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeMojo.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeMojo.java?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeMojo.java (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeMojo.java Thu Aug 14 19:46:18 2008 @@ -0,0 +1,201 @@ +package org.apache.maven.plugin.reactor; + +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed 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.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.maven.artifact.ArtifactUtils; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; +import org.apache.maven.shared.invoker.Invoker; +import org.codehaus.plexus.util.StringUtils; +import org.codehaus.plexus.util.dag.DAG; +import org.codehaus.plexus.util.dag.Vertex; + +/** + * Goal to build a project X and all of the reactor projects on which X depends + * + * @author <a href="mailto:[EMAIL PROTECTED]">Dan Fabulich</a> + * @goal make + * @aggregator + * @phase process-sources + */ +public class MakeMojo + extends AbstractMojo +{ + /** + * Location of the file. + * @parameter expression="${basedir}" + * @required + */ + File baseDir; + + /** + * @parameter expression="${project.collectedProjects}" + */ + List collectedProjects; + + /** + * @parameter expression="${make.group}" default-value="${project.groupId}" + * @required + */ + String defaultGroup; + + /** + * A list of artifacts to build, e.g. "com.mycompany:bar,com.mycompany:foo" or just "foo,bar", or just "foo" + * @parameter expression="${make.artifacts}" + */ + String artifactList; + + /** + * A list of relative paths to build, e.g. "foo,baz/bar" + * @parameter expression="${make.folders}" + */ + String folderList; + + /** + * Goals to run on subproject + * @parameter expression="${make.goals}" default-value="install" + */ + String goals; + + /** + * @component + */ + Invoker invoker; + + /** + * Don't really do anything; just print a command that describes what the command would have done + * @parameter expression="${make.printOnly}" + */ + private boolean printOnly = true; + + public void execute() + throws MojoExecutionException, MojoFailureException + { + if (artifactList == null && folderList == null) { + throw new MojoFailureException("You must specify either folders or projects with -Dmake.folders=foo,baz/bar or -Dmake.projects=com.mycompany:foo,com.mycompany:bar"); + } + String[] reactorIncludes; + try + { + if (collectedProjects.size() == 0) { + throw new NonReactorException(); + } + SuperProjectSorter ps = new SuperProjectSorter( collectedProjects ); + DAG dag = ps.getDAG(); + + // gather projects + collectArtifactListFromFolderList( collectedProjects ); + String[] artifacts = StringUtils.split( artifactList, "," ); + Set visited = new HashSet(); + Set out = new HashSet(); + for (int i = 0; i < artifacts.length; i++) { + String project = artifacts[i]; + if ( project.indexOf(':') == -1 ) { + project = defaultGroup + ":" + project; + } + Vertex projectVertex = dag.getVertex( project ); + if ( projectVertex == null ) throw new MissingProjectException(project); + gatherProjects( projectVertex, ps, visited, out ); + } + + // sort them again + ps = new SuperProjectSorter( new ArrayList( out ) ); + List sortedProjects = ps.getSortedProjects(); + + // construct array of relative POM paths + reactorIncludes = new String[sortedProjects.size()]; + for ( int i = 0; i < sortedProjects.size(); i++ ) + { + MavenProject mp = (MavenProject) sortedProjects.get( i ); + String path = RelativePather.getRelativePath( baseDir, mp.getFile() ); + reactorIncludes[i] = path; + } + } + catch (MojoFailureException e) { + throw e; + } + catch ( Exception e ) + { + throw new MojoExecutionException( "Problem generating dependency tree", e ); + } + + new SimpleInvoker().runReactor( reactorIncludes, Arrays.asList( goals.split( "," ) ), invoker, printOnly, getLog() ); + + } + + void collectArtifactListFromFolderList(List collectedProjects) throws MojoFailureException + { + if ( folderList == null ) + return; + String[] folders = StringUtils.split( folderList, "," ); + Set pathSet = new HashSet(); + for ( int i = 0; i < folders.length; i++ ) + { + File file = new File( baseDir, folders[i] ); + if ( !file.exists() ) + { + throw new MojoFailureException("Folder doesn't exist: " + file.getAbsolutePath() ); + } + String path = file.getAbsolutePath(); + pathSet.add( path ); + } + if (artifactList == null) artifactList = ""; + StringBuffer artifactBuffer = new StringBuffer(artifactList); + for ( int i = 0; i < collectedProjects.size(); i++ ) + { + MavenProject mp = (MavenProject) collectedProjects.get( i ); + if ( pathSet.contains( mp.getFile().getParentFile().getAbsolutePath() ) ) + { + if ( artifactBuffer.length() > 0 ) + { + artifactBuffer.append( ',' ); + } + String id = ArtifactUtils.versionlessKey( mp.getGroupId(), mp.getArtifactId() ); + artifactBuffer.append( id ); + } + } + if ( artifactBuffer.length() == 0 ) + { + throw new MojoFailureException("No folders matched: " + folderList); + } + artifactList = artifactBuffer.toString(); + } + + protected Set gatherProjects( Vertex v, SuperProjectSorter ps, Set visited, Set out ) + { + visited.add( v ); + out.add( ps.getProjectMap().get( v.getLabel() ) ); + List children = v.getChildren(); + for ( int i = 0; i < children.size(); i++ ) + { + Vertex child = (Vertex) children.get( i ); + if ( visited.contains( child ) ) + continue; + gatherProjects( child, ps, visited, out ); + } + return out; + } +} Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeMyChanges.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeMyChanges.java?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeMyChanges.java (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MakeMyChanges.java Thu Aug 14 19:46:18 2008 @@ -0,0 +1,107 @@ +package org.apache.maven.plugin.reactor; + +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed 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.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; +import org.apache.maven.scm.ScmFile; +import org.apache.maven.scm.ScmFileSet; +import org.apache.maven.scm.command.status.StatusScmResult; +import org.apache.maven.scm.manager.ScmManager; +import org.apache.maven.scm.repository.ScmRepository; +import org.codehaus.plexus.util.StringUtils; + +/** + * Goal to build all projects that you personally have changed (according to SCM) + * + * @author <a href="mailto:[EMAIL PROTECTED]">Dan Fabulich</a> + * @goal makeMyChanges + * @aggregator + * @phase process-sources + */ +public class MakeMyChanges + extends MakeDependentsMojo +{ + /** + * @parameter expression="${make.scmUrl}" default-value="${project.scm.connection}" + * @required + */ + private String scmUrl; + + /** + * @parameter expression="${component.org.apache.maven.scm.manager.ScmManager}" + */ + private ScmManager scmManager; + + private MavenProject project; + + public void execute() + throws MojoExecutionException, MojoFailureException + { + if (collectedProjects.size() == 0) { + throw new NonReactorException(); + } + StatusScmResult result = null; + try + { + ScmRepository repository = scmManager.makeScmRepository( scmUrl ); + result = scmManager.status( repository, new ScmFileSet( baseDir ) ); + } + catch ( Exception e ) + { + throw new MojoExecutionException("Couldn't configure SCM repository: " + e.getLocalizedMessage(),e); + } + + List changedFiles = result.getChangedFiles(); + // TODO There's a cleverer/faster way to code this...? + List projectDirectories = getProjectDirectories(); + Set changedDirectories = new HashSet(); + for (int i = 0; i < changedFiles.size(); i++) { + ScmFile changedScmFile = (ScmFile) changedFiles.get( i ); + File changedFile = new File(changedScmFile.getPath()); + for (int j = 0; j < projectDirectories.size(); j++) { + File projectDirectory = (File) projectDirectories.get( j ); + if (changedFile.getAbsolutePath().startsWith( projectDirectory.getAbsolutePath() )) { + changedDirectories.add( RelativePather.getRelativePath( baseDir, projectDirectory ) ); + break; + } + } + } + folderList = StringUtils.join( changedDirectories.iterator(), "," ); + getLog().info( "Going to make dependents for: " + folderList ); + super.execute(); + + } + + private List getProjectDirectories() { + List dirs = new ArrayList(collectedProjects.size()); + for (int i = 0; i < collectedProjects.size(); i++) + { + MavenProject mp = (MavenProject) collectedProjects.get( i ); + dirs.add( mp.getFile().getParentFile() ); + } + return dirs; + } + +} Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MissingProjectException.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MissingProjectException.java?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MissingProjectException.java (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/MissingProjectException.java Thu Aug 14 19:46:18 2008 @@ -0,0 +1,31 @@ +package org.apache.maven.plugin.reactor; + +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed 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.plugin.MojoFailureException; + +class MissingProjectException + extends MojoFailureException +{ + + private static final long serialVersionUID = 1L; + + public MissingProjectException(String project) + { + super( "Couldn't find project " + project + " in reactor; make sure you specified the correct group:artifactId (may differ from folder name)" ); + } +} Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/NonReactorException.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/NonReactorException.java?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/NonReactorException.java (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/NonReactorException.java Thu Aug 14 19:46:18 2008 @@ -0,0 +1,29 @@ +package org.apache.maven.plugin.reactor; + +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed 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.plugin.MojoFailureException; + +class NonReactorException + extends MojoFailureException +{ + private static final long serialVersionUID = 1L; + + public NonReactorException() { + super("This isn't a reactor build. This command must be run from the root of the reactor (the project with <modules> in it)"); + } +} Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/RelativePather.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/RelativePather.java?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/RelativePather.java (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/RelativePather.java Thu Aug 14 19:46:18 2008 @@ -0,0 +1,117 @@ +package org.apache.maven.plugin.reactor; + +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed 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.Iterator; +import java.util.LinkedList; + +/** + * Calculates relative paths + * @author <a href="mailto:[EMAIL PROTECTED]">Dan Fabulich</a> + * + */ +class RelativePather { + /** + * Calculates a relative path + * @param context the "current" context directory + * @param dest the directory to be described by a relative path + * @return a relative path from the context directory to the dest directory + */ + public static String getRelativePath(File context, File dest) { + LinkedList contextChunks = getPathChunks(context); + LinkedList destChunks = getPathChunks(dest); + if (!contextChunks.getFirst().equals(destChunks.getFirst())) throw new DifferentRootsException("Roots differ"); + int count = 0; + Iterator contextChunker = contextChunks.iterator(); + Iterator destChunker = destChunks.iterator(); + String contextChunk = (String) contextChunker.next(); + String destChunk = (String) destChunker.next(); + boolean pathsDiffer = false; + while (true) { + count++; + if (!contextChunker.hasNext()) break; + if (!destChunker.hasNext()) break; + contextChunk = (String) contextChunker.next(); + destChunk = (String) destChunker.next(); + if (!contextChunk.equals(destChunk)) { + pathsDiffer = true; + break; + } + } + + // the paths agree for the first N chunks + + StringBuffer relativePath = new StringBuffer(); + + if (count < contextChunks.size()) { + int dotDotCount = contextChunks.size() - count; + for (int i = 0; i < dotDotCount; i++) { + relativePath.append(".."); + // omit trailing slash + if (i < dotDotCount -1) { + relativePath.append(File.separatorChar); + } + } + } + if (pathsDiffer) { + if (relativePath.length() > 0) { + relativePath.append(File.separatorChar); + } + relativePath.append(destChunk); + } + while (destChunker.hasNext()) { + if (relativePath.length() > 0) { + relativePath.append(File.separatorChar); + } + relativePath.append(destChunker.next()); + } + + return relativePath.toString(); + } + + private static LinkedList getPathChunks(File f) { + LinkedList l = new LinkedList(); + while (f.getParentFile() != null) { + l.addFirst(f.getName()); + f = f.getParentFile(); + } + l.addFirst(f.getAbsolutePath()); + return l; + } + + static class DifferentRootsException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public DifferentRootsException() { + super(); + } + + public DifferentRootsException(String message, Throwable cause) { + super(message, cause); + } + + public DifferentRootsException(String message) { + super(message); + } + + public DifferentRootsException(Throwable cause) { + super(cause); + } + + } +} Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/ResumeMojo.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/ResumeMojo.java?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/ResumeMojo.java (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/ResumeMojo.java Thu Aug 14 19:46:18 2008 @@ -0,0 +1,168 @@ +package org.apache.maven.plugin.reactor; + +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed 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.Arrays; +import java.util.List; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectSorter; +import org.apache.maven.shared.invoker.Invoker; + +/** + * Goal to resume building a reactor at a certain point + * + * @author <a href="mailto:[EMAIL PROTECTED]">Dan Fabulich</a> + * @goal resume + * @aggregator + * @phase process-sources + */ +public class ResumeMojo + extends AbstractMojo +{ + + /** + * @parameter expression="${project.collectedProjects}" + */ + private List collectedProjects; + + /** + * Location of the file. + * @parameter expression="${basedir}" + * @required + */ + private File baseDir; + + /** + * @parameter expression="${make.group}" default-value="${project.groupId}" + * @required + */ + private String continueFromGroup; + + /** + * The artifact from which we'll resume, e.g. "com.mycompany:foo" or just "foo" + * @parameter expression="${fromArtifact}" + */ + private String continueFromProject; + + /** + * The project folder from which we'll resume + * @parameter expression="${from}" + */ + private File continueFromFolder; + + /** + * Goals to run on subproject + * @parameter expression="${make.goals}" default-value="install" + */ + private String goals; + + /** + * @component + */ + private Invoker invoker; + + /** + * Don't really do anything; just print a message that describes what the command would have done + * @parameter expression="${make.printOnly}" + */ + private boolean printOnly = true; + + public void execute() + throws MojoExecutionException, MojoFailureException + { + if ( continueFromFolder == null && continueFromProject == null ) + { + throw new MojoFailureException("You must specify either a folder or a project with -Dfrom=baz/bar or -DfromArtifact=com.mycompany:foo (groupId is optional)"); + } + if (continueFromFolder != null && continueFromProject != null ) + { + throw new MojoFailureException("You can't specify both a folder (" + continueFromFolder + ") and an artifact (" + continueFromProject + ")"); + } + if ( continueFromFolder != null && !continueFromFolder.exists() ) + { + throw new MojoFailureException("Folder doesn't exist: " + continueFromFolder.getAbsolutePath() ); + } + String[] reactorIncludes; + try + { + + if (collectedProjects.size() == 0) { + throw new NonReactorException(); + } + ProjectSorter ps = new ProjectSorter( collectedProjects ); + + List sortedProjects = ps.getSortedProjects(); + + String projectName = null; + if ( continueFromProject != null) + { + projectName = continueFromProject; + if ( projectName.indexOf(':') != -1 ) { + int index = continueFromProject.indexOf(':'); + continueFromGroup = continueFromProject.substring( 0, index ); + projectName = continueFromProject.substring( index+1 ); + } + } + + boolean found = false; + int i = 0; + for (; i < sortedProjects.size(); i++) { + MavenProject mp = (MavenProject) sortedProjects.get( i ); + if ( continueFromFolder == null ) + { + if ( continueFromGroup.equals( mp.getGroupId() ) && projectName.equals( mp.getArtifactId() ) ) + { + found = true; + break; + } + } else { + if ( continueFromFolder.equals( mp.getFile().getParentFile() ) ) + { + found = true; + break; + } + } + } + + if (!found) throw new MissingProjectException(continueFromGroup + ":" + projectName); + + // construct array of relative POM paths + reactorIncludes = new String[sortedProjects.size() - i]; + for ( int j = i; j < sortedProjects.size(); j++ ) + { + MavenProject mp = (MavenProject) sortedProjects.get( j ); + String path = RelativePather.getRelativePath( baseDir, mp.getFile() ); + reactorIncludes[j- i] = path; + } + } + catch (MojoFailureException e) { + throw e; + } + catch ( Exception e ) + { + throw new MojoExecutionException( "Problem generating dependency tree", e ); + } + + new SimpleInvoker().runReactor( reactorIncludes, Arrays.asList( goals.split( "," ) ), invoker, printOnly, getLog() ); + + } +} Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/SimpleInvoker.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/SimpleInvoker.java?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/SimpleInvoker.java (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/SimpleInvoker.java Thu Aug 14 19:46:18 2008 @@ -0,0 +1,104 @@ +package org.apache.maven.plugin.reactor; + +/* + * Copyright 2008 The Apache Software Foundation. + * + * Licensed 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.List; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.shared.invoker.CommandLineConfigurationException; +import org.apache.maven.shared.invoker.DefaultInvocationRequest; +import org.apache.maven.shared.invoker.InvocationRequest; +import org.apache.maven.shared.invoker.InvocationResult; +import org.apache.maven.shared.invoker.Invoker; +import org.apache.maven.shared.invoker.MavenCommandLineBuilder; + +/** Simplified wrapper for Maven invoker + * + * @author <a href="mailto:[EMAIL PROTECTED]">Dan Fabulich</a> + * + */ +class SimpleInvoker +{ + /** Runs a "mvn --reactor" build with the specified includes + * + * @param reactorIncludes the list of include patterns for --reactor + * @param goalList the list of goals (you can also pass other flags in here; they're just command-line args) + * @param invoker the Maven Invoker (let Maven provide to you as a component) + * @param printOnly if true, don't actually run anything, just log a message + * @param log logger + * @throws InvokerExecutionException if build fails for any reason + */ + void runReactor( String[] reactorIncludes, List goalList, Invoker invoker, boolean printOnly, Log log ) + throws InvokerExecutionException + { + InvocationRequest request = new DefaultInvocationRequest(); + request.activateReactor( reactorIncludes, null/* excludes */); + request.setGoals( goalList ); + request.setRecursive( false ); + try + { + log.info( "Executing: " + new MavenCommandLineBuilder().build( request ) ); + } + catch ( CommandLineConfigurationException e ) + { + throw new InvokerExecutionException( "Failed to display command line", e ); + } + + if ( !printOnly ) + { + try + { + InvocationResult result = invoker.execute( request ); + if ( result.getExecutionException() != null ) + throw result.getExecutionException(); + if ( result.getExitCode() != 0 ) + throw new InvokerExecutionException( "Exit code was " + result.getExitCode() ); + } + catch ( Exception e ) + { + throw new InvokerExecutionException( "Maven build failed: " + e.getLocalizedMessage(), e ); + } + } + } + + class InvokerExecutionException extends MojoExecutionException { + + private static final long serialVersionUID = 1L; + + public InvokerExecutionException( Object source, String shortMessage, String longMessage ) + { + super( source, shortMessage, longMessage ); + } + + public InvokerExecutionException( String message, Exception cause ) + { + super( message, cause ); + } + + public InvokerExecutionException( String message, Throwable cause ) + { + super( message, cause ); + } + + public InvokerExecutionException( String message ) + { + super( message ); + } + + } +} Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/SuperProjectSorter.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/SuperProjectSorter.java?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/SuperProjectSorter.java (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/main/java/org/apache/maven/plugin/reactor/SuperProjectSorter.java Thu Aug 14 19:46:18 2008 @@ -0,0 +1,247 @@ +package org.apache.maven.plugin.reactor; + +/* + * 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.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.maven.artifact.ArtifactUtils; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Extension; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.ReportPlugin; +import org.apache.maven.project.DuplicateProjectException; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.dag.CycleDetectedException; +import org.codehaus.plexus.util.dag.DAG; +import org.codehaus.plexus.util.dag.TopologicalSorter; + +/** + * Sort projects by dependencies. Just like ProjectSorter from maven-project, but this one exposes + * the DAG and the projectMap in getters. + * + * + * @author <a href="mailto:[EMAIL PROTECTED]">Dan Fabulich</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Brett Porter</a> + */ +public class SuperProjectSorter +{ + private final DAG dag; + + private final Map projectMap; + + 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 + */ + public SuperProjectSorter( List projects ) + throws CycleDetectedException, DuplicateProjectException + { + dag = new DAG(); + + 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 ) + { + throw new DuplicateProjectException( "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; + } + + public List getDependents( String id ) + { + return dag.getParentLabels( id ); + } + + public DAG getDAG() + { + return dag; + } + + public Map getProjectMap() + { + return projectMap; + } + +} Added: maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/org/apache/maven/plugin/reactor/RelativePatherTest.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/org/apache/maven/plugin/reactor/RelativePatherTest.java?rev=686117&view=auto ============================================================================== --- maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/org/apache/maven/plugin/reactor/RelativePatherTest.java (added) +++ maven/sandbox/trunk/plugins/maven-reactor-plugin/src/test/java/org/apache/maven/plugin/reactor/RelativePatherTest.java Thu Aug 14 19:46:18 2008 @@ -0,0 +1,70 @@ +package org.apache.maven.plugin.reactor; + +import java.io.File; + +import org.apache.maven.plugin.reactor.RelativePather.DifferentRootsException; + +import junit.framework.TestCase; + +public class RelativePatherTest extends TestCase { + File root; + File differentRoot; + char S = File.separatorChar; + + public void setUp() { + File[] roots = File.listRoots(); + root = roots[0]; + if (roots.length > 1) { + differentRoot = roots[1]; + } + } + + public void testIdenticalRoots() { + assertEquals("", getRelativePath(root, root)); + } + + public void testDifferentRoots() { + // skip this test on systems with only one root + if (differentRoot == null) return; + try { + getRelativePath(root, differentRoot); + fail("Expected different roots exception"); + } catch (DifferentRootsException e) {} + } + + public void testIdenticalFoo() { + File foo = new File(root, "foo"); + assertEquals("", getRelativePath(foo, foo)); + } + + public void testIdenticalFooFoo() { + File foo = new File(root, "foo/foo"); + assertEquals("", getRelativePath(foo, foo)); + } + + public void testFooBar() { + File foo = new File(root, "foo"); + File bar = new File(root, "bar"); + assertEquals(".." + S + "bar", getRelativePath(foo, bar)); + } + + public void testRootFoo() { + File foo = new File(root, "foo"); + assertEquals("foo", getRelativePath(root, foo)); + } + + public void testFooRoot() { + File foo = new File(root, "foo"); + assertEquals("..", getRelativePath(foo, root)); + } + + public void testFooFooBarBar() { + File foo = new File(root, "foo/foo"); + File bar = new File(root, "bar/bar"); + assertEquals(".." + S + ".." + S + "bar" + S + "bar", getRelativePath(foo, bar)); + } + + public String getRelativePath(File context, File dest) { + return RelativePather.getRelativePath(context, dest); + } +} Modified: maven/sandbox/trunk/plugins/pom.xml URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/plugins/pom.xml?rev=686117&r1=686116&r2=686117&view=diff ============================================================================== --- maven/sandbox/trunk/plugins/pom.xml (original) +++ maven/sandbox/trunk/plugins/pom.xml Thu Aug 14 19:46:18 2008 @@ -26,6 +26,7 @@ <module>maven-plugin-management-plugin</module> <module>maven-pom-plugin</module> <module>maven-property-setting-plugin</module> + <module>maven-reactor-plugin</module> <module>maven-shade-plugin</module> <module>maven-swizzle-plugin</module> <module>maven-xcode-plugin</module>