diff --git a/maven-plugins/maven-ant-plugin/pom.xml b/maven-plugins/maven-ant-plugin/pom.xml
new file mode 100644
index 0000000000..552daaee86
--- /dev/null
+++ b/maven-plugins/maven-ant-plugin/pom.xml
@@ -0,0 +1,19 @@
+
+ 4.0.0
+
+ maven-plugin-parent
+ org.apache.maven.plugins
+ 2.0-SNAPSHOT
+
+ maven-ant-plugin
+ 2.0-alpha-1-SNAPSHOT
+ maven-plugin
+ Maven Ant Plugin
+
+
+ org.apache.maven
+ maven-project
+ 2.0-SNAPSHOT
+
+
+
diff --git a/maven-plugins/maven-ant-plugin/src/main/java/org/apache/maven/plugin/ant/AntBuildWriter.java b/maven-plugins/maven-ant-plugin/src/main/java/org/apache/maven/plugin/ant/AntBuildWriter.java
new file mode 100644
index 0000000000..d1d947864d
--- /dev/null
+++ b/maven-plugins/maven-ant-plugin/src/main/java/org/apache/maven/plugin/ant/AntBuildWriter.java
@@ -0,0 +1,529 @@
+package org.apache.maven.plugin.ant;
+
+/*
+ * Copyright 2001-2005 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.artifact.Artifact;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.Resource;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
+import org.codehaus.plexus.util.xml.XMLWriter;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author Brett Porter
+ * @version $Id$
+ */
+public class AntBuildWriter
+{
+ private MavenProject project;
+
+ private File localRepository;
+
+ public AntBuildWriter( MavenProject project, File localRepository )
+ {
+ this.project = project;
+ this.localRepository = localRepository;
+ }
+
+ public void write()
+ throws AntPluginException
+ {
+ writeBuildXml();
+
+ System.out.println(
+ "Wrote Ant project for " + project.getArtifactId() + " to " + project.getBasedir().getAbsolutePath() );
+ }
+
+ // ----------------------------------------------------------------------
+ // build.xml
+ // ----------------------------------------------------------------------
+
+ protected void writeBuildXml()
+ throws AntPluginException
+ {
+ FileWriter w;
+
+ try
+ {
+ // TODO: parameter
+ w = new FileWriter( new File( project.getBasedir(), "build.xml" ) );
+ }
+ catch ( IOException ex )
+ {
+ throw new AntPluginException( "Exception while opening file.", ex );
+ }
+
+ XMLWriter writer = new PrettyPrintXMLWriter( w );
+
+ writer.startElement( "project" );
+ writer.addAttribute( "name", project.getArtifactId() );
+ writer.addAttribute( "default", "jar" );
+ writer.addAttribute( "basedir", "." );
+
+ writeProperties( writer );
+
+ writeBuildPathDefinition( writer );
+
+ writeCleanTarget( writer );
+ List compileSourceRoots = removeEmptyCompileSourceRoots( project.getCompileSourceRoots() );
+ writeCompileTarget( writer, compileSourceRoots );
+
+ // TODO: what if type is not JAR?
+ writeJarTarget( writer );
+
+ List testCompileSourceRoots = removeEmptyCompileSourceRoots( project.getTestCompileSourceRoots() );
+ writeCompileTestsTarget( writer, testCompileSourceRoots );
+ writeTestTargets( writer, testCompileSourceRoots );
+
+ writeGetDepsTarget( writer );
+
+ writer.endElement(); // project
+
+ close( w );
+ }
+
+ private void writeCompileTestsTarget( XMLWriter writer, List testCompileSourceRoots )
+ {
+ writer.startElement( "target" );
+ writer.addAttribute( "name", "compile-tests" );
+ writer.addAttribute( "depends", "junit-present, compile" );
+ writer.addAttribute( "description", "Compile the test code" );
+ writer.addAttribute( "if", "junit.present" );
+
+ writeCompileTasks( writer, project.getBasedir(), "${maven.test.output}", testCompileSourceRoots,
+ project.getBuild().getTestResources(), "${maven.build.output}" );
+
+ writer.endElement(); // target
+ }
+
+ private void writeTestTargets( XMLWriter writer, List testCompileSourceRoots )
+ {
+ writer.startElement( "target" );
+ writer.addAttribute( "name", "test" );
+ writer.addAttribute( "depends", "junit-present, compile-tests" );
+ writer.addAttribute( "if", "junit.present" );
+ writer.addAttribute( "description", "Run the test cases" );
+
+ if ( !testCompileSourceRoots.isEmpty() )
+ {
+ writer.startElement( "mkdir" );
+ writer.addAttribute( "dir", "${maven.test.reports}" );
+ writer.endElement(); //mkdir
+
+ writer.startElement( "junit" );
+ writer.addAttribute( "printSummary", "yes" );
+ writer.addAttribute( "haltonerror", "true" );
+ writer.addAttribute( "haltonfailure", "true" );
+ writer.addAttribute( "fork", "true" );
+ writer.addAttribute( "dir", "." );
+
+ writer.startElement( "sysproperty" );
+ writer.addAttribute( "key", "basedir" );
+ writer.addAttribute( "value", "." );
+ writer.endElement(); // sysproperty
+
+ writer.startElement( "formatter" );
+ writer.addAttribute( "type", "xml" );
+ writer.endElement(); // formatter
+
+ writer.startElement( "formatter" );
+ writer.addAttribute( "type", "plain" );
+ writer.addAttribute( "usefile", "false" );
+ writer.endElement(); // formatter
+
+ writer.startElement( "classpath" );
+ writer.startElement( "path" );
+ writer.addAttribute( "refid", "build.classpath" );
+ writer.endElement(); // path
+ writer.startElement( "pathelement" );
+ writer.addAttribute( "location", "${maven.build.output}" );
+ writer.endElement(); // pathelement
+ writer.startElement( "pathelement" );
+ writer.addAttribute( "location", "${maven.test.output}" );
+ writer.endElement(); // pathelement
+ writer.endElement(); // classpath
+
+ writer.startElement( "batchtest" );
+ for ( Iterator i = testCompileSourceRoots.iterator(); i.hasNext(); )
+ {
+ writer.startElement( "fileset" );
+ String testSrcDir = (String) i.next();
+ writer.addAttribute( "dir", toRelative( project.getBasedir(), testSrcDir ) );
+/* TODO: need to get these from the test plugin somehow?
+ UnitTest unitTest = project.getBuild().getUnitTest();
+ writeIncludesExcludes( writer, unitTest.getIncludes(), unitTest.getExcludes() );
+ // TODO: m1 allows additional test exclusions via maven.ant.excludeTests
+*/
+ writeIncludesExcludes( writer, Collections.singletonList( "**/*Test.java" ),
+ Collections.singletonList( "**/*Abstract*Test.java" ) );
+ writer.endElement(); // fileset
+ }
+ writer.endElement(); // batchtest
+
+ writer.endElement(); // junit
+ }
+ writer.endElement(); // target
+
+ writer.startElement( "target" );
+ writer.addAttribute( "name", "test-junit-present" );
+
+ writer.startElement( "available" );
+ writer.addAttribute( "classname", "junit.framework.Test" );
+ writer.addAttribute( "property", "junit.present" );
+ writer.endElement(); // available
+
+ writer.endElement(); // target
+
+ writer.startElement( "target" );
+ writer.addAttribute( "name", "junit-present" );
+ writer.addAttribute( "depends", "test-junit-present" );
+ writer.addAttribute( "unless", "junit.present" );
+
+ writer.startElement( "echo" );
+ writer.writeText( "================================= WARNING ================================" );
+ writer.endElement(); // echo
+
+ writer.startElement( "echo" );
+ writer.writeText( " Junit isn't present in your $ANT_HOME/lib directory. Tests not executed. " );
+ writer.endElement(); // echo
+
+ writer.startElement( "echo" );
+ writer.writeText( "==========================================================================" );
+ writer.endElement(); // echo
+
+ writer.endElement(); // target
+ }
+
+ private void writeJarTarget( XMLWriter writer )
+ {
+ writer.startElement( "target" );
+ writer.addAttribute( "name", "jar" );
+ writer.addAttribute( "depends", "compile,test" );
+ writer.addAttribute( "description", "Clean the JAR" );
+
+ writer.startElement( "jar" );
+ writer.addAttribute( "jarfile", "${maven.build.directory}/${maven.build.final.name}.jar" );
+ writer.addAttribute( "basedir", "${maven.build.output}" );
+ writer.addAttribute( "excludes", "**/package.html" );
+ writer.endElement(); // jar
+
+ writer.endElement(); // target
+ }
+
+ private void writeCleanTarget( XMLWriter writer )
+ {
+ writer.startElement( "target" );
+ writer.addAttribute( "name", "clean" );
+ writer.addAttribute( "description", "Clean the output directory" );
+
+ writer.startElement( "delete" );
+ writer.addAttribute( "dir", "${maven.build.directory}" );
+ writer.endElement(); // delete
+
+ writer.endElement(); // target
+ }
+
+ private void writeCompileTarget( XMLWriter writer, List compileSourceRoots )
+ {
+ writer.startElement( "target" );
+ writer.addAttribute( "name", "compile" );
+ writer.addAttribute( "depends", "get-deps" );
+ writer.addAttribute( "description", "Compile the code" );
+
+ writeCompileTasks( writer, project.getBasedir(), "${maven.build.output}", compileSourceRoots,
+ project.getBuild().getResources(), null );
+
+ writer.endElement(); // target
+ }
+
+ private static void writeCompileTasks( XMLWriter writer, File basedir, String outputDirectory,
+ List compileSourceRoots, List resources, String additionalClassesDirectory )
+ {
+ writer.startElement( "mkdir" );
+ writer.addAttribute( "dir", outputDirectory );
+ writer.endElement(); // mkdir
+
+ if ( !compileSourceRoots.isEmpty() )
+ {
+ writer.startElement( "javac" );
+ writer.addAttribute( "destdir", outputDirectory );
+ writer.addAttribute( "excludes", "**/package.html" );
+ writer.addAttribute( "debug", "true" ); // TODO: use compiler setting
+ writer.addAttribute( "deprecation", "true" ); // TODO: use compiler setting
+ writer.addAttribute( "optimize", "false" ); // TODO: use compiler setting
+
+ for ( Iterator i = compileSourceRoots.iterator(); i.hasNext(); )
+ {
+ String srcDir = (String) i.next();
+
+ writer.startElement( "src" );
+ writer.startElement( "pathelement" );
+ writer.addAttribute( "location", toRelative( basedir, srcDir ) );
+ writer.endElement(); // pathelement
+ writer.endElement(); // src
+ }
+
+ if ( additionalClassesDirectory == null )
+ {
+ writer.startElement( "classpath" );
+ writer.addAttribute( "refid", "build.classpath" );
+ writer.endElement(); // classpath
+ }
+ else
+ {
+ writer.startElement( "classpath" );
+ writer.startElement( "path" );
+ writer.addAttribute( "refid", "build.classpath" );
+ writer.endElement(); // path
+ writer.startElement( "pathelement" );
+ writer.addAttribute( "location", additionalClassesDirectory );
+ writer.endElement(); // pathelement
+ writer.endElement(); // classpath
+
+ }
+
+ writer.endElement(); // javac
+ }
+
+ for ( Iterator i = resources.iterator(); i.hasNext(); )
+ {
+ Resource resource = (Resource) i.next();
+
+ if ( new File( resource.getDirectory() ).exists() )
+ {
+ String outputDir = outputDirectory;
+ if ( resource.getTargetPath() != null && resource.getTargetPath().length() > 0 )
+ {
+ outputDir = outputDir + "/" + resource.getTargetPath();
+
+ writer.startElement( "mkdir" );
+ writer.addAttribute( "dir", outputDir );
+ writer.endElement(); // mkdir
+ }
+
+ writer.startElement( "copy" );
+ writer.addAttribute( "todir", outputDir );
+
+ writer.startElement( "fileset" );
+ writer.addAttribute( "dir", toRelative( basedir, resource.getDirectory() ) );
+
+ writeIncludesExcludes( writer, resource.getIncludes(), resource.getExcludes() );
+
+ writer.endElement(); // fileset
+
+ writer.endElement(); // copy
+ }
+ }
+ }
+
+ private static List removeEmptyCompileSourceRoots( List compileSourceRoots )
+ {
+ List newCompileSourceRootsList = new ArrayList();
+ if ( compileSourceRoots != null )
+ {
+ // copy as I may be modifying it
+ for ( Iterator i = compileSourceRoots.iterator(); i.hasNext(); )
+ {
+ String srcDir = (String) i.next();
+ if ( new File( srcDir ).exists() )
+ {
+ newCompileSourceRootsList.add( srcDir );
+ }
+ }
+ }
+ return newCompileSourceRootsList;
+ }
+
+ private static void writeIncludesExcludes( XMLWriter writer, List includes, List excludes )
+ {
+ for ( Iterator i = includes.iterator(); i.hasNext(); )
+ {
+ String include = (String) i.next();
+ writer.startElement( "include" );
+ writer.addAttribute( "name", include );
+ writer.endElement(); // include
+ }
+ for ( Iterator i = excludes.iterator(); i.hasNext(); )
+ {
+ String exclude = (String) i.next();
+ writer.startElement( "exclude" );
+ writer.addAttribute( "name", exclude );
+ writer.endElement(); // exclude
+ }
+ }
+
+ private void writeGetDepsTarget( XMLWriter writer )
+ {
+ writer.startElement( "target" );
+ writer.addAttribute( "name", "test-offline" );
+
+ writer.startElement( "condition" );
+ writer.addAttribute( "property", "maven.mode.offline" );
+ writer.startElement( "equals" );
+ writer.addAttribute( "arg1", "${build.sysclasspath}" );
+ writer.addAttribute( "arg2", "only" );
+ writer.endElement(); // equals
+ writer.endElement(); // condition
+
+ writer.endElement(); // target
+ writer.startElement( "target" );
+ writer.addAttribute( "name", "get-deps" );
+ writer.addAttribute( "depends", "test-offline" );
+ writer.addAttribute( "description", "Download all dependencies" );
+ writer.addAttribute( "unless", "maven.mode.offline" ); // TODO: check, and differs from m1
+
+ writer.startElement( "mkdir" );
+ writer.addAttribute( "dir", "${maven.repo.local}" );
+ writer.endElement(); // mkdir
+
+ // TODO: proxy - probably better to use wagon!
+
+ for ( Iterator i = project.getArtifacts().iterator(); i.hasNext(); )
+ {
+ Artifact artifact = (Artifact) i.next();
+
+ // TODO: should the artifacthandler be used instead?
+ String path = toRelative( localRepository, artifact.getFile().getPath() );
+
+ for ( Iterator j = project.getRepositories().iterator(); j.hasNext(); )
+ {
+ Repository repository = (Repository) j.next();
+
+ writer.startElement( "get" );
+ writer.addAttribute( "src", repository.getUrl() + "/" + path );
+ writer.addAttribute( "dest", "${maven.repo.local}/" + path );
+ writer.addAttribute( "usetimestamp", "true" );
+ writer.addAttribute( "ignoreerrors", "true" );
+ writer.endElement(); // get
+ }
+ }
+
+ writer.endElement(); // target
+ }
+
+ private void writeBuildPathDefinition( XMLWriter writer )
+ {
+ writer.startElement( "path" );
+ writer.addAttribute( "id", "build.classpath" );
+ writer.startElement( "fileset" );
+ writer.addAttribute( "dir", "${maven.repo.local}" );
+ for ( Iterator i = project.getArtifacts().iterator(); i.hasNext(); )
+ {
+ Artifact artifact = (Artifact) i.next();
+ writer.startElement( "include" );
+ writer.addAttribute( "name", toRelative( localRepository, artifact.getFile().getPath() ) );
+ writer.endElement(); // include
+ }
+ writer.endElement(); // fileset
+ writer.endElement(); // path
+ }
+
+ private void writeProperties( XMLWriter writer )
+ {
+ // TODO: optional in m1
+ // TODO: USD properties
+ writer.startElement( "property" );
+ writer.addAttribute( "file", "${user.home}/.m2/maven.properties" );
+ writer.endElement(); // property
+
+ writer.startElement( "property" );
+ writer.addAttribute( "name", "maven.build.output" );
+ writer.addAttribute( "value", toRelative( project.getBasedir(), project.getBuild().getOutputDirectory() ) );
+ writer.endElement(); // property
+
+ writer.startElement( "property" );
+ writer.addAttribute( "name", "maven.build.directory" );
+ writer.addAttribute( "value", toRelative( project.getBasedir(), project.getBuild().getDirectory() ) );
+ writer.endElement(); // property
+
+ writer.startElement( "property" );
+ writer.addAttribute( "name", "maven.build.final.name" );
+ writer.addAttribute( "value", project.getBuild().getFinalName() );
+ writer.endElement(); // property
+
+ // TODO: property?
+ writer.startElement( "property" );
+ writer.addAttribute( "name", "maven.test.reports" );
+ writer.addAttribute( "value", "${maven.build.directory}/test-reports" );
+ writer.endElement(); // property
+
+ writer.startElement( "property" );
+ writer.addAttribute( "name", "maven.test.output" );
+ writer.addAttribute( "value", toRelative( project.getBasedir(), project.getBuild().getTestOutputDirectory() ) );
+ writer.endElement(); // property
+
+ writer.startElement( "property" );
+ writer.addAttribute( "name", "maven.repo.local" );
+ writer.addAttribute( "value", "${user.home}/.m2/repository" );
+ writer.endElement(); // property
+
+/* TODO: offline setting
+ writer.startElement( "property" );
+ writer.addAttribute( "name", "maven.mode.offline" );
+ writer.addAttribute( "value", project.getBuild().getOutput() );
+ writer.endElement(); // property
+*/
+ }
+
+ private void close( Writer closeable )
+ {
+ if ( closeable == null )
+ {
+ return;
+ }
+
+ try
+ {
+ closeable.close();
+ }
+ catch ( Exception e )
+ {
+ // ignore
+ // TODO: warn
+ }
+ }
+
+ // TODO: move to plexus-utils or use something appropriate from there (eclipse plugin too)
+ private static String toRelative( File basedir, String absolutePath )
+ {
+ String relative;
+
+ absolutePath = absolutePath.replace( '\\', '/' );
+ String basedirPath = basedir.getAbsolutePath().replace( '\\', '/' );
+
+ if ( absolutePath.startsWith( basedirPath ) )
+ {
+ relative = absolutePath.substring( basedirPath.length() + 1 );
+ }
+ else
+ {
+ relative = absolutePath;
+ }
+
+ return relative;
+ }
+
+}
diff --git a/maven-plugins/maven-ant-plugin/src/main/java/org/apache/maven/plugin/ant/AntMojo.java b/maven-plugins/maven-ant-plugin/src/main/java/org/apache/maven/plugin/ant/AntMojo.java
new file mode 100644
index 0000000000..ad0318073c
--- /dev/null
+++ b/maven-plugins/maven-ant-plugin/src/main/java/org/apache/maven/plugin/ant/AntMojo.java
@@ -0,0 +1,67 @@
+package org.apache.maven.plugin.ant;
+
+/*
+ * Copyright 2001-2005 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.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+
+import java.io.File;
+
+/**
+ * A Maven2 plugin to generate an Ant build file.
+ * @author Brett Porter
+ * @version $Id$
+ * @goal ant
+ * @requiresDependencyResolution
+ * @todo change this to use the artifact ant tasks instead of :get
+ */
+public class AntMojo
+ extends AbstractMojo
+{
+ /**
+ * The project to create a build for.
+ * @parameter expression="${project}"
+ * @required
+ */
+ private MavenProject project;
+
+ /**
+ * The location of the local repository.
+ * @parameter expression="${localRepository}"
+ * @required
+ */
+ private ArtifactRepository localRepository;
+
+ public void execute()
+ throws MojoExecutionException
+ {
+ // TODO: read back previous
+
+ AntBuildWriter antBuildWriter = new AntBuildWriter( project, new File( localRepository.getBasedir() ) );
+
+ try
+ {
+ antBuildWriter.write();
+ }
+ catch ( AntPluginException e )
+ {
+ throw new MojoExecutionException( "Error building Ant script", e );
+ }
+ }
+}
diff --git a/maven-plugins/maven-ant-plugin/src/main/java/org/apache/maven/plugin/ant/AntPluginException.java b/maven-plugins/maven-ant-plugin/src/main/java/org/apache/maven/plugin/ant/AntPluginException.java
new file mode 100644
index 0000000000..d82381c283
--- /dev/null
+++ b/maven-plugins/maven-ant-plugin/src/main/java/org/apache/maven/plugin/ant/AntPluginException.java
@@ -0,0 +1,34 @@
+package org.apache.maven.plugin.ant;
+
+/*
+ * Copyright 2001-2005 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.
+ */
+
+/**
+ * @author Brett Porter
+ * @version $Id$
+ */
+public class AntPluginException extends Exception
+{
+ public AntPluginException( String msg )
+ {
+ super( msg );
+ }
+
+ public AntPluginException( String msg, Throwable cause )
+ {
+ super( msg, cause );
+ }
+}