Import sandbox antlibs
git-svn-id: https://svn.apache.org/repos/asf/ant/sandbox/antlibs/dotnet/trunk@161469 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/README b/README
new file mode 100644
index 0000000..70bc73d
--- /dev/null
+++ b/README
@@ -0,0 +1,38 @@
+dotnet sandbox README
+=====================
+
+Author:
+-------
+
+Stefan Bodewig, but feel free to go ahead and modify to your liking.
+
+Goal:
+-----
+
+Provide a simple infrastructure to execute .NET applications from
+within Ant for different VMs so that the user doesn't have to change
+the build file when she wants to run Mono on Linux and Microsoft's VM
+on Windows.
+
+This sounds far more ambitioned than it actually is.
+
+Short term goals are:
+
+* A <dotnetexec> task that can be used as
+
+ <dotnetexec executable="ExampleCsc.exe"/>
+
+ without testing for the environment (see the dotnet.xml build file
+ for Ant's tests as an example for what may become simpler with
+ this).
+
+* A <nant> task.
+
+* A <msbuild> task - if only for the fun of having it.
+
+* A <wix> task.
+
+* A <nunit> task.
+
+Those tasks should end up in an antlib of their own in order to be
+distributable independent of Ant.
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..6db1d04
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2003-2004 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.
+-->
+<project default="compile">
+
+ <target name="setup">
+ <property name="build" value="build"/>
+ <property name="build.classes" value="${build}/classes"/>
+ <property name="build.testclasses" value="${build}/test-classes"/>
+ <property name="build.lib" value="${build}/lib"/>
+ <property name="jarname" value="${build.lib}/dotnet.jar"/>
+ <mkdir dir="${build.classes}"/>
+ <mkdir dir="${build.testclasses}"/>
+ <mkdir dir="${build.lib}"/>
+ </target>
+
+ <target name="compile" depends="setup">
+ <javac
+ srcdir="src/main"
+ destdir="${build.classes}"
+ debug="true"
+ />
+ </target>
+
+ <target name="antlib" depends="compile">
+ <copy todir="${build.classes}">
+ <fileset dir="src/main" includes="**/antlib.xml"/>
+ </copy>
+ <jar
+ destfile="${jarname}"
+ basedir="${build.classes}"
+ />
+ </target>
+
+ <target name="setup-for-tests" depends="setup">
+ <ant
+ antfile="../../../build.xml"
+ target="test-jar"
+ inheritall="false"
+ />
+ </target>
+
+ <target name="compile-tests" depends="setup-for-tests, antlib">
+ <javac
+ srcdir="src/testcases"
+ destdir="${build.testclasses}"
+ debug="true"
+ >
+ <classpath>
+ <pathelement location="${jarname}"/>
+ <pathelement location="../../../build/lib/ant-testutil.jar"/>
+ </classpath>
+ </javac>
+ </target>
+
+ <target name="test" depends="compile-tests">
+ <junit
+ printsummary="false"
+ haltonfailure="false"
+ failureproperty="tests.failed"
+ filtertrace="false"
+ >
+ <classpath>
+ <pathelement location="${jarname}"/>
+ <pathelement location="../../../build/lib/ant-testutil.jar"/>
+ <pathelement location="${build.testclasses}"/>
+ </classpath>
+
+ <batchtest>
+ <fileset dir="src/testcases"/>
+ </batchtest>
+
+ <formatter type="plain" usefile="false"/>
+ </junit>
+
+ <fail if="tests.failed">At least one test has failed.</fail>
+ </target>
+</project>
\ No newline at end of file
diff --git a/docs/dotnetexec.html b/docs/dotnetexec.html
new file mode 100644
index 0000000..f66cd4a
--- /dev/null
+++ b/docs/dotnetexec.html
@@ -0,0 +1,32 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Language" content="en-us"></meta>
+ <title>DotNetExec Task</title>
+ </head>
+
+ <body>
+ <h2><a name="dotnetexec">DotNetExec</a></h2>
+
+ <h3>Description</h3>
+
+ <p>Executes a .NET assembly that's on your PATH or pointed to
+ directly by the executable attribute.</p>
+
+ <p>This task is an extension of Ant's <a
+ href="http://ant.apache.org/manual/CoreTasks/exec.html">exec</a>
+ task and supports all attributes and nested child elements of that
+ task. Use the executable attribute to specify the name of the
+ assembly (including the extension).</p>
+
+ <p>This task allows you to choose the .NET framework via the
+ <code>vm</code> attribute. The default value is "microsoft" on
+ Windows and "mono" on all other platforms. "microsoft" is a magic
+ name that means "run the assembly as executable directly" - this
+ may also work for Mono on Linux systems with the binfmt feature
+ described in the <a
+ href="http://www.go-mono.org/faq.html#q86">Mono FAQ</a>.</p>
+
+ <hr/>
+ <p align="center">Copyright © 2003-2004 The Apache Software Foundation. All rights Reserved.</p>
+ </body>
+</html>
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000..f5fcb91
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,142 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Language" content="en-us"></meta>
+ <title>Dotnet Ant Library</title>
+ </head>
+
+ <body>
+ <h2>Introduction</h2>
+
+ <p>This is a library of Ant tasks that support using .NET
+ executables accross different platforms and in particular support
+ using common .NET development tools like <a
+ href="http://nant.sourceforge.net/">NAnt</a> or <a
+ href="http://www.nunit.org/">NUnit</a> from within Ant.</p>
+
+ <h2>Requirements</h2>
+
+ <p>The current version requires Ant 1.6.2 or later and may even
+ work better for a CVS build of Ant created from CVS HEAD.</p>
+
+ <h2>Where is it?</h2>
+
+ <p>The source code for the library currently lives in the
+ developer sandbox in Ant's CVS - <a
+ href="http://cvs.apache.org/viewcvs.cgi/ant/proposal/sandbox/dotnet/">http://cvs.apache.org/viewcvs.cgi/ant/proposal/sandbox/dotnet/</a>.
+ A binary can be found at <a
+ href="http://cvs.apache.org/~bodewig/dotnet/dotnet.jar">http://cvs.apache.org/~bodewig/dotnet/dotnet.jar</a>.
+ A zip file containing the docs is also <a
+ href="http://cvs.apache.org/~bodewig/dotnet/docs.zip">available</a>.</p>
+
+ <p>Note that these are temporary locations and may change later.</p>
+
+ <h2>Feedback</h2>
+
+ <p>Right now direct any feedback either directly to <a
+ href="mailto:bodewig@apache.org">me</a> or the <a
+ href="http://ant.apache.org/mail.html#Developer List">Ant
+ developer list</a>.
+
+ <h2>Installation</h2>
+
+ <p>If you are building this from sources, run the antlib target
+ and you'll get a file <code>dotnet.jar</code>. If you've
+ downloaded <code>dotnet.jar</code>, you are already ready.</p>
+
+ <p>There are several ways to use the tasks:</p>
+
+ <ul>
+ <li>The traditional way:
+ <pre>
+ <taskdef
+ resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml">
+ <classpath>
+ <pathelement location="YOUR-PATH-TO/dotnet.jar"/>
+ </classpath>
+ </taskdef>
+ </pre>
+
+ With this you can use the tasks like plain Ant tasks, they'll
+ live in the default namespace. I.e. if you can run
+ <exec> without any namespace prefix, you can do so for
+ <dotnetexec> as well.
+ </li>
+
+ <li>Similar, but assigning a namespace URI
+ <pre>
+ <taskdef
+ uri="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml">
+ <classpath>
+ <pathelement location="YOUR-PATH-TO/dotnet.jar"/>
+ </classpath>
+ </taskdef>
+ </pre>
+
+ This puts you task into a separate namespace than Ant's
+ namespace. You would use the tasks like
+
+ <pre>
+ <project
+ xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ xmlns="antlib:org.apache.tools.ant">
+ ...
+ <dn:nant>
+ <dn:target name="my-target"/>
+ </dn:nant>
+ </pre>
+
+ or
+
+ <pre>
+ <nant xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet">
+ <target name="my-target"/>
+ </nant>
+ </pre>
+
+ or a variation thereof.
+ </li>
+
+ <li>Using Ant's autodiscovery. Place <code>dotnet.jar</code>
+ into a directory and use <code>ant -lib
+ DIR-CONTAINING-THE-JAR</code> or copy it into
+ <code>ANT_HOME/lib</code> - and then in your build file, simply
+ declare the namespace on the <code>project</code> tag:
+
+ <pre>
+ <project
+ xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ xmlns="antlib:org.apache.tools.ant">
+ </pre>
+
+ And all tasks of this library will automatically be available
+ in the <code>dn</code> namespace without any
+ <code>taskdef</code>.
+ </li>
+ </ul>
+
+ <h2>Tasks</h2>
+
+ <ul>
+ <li><a href="dotnetexec.html">dotnetexec</a> - run a .NET
+ assembly that's in your PATH. You can chose the framework that
+ is going to be used - defaults to Mono on non-Windows platforms
+ and Microsoft's on Windows.</li>
+
+ <li><a href="nant.html">nant</a> - execute the NAnt build
+ tool.</li>
+
+ <li><a href="msbuild.html">msbuild</a> - execute the MSBuild build
+ tool, untested.</li>
+
+ <li><a href="wix.html">wix</a> - execute the WiX toolset, untested.</li>
+
+ <li><a href="nunit.html">nunit</a> - execute the
+ nunit-console.exe <a href="http://www.nunit.org/">NUnit</a>
+ test runner.</li>
+ </ul>
+
+ <hr/>
+ <p align="center">Copyright © 2003-2004 The Apache Software Foundation. All rights Reserved.</p>
+ </body>
+</html>
diff --git a/docs/msbuild.html b/docs/msbuild.html
new file mode 100644
index 0000000..2ac93bc
--- /dev/null
+++ b/docs/msbuild.html
@@ -0,0 +1,109 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Language" content="en-us"></meta>
+ <title>MSBuild Task</title>
+ </head>
+
+ <body>
+ <h2><a name="dotnetexec">MSBuild</a></h2>
+
+ <h3>Description</h3>
+
+ <p>Runs the MSBuild build tool presented at the 2003 PDC. This
+ task is completely untested as the developers have no access to
+ the tool, it has been implemented by looking at the docs only.</p>
+
+ <p>You can either use an existing build file or nest a build file
+ (snippet) as a child into the task. If you don't specify either,
+ MSBuild's default build file search algorithm will apply.</p>
+
+ <h3>Parameters</h3>
+ <table border="1" cellpadding="2" cellspacing="0">
+ <tr>
+ <td valign="top"><b>Attribute</b></td>
+ <td valign="top"><b>Description</b></td>
+ <td align="center" valign="top"><b>Required</b></td>
+ </tr>
+ <tr>
+ <td valign="top">buildfile</td>
+ <td valign="top">External build file to invoke MSBuild on.</td>
+ <td align="center">No.</td>
+ </tr>
+ <tr>
+ <td valign="top">vm</td>
+ <td valign="top">Same as <a
+ href="dotnetexec.html">dotnetexec</a>'s vm attribute.
+ Specify the framework to use.</td>
+ <td align="center">No.</td>
+ </tr>
+ </table>
+
+ <h3>Parameters specified as nested elements</h3>
+ <h4>target</h4>
+
+ <p><code>target</code> has a single required attribute name -
+ specifies a target to be run.</p>
+
+ <h4>property</h4>
+
+ <p><code>property</code> has two required attributes. name and
+ value that specify name and value of a property that is to be
+ defined in the MSBuild invocation.</p>
+
+ <h4>build</h4>
+
+ <p>This element allows no attributes. You can nest a MSBuild build
+ file into it and MSBuild will be executed on that. You can also nest
+ a build file snippet instead and Ant will wrap the necessary MSBuild
+ <code><Project> around it.</code></p>
+
+ <h3>Examples</h3>
+
+ <p>Let MSBuild search for a *.proj file in the (Ant) project's base
+ directory and execute the default target in it:</p>
+
+ <pre><msbuild/></pre>
+
+ <p>Let MSBuild execute the targets named foo and bar in the build
+ file msbuild.proj in Ant's basedir and pass the property
+ <code>/property:test=testvalue</code> to it:</p>
+
+ <pre>
+ <msbuild buildfile="msbuild.proj">
+ <target name="foo"/>
+ <target name="bar"/>
+ <property name="test" value="testvalue"/>
+ </msbuild>
+ </pre>
+
+ <p>Define a build file embeded into the task, let MSBuild execute the
+ echo target of that build file.</p>
+
+ <pre>
+ <msbuild>
+ <target name="echo">
+ <build>
+ <Project DefaultTargets="empty">
+ <Target Name="empty"/>
+ <Target Name="echo">
+ <Task Name="Echo" Message="This is MSBuild"/>
+ </Target>
+ </Project>
+ </build>
+ </msbuild>
+ </pre>
+
+ <p>Run MSBuild's Echo task (if there actually is one):</p>
+
+ <pre>
+ <msbuild>
+ <build>
+ <Task Name="Echo" Message="This is MSBuild"/>
+ </build>
+ </msbuild>
+ </pre>
+
+ <hr/>
+ <p align="center">Copyright © 2003-2004 The Apache Software Foundation. All rights Reserved.</p>
+ </body>
+</html>
\ No newline at end of file
diff --git a/docs/nant.html b/docs/nant.html
new file mode 100644
index 0000000..07a92a2
--- /dev/null
+++ b/docs/nant.html
@@ -0,0 +1,108 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Language" content="en-us"></meta>
+ <title>NAnt Task</title>
+ </head>
+
+ <body>
+ <h2><a name="dotnetexec">NAnt</a></h2>
+
+ <h3>Description</h3>
+
+ <p>Runs the <a href="http://nant.sourceforge.net/">NAnt</a> build
+ tool.</p>
+
+ <p>You can either use an existing build file or nest a build file
+ (snippet) as a child into the task. If you don't specify either,
+ NAnt's default build file search algorithm will apply.</p>
+
+ <h3>Parameters</h3>
+ <table border="1" cellpadding="2" cellspacing="0">
+ <tr>
+ <td valign="top"><b>Attribute</b></td>
+ <td valign="top"><b>Description</b></td>
+ <td align="center" valign="top"><b>Required</b></td>
+ </tr>
+ <tr>
+ <td valign="top">buildfile</td>
+ <td valign="top">External build file to invoke NAnt on.</td>
+ <td align="center">No.</td>
+ </tr>
+ <tr>
+ <td valign="top">vm</td>
+ <td valign="top">Same as <a
+ href="dotnetexec.html">dotnetexec</a>'s vm attribute.
+ Specify the framework to use.</td>
+ <td align="center">No.</td>
+ </tr>
+ </table>
+
+ <h3>Parameters specified as nested elements</h3>
+ <h4>target</h4>
+
+ <p><code>target</code> has a single required attribute name -
+ specifies a target to be run.</p>
+
+ <h4>property</h4>
+
+ <p><code>property</code> has two required attributes. name and
+ value that specify name and value of a property that is to be
+ defined in the NAnt invocation.</p>
+
+ <h4>build</h4>
+
+ <p>This element allows no attributes. You can nest a NAnt build
+ file into it and NAnt will be executed on that. You can also nest
+ a build file snippet instead and Ant will wrap the necessary NAnt
+ <code><project> around it.</code></p>
+
+ <h3>Examples</h3>
+
+ <p>Let NAnt search for a *.build file in the (Ant) project's base
+ directory and execute the default target in it:</p>
+
+ <pre><nant/></pre>
+
+ <p>Let NAnt execute the targets named foo and bar in the build
+ file nant.build in Ant's basedir and pass the property
+ <code>-D:test=testvalue</code> to it:</p>
+
+ <pre>
+ <nant buildfile="nant.build">
+ <target name="foo"/>
+ <target name="bar"/>
+ <property name="test" value="testvalue"/>
+ </nant>
+ </pre>
+
+ <p>Define a build file embeded into the task, let NAnt execute the
+ echo target of that build file.</p>
+
+ <pre>
+ <nant>
+ <target name="echo">
+ <build>
+ <project basedir="." default="empty">
+ <target name="empty"/>
+ <target name="echo">
+ <echo message="this is NAnt"/>
+ </target>
+ </project>
+ </build>
+ </nant>
+ </pre>
+
+ <p>Run NAnt's echo task:</p>
+
+ <pre>
+ <nant>
+ <build>
+ <echo message="this is NAnt"/>
+ </build>
+ </nant>
+ </pre>
+
+ <hr/>
+ <p align="center">Copyright © 2003-2004 The Apache Software Foundation. All rights Reserved.</p>
+ </body>
+</html>
\ No newline at end of file
diff --git a/docs/nunit.html b/docs/nunit.html
new file mode 100644
index 0000000..e7ddd11
--- /dev/null
+++ b/docs/nunit.html
@@ -0,0 +1,177 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Language" content="en-us"></meta>
+ <title>NUnit Task</title>
+ </head>
+
+ <body>
+ <h2><a name="dotnetexec">NUnit</a></h2>
+
+ <h3>Description</h3>
+
+ <p>Runs the <a href="http://www.nunit.org/">NUnit</a> console
+ test runner.</p>
+
+ <h3>Parameters</h3>
+ <table border="1" cellpadding="2" cellspacing="0">
+ <tr>
+ <td valign="top"><b>Attribute</b></td>
+ <td valign="top"><b>Description</b></td>
+ <td align="center" valign="top"><b>Required</b></td>
+ </tr>
+ <tr>
+ <td valign="top">vm</td>
+ <td valign="top">Same as <a
+ href="dotnetexec.html">dotnetexec</a>'s vm attribute.
+ Specify the framework to use.</td>
+ <td align="center">No.</td>
+ </tr>
+ <tr>
+ <td valign="top">config</td>
+ <td valign="top">Config file to use</td>
+ <td align="center">No.</td>
+ </tr>
+ <tr>
+ <td valign="top">output</td>
+ <td valign="top">Where test output should go.</td>
+ <td align="center">No.</td>
+ </tr>
+ <tr>
+ <td valign="top">error</td>
+ <td valign="top">Where test error output should go.</td>
+ <td align="center">No.</td>
+ </tr>
+ <tr>
+ <td valign="top">xmlout</td>
+ <td valign="top">Where NUnit's XML output should go.</td>
+ <td align="center">No.</td>
+ </tr>
+ <tr>
+ <td valign="top">transform</td>
+ <td valign="top">The transformation to apply.</td>
+ <td align="center">No.</td>
+ </tr>
+ <tr>
+ <td valign="top">thread</td>
+ <td valign="top">Causes a separate thread to be created for
+ running the tests - see the NUnit documentation for
+ details.</td>
+ <td align="center">No - defaults to false.</td>
+ </tr>
+ <tr>
+ <td valign="top">noshadow</td>
+ <td valign="top">Disables shadow copying of the assembly in
+ order to provide improved performance..</td>
+ <td align="center">No - defaults to false.</td>
+ </tr>
+ <tr>
+ <td valign="top">fixture</td>
+ <td valign="top">Test fixture to run.</td>
+ <td align="center">No.</td>
+ </tr>
+ <tr>
+ <td valign="top">labels</td>
+ <td valign="top">Causes an identifying label to be displayed
+ at the start of each test case.</td>
+ <td align="center">No - defaults to false.</td>
+ </tr>
+ <tr>
+ <td valign="top">failOnError</td>
+ <td valign="top">Stops the build if NUnit returns with a code
+ indicating an error or failure.</td>
+ <td align="center">No - defaults to false.</td>
+ </tr>
+ </table>
+
+ <h3>Parameters specified as nested elements</h3>
+ <h4>testassembly</h4>
+
+ <p><code>testassembly</code> has a single required attribute name -
+ specifies an assembly or a project file holding tests.</p>
+
+ <h4>include/exclude</h4>
+
+ <p><code>in/exclude</code> have a single required attribute name -
+ specifies a category to include or exclude from the tests.</p>
+
+ <p><b>Note</b> that in current versions of NUnit (up to 2.2) you
+ may choose to either include or exclude categories in a run, but
+ not both. This task does <b>not</b> enforce this restriction
+ since future versions of NUnit may change behavior.</p>
+
+ <h4>redirector</h4>
+
+ <p>A nested <a
+ href="http://ant.apache.org/manual/CoreTypes/redirector.html">I/O
+ Redirector</a> can be specified. Any file mapping is done using a
+ <code>null</code> sourcefile; therefore not all <a
+ href="http://ant.apache.org/manual/CoreTypes/mapper.html">Mapper</a>
+ types will return results.</p>
+
+ <h4>env</h4> <p>It is possible to specify environment variables to
+ pass to the system command via nested <code><env></code>
+ elements. They support the same attributes as the nested <a
+ href="http://ant.apache.org/manual/CoreTasks/exec.html#env"><code>env</code>
+ element of the <code><exec></code> task</a>.</p>
+
+ <h3>Examples</h3>
+
+ <h4>Specify an assembly or project:</h4>
+
+ <pre>
+ <nunit>
+ <testassembly name="nunit.tests.dll"/>
+ </nunit>
+ </pre>
+
+ <p>or</p>
+
+ <pre>
+ <nunit>
+ <testassembly name="nunit.tests.csproj"/>
+ </nunit>
+ </pre>
+
+ <h4>Specifying an Assembly and a Fixture</h4>
+
+ <pre>
+ <nunit fixture="NUnit.Tests.AssertionTests">
+ <testassembly name="nunit.tests.dll"/>
+ </nunit>
+ </pre>
+
+ <h4>Specifying Test Categories to Include</h4>
+
+ <pre>
+ <nunit>
+ <testassembly name="nunit.tests.dll"/>
+ <include name="Baseline"/>
+ </nunit>
+ </pre>
+
+ <h4>Specifying the XML file name</h4>
+
+ <pre>
+ <nunit xmlout="console-test.xml">
+ <testassembly name="nunit.tests.dll"/>
+ </nunit>
+ </pre>
+
+ <p>changes the name of the output file to "console-test.xml" -
+ note that this task will resolve file names relative to the
+ project's base directory, not the current working directory.</p>
+
+ <h4>Specifying Multiple Assemblies</h4>
+
+ <pre>
+ <nunit>
+ <testassembly name="assembly1.dll"/>
+ <testassembly name="assembly2.dll"/>
+ <testassembly name="assembly3.dll"/>
+ </nunit>
+ </pre>
+
+ <hr/>
+ <p align="center">Copyright © 2004 The Apache Software Foundation. All rights Reserved.</p>
+ </body>
+</html>
\ No newline at end of file
diff --git a/docs/wix.html b/docs/wix.html
new file mode 100644
index 0000000..a79ff99
--- /dev/null
+++ b/docs/wix.html
@@ -0,0 +1,177 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Language" content="en-us"></meta>
+ <title>Wix Task</title>
+ </head>
+
+ <body>
+ <h2>Wix</h2>
+
+ <h3>Description</h3>
+
+ <p>Runs the candle, light or both from the <a
+ href="http://sourceforge.net/projects/wix">Wix</a> toolset.</p>
+
+ <h3>Parameters</h3>
+ <table border="1" cellpadding="2" cellspacing="0">
+ <tr>
+ <td valign="top"><b>Attribute</b></td>
+ <td valign="top"><b>Description</b></td>
+ <td align="center" valign="top"><b>Required</b></td>
+ </tr>
+ <tr>
+ <td valign="top">source</td>
+ <td valign="top">The single source file to process.</td>
+ <td align="center">Either this or at least one nested
+ <sources> set.</td>
+ </tr>
+ <tr>
+ <td valign="top">target</td>
+ <td valign="top">The expected target file.</td>
+ <td align="center">Yes, unless you run candle without light.</td>
+ </tr>
+ <tr>
+ <td valign="top">mode</td>
+ <td valign="top">Which part of the toolset to run, one of
+ "candle", "light" or
+ "both".</td>
+ <td align="center">No, default is "both".</td>
+ </tr>
+ <tr>
+ <td valign="top">vm</td>
+ <td valign="top">Same as <a
+ href="dotnetexec.html">dotnetexec</a>'s vm attribute.
+ Specify the framework to use.</td>
+ <td align="center">No.</td>
+ </tr>
+ </table>
+
+ <h3>Parameters specified as nested elements</h3>
+
+ <h4>sources</h4>
+
+ <p>Specify source files that shall be passed on the command line.
+ This is a <a
+ href="http://ant.apache.org/manual/CoreTypes/fileset.html">fileset</a>.</p>
+
+ <h4>moresources</h4>
+
+ <p>Specify source files that shall not be passed on the command
+ line. This is a <a
+ href="http://ant.apache.org/manual/CoreTypes/fileset.html">fileset</a>.</p>
+
+ <p>Typically this would list include files when running candle or
+ the files that vecome part of the MSI file when running light.
+ The files in this set are only used for timestamp comparisons. If
+ neither these files nor the given "normal" sources are
+ newer than the expected target, the task won't do anything.</p>
+
+
+ <h3>Examples</h3>
+
+ <p>Create <code>product.wixobj</code> from <code>product.wxs</code>:</p>
+
+ <pre>
+ <wix mode="candle" source="product.wxs"/>
+ </pre>
+
+ <p>The same but using a nested sources element:</p>
+
+ <pre>
+ <wix mode="candle">
+ <sources dir=".">
+ <include name="product.wxs"/>
+ </sources>
+ </wix>
+ </pre>
+
+ <p>Create <code>product.msi</code> from <code>product.wixobj</code>:</p>
+
+ <pre>
+ <wix mode="light" source="product.wixobj" target="product.msi"/>
+ </pre>
+
+ <p>Combine the examples into a single step:</p>
+
+ <pre>
+ <wix source="product.wxs" target="product.msi"/>
+ </pre>
+
+ <p>Note that the task wouldn't do anything if
+ <code>product.wxs</code> was older than
+ <code>product.wixobj</code> and <code>product.wixobj</code> was
+ older than <code>product.msi</code>.</p>
+
+ <p>Compile multiple <code>.wxs</code> files at once:</p>
+
+ <pre>
+ <wix mode="candle">
+ <sources dir=".">
+ <include name="*.wxs"/>
+ </sources>
+ </wix>
+ </pre>
+
+ <p>Compile multiple <code>.wxs</code> files at once, specify some
+ include files in addition to that:</p>
+
+ <pre>
+ <wix mode="candle">
+ <sources dir=".">
+ <include name="*.wxs"/>
+ </sources>
+ <moresources dir=".">
+ <include name="*.wxi"/>
+ </moresources>
+ </wix>
+ </pre>
+
+ <p>Link multiple <code>.wixobj</code> files at once:</p>
+
+ <pre>
+ <wix mode="light" target="product.msi">
+ <sources dir=".">
+ <include name="*.wixobj"/>
+ </sources>
+ </wix>
+ </pre>
+
+ <p>Link multiple <code>.wixobj</code> files at once and specify
+ that the files in directory "source" will become part of
+ the package:</p>
+
+ <pre>
+ <wix mode="light" target="product.msi">
+ <sources dir=".">
+ <include name="*.wixobj"/>
+ </sources>
+ <moresources dir="source"/>
+ </wix>
+ </pre>
+
+ <pre>Combine multiple <code>.wxs</code> files and include files
+ into a single package and specify that the package will contain
+ files from the source directory:</pre>
+
+ <pre>
+ <wix target="product.msi">
+ <sources dir=".">
+ <include name="*.wxs"/>
+ </sources>
+ <moresources dir=".">
+ <include name="*.wxi"/>
+ </moresources>
+ <moresources dir="source"/>
+ </wix>
+ </pre>
+
+ <p>Again, if the intermediate <code>.wixobj</code> files are newer
+ that the corresponding <code>.wxs</code> files (and all include
+ files) the candle step will be skipped. If
+ <code>product.msi</code> is newer than all files, the task won't
+ do anything.</p>
+
+ <hr/>
+ <p align="center">Copyright © 2004 The Apache Software Foundation. All rights Reserved.</p>
+ </body>
+</html>
\ No newline at end of file
diff --git a/src/etc/testcases/dotnetexec.xml b/src/etc/testcases/dotnetexec.xml
new file mode 100644
index 0000000..2aaef4b
--- /dev/null
+++ b/src/etc/testcases/dotnetexec.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2003-2004 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.
+-->
+
+<project name="dotnet" basedir="." default="testCSC"
+ xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet">
+
+ <property environment="env"/>
+ <property name="build.dir" location="build"/>
+ <property name="src.dir" location="src"/>
+
+ <property name="out.csc" location="${src.dir}/out.cs"/>
+ <property name="out.app" location="${build.dir}/out.exe"/>
+ <property name="out.type" value="exe"/>
+
+ <taskdef
+ uri="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml">
+ <classpath>
+ <pathelement location="../../../build/lib/dotnet.jar"/>
+ </classpath>
+ </taskdef>
+
+ <target name="probe_for_apps" >
+ <condition property="csc.found">
+ <or>
+ <available file="csc" filepath="${env.PATH}" />
+ <available file="csc.exe" filepath="${env.PATH}" />
+ <available file="csc.exe" filepath="${env.Path}" />
+ </or>
+ </condition>
+ <echo> csc.found=${csc.found}</echo>
+
+ <!-- Mono C# compiler -->
+ <condition property="mcs.found">
+ <available file="mcs" filepath="${env.PATH}" />
+ </condition>
+ <echo> mcs.found=${mcs.found}</echo>
+
+ <!-- any C# compiler -->
+ <condition property="c#.found">
+ <or>
+ <isset property="csc.found"/>
+ <isset property="mcs.found"/>
+ </or>
+ </condition>
+ </target>
+
+ <target name="init" depends="probe_for_apps">
+ <mkdir dir="${build.dir}"/>
+ <property name="testCSC.exe"
+ location="${build.dir}/ExampleCsc.exe" />
+ </target>
+
+ <target name="teardown">
+ <delete dir="${build.dir}"/>
+ </target>
+
+ <target name="validate_csc" depends="init">
+ <fail unless="c#.found">Needed C# compiler is missing</fail>
+ </target>
+
+ <target name="testCSC" depends="validate_csc">
+ <csc
+ destFile="${testCSC.exe}"
+ targetType="exe">
+ <src dir="${src.dir}" includes="ex*.cs"/>
+ </csc>
+ <available property="app.created" file="${testCSC.exe}"/>
+ <fail unless="app.created">No app ${testCSC.exe} created</fail>
+ <dn:dotnetexec executable="${testCSC.exe}" failonerror="true" />
+ <delete file="${testCSC.exe}"/>
+ </target>
+
+</project>
+
diff --git a/src/etc/testcases/msbuild.xml b/src/etc/testcases/msbuild.xml
new file mode 100644
index 0000000..dd1f136
--- /dev/null
+++ b/src/etc/testcases/msbuild.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2003-2004 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.
+-->
+<project name="msbuild" basedir="." default="echo"
+ xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet">
+
+ <taskdef
+ uri="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml">
+ <classpath>
+ <pathelement location="../../../build/lib/dotnet.jar"/>
+ </classpath>
+ </taskdef>
+
+ <property environment="env"/>
+ <condition property="msbuild.found">
+ <or>
+ <available file="MSBuild.exe" filepath="${env.PATH}"/>
+ <available file="MSBuild.exe" filepath="${env.Path}"/>
+ <available file="MSBuild.exe"/>
+ </or>
+ </condition>
+
+ <target name="echo">
+ <msbuild
+ buildfile="src/msbuild.proj"
+ xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ >
+ <target name="echo"/>
+ <property name="foo" value="bar"/>
+ </msbuild>
+ </target>
+
+ <target name="nested-file">
+ <property name="foo" value="bar"/>
+ <msbuild
+ xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ >
+ <build>
+ <Project DefaultTargets="echo">
+ <Target Name="echo">
+ <Task Name="Echo" Message="foo is ${foo}"/>
+ </Target>
+ </Project>
+ </build>
+ </msbuild>
+ </target>
+
+ <target name="nested-task">
+ <property name="foo" value="bar"/>
+ <msbuild
+ xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ >
+ <build>
+ <Task Name="Echo" Message="foo is ${foo}"/>
+ </build>
+ </msbuild>
+ </target>
+
+</project>
\ No newline at end of file
diff --git a/src/etc/testcases/nant.xml b/src/etc/testcases/nant.xml
new file mode 100644
index 0000000..172d0e7
--- /dev/null
+++ b/src/etc/testcases/nant.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2003-2004 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.
+-->
+<project name="nant" basedir="." default="echo"
+ xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet">
+
+ <taskdef
+ uri="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml">
+ <classpath>
+ <pathelement location="../../../build/lib/dotnet.jar"/>
+ </classpath>
+ </taskdef>
+
+ <property environment="env"/>
+ <condition property="nant.found">
+ <or>
+ <available file="NAnt.exe" filepath="${env.PATH}"/>
+ <available file="NAnt.exe" filepath="${env.Path}"/>
+ <available file="NAnt.exe"/>
+ </or>
+ </condition>
+
+ <target name="echo">
+ <nant
+ buildfile="src/nant.build"
+ xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ >
+ <target name="echo"/>
+ <property name="foo" value="bar"/>
+ </nant>
+ </target>
+
+ <target name="nested-file">
+ <property name="foo" value="bar"/>
+ <nant
+ xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ >
+ <build>
+ <project basedir="." default="echo">
+ <target name="echo">
+ <echo message="foo is ${foo}"/>
+ </target>
+ </project>
+ </build>
+ </nant>
+ </target>
+
+ <target name="nested-task">
+ <property name="foo" value="bar"/>
+ <nant
+ xmlns="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ >
+ <build>
+ <echo message="foo is ${foo}"/>
+ </build>
+ </nant>
+ </target>
+</project>
\ No newline at end of file
diff --git a/src/etc/testcases/nunit.xml b/src/etc/testcases/nunit.xml
new file mode 100644
index 0000000..ded9b58
--- /dev/null
+++ b/src/etc/testcases/nunit.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2004 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.
+-->
+<project name="nunit" basedir="." default="echo"
+ xmlns:dn="antlib:org.apache.tools.ant.taskdefs.optional.dotnet">
+
+ <property name="build.dir" value="build"/>
+ <property name="src.dir" location="src"/>
+
+ <taskdef
+ uri="antlib:org.apache.tools.ant.taskdefs.optional.dotnet"
+ resource="org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml">
+ <classpath>
+ <pathelement location="../../../build/lib/dotnet.jar"/>
+ </classpath>
+ </taskdef>
+
+ <property environment="env"/>
+ <condition property="nunit.found">
+ <or>
+ <available file="nunit-console.exe" filepath="${env.PATH}"/>
+ <available file="nunit-console.exe" filepath="${env.Path}"/>
+ <available file="nunit-console.exe"/>
+ </or>
+ </condition>
+
+ <target name="no-assembly">
+ <dn:nunit/>
+ </target>
+
+ <target name="compile-pass">
+ <mkdir dir="${build.dir}"/>
+ <csc destFile="${build.dir}/Pass.dll"
+ targetType="library" references="nunit.framework.dll">
+ <src dir="${src.dir}" includes="pass.cs"/>
+ </csc>
+ </target>
+
+ <target name="compile-fail">
+ <mkdir dir="${build.dir}"/>
+ <csc destFile="${build.dir}/Fail.dll"
+ targetType="library" references="nunit.framework.dll">
+ <src dir="${src.dir}" includes="fail.cs"/>
+ </csc>
+ </target>
+
+ <target name="passing-test" depends="compile-pass">
+ <dn:nunit>
+ <testassembly name="${build.dir}/Pass.dll"/>
+ </dn:nunit>
+ </target>
+
+ <target name="failing-test" depends="compile-fail">
+ <dn:nunit>
+ <testassembly name="${build.dir}/Fail.dll"/>
+ </dn:nunit>
+ </target>
+
+ <target name="failing-test-with-fail" depends="compile-fail">
+ <dn:nunit failonerror="true">
+ <testassembly name="${build.dir}/Fail.dll"/>
+ </dn:nunit>
+ </target>
+
+ <target name="teardown">
+ <delete dir="${build.dir}"/>
+ </target>
+</project>
\ No newline at end of file
diff --git a/src/etc/testcases/src/example.cs b/src/etc/testcases/src/example.cs
new file mode 100644
index 0000000..0616e33
--- /dev/null
+++ b/src/etc/testcases/src/example.cs
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2001-2004 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.
+ *
+ */
+
+using System;
+
+public class Example {
+
+ public static void Main(String[] args) {
+ Example2.echo();
+ }
+}
diff --git a/src/etc/testcases/src/example2.cs b/src/etc/testcases/src/example2.cs
new file mode 100644
index 0000000..f373ec0
--- /dev/null
+++ b/src/etc/testcases/src/example2.cs
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2001-2004 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.
+ *
+ */
+
+using System;
+
+/**
+ * this is just here to create confusion
+ */
+public class Example2 {
+
+ public int some_variable=3;
+
+ public static void echo() {
+ Console.WriteLine("hello, I look like Java, but I'm really .NET");
+ }
+
+}
diff --git a/src/etc/testcases/src/fail.cs b/src/etc/testcases/src/fail.cs
new file mode 100644
index 0000000..44c1205
--- /dev/null
+++ b/src/etc/testcases/src/fail.cs
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004 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.
+ *
+ */
+
+using System;
+using NUnit.Framework;
+
+[TestFixture]
+public class FailingTest
+{
+
+ [Test]
+ public void Fail()
+ {
+ Assert.IsTrue(false);
+ }
+}
diff --git a/src/etc/testcases/src/msbuild.proj b/src/etc/testcases/src/msbuild.proj
new file mode 100644
index 0000000..ded05af
--- /dev/null
+++ b/src/etc/testcases/src/msbuild.proj
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2003-2004 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.
+-->
+<Project DefaultTargets="empty">
+
+ <Target Name="empty"/>
+
+ <Target Name="echo">
+ <Task Name="Echo" Message="foo is ${foo}"/>
+ </Target>
+</Project>
diff --git a/src/etc/testcases/src/nant.build b/src/etc/testcases/src/nant.build
new file mode 100644
index 0000000..cf59b76
--- /dev/null
+++ b/src/etc/testcases/src/nant.build
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2003-2004 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.
+-->
+<project basedir="." default="empty">
+
+ <target name="empty"/>
+
+ <target name="echo">
+ <echo message="foo is ${foo}"/>
+ </target>
+</project>
diff --git a/src/etc/testcases/src/pass.cs b/src/etc/testcases/src/pass.cs
new file mode 100644
index 0000000..51fabf4
--- /dev/null
+++ b/src/etc/testcases/src/pass.cs
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004 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.
+ *
+ */
+
+using System;
+using NUnit.Framework;
+
+[TestFixture]
+public class PassingTest
+{
+
+ [Test]
+ public void Pass()
+ {
+ Assert.IsTrue(true);
+ }
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/AbstractBuildTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/AbstractBuildTask.java
new file mode 100644
index 0000000..3db5439
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/AbstractBuildTask.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2003-2004 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.
+ *
+ */
+
+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;
+
+/**
+ * Base class for NAntTask and MSBuildTask.
+ */
+public abstract class AbstractBuildTask extends Task {
+
+ /**
+ * The buildfile to invoke the build tool for.
+ */
+ private File buildFile;
+
+ /**
+ * The targets to execute.
+ */
+ private List targets = new ArrayList();
+
+ /**
+ * Properties to set.
+ */
+ private List properties = new ArrayList(1);
+
+ /**
+ * Nested build file fragment.
+ */
+ private XMLFragment buildSnippet;
+
+ /**
+ * The vm attribute - if given.
+ */
+ private String vm;
+
+ /**
+ * Empty constructor.
+ */
+ protected AbstractBuildTask() {
+ }
+
+ /**
+ * Sets the name of the build file.
+ */
+ public final void setBuildfile(File f) {
+ 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");
+ }
+ }
+
+ /**
+ * Set the name of the executable for the virtual machine.
+ *
+ * @param value the name of the executable for the virtual machine
+ */
+ public void setVm(String value) {
+ this.vm = value;
+ }
+
+ /**
+ * A target.
+ */
+ public static class Target {
+ private String name;
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ }
+
+ /**
+ * A target to execute.
+ */
+ public final void addTarget(Target t) {
+ targets.add(t);
+ }
+
+ /**
+ * A property.
+ */
+ // XXX, could have reused Property or Environment.Variable
+ // - not decided so far
+ public static class Property {
+ private String name;
+ private String value;
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+ }
+
+ /**
+ * A target to execute.
+ */
+ public final void addProperty(Property t) {
+ properties.add(t);
+ }
+
+ /**
+ * Must return the executable.
+ *
+ * @return must not return null
+ */
+ protected abstract String getExecutable();
+
+ /**
+ * Must return buildfile argument(s).
+ *
+ * @param buildFile the absolute File for the buildfile or null if
+ * the user didn't specify a buildfile.
+ *
+ * @return must not return null
+ */
+ protected abstract String[] getBuildfileArguments(File buildFile);
+
+ /**
+ * Must return target argument(s).
+ *
+ * @return must not return null
+ */
+ protected abstract String[] getTargetArguments(List targets);
+
+ /**
+ * Must return property argument(s).
+ *
+ * @return must not return null
+ */
+ protected abstract String[] getPropertyArguments(List properties);
+
+ /**
+ * Turn the DoucmentFragment into a DOM tree suitable as a build
+ * file when serialized.
+ *
+ * <p>Must throw a BuildException if the snippet can not be turned
+ * into a build file.</p>
+ */
+ 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 = DotNetExecTask.getTask(this, vm,
+ getExecutable(), null);
+ String[] args = getPropertyArguments(properties);
+ for (int i = 0; i < args.length; i++) {
+ exec.createArg().setValue(args[i]);
+ }
+ args = getTargetArguments(targets);
+ for (int i = 0; i < args.length; i++) {
+ exec.createArg().setValue(args[i]);
+ }
+
+ 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]);
+ }
+
+ 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/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTask.java
new file mode 100644
index 0000000..e546cfd
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTask.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2003-2004 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.
+ *
+ */
+
+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.taskdefs.ExecTask;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Environment;
+
+/**
+ * Specialized <exec> that knows how to deal with Mono vs. Microsoft's
+ * VM - and maybe Rotor at some point.
+ */
+public class DotNetExecTask extends ExecTask {
+
+ /**
+ * "Magic" VM argument for Microsoft's VM.
+ */
+ private static final String MS_VM = "microsoft";
+
+ /**
+ * The user supplied executable attribute.
+ */
+ private String executable;
+
+ /**
+ * The .NET VM to use.
+ *
+ * <p>Defaults to Microsoft's on Windows and mono on any other
+ * platform.</p>
+ */
+ private String vm = Os.isFamily("windows") ? MS_VM : "mono";
+
+ /**
+ * Empty Constructor.
+ */
+ public DotNetExecTask() {
+ super();
+ }
+
+ /**
+ * Set the name of the executable program.
+ * @param value the name of the executable program
+ */
+ public void setExecutable(String value) {
+ this.executable = value;
+ }
+
+ /**
+ * Set the name of the executable for the virtual machine or the
+ * magic name "microsoft" which implies that we can invoke the
+ * executable directly.
+ *
+ * @param value the name of the executable for the virtual machine
+ */
+ public void setVm(String value) {
+ this.vm = value;
+ }
+
+ /**
+ * Do the work.
+ *
+ * @throws BuildException if executable is empty or <exec>
+ * throws an exception.
+ */
+ public void execute() throws BuildException {
+ if (executable == null) {
+ throw new BuildException("The executable attribute is required");
+ }
+ setupCommandline();
+ super.execute();
+ }
+
+ /**
+ * If the inherited Commandline doesn't know about the executable
+ * yet, set it and deal with the vm attribute.
+ *
+ * <p>The inherited Commandline may know the executable already if
+ * this task instance is getting reused.</p>
+ */
+ protected void setupCommandline() {
+ if (cmdl.getExecutable() == null) {
+ if (vm.equals(MS_VM)) {
+ // can invoke executable directly
+ super.setExecutable(executable);
+ } else {
+ boolean b = getResolveExecutable();
+ // Mono wants the absolte path of the assembly
+ setResolveExecutable(b || isMono(vm));
+ super.setExecutable(vm);
+ cmdl.createArgument(true)
+ .setValue(resolveExecutable(executable, isMono(vm)));
+ setResolveExecutable(b);
+ }
+ }
+ }
+
+ /**
+ * Whether the given vm looks like the Mono executable.
+ */
+ protected final static boolean isMono(String vm) {
+ return "mono".equals(vm) || "mint".equals(vm);
+ }
+
+ /**
+ * Creates an instance of this task based on a different tasks settings.
+ */
+ public static DotNetExecTask getTask(Task t, String vm,
+ String executable,
+ Environment env) {
+ DotNetExecTask exec = new DotNetExecTask();
+ if (vm != null) {
+ exec.setVm(vm);
+ }
+ exec.setProject(t.getProject());
+ exec.setExecutable(executable);
+ exec.setTaskName(t.getTaskName());
+ if (env != null) {
+ String[] environment = env.getVariables();
+ if (environment != null) {
+ for (int i = 0; i < environment.length; i++) {
+ int idx = environment[i].indexOf("=");
+ Environment.Variable v = new Environment.Variable();
+ v.setKey(environment[i].substring(0, idx));
+ v.setValue(environment[i].substring(idx + 1));
+ exec.addEnv(v);
+ }
+ }
+ }
+
+ return exec;
+ }
+
+}
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTask.java
new file mode 100644
index 0000000..9fe31bc
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTask.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2003-2004 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.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import java.io.File;
+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();
+ }
+
+ protected String getExecutable() {
+ return "MSBuild.exe";
+ }
+
+ protected String[] getBuildfileArguments(File buildFile) {
+ if (buildFile != null) {
+ return new String[] {
+ buildFile.getAbsolutePath()
+ };
+ } else {
+ return new String[0];
+ }
+ }
+
+ protected String[] getTargetArguments(List targets) {
+ if (targets.size() > 0) {
+ StringBuffer sb = new StringBuffer("/targets:");
+ Iterator iter = targets.iterator();
+ boolean first = true;
+ while (iter.hasNext()) {
+ AbstractBuildTask.Target t =
+ (AbstractBuildTask.Target) iter.next();
+ if (!first) {
+ sb.append(";");
+ }
+ sb.append(t.getName());
+ }
+ return new String[]{sb.toString()};
+ } else {
+ return new String[0];
+ }
+ }
+
+ protected String[] getPropertyArguments(List properties) {
+ if (properties.size() > 0) {
+ StringBuffer sb = new StringBuffer("/property:");
+ Iterator iter = properties.iterator();
+ boolean first = true;
+ while (iter.hasNext()) {
+ AbstractBuildTask.Property p =
+ (AbstractBuildTask.Property) iter.next();
+ if (!first) {
+ sb.append(";");
+ }
+ sb.append(p.getName()).append("=").append(p.getValue());
+ }
+ return new String[]{sb.toString()};
+ } else {
+ return new String[0];
+ }
+ }
+
+ /**
+ * Turn the DocumentFragment into a DOM tree suitable as a build
+ * file when serialized.
+ *
+ * <p>If we have exactly one <Project> child, return that.
+ * Otherwise if we have only <Task> children, wrap them into a
+ * <Target> which in turn gets wrapped into a <Project>.
+ * Otherwise, fail.</p>
+ */
+ 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/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTask.java
new file mode 100644
index 0000000..274a6d8
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTask.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2003-2004 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.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import java.io.File;
+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.
+ */
+public class NAntTask extends AbstractBuildTask {
+
+ public NAntTask() {
+ super();
+ }
+
+ protected String getExecutable() {
+ return "NAnt.exe";
+ }
+
+ protected String[] getBuildfileArguments(File buildFile) {
+ if (buildFile != null) {
+ return new String[] {
+ "-buildfile:" + buildFile.getAbsolutePath()
+ };
+ } else {
+ return new String[0];
+ }
+ }
+
+ protected String[] getTargetArguments(List targets) {
+ ArrayList al = new ArrayList(targets.size());
+ Iterator iter = targets.iterator();
+ while (iter.hasNext()) {
+ AbstractBuildTask.Target t = (AbstractBuildTask.Target) iter.next();
+ al.add(t.getName());
+ }
+ return (String[]) al.toArray(new String[al.size()]);
+ }
+
+ protected String[] getPropertyArguments(List properties) {
+ ArrayList al = new ArrayList(properties.size());
+ Iterator iter = properties.iterator();
+ while (iter.hasNext()) {
+ AbstractBuildTask.Property p =
+ (AbstractBuildTask.Property) iter.next();
+ al.add("-D:" + p.getName() + "=" + p.getValue());
+ }
+ return (String[]) al.toArray(new String[al.size()]);
+ }
+
+ /**
+ * Turn the DocumentFragment into a DOM tree suitable as a build
+ * file when serialized.
+ *
+ * <p>If we have exactly one <project> child, return that.
+ * Otherwise assume that this is a valid build file snippet that
+ * just needs an empty project wrapped around it.</p>
+ */
+ 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/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTask.java
new file mode 100644
index 0000000..97cf395
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTask.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2004 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.
+ *
+ */
+
+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.types.Environment;
+import org.apache.tools.ant.types.RedirectorElement;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Task to run the NUnit Console test runner.
+ *
+ * @see http://www.nunit.org/
+ */
+public class NUnitTask extends Task {
+
+ /**
+ * The vm attribute - if given.
+ */
+ private String vm;
+
+ /**
+ * Test assemblies.
+ */
+ private ArrayList testAssemblies = new ArrayList();
+
+ /**
+ * The /config argument.
+ */
+ private File configFile;
+
+ /**
+ * The /output argument.
+ */
+ private File out;
+
+ /**
+ * The /err argument.
+ */
+ private File err;
+
+ /**
+ * The /xml argument.
+ */
+ private File xmlOut;
+
+ /**
+ * The /transform argument.
+ */
+ private File transform;
+
+ /**
+ * The /thread argument.
+ */
+ private boolean thread = false;
+
+ /**
+ * The /fixture argument.
+ */
+ private String fixture;
+
+ /**
+ * Categories to include.
+ */
+ private ArrayList includes = new ArrayList();
+
+ /**
+ * Categories to exclude.
+ */
+ private ArrayList excludes = new ArrayList();
+
+ /**
+ * The /noshadow argument.
+ */
+ private boolean noshadow = false;
+
+ /**
+ * The /labels argument.
+ */
+ private boolean labels = false;
+
+ /**
+ * Redirects everything that NUnit wants to send to the console.
+ */
+ private RedirectorElement redirectorElement;
+
+ /**
+ * Whether a failure should stop the build.
+ */
+ private boolean failOnError = false;
+
+ /**
+ * Support for nested environment variables.
+ */
+ private Environment env = new Environment();
+
+ public NUnitTask() {
+ super();
+ }
+
+ /**
+ * Set the name of the executable for the virtual machine.
+ *
+ * @param value the name of the executable for the virtual machine
+ */
+ public void setVm(String value) {
+ this.vm = value;
+ }
+
+ /**
+ * Sets the name of the config file.
+ */
+ public void setConfig(File c) {
+ configFile = c;
+ }
+
+ /**
+ * The /output argument.
+ */
+ public void setOut(File out) {
+ this.out = out;
+ }
+
+ /**
+ * The /err argument.
+ */
+ public void setError(File err) {
+ this.err = err;
+ }
+
+ /**
+ * The /xml argument.
+ */
+ public void setXmlOut(File out) {
+ this.xmlOut = out;
+ }
+
+ /**
+ * The /transform argument.
+ */
+ public void setTransform(File transform) {
+ this.transform = transform;
+ }
+
+ /**
+ * The /thread argument.
+ */
+ public void setThread(boolean thread) {
+ this.thread = thread;
+ }
+
+ /**
+ * The /fixture argument.
+ */
+ public void setFixture(String fixture) {
+ this.fixture = fixture;
+ }
+
+ /**
+ * The /noshadow argument.
+ */
+ public void setNoshadow(boolean noshadow) {
+ this.noshadow = noshadow;
+ }
+
+ /**
+ * The /labels argument.
+ */
+ public void setLabels(boolean labels) {
+ this.labels = labels;
+ }
+
+ /**
+ * Whether a failure should stop the build.
+ */
+ public void setFailOnError(boolean b) {
+ failOnError = b;
+ }
+
+ /**
+ * Adds a test assembly by name.
+ */
+ public void addTestAssembly(NamedElement a) {
+ testAssemblies.add(a);
+ }
+
+ /**
+ * Adds a category to the include list.
+ */
+ public void addInclude(NamedElement a) {
+ includes.add(a);
+ }
+
+ /**
+ * Adds a category to the exclude list.
+ */
+ public void addExclude(NamedElement a) {
+ excludes.add(a);
+ }
+
+ /**
+ * Add an environment variable to the launched process.
+ *
+ * @param var new environment variable
+ */
+ public void addEnv(Environment.Variable var) {
+ env.addVariable(var);
+ }
+
+ /**
+ * Add a <code>RedirectorElement</code> to this task.
+ *
+ * <p>This does not use the <code>out</code> and
+ * <code>error</code> attributes, it only captures NUnits output
+ * that has not been redirected by those attributes.</p>
+ */
+ public void addConfiguredRedirector(RedirectorElement redirectorElement) {
+ if (this.redirectorElement != null) {
+ throw new BuildException("cannot have > 1 nested <redirector>s");
+ } else {
+ this.redirectorElement = redirectorElement;
+ }
+ }
+
+ public void execute() {
+ if (testAssemblies.size() == 0) {
+ throw new BuildException("You must specify at least one test "
+ + "assembly.");
+ }
+
+ DotNetExecTask exec = DotNetExecTask.getTask(this, vm,
+ "nunit-console.exe",
+ env);
+ Iterator iter = testAssemblies.iterator();
+ while (iter.hasNext()) {
+ NamedElement a = (NamedElement) iter.next();
+ exec.createArg().setValue(a.getName());
+ }
+ if (configFile != null) {
+ exec.createArg().setValue("/config="
+ + configFile.getAbsolutePath());
+ }
+ exec.createArg().setValue("/nologo");
+
+ if (out != null) {
+ exec.createArg().setValue("/output=" + out.getAbsolutePath());
+ }
+ if (err != null) {
+ exec.createArg().setValue("/err=" + err.getAbsolutePath());
+ }
+ if (xmlOut != null) {
+ exec.createArg().setValue("/xml=" + xmlOut.getAbsolutePath());
+ }
+ if (transform != null) {
+ exec.createArg().setValue("/transform="
+ + transform.getAbsolutePath());
+ }
+
+ if (thread) {
+ exec.createArg().setValue("/thread");
+ }
+ if (noshadow) {
+ exec.createArg().setValue("/noshadow");
+ }
+ if (labels) {
+ exec.createArg().setValue("/labels");
+ }
+ if (fixture != null) {
+ exec.createArg().setValue("/fixture=" + fixture);
+ }
+
+ if (includes.size() > 0) {
+ StringBuffer sb = new StringBuffer("/include=");
+ iter = includes.iterator();
+ boolean first = false;
+ while (iter.hasNext()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(",");
+ }
+ NamedElement a = (NamedElement) iter.next();
+ sb.append(a.getName());
+ }
+ exec.createArg().setValue(sb.toString());
+ }
+ if (excludes.size() > 0) {
+ StringBuffer sb = new StringBuffer("/exclude=");
+ iter = excludes.iterator();
+ boolean first = false;
+ while (iter.hasNext()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(",");
+ }
+ NamedElement a = (NamedElement) iter.next();
+ sb.append(a.getName());
+ }
+ exec.createArg().setValue(sb.toString());
+ }
+
+ if (redirectorElement != null) {
+ exec.addConfiguredRedirector(redirectorElement);
+ }
+ exec.setFailonerror(failOnError);
+
+ exec.execute();
+ }
+
+ public static class NamedElement {
+ private String name;
+ public String getName() {return name;}
+ public void setName(String s) {name = s;}
+ }
+}
\ No newline at end of file
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/WixTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/WixTask.java
new file mode 100644
index 0000000..69a8feb
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/WixTask.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2004 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.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Task to run the WiX utility to create MSI files from an XML description.
+ *
+ * @see http://sf.net/projects/wix
+ */
+public class WixTask extends Task {
+
+ /**
+ * The vm attribute - if given.
+ */
+ private String vm;
+
+ /**
+ * The source files.
+ */
+ private ArrayList sources = new ArrayList();
+
+ /**
+ * Additional source files (include files in the case of candle,
+ * or media/files/whatever in the case of light).
+ */
+ private ArrayList moreSources = new ArrayList();
+
+ /**
+ * A single source file.
+ */
+ private File source;
+
+ /**
+ * The target file.
+ */
+ private File target;
+
+ /**
+ * What to do.
+ */
+ private Mode mode;
+
+ public WixTask() {
+ super();
+ }
+
+ /**
+ * Set the name of the executable for the virtual machine.
+ *
+ * @param value the name of the executable for the virtual machine
+ */
+ public void setVm(String value) {
+ this.vm = value;
+ }
+
+ /**
+ * The main source file.
+ *
+ * <p><code>candle</code> may include more files than this one,
+ * the main source is the one passed on the command line.</p>
+ *
+ * @param File object of the main source file.
+ */
+ public void setSource(File f) {
+ source = f;
+ }
+
+ /**
+ * A set of source files.
+ */
+ public void addSources(FileSet fs) {
+ sources.add(fs);
+ }
+
+ /**
+ * A set of additional source files (include files in the case of
+ * candle, or media/files/whatever in the case of light).
+ *
+ * <p>Unlike the files specified as sources, these will not be
+ * passed on the command line, they only help Ant to determine
+ * whether the target is out-of-date.</p>
+ */
+ public void addMoreSources(FileSet fs) {
+ moreSources.add(fs);
+ }
+
+ public void execute() {
+ if (source == null && sources.size() == 0) {
+ throw new BuildException("You must specify at least one source"
+ + " file.");
+ }
+ String m = Mode.BOTH;
+ if (mode != null) {
+ m = mode.getValue();
+ }
+
+ if (target == null && !m.equals(Mode.CANDLE)) {
+ throw new BuildException("You must specify the target if you want"
+ + " to run light.");
+ }
+
+ List lightSources = new ArrayList();
+ if (!m.equals(Mode.LIGHT)) {
+ doCandle(lightSources);
+ } else {
+ if (source != null) {
+ lightSources.add(source);
+ }
+ if (sources.size() > 0) {
+ lightSources.addAll(grabFiles(sources));
+ }
+ }
+ List moreLightSources = new ArrayList();
+ if (moreSources.size() > 0) {
+ moreLightSources = grabFiles(moreSources);
+ }
+ if (!m.equals(Mode.CANDLE)) {
+ doLight(lightSources, moreLightSources);
+ }
+ }
+
+ /**
+ * Invoke candle on all sources that are newer than their targets.
+ *
+ * @param lightSources list that will be filled with File objects
+ * pointing to the generated object files.
+ */
+ private void doCandle(List lightSources) {
+ List s = new ArrayList();
+ if (source != null) {
+ s.add(source);
+ }
+ if (sources != null) {
+ s.addAll(grabFiles(sources));
+ }
+ List ms = new ArrayList();
+ if (moreSources != null) {
+ ms.addAll(grabFiles(moreSources));
+ }
+ Iterator iter = s.iterator();
+ List toProcess = new ArrayList();
+ while (iter.hasNext()) {
+ File thisSource = (File) iter.next();
+ File t = target;
+ if (t == null) {
+ t = getTarget(thisSource);
+ }
+ if (isOutOfDate(t, thisSource, ms)) {
+ toProcess.add(thisSource);
+ lightSources.add(t);
+ }
+ }
+ if (toProcess.size() != 0) {
+ runCandle(toProcess);
+ }
+ }
+
+ /**
+ * Invoke light on all sources that are newer than their targets.
+ */
+ private void doLight(List lightSources, List moreLightSources) {
+ List tmp = new ArrayList(lightSources);
+ tmp.addAll(moreLightSources);
+ if (isOutOfDate(target, tmp)) {
+ runLight(lightSources);
+ }
+ }
+
+ /**
+ * Run candle passing all files in list on the command line.
+ */
+ private void runCandle(List s) {
+ run("candle.exe", s, null);
+ }
+
+ /**
+ * Run light passing all files in list on the command line.
+ */
+ private void runLight(List s) {
+ run("light.exe", s, target);
+ }
+
+ /**
+ * Runs the specified command passing list on the command line an
+ * potentially adding an /out parameter.
+ */
+ private void run(String executable, List s, File target) {
+ DotNetExecTask exec = DotNetExecTask.getTask(this, vm,
+ executable, null);
+ Iterator iter = s.iterator();
+ while (iter.hasNext()) {
+ File f = (File) iter.next();
+ exec.createArg().setValue(f.getAbsolutePath());
+ }
+ if (target != null) {
+ exec.createArg().setValue("/out");
+ exec.createArg().setValue(target.getAbsolutePath());
+ }
+
+ exec.execute();
+ }
+
+ /**
+ * Is t older than s or any of the files in list?
+ */
+ private boolean isOutOfDate(File t, File s, List l) {
+ return t.lastModified() < s.lastModified() || isOutOfDate(t, l);
+ }
+
+ /**
+ * Is t older than any of the files in list?
+ */
+ private boolean isOutOfDate(File t, List l) {
+ Iterator iter = l.iterator();
+ while (iter.hasNext()) {
+ File f = (File) iter.next();
+ if (t.lastModified() < f.lastModified()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Turn the fileset collection into a list of Files.
+ */
+ private List grabFiles(List s) {
+ List r = new ArrayList();
+ Iterator iter = s.iterator();
+ while (iter.hasNext()) {
+ FileSet fs = (FileSet) iter.next();
+ DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+ String[] f = ds.getIncludedFiles();
+ File base = fs.getDir(getProject());
+ for (int i = 0; i < f.length; i++) {
+ r.add(new File(base, f[i]));
+ }
+ }
+ return r;
+ }
+
+ /**
+ * Generates the name of a candle target from the source file.
+ *
+ * <p>Simply chops of the extension and adds .wixobj.</p>
+ */
+ private File getTarget(File s) {
+ String name = s.getAbsolutePath();
+ int dot = name.lastIndexOf(".");
+ if (dot > -1) {
+ return new File(name.substring(0, dot) + ".wixobj");
+ } else {
+ return new File(name + ".wixobj");
+ }
+ }
+
+ public static class Mode extends EnumeratedAttribute {
+ private final static String CANDLE = "candle";
+ private final static String LIGHT = "light";
+ private final static String BOTH = "both";
+
+ public Mode() {
+ super();
+ }
+
+ public String[] getValues() {
+ return new String[] {CANDLE, LIGHT, BOTH,};
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml
new file mode 100644
index 0000000..ee05e23
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/antlib.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2003-2004 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.
+-->
+<antlib>
+ <taskdef
+ name="dotnetexec"
+ classname="org.apache.tools.ant.taskdefs.optional.dotnet.DotNetExecTask"
+ />
+ <taskdef
+ name="msbuild"
+ classname="org.apache.tools.ant.taskdefs.optional.dotnet.MSBuildTask"
+ />
+ <taskdef
+ name="nant"
+ classname="org.apache.tools.ant.taskdefs.optional.dotnet.NAntTask"
+ />
+ <taskdef
+ name="wix"
+ classname="org.apache.tools.ant.taskdefs.optional.dotnet.WixTask"
+ />
+ <taskdef
+ name="nunit"
+ classname="org.apache.tools.ant.taskdefs.optional.dotnet.NUnitTask"
+ />
+</antlib>
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTaskTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTaskTest.java
new file mode 100644
index 0000000..665f9a1
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/DotNetExecTaskTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2003-2004 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.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the DotNetExecTask task, based off Ant's DotnetTest.
+ *
+ */
+public class DotNetExecTaskTest extends BuildFileTest {
+
+ /**
+ * Description of the Field
+ */
+ private final static String TASKDEFS_DIR = "src/etc/testcases/";
+
+
+ /**
+ * Constructor
+ *
+ * @param name testname
+ */
+ public DotNetExecTaskTest(String name) {
+ super(name);
+ }
+
+
+ /**
+ * The JUnit setup method
+ */
+ public void setUp() {
+ configureProject(TASKDEFS_DIR + "dotnetexec.xml");
+ }
+
+
+ /**
+ * The teardown method for JUnit
+ */
+ public void tearDown() {
+ executeTarget("teardown");
+ }
+
+
+ /**
+ * A unit test for JUnit
+ */
+ public void testCSC() throws Exception {
+ executeTarget("testCSC");
+ }
+}
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTaskTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTaskTest.java
new file mode 100644
index 0000000..40dab15
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/MSBuildTaskTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2003-2004 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.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the MSBuildTask task.
+ */
+public class MSBuildTaskTest extends BuildFileTest {
+
+ /**
+ * Description of the Field
+ */
+ private final static String TASKDEFS_DIR = "src/etc/testcases/";
+
+ /**
+ * Constructor
+ *
+ * @param name testname
+ */
+ public MSBuildTaskTest(String name) {
+ super(name);
+ }
+
+ /**
+ * The JUnit setup method
+ */
+ public void setUp() {
+ configureProject(TASKDEFS_DIR + "msbuild.xml");
+ }
+
+ public void testEcho() throws Exception {
+ if (getProject().getProperty("msbuild.found") != null) {
+ 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/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTaskTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTaskTest.java
new file mode 100644
index 0000000..edce890
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NAntTaskTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2003-2004 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.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the NAntTask task.
+ */
+public class NAntTaskTest extends BuildFileTest {
+
+ /**
+ * Description of the Field
+ */
+ private final static String TASKDEFS_DIR = "src/etc/testcases/";
+
+ /**
+ * Constructor
+ *
+ * @param name testname
+ */
+ public NAntTaskTest(String name) {
+ super(name);
+ }
+
+ /**
+ * The JUnit setup method
+ */
+ public void setUp() {
+ configureProject(TASKDEFS_DIR + "nant.xml");
+ }
+
+ public void testEcho() throws Exception {
+ if (getProject().getProperty("nant.found") != null) {
+ 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");
+ }
+ }
+}
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTaskTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTaskTest.java
new file mode 100644
index 0000000..3ccefb4
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/dotnet/NUnitTaskTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2004 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.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the NUnitTask task.
+ */
+public class NUnitTaskTest extends BuildFileTest {
+
+ /**
+ * Description of the Field
+ */
+ private final static String TASKDEFS_DIR = "src/etc/testcases/";
+
+ /**
+ * Constructor
+ *
+ * @param name testname
+ */
+ public NUnitTaskTest(String name) {
+ super(name);
+ }
+
+ /**
+ * The JUnit setup method
+ */
+ public void setUp() {
+ configureProject(TASKDEFS_DIR + "nunit.xml");
+ }
+
+ /**
+ * The teardown method for JUnit
+ */
+ public void tearDown() {
+ executeTarget("teardown");
+ }
+
+ public void testNoAssembly() {
+ expectSpecificBuildException("no-assembly", "no assembly",
+ "You must specify at least one test assembly.");
+ }
+
+ public void testPass() {
+ if (getProject().getProperty("nunit.found") != null) {
+ expectLogContaining("passing-test",
+ "Tests run: 1, Failures: 0, Not run: 0");
+ }
+ }
+
+ public void testFail() {
+ if (getProject().getProperty("nunit.found") != null) {
+ expectLogContaining("failing-test",
+ "Tests run: 1, Failures: 1, Not run: 0");
+ }
+ }
+
+ public void testFailOnFail() {
+ if (getProject().getProperty("nunit.found") != null) {
+ expectBuildException("failing-test-with-fail", "test should fail");
+ }
+ }
+
+}