diff --git a/proposal/sandbox/dotnet/src/etc/testcases/msbuild.xml b/proposal/sandbox/dotnet/src/etc/testcases/msbuild.xml index 08f92c753..914d17ab0 100644 --- a/proposal/sandbox/dotnet/src/etc/testcases/msbuild.xml +++ b/proposal/sandbox/dotnet/src/etc/testcases/msbuild.xml @@ -27,4 +27,31 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/proposal/sandbox/dotnet/src/etc/testcases/nant.xml b/proposal/sandbox/dotnet/src/etc/testcases/nant.xml index a0f4c775b..f659994f2 100644 --- a/proposal/sandbox/dotnet/src/etc/testcases/nant.xml +++ b/proposal/sandbox/dotnet/src/etc/testcases/nant.xml @@ -27,4 +27,30 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/AbstractBuildTask.java b/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/AbstractBuildTask.java index a3fa5d91a..d6ac81008 100644 --- a/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/AbstractBuildTask.java +++ b/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/AbstractBuildTask.java @@ -54,9 +54,18 @@ package org.apache.tools.ant.taskdefs.optional.dotnet; +import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; +import org.apache.tools.ant.util.DOMElementWriter; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.XMLFragment; + +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -80,6 +89,11 @@ public abstract class AbstractBuildTask extends Task { */ private List properties = new ArrayList(1); + /** + * Nested build file fragment. + */ + private XMLFragment buildSnippet; + /** * Empty constructor. */ @@ -93,6 +107,18 @@ public abstract class AbstractBuildTask extends Task { buildFile = f; } + /** + * Adds a build file fragment. + */ + public void addBuild(XMLFragment f) { + if (buildSnippet == null) { + buildSnippet = f; + } else { + throw new BuildException("You must not specify more than one " + + "build element"); + } + } + /** * A target. */ @@ -180,10 +206,25 @@ public abstract class AbstractBuildTask extends Task { */ protected abstract String[] getPropertyArguments(List properties); + /** + * Turn the DoucmentFragment into a DOM tree suitable as a build + * file when serialized. + * + *

Must throw a BuildException if the snippet can not be turned + * into a build file.

+ */ + protected abstract Element makeTree(DocumentFragment f); + /** * Perform the build. */ public void execute() { + if (buildFile != null && buildSnippet != null) { + throw new BuildException("You must not specify the build file" + + " attribute and a nested build at the" + + " same time"); + } + DotNetExecTask exec = new DotNetExecTask(); exec.setProject(getProject()); exec.setExecutable(getExecutable()); @@ -196,10 +237,48 @@ public abstract class AbstractBuildTask extends Task { for (int i = 0; i < args.length; i++) { exec.createArg().setValue(args[i]); } - args = getBuildfileArguments(buildFile); + + File generatedFile = null; + if (buildSnippet != null) { + try { + generatedFile = getBuildFile(); + } catch (IOException e) { + throw new BuildException(e); + } + args = getBuildfileArguments(generatedFile); + } else { + args = getBuildfileArguments(buildFile); + } + for (int i = 0; i < args.length; i++) { exec.createArg().setValue(args[i]); } - exec.execute(); + + try { + exec.execute(); + } finally { + if (generatedFile != null) { + generatedFile.delete(); + } + } + } + + private File getBuildFile() throws IOException { + File f = null; + if (buildSnippet != null) { + Element e = makeTree(buildSnippet.getFragment()); + f = FileUtils.newFileUtils().createTempFile("build", ".xml", null); + f.deleteOnExit(); + FileOutputStream out = null; + try { + out = new FileOutputStream(f); + (new DOMElementWriter()).write(e, out); + } finally { + if (out != null) { + out.close(); + } + } + } + return f; } } diff --git a/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTask.java b/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTask.java index f830ec2d1..c87fd1c5e 100644 --- a/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTask.java +++ b/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTask.java @@ -59,11 +59,18 @@ import java.util.Iterator; import java.util.ArrayList; import java.util.List; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + /** * Runs a MSBuild build process. */ public class MSBuildTask extends AbstractBuildTask { + private static final String TARGET = "generated-by-ant"; + public MSBuildTask() { super(); } @@ -119,4 +126,32 @@ public class MSBuildTask extends AbstractBuildTask { return new String[0]; } } + + /** + * Turn the DocumentFragment into a DOM tree suitable as a build + * file when serialized. + * + *

If we have exactly one child, return that. + * Otherwise if we have only children, wrap them into a + * which in turn gets wrapped into a . + * Otherwise, fail.

+ */ + protected Element makeTree(DocumentFragment f) { + NodeList nl = f.getChildNodes(); + if (nl.getLength() == 1 + && nl.item(0).getNodeType() == Node.ELEMENT_NODE + && nl.item(0).getNodeName().equals("Project")) { + return (Element) nl.item(0); + } else { + Element p = f.getOwnerDocument().createElement("Project"); + p.setAttribute("DefaultTargets", TARGET); + + Element t = f.getOwnerDocument().createElement("Target"); + t.setAttribute("Name", TARGET); + + p.appendChild(t); + t.appendChild(f); + return p; + } + } } diff --git a/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTask.java b/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTask.java index bd228e9fa..95ae7c93a 100644 --- a/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTask.java +++ b/proposal/sandbox/dotnet/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTask.java @@ -59,6 +59,11 @@ import java.util.Iterator; import java.util.ArrayList; import java.util.List; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + /** * Runs a NAnt build process. */ @@ -102,4 +107,25 @@ public class NAntTask extends AbstractBuildTask { } return (String[]) al.toArray(new String[al.size()]); } + + /** + * Turn the DocumentFragment into a DOM tree suitable as a build + * file when serialized. + * + *

If we have exactly one child, return that. + * Otherwise assume that this is a valid build file snippet that + * just needs an empty project wrapped around it.

+ */ + protected Element makeTree(DocumentFragment f) { + NodeList nl = f.getChildNodes(); + if (nl.getLength() == 1 + && nl.item(0).getNodeType() == Node.ELEMENT_NODE + && nl.item(0).getNodeName().equals("project")) { + return (Element) nl.item(0); + } else { + Element e = f.getOwnerDocument().createElement("project"); + e.appendChild(f); + return e; + } + } } diff --git a/proposal/sandbox/dotnet/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTaskTest.java b/proposal/sandbox/dotnet/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTaskTest.java index 65bc3cb35..efe7797cc 100644 --- a/proposal/sandbox/dotnet/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTaskTest.java +++ b/proposal/sandbox/dotnet/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTaskTest.java @@ -86,4 +86,16 @@ public class MSBuildTaskTest extends BuildFileTest { expectLogContaining("echo", "foo is bar"); } } + + public void testNestedFile() throws Exception { + if (getProject().getProperty("msbuild.found") != null) { + expectLogContaining("nested-file", "foo is bar"); + } + } + + public void testNestedTask() throws Exception { + if (getProject().getProperty("msbuild.found") != null) { + expectLogContaining("nested-task", "foo is bar"); + } + } } diff --git a/proposal/sandbox/dotnet/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTaskTest.java b/proposal/sandbox/dotnet/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTaskTest.java index 95d505234..e2f8cd442 100644 --- a/proposal/sandbox/dotnet/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTaskTest.java +++ b/proposal/sandbox/dotnet/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTaskTest.java @@ -86,4 +86,16 @@ public class NAntTaskTest extends BuildFileTest { expectLogContaining("echo", "foo is bar"); } } + + public void testNestedFile() throws Exception { + if (getProject().getProperty("nant.found") != null) { + expectLogContaining("nested-file", "foo is bar"); + } + } + + public void testNestedTask() throws Exception { + if (getProject().getProperty("nant.found") != null) { + expectLogContaining("nested-task", "foo is bar"); + } + } }