[gant] 39/51: Imported Upstream version 1.9.11

Emmanuel Bourg ebourg-guest at moszumanska.debian.org
Fri Jul 31 12:07:12 UTC 2015


This is an automated email from the git hooks/post-receive script.

ebourg-guest pushed a commit to branch master
in repository gant.

commit a2e08f9e0a8cac09888da60ee935998926a5a46c
Author: Emmanuel Bourg <ebourg at apache.org>
Date:   Fri Jul 31 12:20:51 2015 +0200

    Imported Upstream version 1.9.11
---
 .gitignore                                         |  19 +
 LICENCE.txt                                        | 201 ++++++
 README.md                                          |  98 +++
 README_Install.txt                                 | 110 ++++
 artwork/logo.svg                                   | 113 ++++
 build.gradle                                       | 694 +++++++++++++++++++++
 ciBuild                                            |   6 +
 documentation/gant.1                               |  72 +++
 examples/ivy/build.gant                            |  46 ++
 examples/ivy/build.xml                             |  58 ++
 examples/ivy/source/example/Hello.java             |  27 +
 examples/testScripts/explicitClean.gant            |  34 +
 examples/testScripts/gantClean.gant                |  32 +
 issues.txt                                         |  56 ++
 overview.html                                      |  60 ++
 packaging/AntDebTask/ant_deb_task.properties       |   2 +
 packaging/AntDebTask/build.gant                    | 138 ++++
 packaging/AntDebTask/gant                          |  33 +
 packaging/AntDebTask/postinst                      |   4 +
 packaging/AntDebTask/prerm                         |   3 +
 releaseNotes.txt                                   | 590 ++++++++++++++++++
 scripts/bash_completion.d/gant                     |  77 +++
 scripts/bin/startGroovy.bat                        | 258 ++++++++
 scripts/bin_requiresGroovy/gant                    | 119 ++++
 scripts/bin_requiresGroovy/gant.bat                |  71 +++
 scripts/bin_standalone/gant                        | 111 ++++
 scripts/bin_standalone/gant.bat                    |  63 ++
 scripts/bin_standalone/startGroovy                 | 281 +++++++++
 scripts/bnd/groovy.bnd                             |   4 +
 scripts/conf/gant-starter.conf                     |  44 ++
 settings.gradle                                    |  17 +
 .../org/codehaus/gant/ant/tests/GANT_80.gant       |  19 +
 .../groovy/org/codehaus/gant/ant/tests/GANT_80.xml |  29 +
 .../org/codehaus/gant/ant/tests/Gant_Test.java     | 414 ++++++++++++
 .../org/codehaus/gant/ant/tests/basedir.gant       |  19 +
 .../groovy/org/codehaus/gant/ant/tests/basedir.xml |  55 ++
 .../groovy/org/codehaus/gant/ant/tests/build.gant  |  69 ++
 .../org/codehaus/gant/ant/tests/build.properties   |   1 +
 .../org/codehaus/gant/ant/tests/commonBits.xml     |  37 ++
 .../org/codehaus/gant/ant/tests/gantTest.xml       |  80 +++
 .../gant/ant/tests/testErrorCodeReturns.xml        |  33 +
 src/main/groovy/gant/Gant.groovy                   | 677 ++++++++++++++++++++
 src/main/groovy/gant/GantException.java            |  35 ++
 src/main/groovy/gant/MissingTargetException.java   |  28 +
 src/main/groovy/gant/TargetExecutionException.java |  28 +
 .../gant/TargetMissingPropertyException.java       |  30 +
 src/main/groovy/gant/package.html                  |  17 +
 src/main/groovy/gant/targets/Clean.groovy          |  74 +++
 src/main/groovy/gant/targets/Maven.groovy          | 442 +++++++++++++
 src/main/groovy/gant/targets/package.html          |  21 +
 src/main/groovy/gant/tools/AntFile.groovy          |  76 +++
 src/main/groovy/gant/tools/Execute.groovy          | 114 ++++
 src/main/groovy/gant/tools/Ivy.groovy              |  60 ++
 src/main/groovy/gant/tools/LaTeX.groovy            | 205 ++++++
 src/main/groovy/gant/tools/Subdirectories.groovy   |  76 +++
 src/main/groovy/gant/tools/package.html            |  21 +
 .../org/codehaus/gant/AbstractInclude.groovy       | 172 +++++
 .../groovy/org/codehaus/gant/GantBinding.groovy    | 306 +++++++++
 src/main/groovy/org/codehaus/gant/GantBuilder.java | 111 ++++
 src/main/groovy/org/codehaus/gant/GantEvent.groovy |  45 ++
 .../groovy/org/codehaus/gant/GantMetaClass.java    | 209 +++++++
 src/main/groovy/org/codehaus/gant/GantState.java   |  83 +++
 .../groovy/org/codehaus/gant/IncludeTargets.groovy |  91 +++
 .../groovy/org/codehaus/gant/IncludeTool.groovy    | 122 ++++
 src/main/groovy/org/codehaus/gant/ant/Gant.java    | 214 +++++++
 src/main/groovy/org/codehaus/gant/ant/package.html |  16 +
 src/main/groovy/org/codehaus/gant/package.html     |  16 +
 src/site/site.xml                                  |  55 ++
 .../groovy/gant/targets/tests/Clean_Test.groovy    | 117 ++++
 .../groovy/gant/targets/tests/Maven_Test.groovy    | 165 +++++
 .../groovy/gant/tools/tests/AntFile_Test.groovy    | 109 ++++
 .../groovy/gant/tools/tests/Execute_Test.groovy    |  82 +++
 src/test/groovy/gant/tools/tests/LaTeX_Test.groovy | 147 +++++
 .../org/codehaus/gant/ant/tests/Gant_Test.java     | 120 ++++
 .../groovy/org/codehaus/gant/ant/tests/build.gant  |  81 +++
 .../org/codehaus/gant/ant/tests/build.properties   |   1 +
 .../org/codehaus/gant/ant/tests/commonBits.xml     |  37 ++
 .../org/codehaus/gant/ant/tests/gantTest.xml       |  80 +++
 .../codehaus/gant/tests/BuildListener_Test.groovy  |  72 +++
 .../org/codehaus/gant/tests/CallPrint_Test.groovy  |  45 ++
 .../codehaus/gant/tests/CommentAccess_Test.groovy  |  39 ++
 .../gant/tests/CustomClassLoader_Test.groovy       |  46 ++
 .../org/codehaus/gant/tests/Depends_Test.groovy    | 254 ++++++++
 .../org/codehaus/gant/tests/DryRun_Test.groovy     |  53 ++
 .../gant/tests/ExecutingTargets_Test.groovy        | 133 ++++
 .../codehaus/gant/tests/GantBinding_Test.groovy    | 313 ++++++++++
 .../codehaus/gant/tests/GantBuilder_Test.groovy    |  53 ++
 .../org/codehaus/gant/tests/GantTestCase.java      | 182 ++++++
 .../org/codehaus/gant/tests/Hooks_Test.groovy      | 219 +++++++
 .../org/codehaus/gant/tests/Include_Test.groovy    | 591 ++++++++++++++++++
 .../codehaus/gant/tests/ListingTargets_Test.groovy | 266 ++++++++
 .../codehaus/gant/tests/NoAntObject_Test.groovy    | 103 +++
 .../org/codehaus/gant/tests/Options_Test.groovy    |  53 ++
 .../codehaus/gant/tests/ReturnValue_Test.groovy    |  70 +++
 .../org/codehaus/gant/tests/SubGant_Test.groovy    |  81 +++
 .../gant/tests/TargetMetaClassLookup_Test.groovy   |  64 ++
 .../org/codehaus/gant/tests/Targets_Test.groovy    | 243 ++++++++
 .../gant/tests/ToolMetaClassLookup_Test.groovy     |  61 ++
 .../codehaus/gant/tests/XMLProcessing_Test.groovy  |  57 ++
 .../codehaus/gant/tests/bugs/Assorted_Test.groovy  | 206 ++++++
 .../codehaus/gant/tests/bugs/GANT_108_Test.groovy  |  99 +++
 .../codehaus/gant/tests/bugs/GANT_33_Test.groovy   | 118 ++++
 .../codehaus/gant/tests/bugs/GANT_4_Test.groovy    |  90 +++
 .../gant/tests/bugs/Regression_1_9_4_Test.groovy   |  80 +++
 .../bugs/subPackage/GANT_29_SampleTool.groovy      |  24 +
 105 files changed, 12095 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..768d7f0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,19 @@
+*~
+/artwork/*.png
+/bin/
+/out/
+.gradle
+/build/
+/gant/
+/gant_groovy*/
+/packaging/AntDebTask/debs
+texput.log
+nbbuild.xml
+/nbproject/
+Gant.iws
+Gant.iml
+Gant.ipr
+/.idea/
+.classpath
+.project
+/.settings/
diff --git a/LICENCE.txt b/LICENCE.txt
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENCE.txt
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5ec062d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,98 @@
+# Introduction
+
+Gant is a lightweight dependency programming framework for Groovy and Java systems.
+
+Gant was originally created as a build framework: [Groovy](http://groovy.codehaus.org) has AntBuilder and
+Gant was a framework built around it, created so as to be able to avoid using XML with Ant. Groovy makes a
+much better build specification language than XML; Gant gives access to all the Ant tasks using Groovy. So
+successful was this model that Gant was forked to create the official Groovy Front-End to Ant that is now an
+Ant standard feature.
+
+Experimentation with Gant showed though that the computational model at the heart of Gant was not going to
+allow for a fully fledged build framework.  Thus was [Gradle](http://www.gradle.org) born.  Gradle is now
+the standard Groovy-based build framework.  Even Gant, which originally used Gant for its build, now uses
+Gradle for its build.
+
+Gant is an integral part of the [Grails](http://www.grails.org) Web application framework.
+
+Gant is the basis for the [GINT](https://studio.plugins.atlassian.com/wiki/display/GINT/Home) integration
+testing framework.
+
+# Overview
+
+Gant is a tool for scripting Ant tasks using Groovy instead of XML to specify the logic. A Gant
+specification is a Groovy script and so can bring all the power of Groovy to bear directly, something not
+possible with Ant scripts. Whilst it might be seen as a competitor to Ant, Gant uses Ant tasks for many of
+the actions, so Gant is really an alternative way of doing things using Ant, but using a programming
+language rather than XML to specify the rules.
+
+Here is an example Gant script:
+
+    includeTargets << gant.targets.Clean
+    cleanPattern << [ '**/*~' ,  '**/*.bak' ]
+    cleanDirectory << 'build'
+
+    target ( stuff : 'A target to do some stuff.' ) {
+      println ( 'Stuff' )
+      depends ( clean )
+      echo ( message : 'A default message from Ant.' )
+      otherStuff ( )
+    }
+
+    target ( otherStuff : 'A target to do some other stuff' ) {
+      println ( 'OtherStuff' )
+      echo ( message : 'Another message from Ant.' )
+      clean ( )
+    }
+
+    setDefaultTarget ( stuff )
+    
+In this script there are two targets, `stuff` and `otherStuff` -- the default target for this build is
+designated as stuff and is the target run when Gant is executed from the command line with no target as
+parameter.
+
+Targets are closures so they can be called as functions, in which case they are executed as you expect, or
+they can be dependencies to other targets by being parameters to the depends function, in which case they
+are executed if an only if they have not been executed already in this run. (There is a page with some more
+information on Targets.)
+
+You may be wondering about the stuff at the beginning of the script. Gant has two ways of using pre-built
+sub-scripts, either textual inclusion of another Gant script or the inclusion of a pre-compiled class. The
+example here shows the latter -- the class `gant.targets.Clean` is a class that provides simple clean
+capabilities.
+
+The default name for the Gant script is build.gant, in the same way that the default for an Ant script in
+build.xml.
+
+Gant provides a way of finding what the documented targets are:
+
+> |> gant -p  
+> clean       Action the cleaning.  
+> clobber     Action the clobbering.  Do the cleaning first.  
+> otherStuff  A target to do some other stuff.  
+> stuff       A target to do some stuff.  
+>  
+> Default target is stuff.  
+> |>  
+
+The messages on this output are exactly the strings associated with the target name in the introduction to the target.
+
+# The Source
+
+The Gant mainline source is in a [Git repository](https://github.com/Gant/Gant) held on GitHub. Feel free to
+fork, amend and send in pull requests. The master branch is currently both the 1.9.x series maintenance
+branch and the development branch. All development should though happen on feature branches until accepted
+and merged into master..
+
+The Git repository held at Codehaus is an administrative mirror and shouldn't really be the repository to
+fork in order to work on Gant development.
+
+# Support
+
+Although GitHub is used for the Gant source, [Codehaus](http://www.codehaus.org) is used for the
+[website](http://gant.codehaus.org), wiki, [issue tracker](http://jira.codehaus.org/browse/GANT) and
+[continuous integration](http://bamboo.ci.codehaus.org/browse/GANT).
+
+# Licence
+
+Gant is licenced under ASL 2.0.
diff --git a/README_Install.txt b/README_Install.txt
new file mode 100644
index 0000000..5f6cc4a
--- /dev/null
+++ b/README_Install.txt
@@ -0,0 +1,110 @@
+Gant -- A Groovy way of scripting Ant tasks.
+
+
+This is Gant, a Groovy way of working with Ant tasks -- no more XML :-)
+
+The method of installation depends on whether you have downloaded a tarball or
+zipfile distribution, or you have a Git clone -- or even a Bazaar branch -- of
+the source.
+
+
+Distribution
+------------
+
+The Gant distributions contain a ready-made install directory hierarchy.
+Untar the tarball or unzip the zipfile to the location where you want the Gant
+installation to reside. A directory with the name structured
+gant-<gant-version-number> will be created in the location specified for the
+untar or unzip.
+
+There are a number of distinct distributions:
+
+          1. Requires a separate Groovy installation. There are builds:
+                a. compiled against Groovy 1.7.10; and
+                b. compiled against Groovy 1.8.6; and
+                c. compiled against Groovy 2.0.0-beta-2
+
+          2. Self-contained, includes all dependent jars.
+
+You might like to set up an environment variable GANT_HOME set to the
+directory created by the untar or unzip, though this is not essential, it is
+just an efficiency.
+
+The script $GANT_HOME/bin/gant for systems with a Posix shell, or
+$GANT_HOME/bin/gant.bat on Windows is the mechanism for launching a Gant run.
+
+Distributions 1a, 1b and 1c only include the direct Gant materials. The Maven
+target set depends on use of the Maven Ant tasks, and the Ivy tool depends on
+the Ivy jar, these will have to be downloaded and installed into
+$GANT_HOME/lib unless they are already available on on your CLASSPATH.
+
+
+Using a Git Clone
+-----------------
+
+Gant's mainline is a Git repository on GitHub, see
+
+       https://github.com/Gant/Gant
+
+you should fork this on GitHub and then clone to give you a local repository.
+
+The repository on Codehaus at:
+
+       git://git.codehaus.org/gant.git
+
+is an administrative clone of the GitHub mainline and should not be used in
+normal circumstances.
+
+Gradle is used as the build system for Gant, so you will need to set the
+gant_installPath property in ~/.gradle/gradle.properties so you can install
+Gant. So for example:
+
+       gant_installPath = ${System.properties.'user.home'}/lib/JavaPackages/gant-trunk
+
+Then you type:
+
+     ./gradlew :gant:install
+
+and all the necessary magic happens. The first time you use the Gradle
+Wrapper, it will connect to the Internet to download the various jars that
+comprise Gradle. This takes a while. However this is only needed the first
+time, thereafter it uses the version you downloaded.
+
+You probably want to set the GROOVY_HOME environment variable to point at the
+Groovy installation that the Gant installation is to work with.
+
+
+Using a Bazaar Branch
+---------------------
+
+For anyone prefering to use Bazaar rather than Git, there is an automated
+bridge of the master branch of the Git clone on Launchpad.
+
+To get a branch:
+
+        bzr branch lp:gant Gant
+
+or if you want to use bzr-git directly:
+
+        bzr branch git://github.com/Gant/Gant.git Gant
+
+(If you are going to actively develop Gant, you almost certainly want to have
+a shared repository in which this mirror branch is kept so that you can then
+make feature branches from it.)
+
+All the information in the previous section about Gradle and building Gant
+apply when using Bazaar.
+
+
+Contact
+-------
+
+If you have any problems using Gant, or have any ideas for improvements,
+please make use of the Gant users mailing list: user at gant.codehaus.org
+
+Russel Winder <russel at winder.org.uk>
+
+
+;;; Local Variables: ***
+;;; fill-column: 78 ***
+;;; End: ***
diff --git a/artwork/logo.svg b/artwork/logo.svg
new file mode 100644
index 0000000..719dfc9
--- /dev/null
+++ b/artwork/logo.svg
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="79.328339"
+   height="39.576115"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="logo.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.0"
+   inkscape:export-filename="/home/users/russel/Repositories/Bazaar/Checkouts/Gant/Trunk/artwork/logo_350x172.png"
+   inkscape:export-xdpi="384.09"
+   inkscape:export-ydpi="384.09">
+  <defs
+     id="defs4">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.605648"
+     inkscape:cx="49.655191"
+     inkscape:cy="21.344586"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer2"
+     showgrid="false"
+     inkscape:window-width="999"
+     inkscape:window-height="1009"
+     inkscape:window-x="272"
+     inkscape:window-y="105"
+     inkscape:showpageshadow="false"
+     showborder="false" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Star"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-159.69921,-291.78099)" />
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="Text"
+     transform="translate(-159.69921,-291.78099)">
+    <path
+       sodipodi:type="star"
+       style="fill:#dc6414;fill-opacity:1;stroke:#000000;stroke-opacity:1"
+       id="path2387"
+       sodipodi:sides="5"
+       sodipodi:cx="181.06738"
+       sodipodi:cy="261.19583"
+       sodipodi:r1="18.98089"
+       sodipodi:r2="9.4904451"
+       sodipodi:arg1="2.2161771"
+       sodipodi:arg2="2.8444957"
+       inkscape:flatsided="false"
+       inkscape:rounded="0"
+       inkscape:randomized="0"
+       d="M 169.65033,276.35911 L 171.99271,263.97412 L 163.11818,255.02328 L 175.62085,253.42384 L 181.39122,242.2177 L 186.77591,253.61419 L 199.21673,255.63926 L 190.04198,264.28211 L 191.96045,276.73981 L 180.90546,270.6849 L 169.65033,276.35911 z"
+       transform="matrix(2.1548655,0,0,1.1017661,-191.02812,25.684153)" />
+    <text
+       xml:space="preserve"
+       style="font-size:12px;font-style:normal;font-weight:normal;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="164.73978"
+       y="319.31726"
+       id="text2383"><tspan
+         sodipodi:role="line"
+         id="tspan2385"
+         x="164.73978"
+         y="319.31726"
+         style="font-size:28px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-opacity:1;font-family:ITC Stone Sans;-inkscape-font-specification:ITC Stone Sans Bold">Gant</tspan></text>
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3162"
+       style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"><flowRegion
+         id="flowRegion3164"><rect
+           id="rect3166"
+           width="9.811533"
+           height="13.379363"
+           x="189.80856"
+           y="285.45709" /></flowRegion><flowPara
+         id="flowPara3168" /></flowRoot>  </g>
+</svg>
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..fee62c1
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,694 @@
+// -*- mode:groovy; coding:utf-8 -*-
+
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2014  Russel Winder <russel at winder.org.uk>
+//
+//  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: Russel Winder <russel at winder.org.uk>
+
+apply plugin: 'eclipse'
+apply plugin: 'idea'
+
+import org.apache.tools.ant.filters.ReplaceTokens
+
+ext.artifact = 'gant'
+ext.mavenNameExtension = '_groovy'
+
+/*
+ *  As discussed on the Groovy developer mail list (thanks to Roshan Dawrani and Paul King), the grammar for
+ *  OSGi bundle numbers is fixed and slightly different to the expected grammar for version numbers and Maven
+ *  artefacts:
+ *
+ *   version::= major('.'minor('.'micro('.'qualifier)?)?)?
+ *   major::= digit+
+ *   minor::= digit+
+ *   micro::= digit+
+ *   qualifier::= (alpha|digit|'_'|'-')+
+ *   digit::= [0..9]
+ *   alpha::= [a..zA..Z]
+ *
+ *  The core difference is that for OSGi bundle numbers the qualifier is separated by a full stop where in
+ *  other situations a minus is used.
+ */
+final gantVersionBase = '1.9.11'
+final isPrereleaseSnapshot = false
+
+final createVersionString = {isForOSGi -> gantVersionBase + (isPrereleaseSnapshot ? (isForOSGi ? '.': '-') + 'SNAPSHOT': '')}
+
+final debPackagingNumber = '1'
+
+final gantVersion = createVersionString false
+final gantPrefix = artifact + '-' + gantVersion
+final gantBundleVersion =  createVersionString true
+
+//  Nominate for each supported series of Groovy, exactly which version to use.
+
+final groovyArtefactName = 'groovy-all'
+
+ext.groovyVersions = [
+  '2.0': '2.0.8',
+  '2.1': '2.1.9',
+  '2.2': '2.2.2',
+  '2.3': '2.3.0',
+]
+
+//  One series of Groovy needs using for the standalone distribution. This version of Groovy will be packaged with
+//  the "standalone" distribution of Gant.  It will generally be the latest widely available released version of Groovy.
+
+final groovyStandaloneSeries = '2.2'
+
+//  Organize the build using subprojects.  There is a subproject gant which is for the build using the
+//  locally installed Groovy and there is one for each version of Groovy obtained from the Maven repository
+//  that is supported.  These functions ease doing the iteration over all the subprojects.  NB Gradle
+//  requires the directories for each of the subprojects to exist.  There is an assumption that each
+//  subproject has its own source, etc.  This build slightly perverts the general approach by using exactly
+//  the same source for each subproject, the only difference is the version of Groovy used for compilation.
+
+def forEachDistributionVersion(Closure c) {
+  groovyVersions.keySet().each{String s -> c(artifact + mavenNameExtension + s) }
+}
+
+def forEachProject(Closure c) {
+  c artifact
+  forEachDistributionVersion c
+}
+
+forEachProject{item ->  if (! new File(item).isDirectory()) { mkdir item }}
+
+ext.distributionTasks = []
+ext.debTasks = []
+
+//  Using the JackRabbit wagon gets round some problems associated with uploading the distributions that
+//  occurs with the standard wagon.  However, it does not solve the problem of not creating missing
+//  directories that gives difficulties with new artefact uploads.  Have to cadaver in and create the
+//  hierarchy first:-( Using the lightweight HTTP wagon still requires creating the directory structure
+//  with cadaver or equivalent:-(
+
+final webdavWagonName = 'org.apache.maven.wagon:wagon-webdav-jackrabbit:2.5'
+//final webdavWagonName = 'org.apache.maven.wagon:wagon-http-lightweight:2.5'
+
+//  In creating distributions which include jar files for the source, javadoc, and groovydoc, it is
+//  imperative to ensure that they do not get located into the library directory for jars containing
+//  compiled code for execution: it is critical to avoid getting the source, javadoc, and groovydoc jars on
+//  the classpath.  Rather than build with defaults and sift when creating the distributions, cause the
+//  source, javadoc, and groovydoc jars to be located in a different place.  This is the name of that place
+//  which will be a peer to the executables jars directory.
+
+final docsJarsDirName = 'docsJars'
+
+// =====================================================================
+//
+//  Specifications of things for all the (sub)projects.
+
+allprojects{
+  group =  'org.codehaus.gant'
+  version = gantVersion
+}
+
+final signingPropertiesAreSet = {->
+  project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && project.hasProperty('signing.secretKeyRingFile')
+}
+
+subprojects{
+  apply plugin: 'groovy'
+  apply plugin: 'osgi'
+  if (signingPropertiesAreSet()) { apply plugin: 'signing' }
+  sourceCompatibility = 6
+  targetCompatibility = 6
+  configurations{deployJars}
+  sourceSets{
+    //  NB All the subprojects are actually using the same source code and this is in a different place so
+    //  the location of the source must be specified explicitly.
+    main{groovy{srcDir '../src/main/groovy'}}
+    test{groovy{srcDir '../src/test/groovy'}}
+    integTest{groovy{srcDir '../src/integTest/groovy'}}
+  }
+  metaInf << fileTree(dir: '..').matching{include 'LICENCE.txt'}
+  final theVendor = 'The Codehaus'
+  final theTitle = 'Gant: Scripting Ant tasks with Groovy.'
+  jar{
+    manifest{
+      name = 'Gant'
+      version = gantBundleVersion
+      symbolicName = 'gant'
+      instruction 'Bundle-Vendor', theVendor
+      instruction 'Bundle-Description', group
+      instruction 'Bundle-DocURL', 'http://gant.codehaus.org'
+      instruction 'Built-By', System.properties.'user.name'
+      instruction 'Extension-Name', artifact
+      instruction 'Specification-Title', theTitle
+      instruction 'Specification-Version', gantBundleVersion
+      instruction 'Specification-Vendor', theVendor
+      instruction 'Implementation-Title', theTitle
+      instruction 'Implementation-Version', gantBundleVersion
+      instruction 'Implementation-Vendor', theVendor
+      instruction 'provider', theVendor
+      instruction 'Export-Package', "*;version=${gantVersion}"
+      instruction 'Import-Package', '*;resolution:=optional'
+    }
+  }
+  repositories{
+    if (project.hasProperty('gant_useMavenLocal') && gant_useMavenLocal) { mavenLocal() }
+    mavenCentral()
+    maven{url 'http://repository.codehaus.org/'}
+  }
+  dependencies{
+    compile(
+      'commons-cli:commons-cli:1.2',
+      'org.apache.ant:ant:1.9.2'
+    )
+    testCompile 'junit:junit:4.11'
+    testRuntime 'org.apache.ivy:ivy:2.3.0'
+    deployJars webdavWagonName
+  }
+  compileGroovy.options.compilerArgs = ['-Xlint']
+  [compileGroovy, compileTestGroovy]*.options*.encoding = 'UTF-8'
+  test{
+    //  The Gant Ant task integration test (which is still a unit test:-( has to know the absolute
+    //  locations of certain files.  Because Gradle uses a multi-project build there is an extra level
+    //  complexity in paths compared to Eclipse, IntelliJ IDEA or Gant builds because the multi-project
+    //  builds happen in subdirectories.  org.codehaus.gant.ant.tests.Gant_Test has a decision to make, it
+    //  needs to know whether this is a Gradle build or not.  Use a property.
+    systemProperties['buildFrameworkIdentifier'] = 'Gradle'
+  }
+  clean.doLast{
+    delete 'texput.log', 'target_forMavenTest'
+  }
+  task integTest(type: Test, dependsOn: /* 'assemble' */ 'classes') {
+    include file('src/integTest/groovy').absolutePath + '/org/codehaus/gant/ant/tests/*_Test.*'
+  }
+  if (signingPropertiesAreSet()) {
+    signing{sign configurations.archives}
+  }
+  final packageTitle = 'Gant ' + gantVersion
+  final copyrightString = 'Copyright © 2006–2013  The Codehaus.  All Rights Reserved.'
+  javadoc{
+    options{
+      overview 'overview.html'
+      showAll()
+      encoding 'UTF-8'
+      setUse true
+      author true
+      version true
+      windowTitle packageTitle
+      docTitle packageTitle
+      footer copyrightString
+    }
+  }
+  javadoc.doFirst{
+    javadoc.title = packageTitle
+    javadoc.options.docTitle = javadoc.title
+  }
+  groovydoc{
+    overview = 'overview.html'
+    includePrivate = false
+    use = true
+    windowTitle = packageTitle
+    docTitle = packageTitle
+    header = packageTitle
+    footer = copyrightString
+  }
+  task documentation(dependsOn: ['javadoc', 'groovydoc'], description: 'Create the API documentation.')
+  final docsJarsDir = new File(buildDir, docsJarsDirName)
+  task javadocArtifact(type: Jar, dependsOn: 'javadoc') {
+    classifier = 'javadoc'
+    from docsDir
+  }
+  javadocArtifact.destinationDir = docsJarsDir
+  task groovydocArtifact(type: Jar, dependsOn: 'groovydoc') {
+    classifier = 'groovydoc'
+    from docsDir
+  }
+  groovydocArtifact.destinationDir = docsJarsDir
+  task sourceArtifact(type: Jar) {
+    classifier = 'sources'
+    from sourceSets.main.allSource
+  }
+  sourceArtifact.destinationDir = docsJarsDir
+  task allArtifacts(dependsOn: [jar, javadocArtifact, groovydocArtifact, sourceArtifact])
+  artifacts {
+    archives javadocArtifact
+    archives groovydocArtifact
+    archives sourceArtifact
+  }
+  defaultTasks 'build'
+}
+
+// =====================================================================
+//
+//  Use the locally installed Groovy or the standalone version from the Maven repository.  This subproject
+//  is used for local installation and also for generating the documentation.
+
+project(':gant'){
+  //  If the user has GROOVY_HOME set then use that Groovy rather than the one specified in the properties
+  //  files.  However we have to fiddle to find the version number.
+  final groovyHome = System.getenv().'GROOVY_HOME'
+  final groovyLib = null
+  def groovyVersion
+  def versionMessage
+  if (groovyHome) {
+    groovyLib = new File(groovyHome, 'lib')
+    final groovyVersionPatternString = /^groovy-(all-)?([0-9].*)\.jar/
+    final items = groovyLib.listFiles({File dir, String name -> return (name =~ groovyVersionPatternString).find()} as FilenameFilter)
+    assert items
+    groovyVersion = (items[0].name =~ groovyVersionPatternString)[0][2]
+    assert groovyVersion
+    repositories{flatDir(name: 'groovyInstallation', dirs: [new File(groovyHome, 'embeddable'), groovyLib])}
+    versionMessage = 'Using Groovy version ' + groovyVersion + ' from ' + groovyHome
+  }
+  else {
+    groovyVersion = groovyVersions[groovyStandaloneSeries]
+    versionMessage = 'Using Groovy version ' + groovyVersion
+  }
+  dependencies{compile(group: 'org.codehaus.groovy', name: groovyArtefactName, version: groovyVersion)}
+  compileGroovy.doFirst{println('\n\t' + versionMessage +'\n')}
+  final buildPath = [System.properties.'user.dir', 'gant', 'build', 'classes']
+  final classPath = []
+  classPath << (buildPath + ['main']).join(File.separator)
+  classPath << (buildPath + ['test']).join(File.separator)
+  configurations.testRuntime.files.each { file -> classPath <<  file.parent }
+  test.environment([
+                       GROOVY_ANT_TASK_TEST_VERSION:  groovyVersion,
+                       gradleClasspathString: classPath.join(System.properties.'path.separator')
+                     ])
+  final installDirectory = '/usr/share/gant'
+  try { installDirectory = evaluate('"' + gant_installPath + '"') }
+  catch (MissingPropertyException mpe) { /* Intentionally left blank. */ }
+  task install(dependsOn: 'assemble', description: "Install Gant (compiled against Groovy ${groovyVersion}) to ${installDirectory}.") << {
+    delete installDirectory
+    final installBinDirectory = installDirectory + '/bin'
+    final scriptsDirectory = '../scripts'
+    copy{
+      into installBinDirectory
+      from([scriptsDirectory + '/bin', scriptsDirectory + '/bin_requiresGroovy'])
+      filter ReplaceTokens, tokens: [
+                 GROOVYPATH: 'embeddable',
+                 GROOVYJAR: groovyArtefactName + '-' + groovyVersion + '.jar'
+               ]
+    }
+    ant.chmod(perm: 'a+x'){fileset(dir: installBinDirectory, includes: 'gant*')}
+    copy{
+      into installDirectory + '/conf'
+      from scriptsDirectory + '/conf/gant-starter.conf'
+    }
+    copy{
+      into installDirectory + '/lib'
+      from new File(buildDir, 'libs')
+    }
+  }
+  task uninstall(type: Delete, description: "Delete ${installDirectory} so as to remove the Gant installation.") { delete installDirectory }
+}
+
+// =====================================================================
+//
+//  The subprojects compiling the source against specific Groovy version from the Maven repository.
+
+final ciBuildTasks = []
+
+final pomSpecification = {
+  project{
+    name 'Gant'
+    url 'http://gant.codehaus.org.uk'
+    description 'A framework for programming dependencies.'
+    packaging 'bundle'
+    licenses{
+      license{
+        name 'The Apache Software License, Version 2.0'
+        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+        distribution 'repo'
+      }
+    }
+    scm{
+      url 'scm:git at github.com:Gant/Gant.git'
+      connection 'scm:git at github.com:Gant/Gant.git'
+      developerConnection 'scm:git at github.com:Gant/Gant.git'
+    }
+    developers{
+      developer{name 'Russel Winder'}
+    }
+  }
+}
+
+forEachDistributionVersion{projectName->
+  final groovyVersion = groovyVersions[projectName.replace(artifact + mavenNameExtension, '')]
+  project(projectName){
+    apply plugin: 'maven'
+    dependencies{compile(group: 'org.codehaus.groovy', name: groovyArtefactName, version: groovyVersion)}
+    compileGroovy.doFirst{println('\n\tUsing Groovy version ' + groovyVersion + '\n')}
+    final buildPath = [System.properties.'user.dir', projectName, 'build', 'classes']
+    final classPath = []
+    classPath << (buildPath + ['main']).join(File.separator)
+    classPath << (buildPath + ['test']).join(File.separator)
+    configurations.testRuntime.files.each{file -> classPath <<  file.parent}
+    test.environment([
+                         GROOVY_ANT_TASK_TEST_VERSION:  groovyVersion,
+                         gradleClasspathString: classPath.join(System.properties.'path.separator')
+                       ])
+    install.repositories.mavenInstaller{pom pomSpecification}
+    gradle.taskGraph.whenReady{taskGraph ->
+      if (taskGraph.hasTask(uploadArchives)) {
+        if (! project.hasProperty('gant_experimentalMavenRepository') && !(project.hasProperty('codehausUsername') && project.hasProperty('codehausPassword'))) {
+          throw new RuntimeException('Must define both codehausUsername and codehausPassword to upload archives.')
+        }
+        if (! signingPropertiesAreSet()) {
+          throw new RuntimeException('Must define signing.keyId, signing.password, and signing.secretKeyRingFile')
+        }
+        uploadArchives.repositories.mavenDeployer{
+          uniqueVersion = false
+          configuration = configurations.deployJars
+          beforeDeployment{MavenDeployment deployment -> signing.signPom(deployment)}
+          if (project.hasProperty('gant_experimentalMavenRepository')) {
+            if (! gant_experimentalMavenRepository) { throw new RuntimeException('gant_experimentalMavenRepository value not reasonable.') }
+            repository url: "file://${rootProject.buildDir}/${gant_experimentalMavenRepository}"
+          }
+          else {
+            //repository(url: 'dav:https://dav.codehaus.org/repository/gant/'){
+            repository(url: 'https://dav.codehaus.org/repository/gant/'){
+              authentication userName: codehausUsername, password: codehausPassword
+            }
+            //snapshotRepository(url: 'dav:https://dav.codehaus.org/snapshots.repository/gant/'){
+            snapshotRepository(url: 'https://dav.codehaus.org/snapshots.repository/gant/'){
+              authentication userName: codehausUsername, password: codehausPassword
+            }
+          }
+          pom pomSpecification
+        }
+      }
+    }
+    final binCopySpec = copySpec{
+      final scriptsDirectory = '../scripts'
+      from('..'){include 'README*'}
+      into('conf'){from(scriptsDirectory + '/conf'){include '*.conf'}}
+      into('lib'){
+        from libsDir
+        rename projectName + '-' + version, artifact + '-' + version + mavenNameExtension + '-' + groovyVersion
+      }
+      into('bin'){
+        fileMode = 0755
+        from([scriptsDirectory + '/bin', scriptsDirectory + '/bin_requiresGroovy'])
+        filter ReplaceTokens, tokens: [
+                   GROOVYPATH: 'embeddable',
+                   GROOVYJAR: groovyArtefactName + '-' + groovyVersion + '.jar'
+                 ]
+      }
+    }
+    task binTgz(type: Tar, dependsOn: 'jar', description: 'Build the distribution tarball.') {
+      baseName = artifact
+      classifier = mavenNameExtension + '-' + groovyVersion
+      compression = Compression.GZIP
+      into(gantPrefix){with binCopySpec}
+    }
+    task binZip(type: Zip, dependsOn: 'jar', description: 'Build the distribution zip file.') {
+      baseName = artifact
+      classifier = mavenNameExtension + '-' + groovyVersion
+      into(gantPrefix){with binCopySpec}
+    }
+    distributionTasks += [binTgz, binZip]
+  }
+  //  Due to weird effective scoping of projects -- caused by cloning of bindings for projects? -- need to
+  //  do the following to get the above tasks into the list defined by the main script.
+  distributionTasks += project(projectName).distributionTasks
+  ciBuildTasks << projectName + ':build'
+}
+
+// =====================================================================
+//
+//  Create the standalone distribution.
+
+final projectNameForStandalone = 'gant_groovy' + groovyStandaloneSeries
+
+final standaloneCopySpec = copySpec{
+  final scriptsDirectory = 'scripts'
+  final projectBase = project projectNameForStandalone
+  from('.'){include 'README*'}
+  into('conf'){from(scriptsDirectory + '/conf'){include '*.conf'}}
+  into('lib'){
+    from projectBase.libsDir
+    from projectBase.configurations.runtime
+  }
+  into('bin'){
+    fileMode = 0755
+    from([scriptsDirectory + '/bin', scriptsDirectory + '/bin_standalone'])
+    filter ReplaceTokens, tokens: [
+               GROOVYPATH: 'lib',
+               GROOVYJAR: groovyArtefactName + '-' + groovyVersions[groovyStandaloneSeries] + '.jar'
+             ]
+  }
+}
+
+task standaloneBinTgz(type: Tar, dependsOn: projectNameForStandalone + ':jar', description: 'Create a tarball of the standalone distribution.') {
+  baseName = artifact
+  version = gantVersion
+  compression = Compression.GZIP
+  destinationDir = buildDir
+  into(gantPrefix){with standaloneCopySpec}
+}
+
+task standaloneBinZip(type: Zip, dependsOn: projectNameForStandalone + ':jar', description: 'Create a zip file of the standalone distribution.') {
+  baseName = artifact
+  version = gantVersion
+  destinationDir = buildDir
+  into(gantPrefix){with standaloneCopySpec}
+}
+
+distributionTasks += [standaloneBinTgz, standaloneBinZip]
+
+// =====================================================================
+//
+//  Create the deb file of the standalone distribution.
+
+final debsDirectory = new File(buildDir, 'debs')
+final distDirectory = new File(buildDir, 'dist')
+
+task clean(type: Delete) {
+  delete debsDirectory
+  delete distDirectory
+}
+
+task standaloneDeb(dependsOn: standaloneBinTgz, description: 'Create a deb for use with Debian and Ubuntu.') << {
+  final packageName = 'gant-standalone'
+  final architecture = 'all'
+  final createdDebFileName = packageName + '_' + gantVersion + '-' + debPackagingNumber + '_' + architecture + '.deb'
+  final installPrefixBase = 'usr/share/gant'
+  final expandDirectory = (new File(distDirectory, 'gant-' + gantVersion)).path
+  final packagingDirectory = 'packaging/AntDebTask'
+  inputs.file packagingDirectory + '/gant'
+  inputs.file expandDirectory + '/bin/startGroovy'
+  inputs.file expandDirectory + '/conf/gant-starter.conf'
+  inputs.dir expandDirectory + '/lib'
+  outputs.file debsDirectory.absolutePath + '/' + createdDebFileName
+  // Using doLast here causes a concurrent modification exception.
+  //doLast {
+    delete distDirectory
+    distDirectory.mkdirs()
+    ant.taskdef resource: 'ant_deb_task.properties', classpath: [System.properties.'user.home', '.groovy', 'lib', 'ant-deb.jar'].join(System.properties.'file.separator')
+    logger.info "==>  Untaring ${buildDir}/gant-${gantVersion}.tgz to ${distDirectory}"
+    final process = ['sh', '-x', '-c', "cd ${distDirectory} && tar xvf ${buildDir}/gant-${gantVersion}.tgz"].execute()
+    process.consumeProcessOutput()
+    process.waitFor()
+    debsDirectory.mkdirs()
+    final result = ant.deb(todir: debsDirectory, 'package': packageName, section: 'devel', priority: 'optional', architecture: architecture,
+                             depends: 'java2-runtime', postinst: packagingDirectory+ '/postinst', prerm: packagingDirectory + '/prerm',
+                             conflicts: 'gant'){
+      //  Hack required to make Gradle get things right.
+      //version upstream: gantVersion, debian: debPackagingNumber
+      delegate.version upstream: gantVersion, debian: debPackagingNumber
+      maintainer name: 'Russel Winder', email: 'russel at winder.org.uk'
+      description synopsis: 'Gant -- Groovy scripting of Ant tasks.', '''
+Gant is a tool for scripting Ant tasks using Groovy instead of XML to specify
+the logic. A Gant specification is just a Groovy script and so can bring all
+the power of Groovy to bear directly, something not possible with Ant scripts.
+Whilst it might be seen as a competitor to Ant, Gant relies on all the Ant
+tasks for the complex actions, so it is really an alternative way of doing
+builds using Ant, but using a programming language rather than XML to specify
+the rules.
+.
+This package provides a self-contained installation of Gant that does not
+depend on a separate installation of Groovy -- all the jars needed for Gant to
+run are included in the package.
+.
+Homepage: http://gant.codehaus.org/
+'''
+      tarfileset file: packagingDirectory + '/gant', prefix: installPrefixBase + '/bin', filemode: '755'
+      tarfileset file: expandDirectory + '/bin/startGroovy', prefix: installPrefixBase + '/bin', filemode: '644'
+      tarfileset file: expandDirectory + '/conf/gant-starter.conf', prefix: installPrefixBase + '/conf', filemode: '644'
+      tarfileset dir: expandDirectory + '/lib', includes: '*.jar', prefix: installPrefixBase + '/lib', filemode: '644'
+    }
+    //  The deb Ant task appears not to record the name of the resultant deb file so we have to construct it
+    //  by replicating the algorithm:-((
+    assert createdDebFileName == result._package + '_' + result._version + '_' + result._architecture + '.deb'
+    //}
+}
+
+debTasks << standaloneDeb
+
+// =====================================================================
+//
+//  Create the documentation distribution.
+
+task docTgz(type: Tar, dependsOn: [':gant:javadoc', ':gant:groovydoc'], description: 'Create a tarball of the documentation') {
+  baseName = artifact + '_doc'
+  version = gantVersion
+  compression = Compression.GZIP
+  destinationDir = buildDir
+  into(gantPrefix + '/docs'){from project(':gant').docsDir}
+}
+
+task docZip(type: Zip, dependsOn: [':gant:javadoc', ':gant:groovydoc'], description: 'Create a zip file of the documentation') {
+  baseName = artifact + '_doc'
+  version = gantVersion
+  destinationDir = buildDir
+  into(gantPrefix + '/docs'){from project(':gant').docsDir}
+}
+
+distributionTasks += [docTgz, docZip]
+
+// =====================================================================
+//
+//  Create the source distribution.
+
+final srcContent = [
+  'artwork/', 'documentation/', 'examples/', 'packaging', 'scripts/', 'src/',
+  'build.gradle', 'settings.gradle', 'gradlew','gradlew.bat', 'wrapper/',
+  'ciBuild',
+  'Gant.ipr', 'Gant.iws',
+  '.classpath', '.project', '.settings/',
+  'LICENCE.txt',
+  'README_Install.txt',
+  'releaseNotes.txt',
+  'overview.html',
+]
+
+task srcTgz(type: Tar, description: 'Create a tarball of the source.') {
+  baseName = artifact + '_src'
+  version = gantVersion
+  compression = Compression.GZIP
+  destinationDir = buildDir
+  into(gantPrefix){from(projectDir){srcContent.each{include it}}}
+}
+
+task srcZip(type: Zip, description: 'Create a zip file of the source.') {
+  baseName = artifact + '_src'
+  version = gantVersion
+  destinationDir = buildDir
+  into(gantPrefix){from(projectDir){srcContent.each{include it}}}
+}
+
+distributionTasks += [srcTgz, srcZip]
+
+// =====================================================================
+//
+//  Tasks for getting all the distribution materials uploaded to Codehaus.
+
+final checkAuthority = {->
+  if (! project.hasProperty('gant_experimentalDistributionLocation') && !(project.hasProperty('codehausUsername') && project.hasProperty('codehausPassword'))) {
+    throw new RuntimeException('Must define both codehausUsername and codehausPassword to upload distributions.')
+  }
+}
+
+final undertakeUpload = {copySpec, uploadSpec ->
+  if (project.hasProperty('gant_experimentalDistributionLocation')) {
+    if (! gant_experimentalDistributionLocation) { throw new RuntimeException('gant_experimentalDistributionLocation value not reasonable.') }
+    copy copySpec
+  }
+  else {
+    configurations{upload}
+    repositories{
+      if (project.hasProperty('gant_useMavenLocal') && gant_useMavenLocal) { mavenLocal() }
+      mavenCentral()
+    }
+    dependencies { upload 'com.googlecode.sardine:sardine:146' }
+    assert uploadSpec.size() == 2
+    final targetDirectoryUrl = 'https://dav.codehaus.org/' + (gantVersion.contains('SNAPSHOT') ? 'snapshots.' : '') + 'dist/gant/' + uploadSpec[0]
+    /*
+    com.googlecode.sardine.Sardine sardine = com.googlecode.sardine.SardineFactory.begin(codehausUsername, codehausPassword)
+    */
+  }
+}
+
+task buildDistribution(dependsOn: distributionTasks, description: 'Build all the uploadable distribution archives.')
+
+task uploadDistribution(dependsOn: buildDistribution, description: 'Upload all the distribution archives.') << {
+  checkAuthority()
+  undertakeUpload(
+    {
+      distributionTasks.each { task -> from task }
+      into rootProject.buildDir.absolutePath + '/' + gant_experimentalDistributionLocation + '/distributions'
+    },
+    ['distributions', distributionTasks])
+}
+
+// =====================================================================
+//
+//  Tasks for getting all the debs uploaded to Codehaus.
+
+task buildDebs(dependsOn: debTasks, description: 'Build all the uploadable debs.')
+
+task uploadDebs(dependsOn: buildDebs, description: 'Upload all the debs.') << {
+  checkAuthority()
+  undertakeUpload(
+    {
+      debTasks.each{task -> from task}
+      into rootProject.buildDir.absolutePath + '/' + gant_experimentalDistributionLocation + '/debs'
+    },
+    ['debs', debTasks])
+}
+
+
+// =====================================================================
+//
+//  Do a complete release.
+
+final archivesUploadTasks = []
+forEachDistributionVersion{archivesUploadTasks << ':' + it + ':uploadArchives'}
+
+task uploadRelease(dependsOn: archivesUploadTasks + [uploadDistribution, uploadDebs], description: 'Upload all elements of a release.')
+
+// =====================================================================
+//
+//  Odds and sods.
+
+task ciBuild(description: 'Run just the builds that use Groovy from the Maven repository.  Used mainly on CI servers.', dependsOn: ciBuildTasks)
+
+task wrapper(type: Wrapper) {
+  gradleVersion = '1.11'
+}
+
+task clobber(description: 'Do a really detailed clean.') << {
+  forEachProject{item -> delete item}
+  delete buildDir, 'texput.log'
+}
+
+// Russel uses Java 8 with IntelliJ IDEA and assumes everyone else is.
+
+idea {
+    module {
+        excludeDirs += file 'gradle/' // Gradle directory including the wrapper subdirectory.
+        excludeDirs += file '.gradle/' // Gradle directory
+        excludeDirs += file '.settings/' // Eclipse settings directory.
+        excludeDirs += file 'bin' // Eclipse compilation directory.
+        excludeDirs += file 'out' // IDEA compilation directory.
+        excludeDirs += file 'build' // Gradle compilation directory.
+    }
+    project{
+        jdkName = '1.8'
+        ipr{
+            withXml{provider ->
+                provider.asNode().component.find{it.'@name' == 'VcsDirectoryMappings'}.mapping[0].'@vcs' = 'Git'
+            }
+            whenMerged{project ->
+                project.jdk.languageLevel = 'JDK_1_8'
+            }
+        }
+    }
+}
diff --git a/ciBuild b/ciBuild
new file mode 100755
index 0000000..710743f
--- /dev/null
+++ b/ciBuild
@@ -0,0 +1,6 @@
+#! /bin/sh
+
+export LC_ALL=en_GB.UTF-8
+
+rm -rf .gradle
+./gradlew -i clobber ciBuild
diff --git a/documentation/gant.1 b/documentation/gant.1
new file mode 100644
index 0000000..de123f6
--- /dev/null
+++ b/documentation/gant.1
@@ -0,0 +1,72 @@
+.TH gant 1 "2008-05-24" "Russel Winder"
+.SH NAME
+gant \- A build framework based on scripting Ant task using Groovy.
+
+.SH SYNOPSIS
+.B gant
+[\fIoptions\fR] [\fItarget\fR [\fItarget2\fR [\fItarget3\fR] ...\fR]\fR]
+
+.SH DESCRIPTION
+
+.B gant
+is a tool for working with Ant tasks but using Groovy as the scripting language rather than using XML as a
+specification language.
+
+By default it takes information from
+.B build.gant
+which describes the targets.
+
+.TP
+\fB \-c,\-\-usecache\fR
+Whether to cache the generated class and perform modified checks on the file before re-compilation.
+.TP
+\fB \-d,\-\-debug\fR
+Print debug levels of information.
+.TP
+\fB \-f,\-\-file <build\-file>\fR
+Use the named build file instead of the default,
+.BR build.gant .
+.TP
+\fB \-h,\-\-help\fR
+Print out this message.
+.TP
+\fB \-l,\-\-gantlib <library>\fR
+A directory that contains classes to be used as extra Gant modules,
+.TP
+\fB \-n,\-\-dry\-run \fR
+Do not actually action any tasks.
+.TP
+\fB \-p,\-\-projecthelp\fR
+Print out a list of the possible targets.
+.TP
+\fB \-q,\-\-quiet \fR
+Do not print out much when executing.
+.TP
+\fB \-s,\-\-silent\fR
+Print out nothing when executing.
+.TP
+\fB \-v,\-\-verbose\fR
+Print lots of extra information.
+.TP
+\fB \-C, \-\-cachedir <cache-file>\fR
+The directory where to cache generated classes to.
+.TP
+\fB \-D <name>=<value>\fR
+Define <name> to have value <value>.
+Creates a variable named <name> for use in the scripts and a property
+named <name> for the Ant tasks.
+.TP
+\fB \-L,\-\-lib <path>\fR
+Add a directory to search for jars and classes.
+.TP
+\fB \-P,\-\-classpath <path-list>\fR
+Specify a path list to search for jars and classes.
+.TP
+\fB \-T,\-\-targets\fR
+Print out a list of the possible targets.
+.TP
+\fB \-V,\-\-version\fR
+Print the version number and exit.
+
+.SH AUTHOR
+Gant and this manpage written by Russel Winder <russel at winder.org.uk>.
diff --git a/examples/ivy/build.gant b/examples/ivy/build.gant
new file mode 100644
index 0000000..7f1c5e2
--- /dev/null
+++ b/examples/ivy/build.gant
@@ -0,0 +1,46 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2008, 2010, 2013  Russel Winder
+//
+//  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 : Russel Winder <russel at winder.org.uk>
+
+//  Must be in the binding not be local variables so they are available to the closures.
+
+buildDirectory = 'build'
+sourceDirectory = 'source'
+
+ //  The standard cleaning tool.
+
+includeTargets << gant.targets.Clean
+cleanDirectory << buildDirectory
+cleanPattern << ['**/*~' , '**/*.bak']
+
+//  We are testing the Ivy tool so we need to include it.
+
+includeTool << gant.tools.Ivy
+
+//  Cannot have a target called run as it creates an infinite mutual recursion. :-(
+
+target(runTest: 'Run the Ivy "Hello" test.') {
+  def classpathId = 'libraryClasspath'
+  ivy.cachepath(organisation: 'commons-lang', module: 'commons-lang', revision: '2.5',  pathid: classpathId, inline: 'true')
+  mkdir(dir: buildDirectory)
+  javac(srcdir: sourceDirectory, destdir: buildDirectory, debug: 'true', classpathref: classpathId)
+  java(classname: 'example.Hello', classpathref: classpathId) {
+    classpath { pathelement(location: buildDirectory) }
+  }
+}
+
+target(cleanCache: 'Clean the Ivy cache.') { ivy.cleancache() }
+
+setDefaultTarget(runTest)
diff --git a/examples/ivy/build.xml b/examples/ivy/build.xml
new file mode 100644
index 0000000..a7fbef8
--- /dev/null
+++ b/examples/ivy/build.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+
+  Gant - A Groovy way of scripting Ant tasks.
+
+  Copyright © 2006-10 Russel Winder
+
+  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 : Russel Winder <russel at winder.org.uk>
+
+-->
+
+<project name="Ivy_Hello" default="run" xmlns:ivy="antlib:org.apache.ivy.ant">
+
+  <property environment="environment"/>
+  <property name="groovyLibraryDirectory" value="${environment.GROOVY_HOME}/lib" />
+  
+  <property name="buildDirectory" value="build" />
+  <property name="sourceDirectory" value="source" />
+
+  <path id="ivy.lib.path">
+    <fileset dir="${groovyLibraryDirectory}" includes="ivy*.jar"/>
+  </path>  
+  <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
+
+  <target name="run" description="Resolve dependencies, compile and run the project.">
+    <ivy:cachepath organisation="commons-lang" module="commons-lang" revision="2.5"  pathid="lib.path.id" inline="true"/>
+    <mkdir dir="${buildDirectory}" />
+    <javac srcdir="${sourceDirectory}" destdir="${buildDirectory}" classpathref="lib.path.id" />
+    <java classname="example.Hello">
+      <classpath>
+        <path refid="lib.path.id" />
+        <path location="${buildDirectory}" />
+      </classpath>
+    </java>
+  </target>
+  
+  <target name="clean" description="Clean the project.">
+    <delete dir="${buildDirectory}"/>
+    <delete>
+      <fileset dir="." includes="**/*~" defaultexcludes="false"/>
+    </delete>
+  </target>
+
+  <target name="cleanCache" description="Clean the ivy cache.">
+    <ivy:cleancache/>
+  </target>
+</project>
diff --git a/examples/ivy/source/example/Hello.java b/examples/ivy/source/example/Hello.java
new file mode 100644
index 0000000..5aa3a12
--- /dev/null
+++ b/examples/ivy/source/example/Hello.java
@@ -0,0 +1,27 @@
+//   Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2008, 2010, 2013  Russel Winder
+//
+//  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:  Russel Winder <russel at winder.org.uk>
+
+package example;
+
+import org.apache.commons.lang.WordUtils;
+
+public class Hello {
+  public static void main(final String[] args) {
+    String  message = "hello ivy !";
+    System.out.println("Standard message : " + message);
+    System.out.println("Capitalized by " + WordUtils.class.getName()  + " : " + WordUtils.capitalizeFully(message));
+  }
+}
diff --git a/examples/testScripts/explicitClean.gant b/examples/testScripts/explicitClean.gant
new file mode 100644
index 0000000..6fbdf60
--- /dev/null
+++ b/examples/testScripts/explicitClean.gant
@@ -0,0 +1,34 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2008, 2010, 2013  Russel Winder
+//
+//  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:  Russel Winder <russel at winder.org.uk>
+
+target('default': 'The default target.') {
+  println('Default')
+  clean()
+  Ant.echo(message: 'A default message from Ant.')
+  otherStuff()
+}
+
+target(otherStuff: 'Other stuff.') {
+  println('OtherStuff')
+  Ant.echo(message: 'Another message from Ant.')
+  clean()
+}
+
+target(clean: 'Clean the directory and subdirectories.') {
+  println('Clean')
+  Ant.delete(dir: 'build', quiet: 'true')
+  Ant.delete(quiet: 'true') { fileset(dir: '.', includes: '**/*~,**/*.bak', defaultexcludes: 'false') }
+}
diff --git a/examples/testScripts/gantClean.gant b/examples/testScripts/gantClean.gant
new file mode 100644
index 0000000..54d26b8
--- /dev/null
+++ b/examples/testScripts/gantClean.gant
@@ -0,0 +1,32 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2008, 2010, 2013  Russel Winder
+//
+//  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:  Russel Winder <russel at winder.org.uk>
+
+includeTargets << gant.targets.Clean
+cleanPattern << ['**/*~',  '**/*.bak']
+cleanDirectory << 'build'
+
+target('default': 'The default target.') {
+  println('Default')
+  clean()
+  echo(message: 'A default message from Ant.')
+  otherStuff()
+}
+
+target(otherStuff: 'Other stuff') {
+  println('OtherStuff')
+  echo(message: 'Another message from Ant.')
+  clean()
+}
diff --git a/issues.txt b/issues.txt
new file mode 100644
index 0000000..85146f6
--- /dev/null
+++ b/issues.txt
@@ -0,0 +1,56 @@
+Need some better documentation -- in the source, as manual pages and on the Gant website.
+
+In an include statement, if the class name cannot be found then you get a weird error message:
+
+  Caused by: groovy.lang.MissingPropertyException: No such property: org for class: build
+          at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:734)
+
+If there are compilation errors in the Gant file then sometimes the proper error message is not reported,
+just an exception stack trace.  Using groovy on the Gant file generally shows the errors but Gant should
+have done the right thing in the first place.
+
+Get the GANTLIB stuff finished so it actually works.  First of all decide what it is all for :-)  i.e. is the
+concept of a GANTLIB actually useful?
+
+target ( flob ) { . . .} does not generate a sane error message.  Yes, it does. :-)
+
+target ( flob : '' , thing : '' ) { . . . } is treated as an error but should allow for definition of things
+like dependencies.  Pick off the special names that are understood such as dependencies and then error if
+there is more than one left.
+
+Error messages for things like:
+
+      target ( a , '' ) { . . . }
+
+are not good.  Need to provide error handling versions of target.
+
+Add a --propertyfile <filename> option.  Does this achieve anything useful.
+
+In the Maven target set, the compilation always happens against the Groovy installation that initiated the
+Gant run.  Need to add a way of specifying which Groovy jar to compile against.
+
+How to add compilerarg tags to the Maven target set?
+
+The Maven target set and the Ivy tool assume that System.properties.'groovy.home' is set which is not the case
+always.  In particular, this will only be true when Gant is initiated from the command line, it is not true
+when Gant is initiated via the Ant task.
+
+The LaTeX tool does not make use of the return code from (pdf)latex, and it should.
+
+Using a target name of target gives a very weird error message.
+
+The tests currently work fine with Ant or Gant and fail with Maven.  This difference needs investigating.
+
+Why are there all the gant_$$_GarbageCollect_Test.* and gant_$$_GANT_33_Test* files in ~/.gant/cache ?
+
+Deal with all the TODOs.
+
+Maven target set allows test execution after failed compilation.  The Java task has failonerror set true but
+there is no actual termination.  Whatever information the task gives to Ant to terminate is notbeing
+transmitted to the GantBuilder and hence the Maven task.  Clearly the action in the task is not to System.exit!
+
+No Javadoc generation with the Maven target set. 
+
+Loading the groovyc task in Gant startup causes problem when the Gant Ant task is used from Ant.
+
+Add all the above as JIRA issues.
diff --git a/overview.html b/overview.html
new file mode 100644
index 0000000..29887cd
--- /dev/null
+++ b/overview.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>Gant</title>
+  </head>
+
+  <body>
+    <p>
+      Gant is a Groovy-based framework for scripting Ant tasks.
+    </p>
+    <p>
+      Gant is a lightweight wrapper around Groovy's <code>AntBuilder</code> that allows Ant tasks to be
+      scripted using Groovy.  This means it can be used as a replacement for Ant:  instead of specifying
+      things using XML, they are specified with Groovy.
+    </p>
+    <p>
+      A Gant file is a specification of a set of targets plus other bits and pieces of Groovy code.  Thus a
+      Gant specification is of a set of targets just as an Ant specification is.  Each target creates a
+      closure in the binding so that it can be called as a function from other targets.  This means that
+      dependencies between targets are programmed as function calls.
+    </p>
+    <p>
+      Gant has a number of predefined objects, for example <code>ant</code>, <code>includeTargets</code>
+      and <code>includeTool</code>. <code>ant</code> refers to a pre-constructed <code>GantBuilder</code>
+      object. <code>includeTargets</code> is the object that controls the inclusion of ready-made targets,
+      for example <code>gant.targets.Clean</code>.  <code>includeTool</code> is the object that controls the
+      inclusion of ready-made tools, for example <code>gant.tools.Execute</code>.
+    </p>
+    <p>
+      Here is an example Gant script:
+    </p>
+    <blockquote>
+      <pre>
+includeTargets << gant.targets.Clean
+cleanPattern << [ '**/*~' ,  '**/*.bak' ]
+cleanDirectory << 'build'
+
+target ( 'default' : 'The default target.' ) {
+  println ( 'Default' )
+  depends ( clean )
+  echo ( message : 'A default message from Ant.' )
+  otherStuff ( )
+}
+
+target ( otherStuff : 'Other stuff' ) {
+  println ( 'OtherStuff' )
+  echo ( message : 'Another message from Ant.' )
+  clean ( )
+}
+      </pre>
+    </blockquote>
+    <p>
+      The function <code>depends</code> takes a list of targets and 'executes' them if and only if they have
+      not previously been executed.  This means that dependencies can be handled far more flexibly than they
+      can in Ant, leading to simpler target structures.
+    <hr>
+    <address><a href="mailto:russel at winder.org.uk">Russel Winder</a></address>
+    Last modified: 2010-04-05T08:30+01:00
+  </body>
+</html>
diff --git a/packaging/AntDebTask/ant_deb_task.properties b/packaging/AntDebTask/ant_deb_task.properties
new file mode 100644
index 0000000..9ad5bcf
--- /dev/null
+++ b/packaging/AntDebTask/ant_deb_task.properties
@@ -0,0 +1,2 @@
+desktopentry=com.googlecode.ant_deb_task.DesktopEntry
+deb=com.googlecode.ant_deb_task.Deb
diff --git a/packaging/AntDebTask/build.gant b/packaging/AntDebTask/build.gant
new file mode 100644
index 0000000..7d0f37a
--- /dev/null
+++ b/packaging/AntDebTask/build.gant
@@ -0,0 +1,138 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2007–2010, 2013  Russel Winder
+//
+//  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: Russel Winder <russel at winder.org.uk>
+
+//  The overal algorithm here is to take a standalone distribution (could use either a tarball or a
+//  zipfile, prefer to use a tarball if it exists) expand it and then repackage into a deb file.  Do not
+//  include any Windows specific bits.  Furthermore replace the standard launch script with one specifically
+//  designed for the installation with its known locations and dependencies.
+
+//  Use the ant-deb-task from Marius Scurtescu <marius.scurtescu at gmail.com> to create a deb file.
+//  Assume the ant-deb.jar file is in ~/.groovy/lib.
+
+//  Extract the Gant version number from the Gradle build file.  Scanning the text with the regular
+//  expression below should result in a single match resulting in a list of two items, the full match and
+//  the capture group.  The capture group should be the version number.
+
+final matcher = new File('../../build.gradle').text =~ "gantVersionBase\\s*=\\s*'(.*)'"
+assert matcher != null
+assert matcher[0] != null
+assert matcher[0].size() == 2
+
+final gantVersion = matcher[0][1]
+
+//  Name of and properties to be embedded in the deb.
+
+final packageName = 'gant-standalone'
+final section = 'devel'
+final priority = 'optional'
+final architecture = 'all'
+final homepage = 'http://gant.codehaus.org/'
+
+final installPrefixBase = 'usr/share/gant'
+
+final theSynopsis = 'Gant -- Groovy scripting of Ant tasks.'
+final theWords = """
+Gant is a tool for scripting Ant tasks using Groovy instead of XML to specify
+the logic. A Gant specification is just a Groovy script and so can bring all
+the power of Groovy to bear directly, something not possible with Ant scripts.
+Whilst it might be seen as a competitor to Ant, Gant relies on all the Ant
+tasks for the complex actions, so it is really an alternative way of doing
+builds using Ant, but using a programming language rather than XML to specify
+the rules.
+.
+This package provides a self-contained installation of Gant that does not
+depend on a separate installation of Groovy -- all the jars needed for Gant to
+run are included in the package.
+.
+Homepage: ${homepage}
+"""
+
+//  Where to put the deb when uploading.  We need the slide-webdav jar which we get fromt he Maven
+//  repository, so we need to make use of the Maven Ant task to be able to get it.
+
+final antlibXMLns = 'antlib:org.apache.maven.artifact.ant'
+final distributionURL = 'https://dav.codehaus.org/' +(gantVersion.contains('SNAPSHOT') ? 'snapshots.': '') + 'dist/gant/'
+
+//  Load up the Ant Deb task.
+
+ant.taskdef(resource: 'ant_deb_task.properties', classpath: [ System.properties.'user.home', '.groovy', 'lib', 'ant-deb.jar' ].join(System.properties.'file.separator'))
+
+//  Local details of where to expand the standalone distribution and where to make the debs.
+
+final debsDirectory = 'debs'
+final distDirectory = 'dist'
+final expandDirectory = distDirectory + '/gant-' + gantVersion
+
+//  Make sure we can tidy things up.  Also that we can easily run subprocesses.
+
+includeTargets << gant.targets.Clean
+cleanPattern << '**/*~'
+cleanDirectory << [ debsDirectory, distDirectory ]
+
+includeTool << gant.tools.Execute
+
+//  The targets:  create the debs and upload the debs, set the default to build.
+
+target(debFiles: 'Create the deb file of the distribution.') {
+  execute.shell("cd ../.. && gradle standaloneBinTgz")
+  mkdir(dir: distDirectory)
+  delete { fileset(dir: distDirectory, includes: '**/*') }
+  execute.shell("cd ${distDirectory} && tar xvf ../../../build/gant-${gantVersion}.tgz")
+  mkdir(dir: debsDirectory)
+  ////  Why is the ant. needed here ??????
+  ant.deb(todir: debsDirectory, 'package': packageName, section: section, priority: priority, architecture: architecture,
+        depends: 'java2-runtime', postinst: 'postinst', prerm: 'prerm') {
+    version(upstream: gantVersion)
+    maintainer(name: 'Russel Winder', email: 'russel at russel.org.uk')
+    //homepage(homepage)
+    description(synopsis: theSynopsis, theWords)
+    tarfileset(file: 'gant', prefix: installPrefixBase + '/bin', filemode: '755')
+    tarfileset(file: expandDirectory + '/bin/startGroovy', prefix: installPrefixBase + '/bin', filemode: '644')
+    tarfileset(file: expandDirectory + '/conf/gant-starter.conf', prefix: installPrefixBase + '/conf', filemode: '644')
+    tarfileset(dir: expandDirectory + '/lib', includes: '*.jar', prefix: installPrefixBase + '/lib', filemode: '644')
+  }
+}
+
+target(uploadDistribution: 'Upload the deb files to Codehaus.') {
+  depends(debFiles)
+  "${antlibXMLns}:dependencies"(pathId:  'slidePathId') {
+    dependency(groupId: 'slide', artifactId: 'slide-webdavlib', version: '2.1')
+  }
+  def loader = getClass().getClassLoader()
+  def path = path(refid: 'slidePathId')
+ (path.list() as List).each { location -> loader.addURL(new URL('file://' + location)) }
+  def settings = (new XmlSlurper()).parse(System.properties.'user.home' + '/.m2/settings.xml').servers.server.find { item -> item.id == 'codehaus.org' }
+  def credentials =  loader.loadClass('org.apache.commons.httpclient.UsernamePasswordCredentials').getConstructor(String, String).newInstance(settings.username.toString(), settings.password.toString())
+  //  Have to put resource in the binding so that the Closures can access it.
+  resource = loader.loadClass('org.apache.webdav.lib.WebdavResource').getConstructor(String,  loader.loadClass('org.apache.commons.httpclient.Credentials'), boolean).newInstance(distributionURL, credentials, true)
+  if (resource.statusCode != 200) { println('Failed to open ' + distributionURL) }
+  else {
+    final serverUploadProducts = [:]
+    final serverDistributionsDirectory = 'debs'
+    new File(debsDirectory).eachFile { file -> serverUploadProducts[ file.path ] = serverDistributionsDirectory + '/' + file.name
+    }
+    serverUploadProducts.each { source, destination ->
+      def serverPath = resource.path + '/' + destination
+      print('Uploading ' + source + ' -> ' + destination + ': ')
+      def result = 'Failed.'
+      if (resource.putMethod(serverPath, new File(source))) { result = 'OK.' }
+      println(result + ' Status: ' + resource.statusMessage)
+    }
+  }
+  if (resource != null) { resource.close() }
+}
+
+setDefaultTarget(debFiles)
diff --git a/packaging/AntDebTask/gant b/packaging/AntDebTask/gant
new file mode 100644
index 0000000..16d173e
--- /dev/null
+++ b/packaging/AntDebTask/gant
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+#  Gant -- A Groovy way of scripting Ant tasks.
+#
+#  Copyright © 2008, 2010, 2013  Russel Winder
+#
+#  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 : Russel Winder <russel at winder.org.uk>
+
+#  Gant initiation script for Debian and Ubuntu.  This version does not require a Groovy or Ant installation
+#  since it has all the necessary jars in the $GANT_HOME/lib directory.
+
+GANT_HOME=/usr/share/gant
+GROOVY_HOME="$GANT_HOME"
+ANT_HOME="$GANT_HOME"
+
+GROOVY_APP_NAME=Gant
+GROOVY_CONF="$GANT_HOME/conf/gant-starter.conf"
+
+. "$GROOVY_HOME/bin/startGroovy"
+
+JAVA_OPTS="$JAVA_OPTS -Dgant.home=$GANT_HOME -Dant.home=$ANT_HOME"
+
+startGroovy gant.Gant "$@"
diff --git a/packaging/AntDebTask/postinst b/packaging/AntDebTask/postinst
new file mode 100755
index 0000000..00b3dca
--- /dev/null
+++ b/packaging/AntDebTask/postinst
@@ -0,0 +1,4 @@
+#! /bin/sh
+
+cd /usr/bin
+ln -s /usr/share/gant/bin/gant gant
diff --git a/packaging/AntDebTask/prerm b/packaging/AntDebTask/prerm
new file mode 100755
index 0000000..cb2179d
--- /dev/null
+++ b/packaging/AntDebTask/prerm
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+rm /usr/bin/gant
diff --git a/releaseNotes.txt b/releaseNotes.txt
new file mode 100644
index 0000000..54d2428
--- /dev/null
+++ b/releaseNotes.txt
@@ -0,0 +1,590 @@
+1.9.11
+------
+
+Updated 2.2 series to 2.2.2.
+
+Drop support for Groovy 1.8.
+
+Add support for Groovy 2.3.
+
+Fix a problem with the Windows batch launch script. Thanks to Hubbitus.
+
+
+1.9.10
+------
+
+Updated to Groovy 1.8.9, 2.0.8, 2.1.9.
+
+This release triggered by the arrival of Groovy 2.2.0.
+
+
+1.9.9
+-----
+
+Updated to Groovy 1.8.8, 2.0.6 and 2.1.0.
+
+Various changes to cause less compilation warnings.
+
+This release triggered by the release of Groovy 2.1.0
+
+
+1.9.8
+-----
+
+Updated to Groovy 1.8.6 and 2.0.0.
+
+Abandoned support for Groovy 1.7.x series. Groovy 1.8 series brought a parameterized Closure class and
+supporting the two versions of Closure in the same code base is too much hassle.
+
+This release was tirggered by the release of Groovy 2.0.0.
+
+
+1.9.7
+-----
+
+No substantive changes to Gant, per se.  Groovy 1.7.10, 1.8.4 and 2.0.0-beta-1 are the ones built against.
+
+Various minor changes to the build framework and project files have been made.  Various launch scripts have
+been re-synchronized with those of Groovy.  Various changes made to allow for using Java 7 as well as Java
+6, but none in Gant itself only in the tests.
+
+This release actually triggered by the release of Groovy 2.0.0-beta-1 since it is a revolutionary change to
+the numbering of Groovy -- 1.9.x series has been dropped and replaced by the 2.0.x series, i.e. the changes
+have been deemed a major change.  Which is probably right.
+
+
+1.9.6
+-----
+
+No substantive changes to Gant, this release is made post release of Groovy 1.8.1 and 1.9.0-beta-1
+principally to get a version of Gant compiled against he Groovy 1.9 series into the Maven repository.
+
+GroovyDoc, JavaDoc, and source artefacts are now built and published.
+
+
+1.9.5
+-----
+
+GroovyShell.parse(InputStream, String) has been removed in Groovy 1.9.x.  This introduces and
+incompatibility with the 1.6.x API.  Drop Gant support for Groovy 1.6.9.
+
+Switch to using Groovy 1.8.0 (instead of 1.7.10) as the bundled version of Groovy for the stand-alone Gant
+distribution.
+
+
+1.9.4
+-----
+
+Add Groovy 1.8 to the Groovy series supported by Gant.
+
+Groovy 1.6.9 is now used for the 1.6 series build of Gant and 1.7.8 for the 1.7 series build.
+
+Deb files are now built as part of the release process.
+
+Remove the Maven Ant task jar from the repository and the distribution.
+
+
+1.9.3
+-----
+
+Updated the Groovy 1.7.x series to be 1.7.3.
+
+Minor fixes to the exit code and other processing for the Windows launch scripts to keep in line with Groovy
+ones.
+
+Corrected Windows batch file processing to avoid assumptions made in startGroovy.bat.
+
+This release is really being made because it transpires that the 1.9.2 release for the Groovy 1.7 series was
+compiled against Groovy 1.7.1 which had a breaking API change that was reverted for Groovy 1.7.2 and thus
+1.7.3.  The consequence is that the version 1.9.2 gant_groovy1.7 artefact is incompatible with Groovy 1.7.2
+and 1.7.3.
+
+
+1.9.2
+------
+
+Various minor bug fixes and refactorings, including switching to Groovy 1.7.1 as the main version of Groovy,
+JUnit 4.8.1 as the unit test framework, and Ant 1.8.0 as the principal version of Ant used.
+
+Maven and Gant builds removed in favour of focusing solely on Gradle as the build for the Gant project.
+
+
+1.9.1
+-----
+
+The change to the Gradle build tool for release of Gant 1.9.0 led to a an error in the stream processing of
+the launch scripts which led to a failure to start Gant.  This release is to fix that problem.
+
+
+1.9.0
+-----
+
+Added the ability to skip the tests when using the Maven target set.  Use -DskipTest=true on the command
+line to stop the tests being compiled and run, otherwise they will be.
+
+Change the way in which the final message is output when Gant is executed from the command line from being
+hardwired to being the execution of a hook, terminateHook.  cf. GANT-104.
+
+Altered the Gant Ant task so as to provide an inheritAll attribute.  cf. GANT-110.
+
+Switched GantException from extending RuntimeException to extending org.apache.tools.ant.BuildException so
+as to allow better consistency with use of Gant from Ant.  cf. GANT-111.
+
+Switch from using Ant as a boostrap and Gant for other processing to using Gradle for all build issues
+(except distribution release as there is still a problem there).
+
+Updated to Groovy 1.7.0 for Groovy 1.7.x and Groovy 1.6.7 for Groovy 1.6.x.
+
+Switch from using Ant as a boostrap and then Gant to manage the project to using Gradle for all build and
+install activity.
+
+
+1.8.1
+-----
+
+Upgrade to Ivy 2.1.0.
+
+Upgrade to Groovy 1.7-beta-2
+
+
+1.8.0
+-----
+
+Upgrade to using JUnit 4.7, in line with Groovy 1.7.x.
+
+Added the ability for each target to have a per-target prehook and posthook, and for there to be a global
+prehook and posthook -- which are the same for all targets.  The hooks can either be a closure or a list of
+closures.  Global prehooks are executed before per-target prehooks, which are executed before the build
+listeners are informed and the target body is executed.  Global posthooks are executed after the per-target
+posthooks which are executed after the target body and the buildlisteners.  The logging of entry and exit to
+each target is implemented as the default per-target prehook/posthook. cf.  GANT-90, GANT-99 and GANT-100.
+
+Remove (finally) the name Ant from the binding.  The symbol has been deprecated for ages.
+
+Fixed GANT-91 and GANT-93.
+
+Added nestedJavacCompilerArgs property to the Maven target set to allow for nested compilerarg elements to
+the nested javac element of a groovyc element.
+
+Upgraded to using Groovy 1.6.5.
+
+
+1.7.0
+-----
+
+Added the binding variable initiatingTarget which is set by the Gant infrastructure just prior to processing
+each target, it allows the Gant script to know what the initiating target is.
+
+Added properties gant.version (the version of Gant currently executing) and gant.file (the initial Gant file
+being processed) to the binding to allow the script to process these data.
+
+Upgrade to using Groovy 1.5.8 instead of 1.5.7 as the Groovy 1.5.x version.
+
+Upgrade to using Groovy 1.6.4 instead of 1.6.0 as the Groovy 1.6.x version.
+
+Amend the way symbolic links are processed in the launch scripts on Mac OS X to correct various faults.
+
+Added features to solve GANT-44.  The binding variable 'targets' is now an entry in the binding and contains
+the list of as yet uncompleted targets.  This is the target list from the command line with all the already
+processed ones removed.  The list contents are mutable within the Gant script but the variable itself is
+read-only and so cannot be changed to refer to another list.
+
+Various names present in the binding have been made read only within Gant scripts: target, message, ant,
+includeTargets, includeTool, targetDescriptions, setDefaultTarget, initiatingTarget, targets.  A build fails
+if an assignment is attempted on any of them.
+
+Made 'finalize' a special target name.  'finalize' is always called if present whether a build finishes
+normally or duie to an exception.  cf.  GANT-81.
+
+setDefaultTarget used to generate a target called default which was problematic if a script defined a target
+of that name.  The default target processing has been changed to avoid this.
+
+Error messages now appear on standard error, previously they appeared on standard out along with other forms
+of output.  cf. GANT-77.
+
+Gant now provides output about the targets being processed so is a little more "Ant-like" -- but note there
+are significant differences, Gant outputs information about starting and completing a target.  cf. GANT-77, GANT-80.
+
+Gant jar is now OSGi compliant.  cf. GANT-83.
+
+Should now never need the ant. when calling Ant tasks. cf. GANT-10.
+
+
+1.6.1 ( r10179 )
+----------------
+
+Groovy 1.6.0 is released, declare a Gant bug-fix release so as to avoid any confusion regarding versions of
+Gant in the Maven repository and elsewhere.
+
+
+1.6.0 ( r10161 )
+---------------
+
+A first cut at adding BuildListeners added by Graeme Rocher.  cf. GANT-70.
+
+Fix the Posix shell scripts to try and deal with the weirdness of the Mac OS X readlink compared to the one
+on Ubuntu, MSYS, Cygwin.  Solaris doesn't have readlink by default, the Sunfreeware version is the same as
+the one on Ubuntu, MSYS, Cygwin.
+
+Split the two cases where -2 is the return code, introduce -4 for one of the cases.
+
+Various tinkerings associated with GANT-50, GANT-62, GANT-71.
+
+Upgraded to use Groovy 1.6-RC-2.
+
+Upgraded to use Ivy 2.0.0.
+
+
+1.5.1 ( r10110 )
+----------------
+
+Patch up the startGroovy script to deal with MSYS issues.
+
+Amend the org.codehaus.gant.ant.tests.Gant_Test to ensure things work on Windows as well as Ubuntu, Mac OS X
+and Solaris.
+
+
+1.5.0 ( r10067 )
+----------------
+
+Amend property lookup so that Ant properties appear as entries in the Gant binding, i.e. Ant properties are
+directly accessible as variables -- no need any more for ant.project.properties.skipTests, can just use
+skipTests.  Where there is a name conflict Groovy variables take precedence over Ant properties.
+
+Added nested <definition> tags to the Gant Ant task so as to allow -D... parameters to be specified.
+
+Added nested <gantTarget> tags to the Gant Ant task so as to allow multiple targets to be run.
+
+Correct the Gant Ant task file lookup to use basedir rather than the start directory as the base from which
+to search for the file.
+
+Provide a new constructor to allow Gant to be used in a Groovy Ant Task script.  cf. GANT-50.
+
+Correct some of the cygpath option lists. (Thanks to Paulo Jerônimo for spotting and reporting the problem.)
+
+Extend processing of symblic links in the gant Posix scripts. (Thanks to Nicolas Lalevée for submitting
+GANT-57.)
+
+Update to expect to use Ivy 2.0.0-rc2 at run time.
+
+Fix GANT-30 by removing .groovy and .gant extensions from file names before constructing class names.
+
+GStrings no longer cause problem in depends call -- fixed GANT-55.  GANT-61 is a duplicate of GANT-55.
+
+Serious refactoring of the constructor structure of Gant.  Thanks to Peter Ledbrook.  cf. GANT-48.  NB  This
+is a significant breaking change for any code that creates Gant objects.  The script is no longer loaded as
+part of construction but has been separated out using the loadScript method.  This allows for introduction
+of the loadScriptClass method.
+
+Alter the start up jar load to include only jars with names starting "ant" from the $ANT_HOME/lib directory.
+
+Fix the Windows batch scripts.  cf. GANT-66.  (Thanks to Daniel Skiles and Bob Swift.)
+
+Add the ability to have arbitrary entries in the map that is the parameter to the target.  So as well as:
+    target ( flobadob : 'Description of target flobadob' ) { . . . }
+can now have:
+    target ( name : 'flobadob' , description : 'Description of target flobadob' ) { . . . }
+the map can contain any entry but must have a jey called name.  this means that the name of the
+target can be accessed as it.name and the description as it.description in the closure of the target.
+cf. GANT-56.
+
+Introduce Peter Ledbrook's changes to the naming of the Maven repository artefact and the consequent changes
+to the build system.  The compilation of Gant depends on the version of Groovy used and this has to be
+reflected in the artefacts uploaded to the Maven repository.  It is not possible to use classifiers since
+this requires using the same POM and the POM has to be different for each build.
+
+Partly addressed GANT-63 about losing information about exceptions being thrown.
+
+Part fix for GANT-51.
+
+
+1.4.0 ( r9604 )
+---------------
+
+Remove the assumption that all instances of a given class have the same metaclass.
+
+Fixed the method search so that the GantBuilder object referred to by ant is checked for all closures
+declared in a target. However, this raises issues, cf. GANT-49.
+
+Correct Execute.shell method so it works on Windows without Cygwin or MSYS. cf. GANT-38.
+
+Correct all the tools and target sets so that a GantBinding rather than a Binding is passed.  NB This is a
+breaking API change for anyone who has written their own tools or target sets.
+
+Add groovyc taskdef to the GantBuilder instance so the user doesn't have to.  GANT-19 relates.
+
+Tidied up the tool and target set classes to ensure that both "<<" and "** *" operators work correctly.
+
+Stop the binding entry target from being redefined.
+
+Remove the task entry in the binding.  It was deprecated and advertised as being removed in v1.3.
+
+Added a new Gant constructor to allow precompiled scripts to be used.  Provided by Peter Ledbrook,
+cf. GANT-47.
+
+Fixes:  GANT-19, GANT-32, GANT-38, GANT-42, GANT-45, GANT-46.
+
+Workaround provided for GANT-49, but a final fix is still needed.
+
+1.3.0 ( r9298, tagged as 9302 )
+-------------------------------
+
+Change the way Groovy installs so that it doesn't install into the Groovy installation, but into its own
+hierarchy.  There are two distributions:
+
+            1.  Requires a separate Groovy installation.  Currently there are two version:
+                a.  Compiled against Groovy 1.5.6
+                b.  Compiled against Groovy 1.6-beta-1
+
+            2.  Self-contained, includes all dependent jars.
+
+Various tests amended to work correctly on Windows. Tests previously only checked on Ubuntu, Mac OS X and Solaris.
+
+Created a Gant log.
+
+Created Windows batch files that work.  Posix shell scripts only worked previously.
+
+
+1.2.0 ( r9173 )
+---------------
+
+Introduce the GantBinding class to ensure various things that are needed for Gant to work and to allow more
+efficient cloning for multi-threading builds.
+
+Remove the inserting of the class name for target set classes into the binding.
+
+Make the symbols added to the binding by the tools lowercase rather than upper case.  cf. GANT-29.
+
+The Maven target set used to provide access to properties via the symbol Maven, this is changed to
+maven.  This change is to make things consistent with the above change of case of tool symbols. All uses of
+Maven as a reference from the binding must be replaced by maven.
+
+Add in checks for duplicate symbols in the binding.
+
+Change --cachedir option to short form -C so that -d can be used for --debug.
+
+Updated Maven Ant Tasks to 2.0.9.
+
+Added the ability to specify remote repositories in the Maven Target set.
+
+Move to Java 1.5 for the Gant source: introduce generics and remove casts wherever sensible.
+
+Ensure numeric return values from targets are promulgated to the exit code for the Gant target processing.
+
+Swap to using negative numbers for error codes generated by Gant itself, leaving positive return codes for
+Gant scripts to use.
+
+Rearrange the tests to only depend on the presence of GROOVY_HOME when it is appropriate.  GROOVY_HOME is
+not needed for execution only for installation of Gant.
+
+
+1.1.2 ( r9087 )
+---------------
+
+Updated to using Ivy 2.0.0-beta2.
+
+Corrected the bug that the Ivy tool was not operating in the correct namespace.  This removes the spurious
+message: "Trying to override old definition of task buildnumber" that used to happen.
+
+Refactored the IncludeTarget and IncludeTool classes to move replicated code into the common superclass
+AbstractTool.
+
+Corrected the way that jars are included on the classpath from ~/.gant/lib, ~/.ant/lib and $ANT_HOME/lib.
+
+Updated TestNG from 5.7 to 5.8 in Maven target set. Amended the properties set so that the TestNG version
+number and and classifier can be set by the user instead of being only hardwired.  The defaults are still
+hardwired in an ugly way though.
+
+Extended the Ivy tool to allow the path to the Ivy jar to be specified using the ** * notation.
+
+Ensured the AntFile and Include tests work on Windows as well as Ubuntu, Solaris, and Mac OS X.
+
+Modified the verbosity level stuff so as to set the verbosity understood by the Ant tasks that get called.
+
+
+1.1.1 ( r9027 )
+---------------
+
+Added the Ivy and Maven Ant Tasks jars to the binary distribution.
+
+Amend the Maven target set to add explicit specification of the source and test directories.  This applies
+the Groovy joint compiler to everything in that directory, i.e. the Maven 2 split of language specific
+directories is not applied.
+
+Amended the Execute tool adding multi-threading of the process output streams to avoid blocking due to
+overful buffers.  cf. GANT-22.  Altered return type of methods so as to return the return code of the
+executed process. cf. GANT-23.
+
+Add a new tool AntFile for reading an Ant XML file and presenting all the targets as targets in a Gant file.
+
+Added a -L|--lib <directory-path> options in the same style as Ant's at the request of Adam DesJardin.
+cf. GANT-24.
+
+Added $HOME/.gant/lib as a repository of jar files as well as $HOME/.ant/lib.
+
+Amended the depends processing to deal with lists of mixed Strings and Closures.
+
+
+1.1.0 ( r8964 )
+---------------
+
+Added metadata to the Maven target set.
+
+Updated the Ivy example a bit.  Switched to Ivy 2.0.0-beta-1.
+
+Added a Gant Ant Task.  (For supporting continuous integration systems that insist on using Ant.)
+Unfortunately, there is a problem with loading the Groovyc task in an Gant script executed from an Ant
+script -- see GANT-19.   The Gant Ant task is written in Java which leads to the build requiring the use of
+the joint Groovy compiler.  This means it is not possible to build Gant using Groovy 1.0.
+
+Added creating Cobertura reports via the coberturaTest target in the Gantfile.
+
+Amended some of the error handling, especially target definition.
+
+Added constructors to allow the Gant script to be a parameter.  This allows programs (including the tests)
+not to have to use a command line approach to starting Gant.  Many of the tests refactored.
+
+Added extra options in the LaTeX tool execution to avoid any interactive mode of LaTeX.
+
+
+1.0.2 ( r8867 )
+---------------
+
+Fixed bug in parameter types of message Closure in gant.Gant.
+
+Declared this release and eradicated 1.0.1 to avoid any hassles with the above bug.
+
+
+1.0.1 ( r8861 )
+---------------
+
+Amended and extended the Maven target set so that it actually works well enough to be useful.
+
+Change the return codes so as to provide easier discrimination of error cases.
+
+Removed --lib option and replaced with --classpath | -P option.  Takes a path not a single jar.
+
+Added setDefaultTarget function to make setting up the default target easier.  Also the help output for the
+target default assumes that the description string is just the name of the default target.
+
+Rearranged the filestore to work better for command line working, Eclipse, and the Maven target set.
+
+Gant now compiles in Eclipse 3.2.2 with Groovy plugin 1.5.0.200712080221.
+
+
+1.0.0 ( r8816 )
+---------------
+
+Changed the lookup sequence in GantMetaClass adding lookup in the Ant object for a method call as a final
+attempt to resolve a name.  This makes Ant. completely optional as requested in GANT-10.
+
+Rearranged the constructors so as to allow for a custom class loader when calling Gant programmatically.
+
+Reverted to -D processing as in 0.3.1 which actually works with Commons CLI 1.0 even though it is a bug.
+0.3.2 and 0.3.3 were broken as -D processing did not work at all.
+
+Added the ** * mechanism for creating target set and tool objects using constructor parameters.
+
+Stopped Gant from issuing FileNotFoundException.
+
+Released to coincide with release of Groovy 1.5.0.
+
+
+0.3.3 ( r8490 )
+---------------
+
+Created a new option (-d,--cachedir) to specify a cache directory for the caching system.  This is used by
+Grails.  Gant release rushed out for the Grails 1.0 release.
+
+Formally announced deprecation of task, should now use target.
+
+
+0.3.2 (r8191)
+-------------
+
+Fixed problem with -V option.
+
+Started a Maven 2 build capability -- this is work in progress and not complete.
+
+Restructured source to fit better with the Maven 2 directory structure.
+
+Corrected various problems with return values.
+
+Changed the location of the repository to http://svn.codehaus.org/groovy/gant
+
+
+0.3.1 (r6962)
+-------------
+
+Added returning a sensible return code -- 0 for success and 1 for failure.
+
+Added extending of the classpath:
+      --lib <path> for individual jars.
+      Searching ~/.ant/lib for user collections of jar files.
+      Searching ANT_HOME/lib for jar files if ANT_HOME is defined.
+
+
+0.3.0 (r6320)
+-------------
+
+Works with both Groovy 1.0 release and the Groovy 1.1-beta-1 release.
+
+Changed from using `task' to using `target' as the string introducing a target.
+
+Added a Maven project processing tool.
+
+Added a mechanism for accessing the documentation string of a target.
+
+Improved the error reporting.
+
+
+0.2.4 (r5374)
+-------------
+
+Use System.properties.'file.separator' instead of / so things work on Windows.
+
+Added the ability to have multiple -D options so as to be able to define any number of variables/properties
+on the command line.
+
+Added specialized Grails build infrastructure.
+
+Implemented local caching of .class files to improve performance when executing scripts. This is an optional
+feature (disabled by default) and is enabled using the -c option of gant.
+
+Added the a LaTeX processing tool.
+
+
+0.2.3 (r4761)
+-------------
+
+Updated to use and work with Groovy 1.0 release.
+
+
+0.2.2 (r4329)
+-------------
+
+Licence changed from LGPL to ASL 2.0.
+
+Updated to use and work with Groovy 1.0 RC-1.
+
+Added gant.tool.Execute, works on Linux, Solaris and Mac OS X, not tested on Windows.
+
+Tidied up code and removed redundant bits.
+
+Package structure of the code changed.
+
+Enforced 1.4 class files.
+
+(There appears never to have been a version 0.2.1.)
+
+
+0.2.0 (r4160)
+------------
+
+First release of Gant.
+
+
+The Epoch (r3965)
+-----------------
+
+No release of 0.1.x of Gant ever made.
diff --git a/scripts/bash_completion.d/gant b/scripts/bash_completion.d/gant
new file mode 100644
index 0000000..fe41c74
--- /dev/null
+++ b/scripts/bash_completion.d/gant
@@ -0,0 +1,77 @@
+# -*- mode:shell-script -*-
+
+#  Gant -- A Groovy way of scripting Ant tasks.
+
+#  Copyright © 2006–2008, 2010, 2013  Russel Winder
+
+#  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.
+
+#  Programmable completion for the Groovy Ant (gant) command under bash.
+#  This file draws heavily on the rake and subversion file that come as standard with Bash 3.
+
+#  Author :  Russel Winder <russel at winder.org.uk>
+#  Licence : ASL 2.0
+
+_gant()
+{
+    local cur prev gantf i
+
+    COMPREPLY=()
+    cur=${COMP_WORDS[COMP_CWORD]}
+    prev=${COMP_WORDS[COMP_CWORD-1]}
+    gantf="build.gant"
+
+    if [[ "$prev" == "-f" || "$prev" == "-l" ]]; then
+        _filedir
+        return 0
+    fi
+
+    if [[ "$cur" == *=* ]]; then
+        prev=${cur/=*/}
+        cur=${cur/*=/}
+        if [[ "$prev" == "--gantfile=" || "$prev" == "--gantlib=" || "$prev" == "--lib=" ]]; then
+            _filedir -o nospace
+            return 0
+        fi
+    fi
+
+    if [[ "$cur" == -* ]]; then
+        COMPREPLY=( $( compgen -W '-q --quiet -s --silent\
+            -h --help\
+            -T --targets -p --projecthelp\
+            -f '--gantfile='\
+            -l '--gantlib='
+            --lib='\
+            -- $cur ))
+    else
+
+        for (( i=0; i < ${#COMP_WORDS[@]}; i++)); do
+            case "${COMP_WORDS[i]}" in
+            -f|-file|-buildfile)
+                eval gantf=${COMP_WORDS[i+1]}
+                break
+                ;;
+            --gantfile=*|--gantfile\=*)
+                eval gantf=${COMP_WORDS[i]/*=/}
+                break
+                ;;
+            esac
+        done
+
+        [ ! -f $gantf ] && return 0
+
+        COMPREPLY=( $( gant -q -f "$gantf" -T | \
+            awk -F ' ' '/^gant / { print $2 }' | \
+            command grep "^$cur" ))
+
+    fi
+}
+complete -F _gant $filenames gant
diff --git a/scripts/bin/startGroovy.bat b/scripts/bin/startGroovy.bat
new file mode 100755
index 0000000..eb705fb
--- /dev/null
+++ b/scripts/bin/startGroovy.bat
@@ -0,0 +1,258 @@
+ at if "%DEBUG%" == "" @echo off
+ at rem ##########################################################################
+ at rem                                                                         ##
+ at rem  Groovy JVM Bootstrap for Windowz                                       ##
+ at rem                                                                         ##
+ at rem ##########################################################################
+
+ at rem
+ at rem $Revision$ $Date$
+ at rem
+
+ at rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal enabledelayedexpansion
+
+set DIRNAME=%~1
+shift
+
+set CLASS=%~1
+shift
+
+if exist "%USERPROFILE%/.groovy/preinit.bat" call "%USERPROFILE%/.groovy/preinit.bat"
+
+ at rem Determine the command interpreter to execute the "CD" later
+set COMMAND_COM="cmd.exe"
+if exist "%SystemRoot%\system32\cmd.exe" set COMMAND_COM="%SystemRoot%\system32\cmd.exe"
+if exist "%SystemRoot%\command.com" set COMMAND_COM="%SystemRoot%\command.com"
+
+ at rem Use explicit find.exe to prevent cygwin and others find.exe from being used
+set FIND_EXE="find.exe"
+if exist "%SystemRoot%\system32\find.exe" set FIND_EXE="%SystemRoot%\system32\find.exe"
+if exist "%SystemRoot%\command\find.exe" set FIND_EXE="%SystemRoot%\command\find.exe"
+
+:check_JAVA_HOME
+ at rem Make sure we have a valid JAVA_HOME
+if not "%JAVA_HOME%" == "" goto have_JAVA_HOME
+set PATHTMP=%PATH%
+:loop
+for /f "delims=; tokens=1*" %%i in ("!PATHTMP!") do (
+    if exist "%%i\..\bin\java.exe" (
+        set "JAVA_HOME=%%i\.."
+        goto found_JAVA_HOME
+    )
+    set PATHTMP=%%j
+    goto loop
+)
+goto check_default_JAVA_EXE
+
+:found_JAVA_HOME
+ at rem Remove trailing \bin\.. from JAVA_HOME
+if "%JAVA_HOME:~-7%"=="\bin\.." SET "JAVA_HOME=%JAVA_HOME:~0,-7%"
+set JAVA_EXE=%JAVA_HOME%\bin\java.exe
+
+:check_default_JAVA_EXE
+if not "%JAVA_HOME%" == "" goto valid_JAVA_HOME
+java -version 2>NUL
+if not ERRORLEVEL 1 goto default_JAVA_EXE
+
+echo.
+echo ERROR: Environment variable JAVA_HOME has not been set.
+echo Attempting to find JAVA_HOME from PATH also failed.
+goto common_error
+
+:have_JAVA_HOME
+ at rem Remove trailing slash from JAVA_HOME if found
+if "%JAVA_HOME:~-1%"=="\" SET JAVA_HOME=%JAVA_HOME:~0,-1%
+
+ at rem Validate JAVA_HOME
+%COMMAND_COM% /C DIR "%JAVA_HOME%" 2>&1 | %FIND_EXE% /I /C "%JAVA_HOME%" >nul
+if not errorlevel 1 goto valid_JAVA_HOME_DIR
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+
+:common_error
+echo Please set the JAVA_HOME variable in your environment
+echo to match the location of your Java installation.
+goto end
+
+:default_JAVA_EXE
+set JAVA_EXE=java.exe
+goto check_GROOVY_HOME
+
+:valid_JAVA_HOME_DIR
+set JAVA_EXE=%JAVA_HOME%\bin\java.exe
+if exist "%JAVA_EXE%" goto valid_JAVA_HOME
+
+echo.
+echo ERROR: No java.exe found at: %JAVA_EXE%
+goto common_error
+
+:valid_JAVA_HOME
+if exist "%JAVA_HOME%\lib\tools.jar" set TOOLS_JAR=%JAVA_HOME%\lib\tools.jar
+
+:check_GROOVY_HOME
+ at rem Define GROOVY_HOME if not set
+if "%GROOVY_HOME%" == "" set GROOVY_HOME=%DIRNAME%..
+
+ at rem Remove trailing slash from GROOVY_HOME if found
+if "%GROOVY_HOME:~-1%"=="\" SET GROOVY_HOME=%GROOVY_HOME:~0,-1%
+
+ at rem classpath handling
+set _SKIP=2
+set CP=
+if "x%~1" == "x-cp" set CP=%~2
+if "x%~1" == "x-classpath" set CP=%~2
+if "x%~1" == "x--classpath" set CP=%~2
+if "x" == "x%CP%" goto init
+set _SKIP=4
+shift
+shift
+
+:init
+ at rem get name of script to launch with full path
+set GROOVY_SCRIPT_NAME=%~f1
+ at rem Get command-line arguments, handling Windowz variants
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+ at rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+rem horrible roll your own arg processing inspired by jruby equivalent
+
+rem escape minus (-d), quotes (-q), star (-s).
+set _ARGS=%*
+if not defined _ARGS goto execute
+set _ARGS=%_ARGS:-=-d%
+set _ARGS=%_ARGS:"=-q%
+rem Windowz will try to match * with files so we escape it here
+rem but it is also a meta char for env var string substitution
+rem so it can't be first char here, hack just for common cases.
+rem If in doubt use a space or bracket before * if using -e.
+set _ARGS=%_ARGS: *= -s%
+set _ARGS=%_ARGS:)*=)-s%
+set _ARGS=%_ARGS:0*=0-s%
+set _ARGS=%_ARGS:1*=1-s%
+set _ARGS=%_ARGS:2*=2-s%
+set _ARGS=%_ARGS:3*=3-s%
+set _ARGS=%_ARGS:4*=4-s%
+set _ARGS=%_ARGS:5*=5-s%
+set _ARGS=%_ARGS:6*=6-s%
+set _ARGS=%_ARGS:7*=7-s%
+set _ARGS=%_ARGS:8*=8-s%
+set _ARGS=%_ARGS:9*=9-s%
+
+rem prequote all args for 'for' statement
+set _ARGS="%_ARGS%"
+
+set _ARG=
+:win9xME_args_loop
+rem split args by spaces into first and rest
+for /f "tokens=1,*" %%i in (%_ARGS%) do call :get_arg "%%i" "%%j"
+goto process_arg
+
+:get_arg
+rem remove quotes around first arg
+for %%i in (%1) do set _ARG=%_ARG% %%~i
+rem set the remaining args
+set _ARGS=%2
+rem remove the leading space we'll add the first time
+if "x%_ARG:~0,1%" == "x " set _ARG=%_ARG:~1%
+rem return
+goto :EOF
+
+:process_arg
+if "%_ARG%" == "" goto execute
+
+rem collect all parts of a quoted argument containing spaces
+if not "%_ARG:~0,2%" == "-q" goto :argIsComplete
+if "%_ARG:~-2%" == "-q" goto :argIsComplete
+rem _ARG starts with a quote but does not end with one:
+rem  add the next part to _ARG until the matching quote is found
+goto :win9xME_args_loop
+
+:argIsComplete
+if "x4" == "x%_SKIP%" goto skip_4
+if "x3" == "x%_SKIP%" goto skip_3
+if "x2" == "x%_SKIP%" goto skip_2
+if "x1" == "x%_SKIP%" goto skip_1
+
+rem now unescape -q, -s, -d
+set _ARG=%_ARG:-s=*%
+set _ARG=%_ARG:-q="%
+set _ARG=%_ARG:-d=-%
+
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %_ARG%
+set _ARG=
+goto win9xME_args_loop
+
+:skip_4
+set _ARG=
+set _SKIP=3
+goto win9xME_args_loop
+
+:skip_3
+set _ARG=
+set _SKIP=2
+goto win9xME_args_loop
+
+:skip_2
+set _ARG=
+set _SKIP=1
+goto win9xME_args_loop
+
+:skip_1
+set _ARG=
+set _SKIP=0
+goto win9xME_args_loop
+
+:4NT_args
+ at rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+ at rem Setup the command line
+set STARTER_CLASSPATH=%GROOVY_HOME%\lib\@GROOVYJAR@
+
+if exist "%USERPROFILE%/.groovy/init.bat" call "%USERPROFILE%/.groovy/init.bat"
+
+ at rem Setting a classpath using the -cp or -classpath option means not to use
+ at rem the global classpath. Groovy behaves then the same as the java
+ at rem interpreter
+if "x" == "x%CP%" goto empty_cp
+:non_empty_cp
+set CP=%CP%;.
+goto after_cp
+:empty_cp
+set CP=.
+if "x" == "x%CLASSPATH%" goto after_cp
+set CP=%CLASSPATH%;%CP%
+:after_cp
+
+set STARTER_MAIN_CLASS=org.codehaus.groovy.tools.GroovyStarter
+set STARTER_CONF=%GROOVY_HOME%\conf\groovy-starter.conf
+
+set GROOVY_OPTS="-Xmx128m"
+set GROOVY_OPTS=%GROOVY_OPTS% -Dprogram.name="%PROGNAME%"
+set GROOVY_OPTS=%GROOVY_OPTS% -Dgroovy.home="%GROOVY_HOME%"
+if not "%TOOLS_JAR%" == "" set GROOVY_OPTS=%GROOVY_OPTS% -Dtools.jar="%TOOLS_JAR%"
+set GROOVY_OPTS=%GROOVY_OPTS% -Dgroovy.starter.conf="%STARTER_CONF%"
+set GROOVY_OPTS=%GROOVY_OPTS% -Dscript.name="%GROOVY_SCRIPT_NAME%"
+
+if exist "%USERPROFILE%/.groovy/postinit.bat" call "%USERPROFILE%/.groovy/postinit.bat"
+
+ at rem Execute Groovy
+"%JAVA_EXE%" %GROOVY_OPTS% %JAVA_OPTS% -classpath "%STARTER_CLASSPATH%" %STARTER_MAIN_CLASS% --main %CLASS% --conf "%STARTER_CONF%" --classpath "%CP%" %CMD_LINE_ARGS%
+
+:end
+ at rem End local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" endlocal
+
+ at rem Optional pause the batch file
+if "%GROOVY_BATCH_PAUSE%" == "on" pause
+%COMSPEC% /C exit /B %ERRORLEVEL%
diff --git a/scripts/bin_requiresGroovy/gant b/scripts/bin_requiresGroovy/gant
new file mode 100755
index 0000000..327e454
--- /dev/null
+++ b/scripts/bin_requiresGroovy/gant
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+#  Gant -- A Groovy way of scripting Ant tasks.
+#
+#  Copyright © 2006–2010, 2013  Russel Winder
+#
+#  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 : Russel Winder <russel at winder.org.uk>
+
+#  Gant initiation script for Linux and UNIX -- requires Groovy version.
+
+#  Solaris 10 does not have readlink as standard -- though some people will have the version from
+#  Sunfreeware which is the same as the version on Ubuntu, Cygwin, MSYS, etc.  Mac OS X has a version of
+#  readlink that is very different to that on Ubuntu, Solaris/Sunfreeware, Cygwin, MSYS, etc.
+#
+#  This function attempts to just do the right thing.
+
+doReadLink() {
+    case `uname` in
+        Darwin)
+            gantLocation=`dirname $1`
+            gantPath=`readlink "$1"`
+            if [ "$gantPath" = "" ]
+            then
+                readlinkValue="$1"
+            else
+                linkDir=`dirname $gantPath`
+                currentDirectory=`pwd`
+                cd $gantLocation
+                cd $linkDir
+                gantLocation=`pwd`
+                gantPath=`basename $gantPath`
+                readlinkValue="$gantLocation/$gantPath"
+                cd $currentDirectory
+            fi
+            ;;
+        SunOS)
+            readlinkPath=`which readlink`
+            if [ `expr "$readlinkPath" : '\([^ ]*\)'` = "no" ]
+            then
+                echo "No readlink command available, please set $2."
+                exit 1
+            else
+                readlinkValue=`readlink -f $1`
+            fi
+            ;;
+        *)
+            readlinkValue=`readlink -f $1`
+            ;;
+    esac
+}
+
+#  If GANT_HOME is not set, deduce a path.  Assume the executable is in $GANT_HOME/bin.
+
+if [ -z "$GANT_HOME" ]
+then
+    if [ -h $0 ]
+    then
+        doReadLink $0 GANT_HOME
+        GANT_HOME=$readlinkValue
+        GANT_HOME=`dirname $GANT_HOME`
+    else
+        GANT_HOME=`dirname $0`
+    fi
+    GANT_HOME=`dirname $GANT_HOME`
+fi
+
+#  If GROOVY_HOME is not set, deduce a path -- this is needed in order to discover the location of the
+#  startGroovy script.  Assume the executable is in $GROOVY_HOME/bin.
+
+if [ -z "$GROOVY_HOME" ]
+then
+    GROOVY_HOME=`which groovy`
+    if [ -h $GROOVY_HOME ]
+    then
+        doReadLink $GROOVY_HOME GROOVY_HOME
+        GROOVY_HOME=$readlinkValue
+    fi
+    GROOVY_HOME=`dirname "$GROOVY_HOME"`
+    GROOVY_HOME=`dirname "$GROOVY_HOME"`
+fi
+
+#  If ANT_HOME is not set, deduce a path -- this is needed in order to discover the location of the jars
+#  associated with the Ant installation.  Assume the executable is in $ANT_HOME/bin.
+
+if [ -z "$ANT_HOME" ]
+then
+    ANT_HOME=`which ant`
+    if [ -h $ANT_HOME ]
+    then
+        doReadLink $ANT_HOME ANT_HOME
+        ANT_HOME=$readlinkValue
+    fi
+    ANT_HOME=`dirname "$ANT_HOME"`
+    ANT_HOME=`dirname "$ANT_HOME"`
+fi
+
+GROOVY_APP_NAME=Gant
+GROOVY_CONF="$GANT_HOME/conf/gant-starter.conf"
+
+. "$GROOVY_HOME/bin/startGroovy"
+
+if $cygwin
+then
+    GANT_HOME=`cygpath --mixed "$GANT_HOME"`
+    ANT_HOME=`cygpath --mixed "$ANT_HOME"`
+fi
+JAVA_OPTS="$JAVA_OPTS -Dgant.home=$GANT_HOME -Dant.home=$ANT_HOME"
+
+startGroovy gant.Gant "$@"
diff --git a/scripts/bin_requiresGroovy/gant.bat b/scripts/bin_requiresGroovy/gant.bat
new file mode 100755
index 0000000..11fa41c
--- /dev/null
+++ b/scripts/bin_requiresGroovy/gant.bat
@@ -0,0 +1,71 @@
+ at if "%DEBUG%" == "" @echo off
+
+ at rem  Gant -- A Groovy way of scripting Ant tasks.
+ at rem
+ at rem  Copyright © 2008,2010 Russel Winder
+ at rem
+ at rem  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
+ at rem  compliance with the License. You may obtain a copy of the License at
+ at rem
+ at rem    http://www.apache.org/licenses/LICENSE-2.0
+ at rem
+ at rem  Unless required by applicable law or agreed to in writing, software distributed under the License is
+ at rem  distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ at rem  implied. See the License for the specific language governing permissions and limitations under the
+ at rem  License.
+ at rem
+ at rem  Author : Russel Winder <russel at winder.org.uk>
+
+ at rem  Gant initiation script for Windows.
+
+ at rem Set local scope for the variables with windows NT shell
+if "%OS%" == "Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.\
+
+ at rem If GANT_HOME is not set, deduce a path.
+
+if not "%GANT_HOME%" == "" goto endSetGantHome
+   set GANT_HOME="%DIRNAME%.."
+:endSetGantHome
+
+ at rem  If GROOVY_HOME is not set, deduce a path -- this is needed in order to discover the location of the
+ at rem  startGroovy script.
+
+if not "%GROOVY_HOME%" == "" goto endSetGroovyHome
+   for %%P in ( %PATH% ) do if exist %%P\groovy.exe set GROOVY_HOME=%%P\..
+   if not "%GROOVY_HOME%" == "" goto endSetGroovyHome
+   for %%P in ( %PATH% ) do if exist %%P\groovy.bat set GROOVY_HOME=%%P\..
+   if not "%GROOVY_HOME%" == "" goto endSetGroovyHome
+      call :environmentVariableError GROOVY_HOME
+      goto :EOF
+:endSetGroovyHome
+
+ at rem  If ANT_HOME is not set, deduce a path -- this is needed in order to discover the location of the jars
+ at rem  asscoiated with the Ant installation.
+
+if not "%ANT_HOME%" == "" goto endSetAntHome
+   for %%P in ( %PATH% ) do if exist %%P\ant.bat set ANT_HOME=%%P\..
+   if not "%ANT_HOME%" == "" goto endSetAntHome
+      call :environmentVariableError ANT_HOME
+      goto :EOF
+:endSetAntHome
+
+set PROGNAME=gant.bat
+set GROOVY_SCRIPT_NAME=gant.bat
+set STARTER_CONF="%GANT_HOME%\conf\gant-starter.conf"
+set JAVA_OPTS=%JAVA_OPTS% -Dgant.home="%GANT_HOME%" -Dant.home="%ANT_HOME%"
+
+"%GANT_HOME%\bin\startGroovy.bat" "%DIRNAME%" gant.Gant %*
+
+ at rem End local scope for the variables with windows NT shell
+if "%OS%" == "Windows_NT" endlocal
+
+%COMSPEC% /C exit /B %ERRORLEVEL%
+
+:environmentVariableError
+ echo.
+ echo ERROR: Environment variable %1 has not been set.
+ echo Attempting to find %1 from PATH also failed.
+ goto :EOF
diff --git a/scripts/bin_standalone/gant b/scripts/bin_standalone/gant
new file mode 100755
index 0000000..bbf7843
--- /dev/null
+++ b/scripts/bin_standalone/gant
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+#  Gant -- A Groovy way of scripting Ant tasks.
+#
+#  Copyright © 2006–2010, 2013  Russel Winder
+#
+#  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 : Russel Winder <russel at winder.org.uk>
+
+#  Gant initiation script for Linux and UNIX -- stand alone version.
+
+#  This version does not require a GROOVY_HOME to be set since it has all the necessary jars in the
+#  $GANT_HOME/lib directory.
+
+#  Solaris 10 does not have readlink as standard -- though some people will have the version from
+#  Sunfreeware which is the same as the version on Ubuntu, Cygwin, MSYS, etc.  Mac OS X has a version of
+#  readlink that is very different to that on Ubuntu, Solaris/Sunfreeware, Cygwin, MSYS, etc.
+#
+#  This function attempts to just do the right thing.
+
+doReadLink() {
+    case `uname` in
+        Darwin)
+            gantLocation=`dirname $1`
+            gantPath=`readlink "$1"`
+            if [ "$gantPath" = "" ]
+            then
+                readlinkValue="$1"
+            else
+                linkDir=`dirname $gantPath`
+                currentDirectory=`pwd`
+                cd $gantLocation
+                cd $linkDir
+                gantLocation=`pwd`
+                gantPath=`basename $gantPath`
+                readlinkValue="$gantLocation/$gantPath"
+                cd $currentDirectory
+            fi
+            ;;
+        SunOS)
+            readlinkPath=`which readlink`
+            if [ `expr "$readlinkPath" : '\([^ ]*\)'` = "no" ]
+            then
+                echo "No readlink command available, please set $2."
+                exit 1
+            else
+                readlinkValue=`readlink -f $1`
+            fi
+            ;;
+        *)
+            readlinkValue=`readlink -f $1`
+            ;;
+    esac
+}
+
+#  If GANT_HOME is not set, deduce a path.  Assume the executable is in $GANT_HOME/bin.
+
+if [ -z "$GANT_HOME" ]
+then
+    if [ -h $0 ]
+    then
+        doReadLink $0 GANT_HOME
+        GANT_HOME=$readlinkValue
+        GANT_HOME=`dirname $GANT_HOME`
+    else
+        GANT_HOME=`dirname $0`
+    fi
+    GANT_HOME=`dirname $GANT_HOME`
+fi
+
+#  Force GROOVY_HOME to be GANT_HOME so that the startGroovy code does the right thing.
+
+GROOVY_HOME="$GANT_HOME"
+
+#  If ANT_HOME is not set, deduce a path -- this is needed in order to discover the location of the jars
+#  associated with the Ant installation.  Assume the executable is in $ANT_HOME/bin.
+
+if [ -z "$ANT_HOME" ]
+then
+    ANT_HOME=`which ant`
+    if [ -h $ANT_HOME ]
+    then
+        doReadLink $ANT_HOME ANT_HOME
+        ANT_HOME=$readlinkValue
+    fi
+    ANT_HOME=`dirname "$ANT_HOME"`
+    ANT_HOME=`dirname "$ANT_HOME"`
+fi
+
+GROOVY_APP_NAME=Gant
+GROOVY_CONF="$GANT_HOME/conf/gant-starter.conf"
+
+. "$GROOVY_HOME/bin/startGroovy"
+
+if $cygwin
+then
+    GANT_HOME=`cygpath --mixed "$GANT_HOME"`
+    ANT_HOME=`cygpath --mixed "$ANT_HOME"`
+fi
+JAVA_OPTS="$JAVA_OPTS -Dgant.home=$GANT_HOME -Dant.home=$ANT_HOME"
+
+startGroovy gant.Gant "$@"
diff --git a/scripts/bin_standalone/gant.bat b/scripts/bin_standalone/gant.bat
new file mode 100755
index 0000000..855c19f
--- /dev/null
+++ b/scripts/bin_standalone/gant.bat
@@ -0,0 +1,63 @@
+ at if "%DEBUG%" == "" @echo off
+
+ at rem  Gant -- A Groovy way of scripting Ant tasks.
+ at rem
+ at rem  Copyright © 2008,2010 Russel Winder
+ at rem
+ at rem  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
+ at rem  compliance with the License. You may obtain a copy of the License at
+ at rem
+ at rem    http://www.apache.org/licenses/LICENSE-2.0
+ at rem
+ at rem  Unless required by applicable law or agreed to in writing, software distributed under the License is
+ at rem  distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ at rem  implied. See the License for the specific language governing permissions and limitations under the
+ at rem  License.
+ at rem
+ at rem  Author : Russel Winder <russel at winder.org.uk>
+
+ at rem  Gant initiation script for Windows.
+
+ at rem Set local scope for the variables with windows NT shell
+if "%OS%" == "Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.\
+
+ at rem If GANT_HOME is not set, deduce a path.
+
+if not "%GANT_HOME%" == "" goto endSetGantHome
+   set GANT_HOME="%DIRNAME%.."
+:endSetGantHome
+
+ at rem  Force GROOVY_HOME to be GANT_HOME so that the startGroovy code does the right thing.
+
+set GROOVY_HOME="%GANT_HOME%"
+
+ at rem  If ANT_HOME is not set, deduce a path -- this is needed in order to discover the location of the jars
+ at rem  asscoiated with the Ant installation.
+
+if not "%ANT_HOME%" == "" goto endSetAntHome
+   for %%P in ( %PATH% ) do if exist %%P\ant.bat set ANT_HOME=%%P\..
+   if not "%ANT_HOME%" == "" goto endSetAntHome
+      call :environmentVariableError ANT_HOME
+      goto :EOF
+:endSetAntHome
+
+set PROGNAME=gant.bat
+set GROOVY_SCRIPT_NAME=gant.bat
+set STARTER_CONF="%GANT_HOME%\conf\gant-starter.conf"
+set JAVA_OPTS="%JAVA_OPTS%" -Dgant.home="%GANT_HOME%" -Dant.home="%ANT_HOME%"
+
+"%GANT_HOME%\bin\startGroovy.bat" "%DIRNAME%" gant.Gant %*
+
+ at rem End local scope for the variables with windows NT shell
+if "%OS%" == "Windows_NT" endlocal
+
+%COMSPEC% /C exit /B %ERRORLEVEL%
+
+:environmentVariableError
+ echo.
+ echo ERROR: Environment variable %1 has not been set.
+ echo Attempting to find %1 from PATH also failed.
+ goto :EOF
diff --git a/scripts/bin_standalone/startGroovy b/scripts/bin_standalone/startGroovy
new file mode 100755
index 0000000..365b1cb
--- /dev/null
+++ b/scripts/bin_standalone/startGroovy
@@ -0,0 +1,281 @@
+# -*- mode:sh -*-
+
+##############################################################################
+##                                                                          ##
+##  Groovy JVM Bootstrap for UN*X                                           ##
+##                                                                          ##
+##############################################################################
+
+##
+## $Revision$
+## $Date$
+##
+
+PROGNAME=`basename "$0"`
+
+#DIRNAME=`dirname "$0"`
+
+SCRIPT_PATH="$0"
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "${PROGNAME}: $*"
+}
+
+die ( ) {
+    warn "$*"
+    exit 1
+}
+
+earlyInit ( ) {
+    return
+}
+
+lateInit ( ) {
+    return
+}
+
+GROOVY_STARTUP="$HOME/.groovy/startup"
+if [ -r "$GROOVY_STARTUP" ] ; then
+    . "$GROOVY_STARTUP"
+fi
+
+earlyInit
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;; 
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+if [ "$1" = "-cp" -o "$1" = "-classpath" -o "$1" = "--classpath" ] ; then
+    CP=$2
+    shift 2
+fi
+
+# Attempt to set JAVA_HOME if it's not already set.
+if [ -z "$JAVA_HOME" ] ; then
+    if $darwin ; then 
+        [ -z "$JAVA_HOME" -a -f "/usr/libexec/java_home" ] && export JAVA_HOME=`/usr/libexec/java_home`
+        [ -z "$JAVA_HOME" -a -d "/Library/Java/Home" ] && export JAVA_HOME="/Library/Java/Home"
+        [ -z "$JAVA_HOME" -a -d "/System/Library/Frameworks/JavaVM.framework/Home" ] && export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Home"
+    else
+        javaExecutable="`which javac`"
+        [ -z "$javaExecutable" -o "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ] && die "JAVA_HOME not set and cannot find javac to deduce location, please set JAVA_HOME."
+        # readlink(1) is not available as standard on Solaris 10.
+        readLink=`which readlink`
+        [ `expr "$readLink" : '\([^ ]*\)'` = "no" ] && die "JAVA_HOME not set and readlink not available, please set JAVA_HOME."
+        javaExecutable="`readlink -f \"$javaExecutable\"`"
+        javaHome="`dirname \"$javaExecutable\"`"
+        javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+        JAVA_HOME="$javaHome"
+        export JAVA_HOME
+
+    fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$GROOVY_HOME" ] && GROOVY_HOME=`cygpath --unix "$GROOVY_HOME"`
+    [ -n "$JAVACMD" ] && JAVACMD=`cygpath --unix "$JAVACMD"`
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+    [ -n "$CP" ] && CP=`cygpath --path --unix "$CP"`
+else
+    if [ -n "$GROOVY_HOME" -a `expr "$GROOVY_HOME":'\/$'` ] ; then
+        GROOVY_HOME=`echo $GROOVY_HOME | sed -e 's/\/$//'`
+    fi
+fi
+
+#  For MSYS, ensure paths are in appropriate format.
+if $msys
+then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`( cd "$JAVA_HOME" ; pwd )`
+fi
+
+# Attempt to set GROOVY_HOME if it is not already set.
+if [ -z "$GROOVY_HOME" -o ! -d "$GROOVY_HOME" ] ; then
+    # Resolve links: $0 may be a link to groovy's home.
+    PRG="$0"
+    # Need this for relative symlinks.
+    while [ -h "$PRG" ] ; do
+        ls=`ls -ld "$PRG"`
+        link=`expr "$ls" : '.*-> \(.*\)$'`
+        if expr "$link" : '/.*' > /dev/null; then
+            PRG="$link"
+        else
+            PRG=`dirname "$PRG"`"/$link"
+        fi
+    done
+    SAVED="`pwd`"
+    cd "`dirname \"$PRG\"`/.."
+    GROOVY_HOME="`pwd -P`"
+    cd "$SAVED"
+fi
+
+# Set the default Groovy config if no specific one is mentioned.
+if [ -z "$GROOVY_CONF" ] ; then
+    GROOVY_CONF="$GROOVY_HOME/conf/groovy-starter.conf"
+fi
+STARTER_CLASSPATH="$GROOVY_HOME/lib/@GROOVYJAR@"
+
+# Create the final classpath. Setting a classpath using the -cp or -classpath option means not to use the
+# global classpath. Groovy behaves then the same as the java interpreter
+if [ -n "$CP" ] ; then
+    CP="$CP":.
+elif [ -n "$CLASSPATH" ] ; then
+    CP="$CLASSPATH":.
+else
+    CP=.
+fi
+
+# Determine the Java command to use to start the JVM.
+if [ -z "$JAVACMD" ] ; then
+    if [ -n "$JAVA_HOME" ] ; then
+        if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+            # IBM's JDK on AIX uses strange locations for the executables
+            JAVACMD="$JAVA_HOME/jre/sh/java"
+        else
+            JAVACMD="$JAVA_HOME/bin/java"
+        fi
+    else
+        JAVACMD="java"
+    fi
+fi
+if [ ! -x "$JAVACMD" ] ; then
+    die "JAVA_HOME is not defined correctly, can not execute: $JAVACMD"
+fi
+if [ -z "$JAVA_HOME" ] ; then
+    warn "JAVA_HOME environment variable is not set"
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query businessSystem maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# Setup Profiler
+useprofiler=false
+if [ "$PROFILER" != "" ] ; then
+    if [ -r "$PROFILER" ] ; then
+        . $PROFILER
+        useprofiler=true
+    else
+        die "Profiler file not found: $PROFILER"
+    fi
+fi
+
+# For Darwin, use classes.jar for TOOLS_JAR
+TOOLS_JAR="$JAVA_HOME/lib/tools.jar"
+#if $darwin; then
+#    TOOLS_JAR="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Classes/classes.jar"
+#fi
+
+# For Darwin, add GROOVY_APP_NAME to the JAVA_OPTS as -Xdock:name
+if $darwin; then
+    JAVA_OPTS="$JAVA_OPTS -Xdock:name=$GROOVY_APP_NAME -Xdock:icon=$GROOVY_HOME/bin/groovy.icns"
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    GROOVY_HOME=`cygpath --mixed "$GROOVY_HOME"`
+    JAVA_HOME=`cygpath --mixed "$JAVA_HOME"`
+    GROOVY_CONF=`cygpath --mixed "$GROOVY_CONF"`
+    CP=`cygpath --path --mixed "$CP"`    
+    TOOLS_JAR=`cygpath --mixed "$TOOLS_JAR"`
+    STARTER_CLASSPATH=`cygpath --path --mixed "$STARTER_CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GROOVY_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GROOVY_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        if [ $CHECK -ne 0 ] ; then
+            patched=`cygpath --path --ignore --mixed "$arg"`
+        else
+            patched="$arg"
+        fi
+        if [ x"$BASH" = x ]; then
+            eval `echo args$i`="\"$arg\""
+        else
+            args[$i]="$patched"
+        fi
+        i=`expr $i + 1`
+    done
+
+    if [ x"$BASH" = x ]; then
+        case $i in
+            0) set -- ;;
+            1) set -- "$args0" ;;
+            2) set -- "$args0" "$args1" ;;
+            3) set -- "$args0" "$args1" "$args2" ;;
+            4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+            5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+            6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+            7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+            8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+            9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+        esac
+    else
+        set -- "${args[@]}"
+    fi
+fi
+
+startGroovy ( ) {
+    CLASS=$1
+    shift
+    # Start the Profiler or the JVM
+    if $useprofiler ; then
+        runProfiler
+    else
+        exec "$JAVACMD" $JAVA_OPTS \
+            -classpath "$STARTER_CLASSPATH" \
+            -Dscript.name="$SCRIPT_PATH" \
+            -Dprogram.name="$PROGNAME" \
+            -Dgroovy.starter.conf="$GROOVY_CONF" \
+            -Dgroovy.home="$GROOVY_HOME" \
+            -Dtools.jar="$TOOLS_JAR" \
+            $STARTER_MAIN_CLASS \
+            --main $CLASS \
+            --conf "$GROOVY_CONF" \
+            --classpath "$CP" \
+            "$@"
+    fi
+}
+
+STARTER_MAIN_CLASS=org.codehaus.groovy.tools.GroovyStarter
+
+lateInit
diff --git a/scripts/bnd/groovy.bnd b/scripts/bnd/groovy.bnd
new file mode 100644
index 0000000..efe1b73
--- /dev/null
+++ b/scripts/bnd/groovy.bnd
@@ -0,0 +1,4 @@
+version = @GANT_BUNDLE_VERSION@
+-nouses = true
+Export-Package = *;version=${version}
+Import-Package = org.codehaus.groovy , org.apache.tools.ant , org.apache.commons.cli , *;resolution:=optional
diff --git a/scripts/conf/gant-starter.conf b/scripts/conf/gant-starter.conf
new file mode 100644
index 0000000..75aef00
--- /dev/null
+++ b/scripts/conf/gant-starter.conf
@@ -0,0 +1,44 @@
+#  Gant -- A Groovy way of scripting Ant tasks.
+#
+#  Copyright © 2008, 2010, 2013  Russel Winder
+#
+#  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 : Russel Winder <russel at winder.org.uk>
+
+# Load user specific libraries that are Gant specific.
+load !{user.home}/.gant/lib/*.jar
+
+# Load user specific libraries that are Ant specific.
+load !{user.home}/.ant/lib/*.jar
+
+# Load user specific libraries that are for Groovy.
+load !{user.home}/.groovy/lib/*.jar
+
+# Load required libraries
+load !{gant.home}/lib/*.jar
+
+# Load Ant libraries.  If xml-apis.jar and xercesImpl.jar are in this directory then it leads to a:
+#
+#  Caught: java.lang.LinkageError: loader constraint violation: loader (instance of <bootloader>) previously initiated loading for a different type with name "org/w3c/dom/NodeList"
+#
+# whenever an XML processing program that (possibly indirectly) uses a DOM is executed.  Get round this by
+# selecting jars, basically all the known Ant jars, and ignoring everything else.
+#
+#  The directory might contain ant.jar but it would be bad to include this since Groovy is distributed
+#  with a version of Ant and that should be used.  See next rule.
+load !{ant.home}/lib/ant-*.jar
+
+# load required libraries
+load !{groovy.home}/lib/*.jar
+
+# tools.jar for ant tasks
+load ${tools.jar}
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..5f4ffea
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,17 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2009--2011, 2013, 2014  Russel Winder
+//
+//  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: Russel Winder <russel at winder.org.uk>
+
+include 'gant', 'gant_groovy2.0', 'gant_groovy2.1', 'gant_groovy2.2', 'gant_groovy2.3'
diff --git a/src/integTest/groovy/org/codehaus/gant/ant/tests/GANT_80.gant b/src/integTest/groovy/org/codehaus/gant/ant/tests/GANT_80.gant
new file mode 100644
index 0000000..abd6188
--- /dev/null
+++ b/src/integTest/groovy/org/codehaus/gant/ant/tests/GANT_80.gant
@@ -0,0 +1,19 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2009 Russel Winder
+//
+//  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.
+
+target ( 'default' : '' ) {
+  println ( 'From println.' )
+  System.err.println ( 'On standard error.' )
+  echo ( message : 'From ant.echo.' )
+}
diff --git a/src/integTest/groovy/org/codehaus/gant/ant/tests/GANT_80.xml b/src/integTest/groovy/org/codehaus/gant/ant/tests/GANT_80.xml
new file mode 100644
index 0000000..888c085
--- /dev/null
+++ b/src/integTest/groovy/org/codehaus/gant/ant/tests/GANT_80.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+Gant - A Groovy way of scripting Ant tasks.
+
+Copyright © 2009-10 Russel Winder
+
+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 : Russel Winder <russel at winder.org.uk>
+-->
+
+<project name="GANT-80 Test" default="default" basedir=".">
+
+  <import file="commonBits.xml"/>
+
+  <target name="default" depends="-defineGantTask">
+    <gant file="GANT_80.gant"/>
+  </target>
+
+</project>
diff --git a/src/integTest/groovy/org/codehaus/gant/ant/tests/Gant_Test.java b/src/integTest/groovy/org/codehaus/gant/ant/tests/Gant_Test.java
new file mode 100644
index 0000000..46e965f
--- /dev/null
+++ b/src/integTest/groovy/org/codehaus/gant/ant/tests/Gant_Test.java
@@ -0,0 +1,414 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008-10 Russel Winder
+//
+//  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.codehaus.gant.ant.tests ;
+
+import java.io.BufferedReader ;
+import java.io.File ;
+import java.io.IOException ;
+import java.io.InputStream ;
+import java.io.InputStreamReader ;
+
+import java.util.ArrayList ;
+import java.util.List ;
+
+import junit.framework.TestCase ;
+
+import org.apache.tools.ant.BuildException ;
+import org.apache.tools.ant.Project ;
+import org.apache.tools.ant.ProjectHelper ;
+
+import org.apache.tools.ant.util.StringUtils ;
+
+/**
+ *  Unit tests for the Gant Ant task.  In order to test things appropriately this test must be initiated
+ *  without any of the Groovy, Gant or related jars in the class path.  Also of course it must be a JUnit
+ *  test with no connection to Groovy or Gant.
+ *
+ *  @author Russel Winder
+ */
+public class Gant_Test extends TestCase {
+  private final String endOfTargetMarker = "------ " ;
+  private final String separator = System.getProperty ( "file.separator" ) ;
+  private final boolean isWindows = System.getProperty ( "os.name" ).startsWith ( "Windows" ) ;
+  private final String locationPrefix = ( "Gradle".equals ( System.getProperty ( "buildFrameworkIdentifier" ) ) ? ".." + separator : "" ) ;
+  private final String path ; {
+    final StringBuilder sb = new StringBuilder ( ) ;
+    sb.append ( "src" ) ;
+    sb.append ( separator ) ;
+    sb.append ( "test" ) ;
+    sb.append ( separator ) ;
+    sb.append ( "groovy" ) ;
+    sb.append ( separator ) ;
+    sb.append ( "org" ) ;
+    sb.append ( separator ) ;
+    sb.append ( "codehaus" ) ;
+    sb.append ( separator ) ;
+    sb.append ( "gant" ) ;
+    sb.append ( separator ) ;
+    sb.append ( "ant" ) ;
+    sb.append ( separator ) ;
+    sb.append ( "tests" ) ;
+    path = sb.toString ( ) ;
+  }
+  private final String canonicalPath ; {
+    try { canonicalPath = ( new File ( locationPrefix + path ) ).getCanonicalPath ( ) ; }
+    catch ( final IOException ioe ) { throw new RuntimeException ( "Path calculation failure." , ioe ) ; }
+  }
+  private final File antFile =  new File ( canonicalPath , "gantTest.xml" ) ;
+  private Project project ;
+  //  This variable is assigned in the Gant script hence the public static.
+  public static String returnValue ;
+
+  @Override protected void setUp ( ) throws Exception {
+    super.setUp ( ) ;
+    project = new Project ( ) ;
+    project.init ( ) ;
+    ProjectHelper.configureProject ( project , antFile ) ;
+    returnValue = "" ;
+  }
+
+  public void testDefaultFileDefaultTarget ( ) {
+    project.executeTarget ( "gantTestDefaultFileDefaultTarget" ) ;
+    assertEquals ( "A test target in the default file." , returnValue ) ;
+  }
+  public void testDefaultFileNamedTarget ( ) {
+    project.executeTarget ( "gantTestDefaultFileNamedTarget" ) ;
+    assertEquals ( "Another target in the default file." , returnValue ) ;
+  }
+  public void testNamedFileDefaultTarget ( ) {
+    project.executeTarget ( "gantTestNamedFileDefaultTarget" ) ;
+    assertEquals ( "A test target in the default file." , returnValue ) ;
+  }
+  public void testNamedFileNamedTarget ( ) {
+    project.executeTarget ( "gantTestNamedFileNamedTarget" ) ;
+    assertEquals ( "Another target in the default file." , returnValue ) ;
+  }
+  public void testGantWithParametersAsNestedTags ( ) {
+    project.executeTarget ( "gantWithParametersAsNestedTags" ) ;
+    assertEquals ( "gant -Dflob=adob -Dburble gantParameters" , returnValue ) ;
+  }
+  public void testMultipleGantTargets ( ) {
+    project.executeTarget ( "gantWithMultipleTargets" ) ;
+    assertEquals ( "A test target in the default file.Another target in the default file." , returnValue ) ;
+  }
+  public void testUnknownTarget ( ) {
+    try { project.executeTarget ( "blahBlahBlahBlah" ) ; }
+    catch ( final BuildException be ) {
+      assertEquals ( "Target \"blahBlahBlahBlah\" does not exist in the project \"Gant Ant Task Test\". " , be.getMessage ( ) ) ;
+      return ;
+    }
+    fail ( "Should have got a BuildException." ) ;
+  }
+  public void testMissingGantfile ( ) {
+    try { project.executeTarget ( "missingGantfile" ) ; }
+    catch ( final BuildException be ) {
+      assertEquals ( "Gantfile does not exist." , be.getMessage ( ) ) ;
+      return ;
+    }
+    fail ( "Should have got a BuildException." ) ;
+  }
+  /*
+   *  Test for the taskdef-related verify error problem.  Whatever it was supposed to do it passes now,
+   *  2008-04-14.
+   */
+  public void testTaskdefVerifyError ( ) {
+    project.executeTarget ( "gantTaskdefVerifyError" ) ;
+    assertEquals ( "OK." , returnValue ) ;
+  }
+  /*
+   *  A stream gobbler for the spawned process used by the <code>runAnt</code> method in the following
+   *  tests.
+   *
+   *  @author Russel Winder
+   */
+  private static final class StreamGobbler implements Runnable {
+    private final InputStream is ;
+    private final StringBuilder sb ;
+    public StreamGobbler ( final InputStream is , final StringBuilder sb ) {
+      this.is = is ;
+      this.sb = sb ;
+    }
+    public void run ( ) {
+      try {
+        final BufferedReader br = new BufferedReader ( new InputStreamReader ( is ) ) ;
+        while ( true ) {
+          final String line = br.readLine ( ) ;  //  Can throw an IOException hence the try block.
+          if ( line == null ) { break ; }
+          sb.append ( line ).append ( '\n' ) ;
+        }
+      }
+      catch ( final IOException ignore ) { fail ( "Got an IOException reading a line in the read thread." ) ; }
+    }
+  }
+  /*
+   *  Run Ant in a separate process.  Return the standard output and the standard error that results as a
+   *  List<String> with two items, item 0 is standard output and item 1 is standard error.
+   *
+   *  <p>This method assumes that either the environment variable ANT_HOME is set to a complete Ant
+   *  installation or that the command ant (ant.bat on Windows) is in the path.</p>
+   *
+   *  <p>As at 2008-12-06 Canoo CruiseControl runs with GROOVY_HOME set to /usr/local/java/groovy, and
+   *  Codehaus Bamboo runs without GROOVY_HOME being set.</p>
+   *
+   *  @param xmlFile the path to the XML file that Ant is to use.
+   *  @param target the target to run, pass "" or null for the default target.
+   *  @param expectedReturnCode the return code that the Ant execution should return.
+   *  @param withClasspath whether the Ant execution should use the full classpath so as to find all the classes.
+   */
+  private List<String> runAnt ( final String xmlFile , final String target , final int expectedReturnCode , final boolean withClasspath ) {
+    final List<String> command = new ArrayList<String> ( ) ;
+    final String antHomeString = System.getenv ( "ANT_HOME" ) ;
+    String antCommand ;
+    if ( antHomeString != null ) { antCommand = antHomeString + separator + "bin" + separator  + "ant" ; }
+    else { antCommand = "ant" ; }
+    if ( isWindows ) {
+      command.add ( "cmd.exe" ) ;
+      command.add ( "/c" ) ;
+      antCommand += ".bat" ;
+    }
+    command.add ( antCommand ) ;
+    command.add ( "-f" ) ;
+    command.add ( xmlFile ) ;
+    if ( withClasspath ) {
+      final String classpathString = "Gradle".equals ( System.getProperty ( "buildFrameworkIdentifier" ) )
+              ? System.getenv ( "gradleClasspathString" )
+              : System.getProperty ( "java.class.path" ) ;
+      for ( final String p : classpathString.split ( System.getProperty ( "path.separator" ) ) ) {
+        command.add ( "-lib" ) ;
+        command.add ( p ) ;
+      }
+    }
+    if ( ( target != null ) && ! target.trim ( ).equals ( "" ) ) { command.add ( target ) ; }
+    final ProcessBuilder pb = new ProcessBuilder ( command ) ;
+    final StringBuilder outputStringBuilder = new StringBuilder ( ) ;
+    final StringBuilder errorStringBuilder = new StringBuilder ( ) ;
+    try {
+      final Process p = pb.start ( ) ;  //  Could throw an IOException hence the try block.
+      final Thread outputGobbler = new Thread ( new StreamGobbler ( p.getInputStream ( ) , outputStringBuilder ) ) ;
+      final Thread errorGobbler = new Thread ( new StreamGobbler ( p.getErrorStream ( ) , errorStringBuilder ) ) ;
+      outputGobbler.start ( ) ;
+      errorGobbler.start ( ) ;
+      try { assertEquals ( expectedReturnCode , p.waitFor ( ) ) ; }
+      catch ( final InterruptedException ignore ) { fail ( "Got an InterruptedException waiting for the Ant process to finish." ) ; }
+      try { outputGobbler.join ( ) ;}
+      catch ( final InterruptedException ignore ) { fail ( "Got an InterruptedException waiting for the output gobbler to terminate." ) ; }
+      try { errorGobbler.join ( ) ;}
+      catch ( final InterruptedException ignore ) { fail ( "Got an InterruptedException waiting for the error gobbler to terminate." ) ; }
+      final List<String> returnList = new ArrayList<String> ( ) ;
+      returnList.add ( outputStringBuilder.toString ( ) ) ;
+      returnList.add ( errorStringBuilder.toString ( ) ) ;
+      return returnList ;
+    }
+    catch ( final IOException ignore ) { fail ( "Got an IOException from starting the process." ) ; }
+    //  Keep the compiler happy, it doesn't realize that execution cannot get here -- i.e. that fail is a non-returning function.
+    return null ;
+  }
+  /**
+   *  The output due to the targets in commonBits.xml.
+   */
+  private final String commonTargetsList = "-defineGantTask:\n\n" ;
+  /*
+   *  Tests stemming from GANT-19 and relating to ensuring the right classpath when loading the Groovyc Ant
+   *  task.
+   */
+  private String createBaseMessage ( ) {
+    final StringBuilder sb = new StringBuilder ( ) ;
+    sb.append ( "Buildfile: " ) ;
+    sb.append ( canonicalPath ).append ( separator ) ;
+    sb.append ( "gantTest.xml\n\n" ) ;
+    sb.append ( commonTargetsList ) ;
+    sb.append ( "gantTestDefaultFileDefaultTarget:\n" ) ;
+    return sb.toString ( ) ;
+  }
+  private String trimTimeFromSuccessfulBuild ( final String message ) {
+    return message.replaceFirst ( "Total time: [0-9]*.*" , "" ) ;
+  }
+  public void testRunningAntFromShellFailsNoClasspath ( ) {
+    //  On Windows the ant.bat file always returns zero :-(
+    final List<String> result = runAnt ( antFile.getPath ( ) , null , ( isWindows ? 0 : 1 ) , false ) ;
+    assert result.size ( ) == 2 ;
+    //assertEquals ( createBaseMessage ( ) , result.get ( 0 ) ) ;
+    final String errorResult = result.get ( 1 ) ;
+    //
+    //  TODO :  Correct this test.
+    //
+    assertTrue ( errorResult.startsWith ( "\nBUILD FAILED\n" ) ) ;
+    //assertTrue ( errorResult.contains ( "org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed" ) ) ;
+    //assertTrue ( errorResult.contains ( "build: 15: unable to resolve class org.codehaus.gant.ant.tests.Gant_Test\n @ line 15, column 1.\n" ) ) ;
+  }
+  public void testRunningAntFromShellSuccessful ( ) {
+    final List<String> result = runAnt ( antFile.getPath ( ) , null , 0 , true ) ;
+    assert result.size ( ) == 2 ;
+    assertEquals ( createBaseMessage ( ) + "test:\n" + endOfTargetMarker + "test\n\nBUILD SUCCESSFUL\n\n", trimTimeFromSuccessfulBuild ( result.get ( 0 ) ) ) ;
+    assertEquals ( "" , result.get ( 1 ) ) ;
+  }
+  /*
+   *  The following tests are based on the code presented in email exchanges on the Groovy developer list by
+   *  Chris Miles.  cf.  GANT-50.  This assumes that the tests are run from a directory other than this one.
+   */
+  private final String basedirAntFilePath = locationPrefix + path + separator + "basedir.xml" ;
+
+  private String createMessageStart ( final String target , final String taskName , final boolean extraClassPathDefinition ) {
+    final StringBuilder sb = new StringBuilder ( ) ;
+    sb.append ( "Buildfile: " ) ;
+    sb.append ( canonicalPath ) ; 
+    sb.append ( separator ) ;
+    sb.append ( "basedir.xml\n     [echo] basedir::ant basedir=" ) ;
+    sb.append ( canonicalPath ) ;
+    sb.append ( "\n\n-define" ) ;
+    sb.append ( taskName ) ;
+    sb.append ( "Task:\n\n" ) ;
+    sb.append ( target ) ;
+    sb.append ( ":\n" ) ;
+    return sb.toString ( ) ;
+  }
+  public void testBasedirInSubdirDefaultProjectForGant ( ) {
+    final String target = "defaultProject" ;
+    final StringBuilder sb = new StringBuilder ( ) ;
+    sb.append ( createMessageStart ( target , "Groovy" , true ) ) ;
+    sb.append ( "   [groovy] basedir::groovy basedir=" ) ;
+    sb.append ( canonicalPath ) ;
+    sb.append ( "\n   [groovy] default:\n   [groovy] \n   [groovy] basedir::gant basedir=" ) ;
+    //
+    //  Currently a Gant object instantiated in a Groovy task in an Ant script does not inherit the basedir
+    //  of the "calling" Ant.  Instead it assumes it is rooted in the process start directory.  According to
+    //  GANT-50 this is an error.  The question is to decide whether it is or not.
+    //
+    //  TODO : Should this be sb.append ( canonicalPath ) ?  cf. GANT-50.
+    //
+    sb.append ( System.getProperty ( "user.dir" ) ) ;
+    //sb.append ( canonicalPath ) ;
+    sb.append ( "\n   [groovy] " + endOfTargetMarker + "default\n   [groovy] \n\nBUILD SUCCESSFUL\n\n" ) ;
+    final List<String> result = runAnt ( basedirAntFilePath , target , 0 , true ) ;
+    assert result.size ( ) == 2 ;
+    assertEquals ( sb.toString ( ) , trimTimeFromSuccessfulBuild ( result.get ( 0 ) ) ) ;
+    assertEquals ( "" , result.get ( 1 ) ) ;
+  }
+  public void testBasedirInSubdirExplicitProjectForGant ( ) {
+    final String target = "explicitProject" ;
+    final StringBuilder sb = new StringBuilder ( ) ;
+    sb.append ( createMessageStart ( target , "Groovy" , true ) ) ;
+    sb.append ( "   [groovy] basedir::groovy basedir=" ) ;
+    sb.append ( canonicalPath ) ;
+    //
+    //  In this case the instantiated Gant object is connected directly to the Project object instantiated
+    //  by Ant and so uses the same basedir.  However it seems that the output (and error) stream are not
+    //  routed through the bit of Ant that prefixes the output with the current task name. :-(
+    //
+    sb.append ( "\ndefault:\nbasedir::gant basedir=" ) ;
+    sb.append ( canonicalPath ) ;
+    sb.append ( "\n" + endOfTargetMarker + "default\n\nBUILD SUCCESSFUL\n\n" ) ;
+    final List<String> result = runAnt ( basedirAntFilePath , target , 0 , true ) ;
+    assert result.size ( ) == 2 ;
+    assertEquals ( sb.toString ( ) , trimTimeFromSuccessfulBuild ( result.get ( 0 ) ) ) ;
+    assertEquals ( "" , result.get ( 1 ) ) ;
+  }
+  public void testBasedirInSubdirGantTask ( ) {
+    final String target = "gantTask" ;
+    final StringBuilder sb = new StringBuilder ( ) ;
+    sb.append ( createMessageStart ( target , "Gant" , false ) ) ;
+    sb.append ( "default:\n     [gant] basedir::gant basedir=" ) ;
+    sb.append ( canonicalPath ) ;
+    sb.append ( "\n" + endOfTargetMarker + "default\n\nBUILD SUCCESSFUL\n\n" ) ;
+    final List<String> result = runAnt ( basedirAntFilePath , target , 0 , true ) ;
+    assert result.size ( ) == 2 ;
+    assertEquals ( sb.toString ( ) , trimTimeFromSuccessfulBuild ( result.get ( 0 ) ) ) ;
+    assertEquals ( "" , result.get ( 1 ) ) ;
+  }
+  //
+  //  Test the GANT-80 issues.
+  //
+  public void test_GANT_80 ( ) {
+    final String antFilePath = canonicalPath + separator + "GANT_80.xml" ;
+    final StringBuilder sb = new StringBuilder ( ) ;
+    sb.append ( "Buildfile: " ) ;
+    sb.append ( antFilePath ) ;
+    sb.append ( "\n\n" ) ;
+    sb.append ( commonTargetsList ) ;
+    sb.append ( "default:\ndefault:\n     [gant] From println.\n     [gant] On standard error.\n     [echo] From ant.echo.\n" + endOfTargetMarker + "default\n\nBUILD SUCCESSFUL\n\n" ) ;
+    final List<String> result = runAnt ( antFilePath , null , 0 , true ) ;
+    assert result.size ( ) == 2 ;
+    assertEquals ( sb.toString ( ) , trimTimeFromSuccessfulBuild ( result.get ( 0 ) ) ) ;
+    assertEquals ( "" , result.get ( 1 ) ) ;
+  }
+  //
+  //  Ensure that errors are handled correctly by checking one error return case.
+  //
+  public void testGantTaskErrorReturn ( ) {
+    final File file = new File ( canonicalPath , "testErrorCodeReturns.xml" ) ;
+    final String target = "usingGantAntTask" ;
+    final StringBuilder sb = new StringBuilder ( ) ;
+    sb.append ( "Buildfile: " ) ;
+    sb.append ( file.getPath ( ) ) ;
+    sb.append ( "\n\n" ) ;
+    sb.append ( commonTargetsList ) ;
+    sb.append ( target ) ;
+    sb.append ( ":\n" ) ;
+    final List<String> result = runAnt ( file.getPath ( ) , target , 1 , true ) ;
+    assert result.size ( ) == 2 ;
+    assertEquals ( sb.toString ( ) , trimTimeFromSuccessfulBuild ( result.get ( 0 ) ) ) ;
+    final String errorResult = result.get(1) ;
+    assertTrue ( errorResult.startsWith ( "\nBUILD FAILED\n" ) ) ;
+    assertTrue ( errorResult.contains ( file.getPath ( ) ) ) ;
+    assertTrue ( errorResult.contains ( "Gantfile does not exist." ) ) ;
+  }
+  /*
+   *  For the moment comment this out because there is no guarantee of a Gant installation.
+   *
+   *  TODO:  Find out how to set up a Gant installation so this can be tested.
+   *
+  public void testExecOfGantScriptReturnErrorCode ( ) {
+    final File file = new File ( path , "testErrorCodeReturns.xml" ) ;
+    final String target = "usingExec" ;
+    final StringBuilder sb = new StringBuilder ( ) ;
+    sb.append ( "Buildfile: " ) ;
+    sb.append ( file.getPath ( ) ) ;
+    sb.append ( "\n\n" ) ;
+    sb.append ( target ) ;
+    sb.append ( ":\n     [exec] Cannot open file  nonexistentGantFile.gant\n     [echo] ErrorLevel: 253\n\nBUILD SUCCESSFUL\n\n" ) ;
+    final List<String> result = runAnt ( file.getPath ( ) , target , 0 , true ) ;
+    assert result.size ( ) == 2 ;
+    assertEquals ( sb.toString ( ) , trimTimeFromSuccessfulBuild ( result.get ( 0 ) ) ) ;
+    assertEquals ( "     [exec] Result: 253\n" , result.get ( 1 ) ) ;
+  }
+  */
+  //
+  //  For dealing with GANT-110 -- thanks to Eric Van Dewoestine for providing the original --
+  //  subsequently amended as Gant evolves.
+  //
+  public void testInheritAll ( ) {
+    final List<String> result = runAnt ( antFile.getPath ( ) , "gantTestInheritAll" , 0 , true ) ;
+    @SuppressWarnings("unchecked") List<String> output = StringUtils.lineSplit ( result.get ( 0 ) ) ;
+    assertEquals ( "     [echo] ${gant.test.inheritAll}" , output.get ( 6 ) ) ;
+    assertEquals ( "gantInheritAll:" , output.get ( 8 ) ) ;
+    assertEquals ( "     [echo] ${gant.test.inheritAll}" , output.get ( 9 ) ) ;
+    assertEquals ( "gantInheritAll:" , output.get ( 11 ) ) ;
+    assertEquals ( "     [echo] gantInheritAllWorks" , output.get ( 12 ) ) ;
+  }
+  //
+  //  For dealing with GANT-111 -- thanks to Eric Van Dewoestine for providing the original --
+  //  subsequently amended as Gant evolves.
+  //
+  public void testGantTaskFail ( ) {
+    final List<String> result = runAnt ( antFile.getPath ( ) , "gantTestFail" , 1 , true ) ;
+    assert result.size ( ) == 2 ;
+    //  The path to the build file and the line number in that file are part of the output,
+    //  so check only the parts of the output that are guaranteed, i.e. not the line number.
+    final String errorMessage = trimTimeFromSuccessfulBuild ( result.get ( 1 ) ) ;
+    assertEquals ( "\nBUILD FAILED\n" + canonicalPath + "/gantTest.xml", errorMessage.substring ( 0 , errorMessage.indexOf ( ':' ) ) ) ; 
+    assertEquals ( ": test fail message\n\n\n" , errorMessage.substring ( errorMessage.lastIndexOf ( ':' ) ) ) ;
+  }
+  
+}
diff --git a/src/integTest/groovy/org/codehaus/gant/ant/tests/basedir.gant b/src/integTest/groovy/org/codehaus/gant/ant/tests/basedir.gant
new file mode 100644
index 0000000..071b0a7
--- /dev/null
+++ b/src/integTest/groovy/org/codehaus/gant/ant/tests/basedir.gant
@@ -0,0 +1,19 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008 Russel Winder
+//
+//  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.
+
+//  This test results from emails by Chris Miles on the Groovy Developer email list.  cf.  GANT-50.
+
+target ( 'default' : '' ) {
+  println ( "basedir::gant basedir=${ant.project.properties.basedir}" )
+}
diff --git a/src/integTest/groovy/org/codehaus/gant/ant/tests/basedir.xml b/src/integTest/groovy/org/codehaus/gant/ant/tests/basedir.xml
new file mode 100644
index 0000000..0fcb924
--- /dev/null
+++ b/src/integTest/groovy/org/codehaus/gant/ant/tests/basedir.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Gant - A Groovy way of scripting Ant tasks.
+
+Copyright © 2008-10 Russel Winder
+
+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 : Russel Winder <russel at winder.org.uk>
+
+This test results from emails by Chris Miles on the Groovy Developer email list.  cf. GANT-50.
+-->
+
+<project name="Basedir_Tests" basedir="." >
+
+  <!--
+     Assume that all the Gant and Groovy classes are on the underlying classpath.
+    -->
+  
+  <echo>basedir::ant basedir=${basedir}</echo>
+
+  <import file="commonBits.xml"/>
+  
+  <target name="defaultProject" depends="-defineGroovyTask"> 
+    <groovy>
+      println ( "basedir::groovy basedir=${ant.project.properties.basedir}" )
+      def gant = new gant.Gant ( )
+      gant.loadScript ( new File ( ant.project.properties.'basedir' + '/basedir.gant' ) )
+      gant.processTargets (  )
+    </groovy>
+  </target>
+  
+  <target name="explicitProject" depends="-defineGroovyTask">
+    <groovy>
+      println ( "basedir::groovy basedir=${ant.project.properties.basedir}" )
+      def gant = new gant.Gant ( ant.project )
+      gant.loadScript ( new File ( ant.project.properties.'basedir' + '/basedir.gant' ) )
+      gant.processTargets (  )
+    </groovy>
+  </target>
+  
+  <target name="gantTask" depends="-defineGantTask">
+    <gant file="basedir.gant"/>
+  </target>
+  
+</project>
diff --git a/src/integTest/groovy/org/codehaus/gant/ant/tests/build.gant b/src/integTest/groovy/org/codehaus/gant/ant/tests/build.gant
new file mode 100644
index 0000000..cfe2e48
--- /dev/null
+++ b/src/integTest/groovy/org/codehaus/gant/ant/tests/build.gant
@@ -0,0 +1,69 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008-10 Russel Winder
+//
+//  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.codehaus.gant.ant.tests.Gant_Test
+
+//  For some reason there has to be an ant. here :-(
+ant.property ( file : 'build.properties' )
+
+target ( test : 'A test target in the default file.' ) { Gant_Test.returnValue = Gant_Test.returnValue + test_description }
+
+target ( blah : 'Another target in the default file.' ) { Gant_Test.returnValue = Gant_Test.returnValue + blah_description }
+
+//// This build file has to work in two contexts.  If GROOVY_HOME is set in the environment then the jars
+//// from that installation of Groovy should be used so as to ensure testing in the right context.  If the
+//// environment does not have a GROOVY_HOME set then grab some specific versions to make things work.
+
+target ( gantTaskdefVerifyError : 'Check that a taskdef works.' ) {
+  final groovyHome = System.getenv ( ).'GROOVY_HOME'
+  //  Just ensure that the environment variables really have been brought in.
+  assert groovyHome == ant.project.properties.'environment.GROOVY_HOME'
+  if ( groovyHome != null ) {
+    taskdef ( name : 'groovyc' , classname: 'org.codehaus.groovy.ant.Groovyc' ) {
+      classpath {
+        fileset ( dir : groovyHome + '/lib' , includes : 'groovy*.jar' )
+        fileset ( dir : groovyHome + '/lib' , includes : 'commons-cli*.jar' )
+      }
+    }
+  }
+  //  Paths are relative to the directory in which this file resides.
+  def artifact = 'urn:maven-artifact-ant'
+  typedef ( resource : 'org/apache/maven/artifact/ant/antlib.xml' , uri : artifact ) {
+    classpath { fileset ( dir : toplevelDirectory + '/jarfiles' , includes : 'maven-ant-tasks-*.jar' ) }
+  }
+  def dependencyClasspathId = 'dependencyClasspath'
+  "${artifact}:dependencies" ( pathId : dependencyClasspathId ) {
+    dependency ( groupId : 'org.codehaus.groovy' , artifactId : 'groovy' , version : System.getenv ( ).GROOVY_ANT_TASK_TEST_VERSION )
+  }
+  taskdef ( name : 'groovyc' , classname: 'org.codehaus.groovy.ant.Groovyc' , classpathref : dependencyClasspathId )
+  Gant_Test.returnValue = 'OK.'
+}
+
+target ( gantParameters : '' ) {  
+  Gant_Test.returnValue = 'gant' + ( flob ? ' -Dflob=' + flob : '' ) + ( burble ? ' -Dburble' : '' ) + ' gantParameters' 
+}
+
+//  For dealing with GANT-110 -- thanks to Eric Van Dewoestine for providing this.
+
+target ( gantInheritAll : 'Check that a inheritAll works.' ) {
+  echo ( message : '${gant.test.inheritAll}' )
+}
+
+//  For dealing with GANT-111 -- thanks to Eric Van Dewoestine for providing this.
+
+target ( testFail : '' ){
+  fail ( message : 'test fail message' )
+}
+
+setDefaultTarget ( test )
diff --git a/src/integTest/groovy/org/codehaus/gant/ant/tests/build.properties b/src/integTest/groovy/org/codehaus/gant/ant/tests/build.properties
new file mode 100644
index 0000000..d3de258
--- /dev/null
+++ b/src/integTest/groovy/org/codehaus/gant/ant/tests/build.properties
@@ -0,0 +1 @@
+toplevelDirectory = ../../../../../../../..
diff --git a/src/integTest/groovy/org/codehaus/gant/ant/tests/commonBits.xml b/src/integTest/groovy/org/codehaus/gant/ant/tests/commonBits.xml
new file mode 100644
index 0000000..c087372
--- /dev/null
+++ b/src/integTest/groovy/org/codehaus/gant/ant/tests/commonBits.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+   Gant - A Groovy way of scripting Ant tasks.
+
+   Copyright © 2009-10 Russel Winder
+
+   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 : Russel Winder <russel at winder.org.uk>
+-->
+
+<project name="Common Ant File Bits for Gant Ant Task Test" xmlns:artifact="urn:maven-artifact-ant" basedir="." >
+
+  <!--
+     Assume that all the Gant and Groovy classes are on the underlying classpath.
+
+     Currently do the needful with the environment variable GROOVY_ANT_TASK_TEST_VERSION.
+    -->
+
+  <target name="-defineGroovyTask">
+    <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" />
+  </target>
+
+  <target name="-defineGantTask">
+    <taskdef name="gant" classname="org.codehaus.gant.ant.Gant"/>
+  </target>
+  
+</project>
diff --git a/src/integTest/groovy/org/codehaus/gant/ant/tests/gantTest.xml b/src/integTest/groovy/org/codehaus/gant/ant/tests/gantTest.xml
new file mode 100644
index 0000000..20eae8b
--- /dev/null
+++ b/src/integTest/groovy/org/codehaus/gant/ant/tests/gantTest.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+   Gant - A Groovy way of scripting Ant tasks.
+
+   Copyright © 2008-10 Russel Winder
+
+   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 : Russel Winder <russel at winder.org.uk>
+-->
+
+<project name="Gant Ant Task Test" default="gantTestDefaultFileDefaultTarget" basedir=".">
+
+  <import file="commonBits.xml"/>
+
+  <target name="gantTestDefaultFileDefaultTarget" depends="-defineGantTask">
+    <gant/>
+  </target>
+ 
+  <target name="gantTestDefaultFileNamedTarget" depends="-defineGantTask">
+    <gant target="blah"/>
+  </target>
+
+ <target name="gantTestNamedFileDefaultTarget" depends="-defineGantTask">
+    <gant file="build.gant"/>
+  </target>
+ 
+  <target name="gantTestNamedFileNamedTarget" depends="-defineGantTask">
+    <gant file="build.gant" target="blah"/>
+  </target>
+
+  <!--  Ensure there is no file of the name used in the Gant Ant task here. -->
+  <target name="missingGantfile" depends="-defineGantTask">
+    <gant file="blahBlahBlahBlah.blah"/>
+  </target>
+
+  <!--  Ensure there is no target called blahBlahBlahBlah. -->
+  <target name="gantTaskdefVerifyError" depends="-defineGantTask">
+    <gant file="build.gant" target="gantTaskdefVerifyError"/>
+  </target>
+
+  <target name="gantWithParametersAsNestedTags" depends="-defineGantTask">
+    <gant file="build.gant" target="gantParameters">
+      <definition name="flob" value="adob"/>
+      <definition name="burble"/>
+    </gant>
+  </target>
+
+  <target name="gantWithMultipleTargets" depends="-defineGantTask">
+    <gant>
+      <gantTarget value="test"/>
+      <gantTarget value="blah"/>
+    </gant>
+  </target>
+
+  <!-- For GANT-110.  Thanks to Eric Van Dewoestine for providing this. -->
+
+  <target name="gantTestInheritAll" depends="-defineGantTask">
+    <property name="gant.test.inheritAll" value="gantInheritAllWorks"/>
+    <gant file="build.gant" target="gantInheritAll"/>
+    <gant file="build.gant" target="gantInheritAll" inheritAll="false"/>
+    <gant file="build.gant" target="gantInheritAll" inheritAll="true"/>
+  </target>
+  
+  <!-- For GANT-111.  Thanks to Eric Van Dewoestine for providing this. -->
+
+  <target name="gantTestFail" depends="-defineGantTask">
+    <gant file="build.gant" target="testFail"/>
+  </target>
+  
+</project>
diff --git a/src/integTest/groovy/org/codehaus/gant/ant/tests/testErrorCodeReturns.xml b/src/integTest/groovy/org/codehaus/gant/ant/tests/testErrorCodeReturns.xml
new file mode 100644
index 0000000..f357e23
--- /dev/null
+++ b/src/integTest/groovy/org/codehaus/gant/ant/tests/testErrorCodeReturns.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+Gant - A Groovy way of scripting Ant tasks.
+
+Copyright © 2009-10 Russel Winder
+
+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 : Russel Winder <russel at winder.org.uk>
+-->
+
+<project name="Test" basedir=".">
+
+  <!--
+     Assume that all the Gant and Groovy classes are on the underlying classpath.
+    -->
+
+  <import file="commonBits.xml"/>
+
+  <target name="usingGantAntTask" depends="-defineGantTask">
+    <gant file="nonexistentGantFile.gant" />
+  </target>
+
+</project>
diff --git a/src/main/groovy/gant/Gant.groovy b/src/main/groovy/gant/Gant.groovy
new file mode 100644
index 0000000..fe8336a
--- /dev/null
+++ b/src/main/groovy/gant/Gant.groovy
@@ -0,0 +1,677 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2011, 2013  Russel Winder
+//
+//  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 gant
+
+import java.lang.reflect.InvocationTargetException
+
+import org.apache.commons.cli.GnuParser
+
+import org.apache.tools.ant.BuildListener
+import org.apache.tools.ant.Project
+
+import org.codehaus.gant.GantBinding
+import org.codehaus.gant.GantEvent
+import org.codehaus.gant.GantMetaClass
+import org.codehaus.gant.GantState
+
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.runtime.InvokerInvocationException
+
+/**
+ *  This class provides infrastructure and an executable command for using Groovy + AntBuilder as a build
+ *  tool in a way similar to Rake and SCons.  However, where Rake and SCons are dependency programming
+ *  systems based on Ruby and Python respectively, Gant is simply a way of scripting Ant tasks; the Ant
+ *  tasks do all the dependency management.
+ *
+ *  <p>A Gant build specification file (default name build.gant) is assumed to contain one or more targets.
+ *  Dependencies between targets are handled as function calls within functions, or by use of the depends
+ *  function. Execution of Ant tasks is by calling methods on the object referred to by `ant', which is
+ *  predefined as a <code>GantBuilder</code> instance.</p>
+ *
+ *  <p>On execution of the gant command, the Gant build specification is read and executed in the context of
+ *  a predefined binding.  An object referred to by `ant' is part of the binding so methods can use this
+ *  object to get access to the Ant tasks without having to create an object explicitly.  A method called
+ *  `target' is part of the predefined binding.  A target has two parameters, a single item map and a
+ *  closure.  The single item map has the target name as the key and the documentation about the target as
+ *  the value.  This documentation is used by the `gant -T' / `gant --targets' / `gant -p' command to
+ *  present a list of all the documented targets.</p>
+ *
+ *  <p>NB In the following example some extra spaces have had to be introduced because some of the patterns
+ *  look like comment ends:-(</p>
+ *
+ *  <p>A trivial example build specification is:</p>
+ *
+ *  <pre>
+ *      target(stuff: 'A target to do some stuff.') {
+ *        clean()
+ *        otherStuff()
+ *      }
+ *      target(otherStuff: 'A target to do some other stuff') {
+ *        depends(clean)
+ *      }
+ *      target(clean: 'Clean the directory and subdirectories') {
+ *        delete(dir: 'build', quiet: 'true')
+ *        delete(quiet: 'true') { fileset(dir: '.', includes: '** /*~,** /*.bak' , defaultexcludes: 'false') }
+ *      }
+ *      setDefaultTarget(stuff)
+ * </pre>
+ *
+ *  <p>or, using some a ready made targets class:</p>
+ *
+ *  <pre>
+ *      includeTargets << gant.targets.Clean
+ *      cleanPattern << [ '** / *~', '** / *.bak' ]
+ *      cleanDirectory << 'build'
+ *      target(stuff: 'A target to do some stuff.') {
+ *        clean()
+ *        otherStuff()
+ *      }
+ *      target(otherStuff: 'A target to do some other stuff') {
+ *        depends(clean)
+ *      }
+ *      setDefaultTarget(stuff)
+ *  </pre>
+ *
+ *  <p><em>Note that there is an space between the two asterisks and the solidus in the fileset line that
+ *  should notbe there, we have to have it in the source because asterisk followed by solidus is end of
+ *  comment in Groovy</em></p>
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ *  @author Graeme Rocher <graeme.rocher at gmail.com>
+ *  @author Peter Ledbrook
+ */
+final class Gant {
+  /**
+   *  The class name to use for a script provided as standard input.
+   */
+  private final standardInputClassName = 'standard_input'
+  /**
+   *  The class name to use for a script provided as an input stream.
+   */
+  private final streamInputClassName = 'stream_input'
+  /**
+   *  The class name to use for a script provided as plain text.
+   */
+  private final textInputClassName = 'text_input'
+   /**
+    *  Closure encapsulating how to load a cached, pre-compiled Gant script from the cache.
+    *
+    *  @param className The name of the class to be loaded.
+    *  @param lastModified ?
+    *  @param url The  URL of the cache
+    *  @return instance of the class.
+    */
+  private final loadClassFromCache = {className, lastModified, url  ->
+    try {
+      final classUrl = binding.classLoader.getResource("${className}.class")
+      if (classUrl) {
+        if (lastModified > classUrl.openConnection().lastModified) {
+          compileScript(cacheDirectory, url.text, className)
+        }
+      }
+      return binding.classLoader.loadClass(className).newInstance()
+    }
+    catch (Exception e) {
+      final fileText = url.text
+      compileScript(cacheDirectory, fileText, className)
+      return binding.groovyShell.parse(fileText, buildClassName)
+    }
+  }
+  /**
+   *  The name of the class actually used for compiling the script.
+   */
+  String buildClassName
+  /**
+   *  Determines whether Gant performs a dry-run or does it for real.
+   */
+  boolean dryRun = false
+  /**
+   *  Determines whether the scripts are cached or not. Defaults to <code>false</code>.
+   */
+  boolean useCache = false
+  /**
+   *  The location where the compiled scripts are cached. Defaults to "$USER_HOME/.gant/cache".
+   */
+  File cacheDirectory = new File("${System.properties.'user.home'}/.gant/cache")
+  /**
+   *  A list of strings containing the locations of Gant modules.
+   */
+  List<String> gantLib = []
+  /**
+   *  The script that will be run when { @link #processTargets() } is called. It is initialised when a
+   *  script is loaded. Note that it has a dynamic type because the script may be loaded from a different
+   *  class loader than the one used to load the Gant class. If we declared it as Script, there would likely
+   *  be ClassCastExceptions.
+   */
+  def script
+  /**
+   *  A bit of state to say whether to output a message about the build result.
+   */
+  private static boolean outputBuildTime = false
+  /**
+   *  The binding object used for this run of Gant.  This binding object replaces the standard one to ensure
+   *  that all the Gant specific things appear in the binding the script executes with.
+   */
+  private final GantBinding binding
+  /**
+   *  Default constructor -- creates a new instance of <code>GantBinding</code> for the script binding,
+   *  and the default class loader.
+   */
+  public Gant() { this((GantBinding)null) }
+  /**
+   *  Constructor that uses the passed <code>GantBinding</code> for the script binding, and the default
+   *  class loader.
+   *
+   *  @param b the <code>GantBinding</code> to use.
+   */
+  public Gant(GantBinding b) { this(b, null) }
+  /**
+   *  Constructor that uses the passed <code>GantBinding</code> for the script binding, and the passed
+   *  <code>ClassLoader</code> as the class loader.
+   *
+   *  @param b the <code>GantBinding</code> to use.
+   *  @param cl the <code>ClassLoader</code> to use.
+   */
+  public Gant(GantBinding b, ClassLoader cl) {
+    binding = b ?: new GantBinding()
+    binding.classLoader = cl ?: getClass().classLoader
+    binding.groovyShell = new GroovyShell((ClassLoader) binding.classLoader, binding)
+    final gantPackage = binding.classLoader.getPackage('gant')
+    binding.'gant.version' = gantPackage?.implementationVersion
+  }
+  /**
+   *  Constructor intended for use in code to be called from the Groovy Ant Task.
+   *
+   *  @param p the <code>org.apache.tools.ant.Project</code> to use.
+   */
+  public Gant(org.apache.tools.ant.Project p) { this(new GantBinding(p)) }
+  /**
+   *  Add a <code>BuildListener</code> instance to this <code>Gant</code> instance.
+   */
+  public void addBuildListener(final BuildListener buildListener) {
+    binding.addBuildListener(buildListener)
+  }
+  /**
+   *  Remove a <code>BuildListener</code> instance from this <code>Gant</code> instance
+   */
+  public void removeBuildListener(final BuildListener buildListener) {
+    binding.removeBuildListener(buildListener)
+  }
+  /**
+   *  Treat the given text as a Gant script and load it.
+   *
+   *  @params text The text of the Gant script to load.
+   *  @return The <code>Gant</code> instance (to allow chaining).
+   */
+  public Gant loadScript(String text) {
+    if (! buildClassName) { buildClassName = textInputClassName }
+    script = binding.groovyShell.parse(text, buildClassName)
+    binding.'gant.file' = '<text>'
+    return this
+  }
+  /**
+   *  Load a Gant script from the given input stream, using the default Groovy encoding to convert the
+   *  bytes to characters.
+   *
+   *  @params scriptSource The stream containing the Gant script source, i.e. the Groovy code, not the
+   *  compiled class.
+   *  @return The <code>Gant</code> instance (to allow chaining).
+   */
+  public Gant loadScript(InputStream scriptSource) {
+    if (! buildClassName) { buildClassName = streamInputClassName }
+    script = binding.groovyShell.parse(new InputStreamReader(scriptSource), buildClassName)
+    binding.'gant.file' = '<stream>'
+    return this
+  }
+  /**
+   *  Load a Gant script from the given file, using the default Groovy encoding to convert the bytes
+   *  to characters.
+   *
+   *  @params scriptFile The file containing the Gant script source, i.e. the Groovy code, not the
+   *  compiled class.
+   *  @return The <code>Gant</code> instance (to allow chaining).
+   */
+  public Gant loadScript(File scriptFile) {
+    return loadScript(scriptFile.toURI().toURL())
+  }
+  /**
+   *  Load a Gant script from the given URL, using the default Groovy encoding to convert the bytes
+   *  to characters.
+   *
+   *  @params scriptUrl The URL where the the Gant script source is located.
+   *  @return The <code>Gant</code> instance (to allow chaining).
+   */
+  public Gant loadScript(URL scriptUrl) {
+    if (! buildClassName) {
+      def filename = scriptUrl.path.substring(scriptUrl.path.lastIndexOf("/") + 1)
+      buildClassName = classNameFromFileName(filename)
+    }
+    if (useCache) {
+      if (binding.classLoader instanceof URLClassLoader) { binding.classLoader.addURL(cacheDirectory.toURI().toURL()) }
+      else { binding.classLoader.rootLoader?.addURL(cacheDirectory.toURI().toURL()) }
+      binding.loadClassFromCache =  loadClassFromCache
+      script = loadClassFromCache(buildClassName, scriptUrl.openConnection().lastModified, scriptUrl)
+    }
+    else { loadScript(scriptUrl.openStream()) }
+    binding.'gant.file' = scriptUrl.toString()
+    return this
+  }
+  /**
+   *  Load a pre-compiled Gant script using the configured class loader.
+   *
+   *  @params className The fully qualified name of the class to load.
+   *  @return The <code>Gant</code> instance (to allow chaining).
+   */
+  public Gant loadScriptClass(String className) {
+    script = binding.classLoader.loadClass(className).newInstance()
+    binding.'gant.file' = '<class>'
+    return this
+  }
+  /**
+   *  Create a class name from a file name.
+   *
+   *  <p>File names may have an extension, e.g. .groovy or .gant, which should be removed to create a class
+   *  name.  Also some characters that are valid in file names are not valid in class names and so must be
+   *  transformed.</p>
+   *
+   *  <p>Up to Gant 1.5.0 the algorithm was to simply transform '\\.' to '_'.  However this means that
+   *  build.groovy got transformed to build_groovy and this caused problems in Eclipse, cf. GANT-30.</p>
+   *
+   *  @param fileName The name of the file.
+   *  @return The transformed name.
+   */
+  private String classNameFromFileName(fileName) {
+    def index = fileName.lastIndexOf('.')
+    if (fileName[index..-1] in [ '.groovy', '.gant' ]) { fileName = fileName[0..<index] }
+    return fileName.replaceAll('\\.', '_')
+  }
+  /**
+   *  Filter the stacktrace of the exception so as to create a printable message with the line number of the
+   *  line in the script being executed that caused the exception.
+   *
+   *  @param exception The exception whose stack trace is to be filtered.
+   *  @return The filteres stacktrace information.
+   */
+  private String constructMessageFrom(exception) {
+    final buffer = new StringBuilder()
+    if (exception instanceof GantException) { exception = exception.cause }
+    for (stackEntry in exception.stackTrace) {
+      if ((stackEntry.fileName == buildClassName) && (stackEntry.lineNumber  != -1)) {
+        def sourceName = (buildClassName == standardInputClassName) ? 'Standard input' : buildClassName
+        buffer.append(sourceName + ', line ' + stackEntry.lineNumber + ' -- ')
+      }
+    }
+    if (exception instanceof InvocationTargetException) { exception = exception.cause }
+    if (exception instanceof InvokerInvocationException) { exception = exception.cause }
+    buffer.append('Error evaluating Gantfile: ' +((exception instanceof RuntimeException) ? exception.message : exception.toString()))
+    buffer.toString()
+  }
+  /**
+   *  Print of the list of targets for the -p and -T options.
+   *
+   *  @param targets The <code>List</code> (of <code>String</code>s) that is the list of targets to achieve.
+   *  @return The return code.
+   */
+  private Integer targetList(targets) {
+    def max = 0
+    binding.targetDescriptions.entrySet().each{item ->
+      final size = item.key.size()
+      if (size > max) { max = size }
+    }
+    println()
+    binding.targetDescriptions.entrySet().each{item ->
+      println(' ' + item.key + ' ' * (max - item.key.size()) + '  ' + item.value)
+    }
+    println()
+    String defaultTargetName = null
+    try {
+      final defaultTarget = binding.defaultTarget
+      assert defaultTarget.class == String
+      if (binding.getVariable(defaultTarget)) { defaultTargetName = defaultTarget }
+      if (defaultTargetName) { println('Default target is ' + defaultTargetName + '.') ; println() }
+    }
+    catch (MissingPropertyException mpe) { /* Intentionally blank. */ }
+    0
+  }
+  /**
+   *  Action the targets.
+   *
+   *  <p>Check to see if there is a finalizer defined in the script and if one is, ensures it is called
+   *  whether the script completed successfully or there was an exception.</p>
+   *
+   *  @param targets The <code>List</code> (of <code>String</code>s) that is the list of targets to achieve.
+   *  @return The return code.
+   */
+  private Integer dispatch(List<String> targets) {
+    Integer returnCode = 0
+    final attemptFinalize = {->
+      final finalizeTarget = owner.binding.getVariable('finalizeTarget')
+      try {
+        switch (finalizeTarget.class) {
+         case Closure:
+          finalizeTarget.call()
+          break
+         case String:
+          owner.binding.getVariable(finalizeTarget).call()
+          break
+         default:
+          throw new RuntimeException('Gant finalizer is neither a closure nor a name.')
+          break
+        }
+      }
+      catch (MissingPropertyException mme) { /* Intentionally blank. */ }
+      catch (Exception e) { throw new TargetExecutionException(e.toString(), e) }
+    }
+    final processDispatch = {target ->
+      try {
+        owner.binding.forcedSettingOfVariable('initiatingTarget', target)
+        def returnValue = owner.binding.getVariable(target).call()
+        returnCode = (returnValue instanceof Number) ? returnValue.intValue() : 0
+      }
+      catch (MissingPropertyException mme) {
+        attemptFinalize()
+        if (target == mme.property) { throw new MissingTargetException("Target ${target} does not exist.", mme) }
+        else { throw new TargetMissingPropertyException(mme.message, mme) }
+      }
+      catch (Exception e) {
+        attemptFinalize()
+        throw new TargetExecutionException(e.toString(), e)
+      }
+    }
+    //  As part of GANT-77 output information about the buildfile.
+    ////binding.ant.project.log('Buildfile: ' + binding.'gant.file' + '\n\n')
+    //  To support GANT-44 the script must have access to the targets and be able to edit it, this means
+    //  iterating over the list of targets but knowing that if might change during execution.  So replace
+    //  the original code:
+    //
+    //    if (targets.size() > 0) { withBuildListeners { targets.each { target -> processDispatch(target) } } }
+    //
+    //  with something a little more amenable to alteration of the list mid loop.
+    binding.forcedSettingOfVariable('targets', targets)
+    if (targets.size() > 0) {
+      withBuildListeners {
+        while (targets.size() > 0) {
+          processDispatch(targets[0])
+          targets.remove(0)
+        }
+      }
+    }
+    else {
+      final defaultTarget = binding.defaultTarget
+      assert defaultTarget.class == String
+      withBuildListeners { processDispatch(defaultTarget) }
+    }
+    attemptFinalize()
+    returnCode
+  }
+  /**
+   *  Execute a dispatch with all the <code>BuildListener</code>s informed.
+   */
+  private withBuildListeners(Closure callable) {
+      final event = new GantEvent((Project)binding.ant.antProject, (GantBinding)binding)
+      try {
+        binding.buildListeners.each{BuildListener listener -> listener.buildStarted(event)}
+        callable.call()
+        binding.buildListeners.each{BuildListener listener -> listener.buildFinished(event)}
+      }
+      catch (Exception e) {
+        event.exception = e
+        binding.buildListeners.each{BuildListener listener -> listener.buildFinished(event)}
+        throw e
+      }
+  }
+  /**
+   *  Process the command line options and then call the function to process the targets.
+   */
+  public Integer processArgs(String[] args) {
+    final rootLoader = binding.classLoader.rootLoader
+    def buildSource = new File("build.gant")
+    //
+    //  Commons CLI 1.0 and 1.1 are broken.  1.0 has one set of ideas about multiple args and is broken.
+    //  1.1 has a different set of ideas about multiple args and is broken. 1.2 appears to be actually
+    //  fixed.  Multiple args are handled in the 1.0 semantics and are not broken:-)
+    //
+    //  1.0 PosixParser silently absorbs unknown single letter options.
+    //
+    //  1.0 cannot deal with options having only a long form as the access mechanism that works only works
+    //  for short form.  This is fixed in 1.1 and 1.2.
+    //
+    //  The PosixParser does not handle incorrectly formed options at all well.  Also the standard printout
+    //  actually assumes GnuParser form.  So although PosixParser is the default for CliBuilder, we actually
+    //  want GnuParser.
+    //
+    //  We can either specify the parser explicitly or simply say "do not use the PosixParser".  The latter
+    //  does of course require knowing that setting posix to false causes the GnuParser to be used.  This
+    //  information is only gleanable by reading the source code.  Given that the BasicParser is more or
+    //  less totally useless and there are only three parsers available, there is not a big issue here.
+    //  However, be explicit for comprehensibility.
+    //
+    //def cli = new CliBuilder(usage: 'gant [option]* [target]*', posix: false)
+    def cli = new CliBuilder(usage: 'gant [option]* [target]*', parser: new GnuParser())
+    cli.c(longOpt: 'usecache', 'Whether to cache the generated class and perform modified checks on the file before re-compilation.')
+    cli.d(longOpt: 'debug', 'Print debug levels of information.')
+    cli.f(longOpt: 'file', args: 1, argName: 'build-file', 'Use the named build file instead of the default, build.gant.')
+    cli.h(longOpt: 'help', 'Print out this message.')
+    cli.l(longOpt: 'gantlib', args: 1, argName: 'library', 'A directory that contains classes to be used as extra Gant modules,')
+    cli.n(longOpt: 'dry-run', 'Do not actually action any tasks.')
+    cli.p(longOpt: 'projecthelp', 'Print out a list of the possible targets.') // Ant uses -p|-projecthelp for this.
+    cli.q(longOpt: 'quiet', 'Do not print out much when executing.')
+    cli.s(longOpt: 'silent', 'Print out nothing when executing.')
+    cli.v(longOpt: 'verbose', 'Print lots of extra information.')
+    cli.C(longOpt: 'cachedir', args: 1, argName: 'cache-file', 'The directory where to cache generated classes to.')
+    cli.D(argName: 'name>=<value', args: 1, 'Define <name> to have value <value>.  Creates a variable named <name> for use in the scripts and a property named <name> for the Ant tasks.')
+    cli.L(longOpt: 'lib', args: 1, argName: 'path', 'Add a directory to search for jars and classes.')
+    cli.P(longOpt: 'classpath', args: 1, argName: 'path-list', 'Specify a path list to search for jars and classes.')
+    cli.T(longOpt: 'targets', 'Print out a list of the possible targets.') // Rake and Rant use -T|--tasks for this.
+    cli.V(longOpt: 'version', 'Print the version number and exit.')
+    def options = cli.parse(args)
+    if (options == null) { println('Error in processing command line options.') ; return -1 }
+    useCache = options.c ? true : false
+    if (options.f) {
+      if (options.f == '-') { buildSource = System.in ; buildClassName = standardInputClassName }
+      else { buildSource = new File((String) options.f) }
+    }
+    if (options.h) { cli.usage() ; return 0 }
+    if (options.l) { gantLib.addAll(options.l.split(System.properties.'path.separator') as List) }
+    if (options.n) { dryRun = true }
+    def function = (options.p || options.T) ? 'targetList' : 'dispatch'
+    if (options.d) { GantState.verbosity = GantState.DEBUG }
+    if (options.q) { GantState.verbosity = GantState.ERRORS_ONLY }
+    if (options.s) { GantState.verbosity = GantState.SILENT }
+    if (options.v) { GantState.verbosity = GantState.VERBOSE }
+    if (useCache && options.C) { cacheDirectory = new File((String) options.C) }
+    if (options.D) {
+      options.Ds.each { definition ->
+        def pair = definition.split('=') as List
+        if (pair.size() < 2) { pair << '' }
+        else if (pair.size() > 2) {
+          // Hack a solution to GROOVY-131. TODO: make this better.
+          def second = pair[1 .. -1].join('=')
+          if (second[0] == '"' && second[-1] !='"') { second = second[1 .. -1] }
+          pair = [pair[0], second]
+        }
+        //  Do not allow the output of the ant.property call to escape.  If the output is allowed out then
+        //  Ant, Gant, Maven, Eclipse and IntelliJ IDEA all behave slightly differently.  This makes testing
+        //  nigh on impossible.  Also the user doesn't need to know about these.
+        binding.ant.logger.messageOutputLevel = GantState.SILENT
+        binding.ant.property(name: pair[0], value: pair[1])
+        binding.ant.logger.messageOutputLevel = GantState.verbosity
+      }
+    }
+    if (options.L) {
+      options.Ls.each { String directoryName ->
+        def directory = new File(directoryName)
+        if (directory.isDirectory()) { directory.eachFile { item -> rootLoader?.addURL(item.toURL()) } }
+        else { println('Parameter to -L|--lib option is not a directory: ' + directory.name) }
+      }
+    }
+    if (options.P) { options.P.split(System.properties.'path.separator').each { String pathitem -> rootLoader?.addURL((new File(pathitem)).toURL()) } }
+    if (options.V) { println('Gant version ' + (binding.'gant.version' ?: '<unknown>')) ; return 0 }
+    //  The rest of the arguments appear to be delivered as a single string as the first item in a list.  This is surely an error but
+    //  with Commons CLI 1.0 it is the case.  So we must partition.  NB the split method delivers an array
+    //  of Strings so we cast to a List.
+    def targets = options.arguments()
+    if ((targets != null) && (targets.size() == 1)) { targets = targets[0].split(' ') as List }
+    def gotUnknownOptions = false ;
+    targets.each { target ->
+      if (target[0] == '-') {
+        println('Unknown option: ' + target)
+        gotUnknownOptions = true
+      }
+    }
+    if (gotUnknownOptions) { cli.usage() ; return -1 ; }
+    try { loadScript(buildSource) }
+    catch (FileNotFoundException fnfe) { binding.ant.project.log('Cannot open file ' + buildSource.name, Project.MSG_ERR) ; return -3 }
+    catch (Exception e) { binding.ant.project.log(constructMessageFrom(e), Project.MSG_ERR) ; return -2 }
+    script.metaClass = new GantMetaClass(script.metaClass, binding)
+    def defaultReturnCode = targets?.size() > 0 ? -11 : -12
+    outputBuildTime = function == 'dispatch'
+    try { return processTargets(function, targets) }
+    catch (TargetExecutionException tee) {
+      if (GantState.verbosity > GantState.NORMAL) { binding.ant.project.log(tee.message, tee, Project.MSG_ERR) }
+      else { binding.ant.project.log(tee.message, Project.MSG_ERR) }
+      return -13
+    }
+    catch (MissingTargetException mte) {
+      if (GantState.verbosity > GantState.NORMAL) { binding.ant.project.log(mte.message, mte, Project.MSG_ERR) }
+      else { binding.ant.project.log(mte.message, Project.MSG_ERR) }
+      return defaultReturnCode
+    }
+    catch (TargetMissingPropertyException tmpe) {
+      if (GantState.verbosity > GantState.NORMAL) { binding.ant.project.log(constructMessageFrom(tmpe), tmpe, Project.MSG_ERR) }
+      else { binding.ant.project.log(constructMessageFrom(tmpe), Project.MSG_ERR) }
+      return defaultReturnCode
+    }
+    catch (Exception e) {
+      if (GantState.verbosity > GantState.NORMAL) { binding.ant.project.log(constructMessageFrom(e), e, Project.MSG_ERR) }
+      else { binding.ant.project.log(constructMessageFrom(e), Project.MSG_ERR) }
+      return -4
+    }
+    //  Cannot get here.  Add an IntelliJ IDEA specific suppression.
+    //noinspection GroovyUnreachableStatement
+    assert 1 == 0
+  }
+  public Integer processTargets() { processTargets('dispatch', [ ]) }
+  public Integer processTargets(String s) { processTargets('dispatch', [ s ]) }
+  public Integer processTargets(List<String> l) { processTargets('dispatch', l) }
+  /**
+   *  Process the targets, but first execute the build script so all the targets and other code are available.
+   */
+  protected Integer processTargets(String function, List<String> targets) {
+    prepareTargets()
+    return executeTargets(function, targets)
+  }
+
+  /**
+   * <p>
+   * Executes a pre-prepared set of targets. This method is typically used in conjunction
+   * with #prepareTargets()</p>
+   *
+   * <pre>
+   *     gant.prepareTargets()
+   *     gant.executeTargets()
+   * </pre>
+   *
+   *  <p>
+   *  The #processTargets() method combines the above two methods
+   *  </p>
+   *
+   * @param function
+   * @param targets
+   * @return
+   */
+  public Integer executeTargets(String function = 'dispatch', List<String> targets = []) {
+	  (Integer) invokeMethod(function, targets)
+  }
+
+  /**
+   * Prepares Gant for execution returning the Gant script that will be used for the execution
+   *
+   * @return The Gant script to be used
+   */
+  public GroovyObject prepareTargets() {
+    // Configure the build based on this instance's settings.
+    if (dryRun) { GantState.dryRun = true }
+    //binding.ant.logger.setMessageOutputLevel(GantState.verbosity)
+    binding.cacheEnabled = useCache
+    binding.gantLib = gantLib
+    if (script == null) { throw new RuntimeException("No script has been loaded!") }
+    script.binding = binding
+    script.run()
+    return script
+  }
+  /**
+   * Sets all the pre hooks
+   */
+  void setAllPerTargetPreHooks(Closure<?> hook) {
+    if (script) { this.script.setAllPerTargetPreHooks(hook) } // Must use function call here, fails using property access.
+  }
+  /**
+   * Sets all the target post hooks
+   */
+  void setAllPerTargetPostHooks(Closure<?> hook) {
+    if (script) { this.script.setAllPerTargetPostHooks(hook) } // Must use function call here, fails using property access.
+  }
+  /**
+   *  Compile a script in the context of dealing with cached compiled build scripts.
+   */
+  private void compileScript(destDir, buildFileText, buildClassName) {
+    if (! destDir.exists()) { destDir.mkdirs() }
+    def configuration = new CompilerConfiguration()
+    configuration.targetDirectory = destDir
+    def unit = new CompilationUnit(configuration, null, new GroovyClassLoader((ClassLoader) binding.classLoader))
+    unit.addSource(buildClassName, new ByteArrayInputStream((byte[]) buildFileText.bytes))
+    unit.compile()
+  }
+  /**
+   *  Render the time interval for printing.
+   */
+  private static String renderTimeInterval(Number seconds) {
+    def buffer = new StringBuffer()
+    def render = { int value, String units ->
+                   buffer.append(value + ' ' + units)
+                   if (value > 1) { buffer.append('s') }
+                   buffer.append(' ')
+    }
+    if (seconds > 60) {
+      int minutes = seconds / 60
+      seconds -= minutes * 60
+      if (minutes > 60) {
+        int hours = minutes / 60
+        minutes -= hours * 60
+        render(hours, 'hour')
+      }
+      render(minutes, 'minute')
+    }
+    buffer.append(String.format('%.2f', seconds) + ' seconds')
+    return buffer.toString()
+  }
+  /**
+   *  The entry point for command line invocation.
+   */
+  public static void main(String[] args) {
+    def startTime = System.nanoTime()
+    def gant = new Gant()
+    def returnValue = gant.processArgs(args)
+    if (outputBuildTime) {
+      def terminateHook = gant.binding.getVariable('terminateHook')
+      if ((terminateHook != null) && (terminateHook instanceof Closure)) {
+        terminateHook.call(returnValue, renderTimeInterval((System.nanoTime() - startTime) / 1e9))
+      }
+    }
+    System.exit(returnValue)
+  }
+}
diff --git a/src/main/groovy/gant/GantException.java b/src/main/groovy/gant/GantException.java
new file mode 100644
index 0000000..9b63954
--- /dev/null
+++ b/src/main/groovy/gant/GantException.java
@@ -0,0 +1,35 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008, 2012, 2013 Peter Ledbrook
+//
+//  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 gant;
+
+//  Peter's original extended RuntimeException.  GANT-111 introduced the problem that this causes problems
+//  for usage with Ant tasks -- where the exception really needs to be a descendent of
+//  org.apache.tools.ant.BuildException.  Making this change should not affect stand alone activity.  Thanks
+//  to Eric Van Dewoestine for providing this change.
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ *  Generic Gant exception.
+ *
+ *  @author Peter Ledbrook
+ */
+public class GantException extends /*RuntimeException*/ BuildException {
+  public static final long serialVersionUID = 1;
+  public GantException() { super(); }
+  public GantException(final String msg) { super(msg); }
+  public GantException(final Exception e) { super(e); }
+  public GantException(final String msg, final Exception e) { super(msg, e); }
+}
diff --git a/src/main/groovy/gant/MissingTargetException.java b/src/main/groovy/gant/MissingTargetException.java
new file mode 100644
index 0000000..2dce7fc
--- /dev/null
+++ b/src/main/groovy/gant/MissingTargetException.java
@@ -0,0 +1,28 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008, 2012, 2013  Peter Ledbrook
+//
+//  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 gant;
+
+/**
+ *  Thrown when an undefined target is invoked.
+ *
+ *  @author Peter Ledbrook
+ */
+public class MissingTargetException extends GantException {
+  public static final long serialVersionUID = 1;
+  public MissingTargetException() { super(); }
+  public MissingTargetException(final String msg) { super(msg); }
+  public MissingTargetException(final Exception e) { super(e); }
+  public MissingTargetException(final String msg, final Exception e) { super(msg, e); }
+}
diff --git a/src/main/groovy/gant/TargetExecutionException.java b/src/main/groovy/gant/TargetExecutionException.java
new file mode 100644
index 0000000..b286e62
--- /dev/null
+++ b/src/main/groovy/gant/TargetExecutionException.java
@@ -0,0 +1,28 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008, 2013  Peter Ledbrook
+//
+//  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 gant;
+
+/**
+ *  Thrown when there is an error running a script.
+ *
+ *  @author Peter Ledbrook
+ */
+public class TargetExecutionException extends GantException {
+  public static final long serialVersionUID = 1;
+  public TargetExecutionException() { super(); }
+  public TargetExecutionException(final String msg) { super(msg); }
+  public TargetExecutionException(final Exception e) { super(e); }
+  public TargetExecutionException(final String msg, final Exception e) { super(msg, e); }
+}
diff --git a/src/main/groovy/gant/TargetMissingPropertyException.java b/src/main/groovy/gant/TargetMissingPropertyException.java
new file mode 100644
index 0000000..41da694
--- /dev/null
+++ b/src/main/groovy/gant/TargetMissingPropertyException.java
@@ -0,0 +1,30 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008, 2012, 2013  Peter Ledbrook
+//
+//  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 gant;
+
+import groovy.lang.MissingPropertyException;
+
+/**
+ *  Thrown when an undefined property is referenced during target execution.
+ *
+ *  @author Peter Ledbrook
+ */
+public class TargetMissingPropertyException extends GantException {
+  public static final long serialVersionUID = 1;
+  public TargetMissingPropertyException() { super(); }
+  public TargetMissingPropertyException(final String msg) { super(msg); }
+  public TargetMissingPropertyException(final MissingPropertyException e) { super(e); }
+  public TargetMissingPropertyException(final String msg, final MissingPropertyException e) { super(msg, e); }
+}
diff --git a/src/main/groovy/gant/package.html b/src/main/groovy/gant/package.html
new file mode 100644
index 0000000..76fecc0
--- /dev/null
+++ b/src/main/groovy/gant/package.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>gant</title>
+  </head>
+
+  <body>
+    <p>
+      This package contains the classes that realize the preconstructed targets and tools infrastructure.
+      It also contains the <code>gant.Gant</code> that is the main class for the Gant framework.
+    </p>
+
+    <hr>
+    <address><a href="mailto:russel at winder.org.uk">Russel Winder</a></address>
+    Last modified: 2010-04-05T08:30+01:00
+  </body>
+</html>
diff --git a/src/main/groovy/gant/targets/Clean.groovy b/src/main/groovy/gant/targets/Clean.groovy
new file mode 100644
index 0000000..4da23d5
--- /dev/null
+++ b/src/main/groovy/gant/targets/Clean.groovy
@@ -0,0 +1,74 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2008, 2010, 2013  Russel Winder
+//
+//  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 gant.targets
+
+import org.codehaus.gant.GantBinding
+
+/**
+ *  A class to provide clean and clobber actions for Gant build scripts.  Maintains separate lists of
+ *  Ant pattern specifications and directory names for clean and for clobber.  The lists are used as the
+ *  specifications when the clean or clobber methods are called.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Clean {
+  private GantBinding binding
+  private performPatternAction(final List<String> l) {
+    if (l.size() > 0) {
+      binding.ant.delete(quiet: 'false') {
+        binding.ant.fileset(dir: '.', includes: l.flatten().join(', '), defaultexcludes: 'false')
+      }
+    }
+  }
+  private performDirectoryAction(final List<String> l) {
+    l.flatten().each{item -> binding.ant.delete(dir: item, quiet: 'false')}
+  }
+  /**
+   *  Constructor for the "includeTargets <<" usage.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   */
+ Clean(final GantBinding binding) {
+    this.binding = binding
+    binding.cleanPattern = []
+    binding.cleanDirectory = []
+    binding.target.call(clean: 'Action the cleaning.') {
+      performPatternAction(binding.cleanPattern)
+      performDirectoryAction(binding.cleanDirectory)
+    }
+    binding.clobberPattern = []
+    binding.clobberDirectory = []
+    binding.target.call(clobber: 'Action the clobbering. Do the cleaning first.') {
+      depends(binding.clean)
+      performPatternAction(binding.clobberPattern)
+      performDirectoryAction(binding.clobberDirectory)
+    }
+  }
+  /**
+   *  Constructor for the "includeTargets **" usage.  Currently ignores keys other than cleanPattern,
+   *  cleanDirectory, clobberPattern, and clobberDirectory.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   *  @param map The <code>Map</code> of initialization parameters.
+   */
+  Clean(final GantBinding binding , final Map<String,String> map) {
+    this(binding)
+    map.each{key , value ->
+      if (['cleanPattern', 'cleanDirectory', 'clobberPattern', 'clobberDirectory'].contains(key)) {
+        binding."${key}" << value
+      }
+    }
+  }
+}
diff --git a/src/main/groovy/gant/targets/Maven.groovy b/src/main/groovy/gant/targets/Maven.groovy
new file mode 100644
index 0000000..3d8a31d
--- /dev/null
+++ b/src/main/groovy/gant/targets/Maven.groovy
@@ -0,0 +1,442 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2007–2011, 2013 Russel Winder
+//
+//  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 gant.targets
+
+import org.codehaus.gant.GantBinding
+import org.codehaus.gant.GantState
+
+/**
+ *  A class to provide the Maven 2 style lifecycle targets associated with a project.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Maven {
+  private final defaultJUnitVersion = '4.8.1'
+  private final defaultTestNGVersion = '5.11'
+  private final readOnlyKeys = [ 'binding', 'compileDependenciesClasspathId', 'testDependenciesClasspathId', 'antlibXMLns', 'mavenPOMId' ]
+  private final Map<String,Object> properties = [
+                                  groupId: '',
+                                  artifactId: '',
+                                  version: '',
+                                  sourcePath: 'src',
+                                  mainSourcePath: '', // Defaults to standard Maven 2 convention.  Set in constructor since it uses a GString dependent on a value in the map.
+                                  testSourcePath: '', // Defaults to standard Maven 2 convention.  Set in constructor since it uses a GString dependent on a value in the map.
+                                  targetPath: 'target',
+                                  mainCompilePath: '', // Defaults to standard Maven 2 convention.  Set in constructor since it uses a GString dependent on a value in the map.
+                                  testCompilePath: '', // Defaults to standard Maven 2 convention.  Set in constructor since it uses a GString dependent on a value in the map.
+                                  testReportPath: '', // Defaults to standard Maven 2 convention.  Set in constructor since it uses a GString dependent on a value in the map.
+                                  metadataPath: '', // Defaults to standard Maven 2 convention.  Set in constructor since it uses a GString dependent on a value in the map.
+                                  javaCompileProperties: [ source: '1.5', target: '1.5', debug: 'false' ],
+                                  groovyCompileProperties: [: ],
+                                  nestedJavacCompilerArgs: [ ],
+                                  compileClasspath: [ ],
+                                  testClasspath: [ ],
+                                  remoteRepositories: [ ],
+                                  compileDependencies: [ ],
+                                  testDependencies: [ ],
+                                  testFramework: 'junit',
+                                  testFrameworkVersion: defaultJUnitVersion,
+                                  testFrameworkClassifier: 'jdk15',
+                                  packaging: 'jar',
+                                  deployURL: '',
+                                  deploySnapshotURL: '',
+                                  deployId: 'dav.codehaus.org',
+                                  manifest: [: ],
+                                  manifestIncludes:  [ ],
+                                  (readOnlyKeys[0]): null,
+                                  (readOnlyKeys[1]): 'compile.dependency.classpath',
+                                  (readOnlyKeys[2]): 'test.dependency.classpath',
+                                  (readOnlyKeys[3]): 'antlib:org.apache.maven.artifact.ant',
+                                  (readOnlyKeys[4]): 'maven.pom'
+                                  ]
+  /**
+   *  Constructor for the "includeTargets <<" usage.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   */
+  Maven(GantBinding binding) {
+    properties.binding = binding
+    properties.binding.maven = this
+    initialize()
+  }
+   /**
+   *  Constructor for the "includeTargets **" usage.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   *  @param map The <code>Map</code> of initialization parameters.
+   */
+   Maven(GantBinding binding, Map<String,String> map) {
+     properties.binding = binding
+     properties.binding.maven = this
+     map.each { key, value -> owner.setProperty(key, value) }
+     initialize()
+   }
+  /**
+   *  Initialize all the values given the information presented to the constructors.  This is the second
+   *  stage of construction and is separated out from the constructors since the GStrings will be
+   *  initialized using the extant values at teh moment of construction and the two constructors need to
+   *  pre-initialize things in slightly different ways.
+   */
+  private initialize() {
+    properties.default_mainSourcePath = "${properties.sourcePath}${System.properties.'file.separator'}main"
+    properties.mainSourcePath = properties.default_mainSourcePath
+    properties.default_testSourcePath = "${properties.sourcePath}${System.properties.'file.separator'}test"
+    properties.testSourcePath = properties.default_testSourcePath
+    properties.mainCompilePath = "${properties.targetPath}${System.properties.'file.separator'}classes"
+    properties.testCompilePath = "${properties.targetPath}${System.properties.'file.separator'}test-classes"
+    properties.testReportPath = "${properties.targetPath}${System.properties.'file.separator'}test-reports"
+    properties.metadataPath = "${properties.mainCompilePath}${System.properties.'file.separator'}META-INF"
+    try { properties.binding.testFailIgnore }
+    catch (MissingPropertyException mpe) { properties.binding.testFailIgnore = false }
+    properties.binding.target.call(initialize: 'Ensure all the dependencies can be met and set classpaths accordingly.') {
+      if (owner.testFramework == 'testng') {
+        testngInstalled = false
+        //
+        //  Need to find a better way of working with the JUnit and TestNG version numbers.  There is to much "magic" here.
+        //
+        if (owner.testFrameworkVersion == defaultJUnitVersion) { owner.testFrameworkVersion = defaultTestNGVersion }
+        owner.testDependencies.each { dependency -> if (dependency.artifactId == 'testng') { testngInstalled = true } }
+        if (! testngInstalled) {
+          owner.testDependencies << [
+                                     groupId: 'org.testng',
+                                     artifactId: 'testng',
+                                     version: owner.testFrameworkVersion,
+                                     scope: 'test',
+                                     classifier: owner.testFrameworkClassifier
+                                     ] }
+      }
+      def createDependencyMap = { dependencyMap, map ->
+        [ 'groupId', 'artifactId', 'version', 'classifier' ].each { property ->
+          if (map [ property ]) { dependencyMap [ property ] =  map [ property ] }
+        }
+        dependencyMap
+      }
+      if (owner.compileDependencies) {
+        owner.binding.ant."${owner.antlibXMLns}:dependencies"(pathId: owner.compileDependenciesClasspathId) {
+          if (owner.remoteRepositories) { owner.remoteRepositories.each { url -> remoteRepository(url: url) } }
+          owner.compileDependencies.each { item -> dependency(createDependencyMap([ scope: 'compile' ], item)) }
+        }
+      }
+      if (owner.testDependencies) {
+        owner.binding.ant."${owner.antlibXMLns}:dependencies"(pathId: owner.testDependenciesClasspathId) {
+          if (owner.remoteRepositories) { owner.remoteRepositories.each { url -> remoteRepository(url: url) } }
+          owner.testDependencies.each { item -> dependency(createDependencyMap([ scope: 'test' ], item)) }
+        }
+      }
+      //  Do not allow the output of the ant.property call to escape.  If the output is allowed out then
+      //  Ant, Gant, Maven, Eclipse and IntelliJ IDEA all behave slightly differently.  This makes testing
+      //  nigh on impossible.  Also the user doesn't need to know about these.
+      owner.binding.ant.logger.messageOutputLevel = GantState.SILENT
+      owner.binding.ant.taskdef(name: 'groovyc', classname: 'org.codehaus.groovy.ant.Groovyc')
+      owner.binding.ant.logger.messageOutputLevel = GantState.verbosity
+      //  Interesting side effect of using properties rather than a method call in the above statement.
+      //  With method call, the value of the expression was equivalent to 0 so that was the value
+      //  returned by this method, which eventually became the return value of the target.  Using
+      //  properties, the assignment means the value of the statement is the assigned value which is
+      //  whatever it is.  In the absence of an explicit return, Groovy uses the value of the last expression,
+      //  which in this case is whatever was assigned above.  This is unlikely to be 0, and anyway is
+      //  liable to change -- which is a bit non-deterministic.  If control gets here assume everything is
+      //  fine and explicitly return 0.
+      0
+    }
+    /*
+    properties.binding.target.call(validate: 'Validate the project is correct and all necessary information is available.') {
+      throw new RuntimeException('Validate not implemented as yet.')
+    }
+    properties.binding.target.call('generate-sources': 'Generate any source code for inclusion in compilation.') {
+      throw new RuntimeException('Generate-sources not implemented as yet.')
+    }
+    properties.binding.target.call('process-sources': 'Process the source code, for example to filter any values.') {
+      throw new RuntimeException('Process-sources not implemented as yet.')
+    }
+    properties.binding.target.call('generate-resources': 'Generate resources for inclusion in the package.') {
+      throw new RuntimeException('Generate-resources not implemented as yet.')
+    }
+    properties.binding.target.call('process-resources': 'Copy and process the resources into the destination directory, ready for packaging.') {
+      throw new RuntimeException('Process-resources not implemented as yet.')
+    }
+    */
+    properties.binding.target.call(compile: "Compile the source code in ${properties.mainSourcePath} to ${properties.mainCompilePath}.") {
+      depends(owner.binding.initialize)
+      owner.binding.ant.mkdir(dir: owner.mainCompilePath)
+      //  If a source path has been explicitly specified then compile everything in it using the joint
+      //  compiler so there is no problem with it containing Groovy as well as Java code.  Otherwise assume
+      //  Maven 2 hierarchy rules.
+      if (owner.mainSourcePath != owner.default_mainSourcePath) {
+        owner.binding.ant.groovyc([ srcdir: owner.mainSourcePath, destdir: owner.mainCompilePath, fork: 'true' ] + owner.groovyCompileProperties) {
+          javac(owner.javaCompileProperties) {
+            if (owner.nestedJavacCompilerArgs) { owner.nestedJavacCompilerArgs.each { arg -> compilerarg(value: arg) } }
+          }
+          classpath {
+            pathelement(path: owner.compileClasspath.join(System.properties.'path.separator'))
+            if (owner.compileDependencies) { path(refid: owner.compileDependenciesClasspathId) }
+          }
+        }
+      }
+      else {
+        try {
+          new File((String) owner.mainSourcePath).eachDir { directory ->
+            switch (directory.name) {
+             case 'java':
+             //  Need to use the joint Groovy compiler here to deal wuth the case where Groovy files are in the
+             //  Java hierarchy.
+             owner.binding.ant.javac([ srcdir: owner.mainSourcePath + System.properties.'file.separator' + 'java', destdir: owner.mainCompilePath, fork: 'true' ] + owner.javaCompileProperties) {
+               classpath {
+                 pathelement(path: owner.compileClasspath.join(System.properties.'path.separator'))
+                 if (owner.compileDependencies) { path(refid: owner.compileDependenciesClasspathId) }
+               }
+             }
+             break
+             case 'groovy':
+             owner.binding.ant.groovyc([ srcdir: owner.mainSourcePath + System.properties.'file.separator' + 'groovy', destdir: owner.mainCompilePath, fork: 'true' ] + owner.groovyCompileProperties) {
+               javac(owner.javaCompileProperties) {
+                 if (owner.nestedJavacCompilerArgs) { owner.nestedJavacCompilerArgs.each { arg -> compilerarg(value: arg) } }
+               }
+               classpath {
+                 pathelement(path: owner.compileClasspath.join(System.properties.'path.separator'))
+                 if (owner.compileDependencies) { path(refid: owner.compileDependenciesClasspathId) }
+               }
+             }
+             break
+            }
+          }
+        }
+        catch (FileNotFoundException fnfe) { throw new RuntimeException('Error: ' + owner.mainSourcePath + ' does not exist.', fnfe) }
+      }
+    }
+    /*
+    properties.binding.target.call('process-classes', 'Post-process the generated files from compilation, for example to do bytecode enhancement on Java classes.') {
+      throw new RuntimeException('Process-classes not implemented as yet.')
+    }
+    properties.binding.target.call('generate-test-sources', 'Generate any test source code for inclusion in compilation.') {
+      throw new RuntimeException('Generate-test-sources not implemented as yet.')
+    }
+    properties.binding.target.call('process-test-sources', 'Process the test source code, for example to filter any values.') {
+      throw new RuntimeException('Process-test-sources not implemented as yet.')
+    }
+    properties.binding.target.call('generate-test-resources', 'Create resources for testing.') {
+      throw new RuntimeException('Generate-test-sources not implemented as yet.')
+    }
+    properties.binding.target.call('process-test-resources', 'Copy and process the resources into the test destination directory.') {
+      throw new RuntimeException('Process-test-sources not implemented as yet.')
+    }
+    */
+    properties.binding.target.call('test-compile': "Compile the test source code in ${properties.testSourcePath} to ${properties.testCompilePath}.") {
+      depends(owner.binding.compile)
+      def doTest = true
+      try { doTest = !(owner.binding.skipTest == 'true') }
+      catch (MissingPropertyException mpe) { /* Intentionally blank */ }
+      if (doTest) {
+        owner.binding.ant.mkdir(dir: owner.testCompilePath )
+        if (owner.testSourcePath != owner.default_testSourcePath) {
+          if ((new File((String) owner.testSourcePath)).isDirectory()) {
+            owner.binding.ant.groovyc([ srcdir: owner.testSourcePath, destdir: owner.testCompilePath, fork: 'true' ] + owner.groovyCompileProperties) {
+              javac(owner.javaCompileProperties) {
+                if (owner.nestedJavacCompilerArgs) { owner.nestedJavacCompilerArgs.each { arg -> compilerarg(value: arg) } }
+              }
+              classpath {
+                pathelement(location: owner.mainCompilePath)
+                pathelement(path: owner.compileClasspath.join(System.properties.'path.separator'))
+                pathelement(path: owner.testClasspath.join(System.properties.'path.separator'))
+                if (owner.compileDependencies) { path(refid: owner.compileDependenciesClasspathId) }
+                if (owner.testDependencies) { path(refid: owner.testDependenciesClasspathId) }
+              }
+            }
+          }
+        }
+        else {
+          if ((new File((String) owner.testSourcePath)).isDirectory()) {
+            try {
+              new File((String) owner.default_testSourcePath).eachDir { directory ->
+                switch (directory.name) {
+                 case 'java':
+                  //  Need to use the joint Groovy compiler here to deal with the case where Groovy files are in the
+                  //  Java hierarchy.
+                  owner.binding.ant.javac([ srcdir: owner.testSourcePath + System.properties.'file.separator' + 'java', destdir: owner.testCompilePath, fork: 'true' ] + owner.javaCompileProperties) {
+                    classpath {
+                      pathelement(location: owner.mainCompilePath)
+                      pathelement(path: owner.compileClasspath.join(System.properties.'path.separator'))
+                      pathelement(path: owner.testClasspath.join(System.properties.'path.separator'))
+                      if (owner.compileDependencies) { path(refid: owner.compileDependenciesClasspathId) }
+                      if (owner.testDependencies) { path(refid: owner.testDependenciesClasspathId) }
+                    }
+                  }
+                  break
+                 case 'groovy':
+                  owner.binding.ant.groovyc([ srcdir: owner.testSourcePath + System.properties.'file.separator' + 'groovy', destdir: owner.testCompilePath, fork: 'true' ] + owner.groovyCompileProperties) {
+                    javac(owner.javaCompileProperties) {
+                      if (owner.nestedJavacCompilerArgs) { owner.nestedJavacCompilerArgs.each { arg -> compilerarg(value: arg) } }
+                    }
+                    classpath {
+                      pathelement(location: owner.mainCompilePath)
+                      pathelement(path: owner.compileClasspath.join(System.properties.'path.separator'))
+                      pathelement(path: owner.testClasspath.join(System.properties.'path.separator'))
+                      if (owner.compileDependencies) { path(refid: owner.compileDependenciesClasspathId) }
+                      if (owner.testDependencies) { path(refid: owner.testDependenciesClasspathId) }
+                    }
+                  }
+                  break
+                }
+              }
+            }
+            catch (FileNotFoundException fnfe) { throw new RuntimeException('Error: ' + owner.testSourcePath + ' does not exist.', fnfe) }
+          }
+        }
+      }
+    }
+    properties.binding.target.call(test: "Run the tests using the ${properties.testFramework} unit testing framework.") {
+      depends(owner.binding.'test-compile')
+      def doTest = true
+      try { doTest = !(owner.binding.skipTest == 'true') }
+      catch (MissingPropertyException mpe) { /* Intentionally blank */ }
+      if (doTest) {
+        switch (owner.testFramework) {
+         case 'testng':
+          owner.binding.ant.taskdef(resource: 'testngtasks') { classpath { path(refid: owner.testDependenciesClasspathId) } }
+          owner.binding.ant.testng(outputdir: owner.testReportPath) {
+            classpath {
+              pathelement(location: owner.mainCompilePath)
+              pathelement(location: owner.testCompilePath)
+              pathelement(path: owner.compileClasspath.join(System.properties.'path.separator'))
+              pathelement(path: owner.testClasspath.join(System.properties.'path.separator'))
+              if (owner.compileDependencies) { path(refid: owner.compileDependenciesClasspathId) }
+              if (owner.testDependencies) { path(refid: owner.testDependenciesClasspathId) }
+            }
+            classfileset(dir: owner.testCompilePath)
+          }
+          break
+         case 'junit':
+         default:
+          owner.binding.ant.mkdir(dir: owner.testReportPath)
+          owner.binding.ant.junit(printsummary: 'yes', failureproperty: 'testsFailed', fork: 'true', forkmode: 'once') {
+            classpath {
+              pathelement(location: owner.mainCompilePath)
+              pathelement(location: owner.testCompilePath)
+              pathelement(path: owner.compileClasspath.join(System.properties.'path.separator'))
+              pathelement(path: owner.testClasspath.join(System.properties.'path.separator'))
+              if (owner.compileDependencies) { path(refid: owner.compileDependenciesClasspathId) }
+              if (owner.testDependencies) { path(refid: owner.testDependenciesClasspathId) }
+            }
+            formatter(type: 'plain')
+            formatter(type: 'xml')
+            sysproperty(key: 'groovy.home', value: System.properties.'groovy.home')
+            batchtest(todir: owner.testReportPath) { fileset(dir: owner.testCompilePath, includes: '**/*Test.class') }
+          }
+          break
+        }
+        try {
+          // owner.binding.ant.project.properties.testsFailed may not exist, hence the MissingPropertyException capture.
+          if (! owner.binding.testFailIgnore && owner.binding.ant.project.properties.testsFailed) { throw new RuntimeException('Tests failed, execution terminating.') }
+        }
+        catch (MissingPropertyException mpe) { /* Intentionally blank */ }
+      }
+    }
+    properties.binding.target.call('package': "Package the artefact as a ${properties.packaging} in ${properties.mainCompilePath}.") {
+      [ 'groupId', 'artifactId', 'version' ].each{item ->
+        if (! owner."${item}") { throw new RuntimeException("maven.${item} must be set to achieve target package.") }
+      }
+      depends(owner.binding.test)
+      if (owner.manifest) {
+        owner.binding.ant.mkdir(dir: owner.metadataPath)
+        owner.binding.ant.manifest(file: owner.metadataPath + System.properties.'file.separator' + 'MANIFEST.MF') {
+          owner.manifest.each{key, value -> attribute(name: key, value: value)}
+        }
+      }
+      if (owner.manifestIncludes) {
+        owner.binding.ant.mkdir(dir: owner.metadataPath)
+        owner.manifestIncludes.each{item ->
+          if (new File((String) item).isDirectory()) { owner.binding.ant.copy(todir: owner.metadataPath) { fileset(dir: item, includes: '*') } }
+          else { owner.binding.ant.copy(todir: owner.metadataPath, file: item) }
+        }
+      }
+      switch (owner.packaging) {
+       case 'war':
+       def artifactPath = owner.targetPath + System.properties.'file.separator' + owner.artifactId + '-' + owner.version
+       owner.packagedArtifact = artifactPath + '.war'
+       owner.binding.ant.mkdir(dir: artifactPath)
+       owner.binding.ant.copy(todir: artifactPath) {
+         fileset(dir: classesDir)
+         fileset(dir: ['src', 'main', 'webapp'].join(System.properties.'file.separator'))
+       }
+       owner.binding.ant.jar(destfile: owner.packagedArtifact) { fileset(dir: artifactPath) }
+       break
+       case 'jar':
+       owner.packagedArtifact = owner.targetPath + System.properties.'file.separator' + owner.artifactId + '-' + owner.version + '.jar'
+       owner.binding.ant.jar(destfile: owner.packagedArtifact) { fileset(dir: owner.mainCompilePath) }
+      }
+    }
+    /*
+    properties.binding.target.call('integration-test': 'Process and deploy the package if necessary into an environment where integration tests can be run.') {
+      throw new RuntimeException('Integration-test not implemented as yet.')
+    }
+    properties.binding.target.call(verify: 'Run any checks to verify the package is valid and meets quality criteria.') {
+      throw new RuntimeException('Verify not implemented as yet.')
+    }
+    */
+    properties.binding.target.call(install: 'Install the artefact into the local repository.') {
+      owner.binding.ant."${owner.antlibXMLns}:pom"(id: mavenPOMId, file: 'pom.xml')
+      /*
+       *  It seems that there is a wierd problem.
+
+      owner.binding.ant.property(name: 'flob.adob', value: 'weed')
+      owner.binding.ant.echo('${flob.adob}')
+      println(owner.binding.ant.project.properties.'flob.adob')
+
+      *  does exactly what you would expect, weed is printed out in both cases.  However:
+
+      owner.binding.ant.'antlib:org.apache.maven.artifact.ant:pom'(id: 'blahblah', file: 'pom.xml')
+      owner.binding.ant.echo('${blahblah.version}')
+      println(owner.binding.ant.project.properties.'blahblah.version')
+
+      * prints out the version number from ant but null from Groovy:-( This means we cannot run the consistency checks between POM and Gant file.
+      */
+      /*
+      [ 'groupId', 'artifactId', ' version' ].each { item ->
+                                                       if (owner.binding.ant.project.properties."${owner.mavenPOMId}.${item}" != owner."${item}") {
+                                                         throw new RuntimeException("${item} in build file and POM not the same.")
+                                                       }
+      }
+      */
+      depends(owner.binding.'package')
+      owner.binding.ant."${owner.antlibXMLns}:install"(file: owner.packagedArtifact ) { pom(refid: mavenPOMId) }
+    }
+    properties.binding.target.call(deploy: "Deploy the artefact: copy the artefact to the remote repository ${ properties.version =~('SNAPSHOT' ? properties.deploySnapshotURL: properties.deployURL) }.") {
+      def label = 'deployURL'
+      if (owner.version =~ 'SNAPSHOT') { label = 'deploySnapshotURL' }
+      def deployURL = owner."${label}"
+       if (! deployURL) { throw new RuntimeException("maven.${label} must be set to achieve target deploy.") }
+      depends(owner.binding.install)
+      owner.binding.ant."${owner.antlibXMLns}:install-provider"(artifactId: 'wagon-webdav', version: '1.0-beta-2')
+      //
+      //  This task does not create new directories on the server if they are needed:-(
+      //
+      owner.binding.ant."${owner.antlibXMLns}:deploy"(file: owner.packagedArtifact ) {
+        pom(refid: owner.mavenPOMId)
+        remoteRepository(url: deployURL, id: owner.deployId)
+      }
+    }
+    properties.binding.target.call(site: 'Create the website.') {
+      depends(owner.binding.initialize)
+      throw new RuntimeException('Site not implemented as yet.')
+    }
+    properties.binding.includeTargets << Clean
+    properties.binding.cleanDirectory << "${properties.targetPath}"
+  }
+  public getProperty(String name) { properties [ name ] }
+  public void setProperty(String name, value) {
+    if (readOnlyKeys.contains(name)) { throw new RuntimeException("Cannot amend the property ${name}.") }
+    properties[name] = value
+  }
+}
diff --git a/src/main/groovy/gant/targets/package.html b/src/main/groovy/gant/targets/package.html
new file mode 100644
index 0000000..0a479d2
--- /dev/null
+++ b/src/main/groovy/gant/targets/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>gant.targets</title>
+  </head>
+
+  <body>
+    <p>
+      This package contains classes that can be used as parameters to <code>includeTargets</code> in a Gant
+      scripts.
+    </p>
+    <p>
+      Classes in this package inject targets into a Gant script.  Currently there is no notion of namespaces
+      so the target namespace is a single flat namespace.
+    </p>
+ 
+    <hr>
+    <address><a href="mailto:russel at winder.org.uk">Russel Winder</a></address>
+    Last modified: 2010-04-05T08:30+01:00
+  </body>
+</html>
diff --git a/src/main/groovy/gant/tools/AntFile.groovy b/src/main/groovy/gant/tools/AntFile.groovy
new file mode 100644
index 0000000..9df7bb9
--- /dev/null
+++ b/src/main/groovy/gant/tools/AntFile.groovy
@@ -0,0 +1,76 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008, 2010, 2013  Russel Winder
+//
+//  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 gant.tools
+
+import org.codehaus.gant.GantBinding
+
+import org.apache.tools.ant.ProjectHelper
+
+/**
+ *  Support for including Ant XML files into a Gant run which sets up the targets from the Ant file as Gant
+ *  targets.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class AntFile {
+  private final GantBinding binding
+  /**
+   *  Constructor for the "includeTool <<" usage.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   */
+  AntFile(final GantBinding binding) { this.binding = binding }
+  /**
+   *  Constructor for the "includeTool **" usage.  It is assumed that the <code>Map</code> entry provides a
+   *  filename or a list of filenames of Ant XML files to load.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   *  @param map The <code>Map</code> of initialization parameters.
+   */
+  AntFile(final GantBinding binding, final Map<String,String> map) {
+    this.binding = binding
+    includeTargets(map.filename)
+  }
+  /**
+   *  Read the named file assuming it is an Ant XML file.  Load the targets into the current project and
+   *  then associate each of the Ant targets with a Gant target.
+   *
+   *  @param fileNameList the list of path to the Ant XML file.
+   */
+  void includeTargets(final List<String> fileNameList) {
+    for (fileName in fileNameList) { includeTargets(fileName) }
+  }
+  /**
+   *  Read the named file assuming it is an Ant XML file.  Load the targets into the current project and
+   *  then associate each of the Ant targets with a Gant target.
+   *
+   *  @param fileName the <code>String</code> specifying the path to the Ant XML file.
+   */
+  void includeTargets(final String fileName) { includeTargets(new File(fileName)) }
+  /**
+   *  Read the named file assuming it is an Ant XML file.  Load the targets into the current project and
+   *  then associate each of the Ant targets with a Gant target.
+   *
+   *  @param fileName the <code>File</code> specifying path to the Ant XML file.
+   */
+  void includeTargets(final File file) {
+    ProjectHelper.configureProject(binding.ant.project, file)
+    binding.ant.project.targets.each{key, value ->
+      assert key == value.name
+      binding.setProperty(key, {value.execute()})
+      if (value.description) { binding.targetDescriptions.put(key, value.description) }
+    }
+  }
+}
diff --git a/src/main/groovy/gant/tools/Execute.groovy b/src/main/groovy/gant/tools/Execute.groovy
new file mode 100644
index 0000000..d37ac65
--- /dev/null
+++ b/src/main/groovy/gant/tools/Execute.groovy
@@ -0,0 +1,114 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2008, 2010, 2013  Russel Winder
+//
+//  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 gant.tools
+
+import org.codehaus.gant.GantBinding
+
+/**
+ *  Provides methods for executing operating system commands ensuring that the pipes are flushed and
+ *  so the execution cannot block on full pipes.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Execute {
+  private final GantBinding binding
+  /**
+   *  Constructor for the "includeTool <<" usage.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   */
+  Execute(final GantBinding binding) { this.binding = binding }
+   /**
+   *  Constructor for the "includeTool **" usage.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   *  @param map The <code>Map</code> of initialization parameters.  Currently ignored.
+    */
+  Execute(final GantBinding binding, final Map<String,String> map) { this.binding = binding }
+ /**
+   *  Handle the output and error streams from the already initializaed and started process to ensure the
+   *  buffers are never filled, and block waiting termination of the process.
+   *
+   *  @param process the executing process.
+   *  @param errProcessing the <code>Closure</code> to process the error stream.
+   *  @param outProcessing the <code>Closure</code> to process the output stream.
+   *  @param command the command used to start the executing process.
+   *  @param tag the tag to print.
+   *  @return the return code of the process.
+   */
+  private manageProcess(final Process process, final Closure errProcessing, final Closure outProcessing, final Object command, final String tag) {
+    //  Command can either be a String or a List.
+    binding.getVariable('message')(tag, command)
+    final errThread = Thread.start { new InputStreamReader(process.err).eachLine(errProcessing) }
+    final inThread = Thread.start { new InputStreamReader(process.in).eachLine(outProcessing) }
+    errThread.join()
+    inThread.join()
+    process.waitFor()
+  }
+  /**
+   *  Execute a command from the PATH.
+   *
+   *  Optional, keyword parameters: <code>outProcessing</code> is a <code>Closure</code> used to process
+   *  lines from standard out; <code>errProcessing is a <code>Closure</code> used to process lines from
+   *  standard error.
+   *
+   *  @param command the command as a single <code>String</code>.
+   *  @return the return code of the process.
+   */
+  def executable(final Map<String,String> keywordParameters = [:], final String command) {
+    manageProcess(command.execute(),
+                    (Closure)(keywordParameters['errProcessing'] ?: { System.err.println(it) }),
+                    (Closure)(keywordParameters['outProcessing'] ?: { println(it) }),
+                    command,
+                    'execute')
+  }
+  /**
+   *  Execute a command from the PATH.
+   *
+   *  Optional, keyword parameters: <code>outProcessing</code> is a <code>Closure</code> used to process
+   *  lines from standard out; <code>errProcessing</code> is a <code>Closure</code> used to process lines
+   *  from standard error.
+   *
+   *  @param command the command as a  list of <code>String</code>s.
+   *  @return the return code of the process.
+   */
+  def executable(final Map<String,String> keywordParameters = [:], final List<String> command) {
+    manageProcess(command.execute(),
+                    (Closure)(keywordParameters['errProcessing'] ?: { System.err.println(it) }),
+                    (Closure)(keywordParameters['outProcessing'] ?: { println(it) }),
+                    command,
+                    'execute')
+  }
+  /**
+   *  Execute a command using a shell.
+   *
+   *  Optional, keyword parameters: <code>outProcessing</code> is a <code>Closure</code> used to process
+   *  lines from standard out; <code>errProcessing</code> is a <code>Closure</code> used to process lines
+   *  from standard error.
+   *
+   *  @param command the command as a single <code>String</code>.
+   *  @return the return code of the process.
+   */
+  def shell(final Map<String,String> keywordParameters = [:], final String command) {
+    final String osName = System.getProperty("os.name")
+    final boolean isWindows = ( osName.length() > 6) ? osName.substring(0, 7).equals("Windows") : false
+    final commandArray = isWindows ? ['cmd', '/c', command] : ['sh', '-c', command]
+    manageProcess(commandArray.execute(),
+                    (Closure)(keywordParameters['errProcessing'] ?: { System.err.println(it) }),
+                    (Closure)(keywordParameters['outProcessing'] ?: { println(it) }),
+                    command,
+                    'shell')
+  }
+}
diff --git a/src/main/groovy/gant/tools/Ivy.groovy b/src/main/groovy/gant/tools/Ivy.groovy
new file mode 100644
index 0000000..d6c55bd
--- /dev/null
+++ b/src/main/groovy/gant/tools/Ivy.groovy
@@ -0,0 +1,60 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2008, 2010, 2013  Russel Winder
+//
+//  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 gant.tools
+
+import org.codehaus.gant.GantBinding
+
+/**
+ *  Provide support for using Ivy.  This simply redirects all method calls to the standard
+ * <code>GantBuilder</code> instance, which in turn selects the method from the Ivy jar.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Ivy {
+  private final GantBinding binding ;
+  private final ivyURI = 'antlib:org.apache.ivy.ant'
+  /**
+   *  Constructor to support "includeTool <<" usage.  Assumes that an Ivy jar is already in the classpath.
+   *  The standard Gant installation includes an Ivy jar and it is automatically included in the classpath.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   */
+  Ivy(final GantBinding binding) {
+    this.binding = binding
+    binding.ant.taskdef(resource: 'org/apache/ivy/ant/antlib.xml' , uri: ivyURI)
+  }
+ /**
+   *  Constructor to support "includeTool **" usage.  By default assumes that an Ivy jar is already in the
+   *  classpath.  The standard Gant installation includes an Ivy jar and it is automatically included in the
+   *  classpath.  However the <code>ivyJarPath</code> field can be set to allow explicit specification of
+   *  the location of the Ivy jar.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   *  @param map The <code>Map</code> of parameters for intialization.
+   */
+  Ivy(final GantBinding binding , final Map<String,String> map) {
+    this.binding = binding
+    if (map.containsKey('ivyJarPath')) {
+      final classpathId = 'ivy.class.path'
+      binding.ant.path(id: classpathId) { binding.ant.fileset(dir: map.ivyJarPath , includes: 'ivy*.jar') }
+      binding.ant.taskdef(resource: 'org/apache/ivy/ant/antlib.xml' , uri: ivyURI , classpathref: classpathId)
+    }
+    else {
+      binding.ant.taskdef(resource: 'org/apache/ivy/ant/antlib.xml' , uri: ivyURI)
+    }
+  }
+  //  To save having to maintain lists of the functions available, simply redirect all method calls to the GantBuilder object.
+  def invokeMethod(String name , args) { binding.ant.invokeMethod(ivyURI + ':' + name , args) }
+}
diff --git a/src/main/groovy/gant/tools/LaTeX.groovy b/src/main/groovy/gant/tools/LaTeX.groovy
new file mode 100644
index 0000000..b9d9f30
--- /dev/null
+++ b/src/main/groovy/gant/tools/LaTeX.groovy
@@ -0,0 +1,205 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2007–2008, 2010, 2013  Russel Winder
+//
+//  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 gant.tools
+
+import org.codehaus.gant.GantBinding
+
+/**
+ *  Provide support for supporting LaTeX document processing.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+class LaTeX {
+  public final ltxExtension = '.ltx'
+  public final texExtension = '.tex'
+  public final dviExtension = '.dvi'
+  public final epsExtension = '.eps'
+  public final pdfExtension = '.pdf'
+  public final psExtension = '.ps'
+  public final auxExtension = '.aux'
+  public final bblExtension = '.bbl'
+  public final blgExtension = '.blg'
+  public final idxExtension = '.idx'
+  public final ilgExtension = '.ilg'
+  public final indExtension = '.ind'
+  public final logExtension = '.log'
+  public final tocExtension = '.toc'
+  public final pdfBookMarkExtension = '.out'
+  public intermediateExtensions = [
+    auxExtension, dviExtension, logExtension, tocExtension,
+    bblExtension, blgExtension,
+    idxExtension, ilgExtension, indExtension,
+    pdfBookMarkExtension
+    ]
+  public final environment = [
+    latexCommand : 'pdflatex',
+    latexOptions : [ '-interaction=nonstopmode', '-halt-on-error' ],
+    bibtexCommand : 'bibtex',
+    bibtexOptions : [ ],
+    makeindexCommand : 'makeindex',
+    makeindexOptions : [ ],
+    dvipsCommand : 'dvips',
+    dvipsOptions : [ ],
+    ps2pdfCommand : 'ps2pdf',
+    ps2pdfOptions : [ ],
+    root : '',
+    dependents : [ ]
+    ]
+  protected final GantBinding binding
+  protected final Execute executor
+  /**
+   *  Constructor for the "includeTool <<" usage.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   */
+  public LaTeX(final GantBinding binding) {
+    this.binding = binding
+    executor = new Execute(binding)
+  }
+ /**
+   *  Constructor for the "includeTool **" usage.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   *  @param map The <code>Map</code> of initialization parameters.
+   */
+  public LaTeX(final GantBinding binding, final Map<String,String> map) {
+    this.binding = binding
+    executor = new Execute(binding)
+    map.each { key, value -> addOption(key, value) }
+  }
+  private void addOption(key, option) {
+    if (option instanceof List) { environment[ key ] += option }
+    else { environment[ key ] << option }
+  }
+  /**
+   *  Add a LaTeX option for the build.
+   *
+   *  @param option The option to add.
+   */
+  public void addLaTeXOption(option) { addOption('latexOptions', option) }
+  /**
+   *  Add a BibTeX option for the build.
+   *
+   *  @param option The option to add.
+   */
+  public void addBibTeXOption(option) { addOption('bibtexOptions', option) }
+  /**
+   *  Add a Makeindex option for the build.
+   *
+   *  @param option The option to add.
+   */
+  public void addMakeindexOption(option) { addOption('makeindexOptions', option) }
+  /**
+   *  Add a DviPS option for the build.
+   *
+   *  @param option The option to add.
+   */
+  public void addDvipsOption(option) { addOption('dvipsOptions', option) }
+  /**
+   *  Add a Ps2Pdf option for the build.
+   *
+   *  @param option The option to add.
+   */
+  public void addPs2pdfOption(option) { addOption('ps2pdfOptions', option) }
+  /**
+   *  Add a collection of options for the build.
+   *
+   *  @param keywordOptions The collection of options to add.
+   */
+  public void addOptions(Map<String,String> keywordOptions) { keywordOptions.each { key, value -> addOption(key, value) } }
+  /**
+   *  Perform the LaTeX source compilation.  The source will be processed enough times to ensure that BibTeX
+   *  and Makeindex requirements are completed.
+   */
+  private void executeLaTeX() {
+    String root = (String) environment.root
+    def sourceName = root + ltxExtension
+    def sourceFile = new File(sourceName)
+    if (! sourceFile.exists()) {
+      sourceFile = new File(sourceName = root + texExtension)
+      if (! sourceFile.exists()) { throw new FileNotFoundException("Neither ${root}.ltx or ${root}.tex exist.") }
+    }
+    def targetExtension = environment.latexCommand == 'pdflatex' ? pdfExtension : dviExtension
+    def targetName = root + targetExtension
+    def targetFile = new File(targetName)
+    def needToUpdate = false
+    if (targetFile.exists()) {
+      (environment.dependents + [ sourceName ]).each { dependent ->
+        if (!(dependent instanceof File)) { dependent = new File((String) dependent) }
+        if (dependent.lastModified() > targetFile.lastModified()) { needToUpdate = true }
+      }
+    }
+    else { needToUpdate = true }
+    if (needToUpdate) {
+      def latexAction = [ environment.latexCommand, *environment.latexOptions, sourceName ]
+      def runLaTeX = { executor.executable(latexAction) }
+      def conditionallyRunLaTeX = {
+        def rerun = new File(root + logExtension).text =~ /(Warning:.*Rerun|Warning:.*undefined citations)/
+        if (rerun) { runLaTeX() }
+        rerun
+      }
+      runLaTeX()
+      def currentDirectory = new File('.')
+      def bibTeXRun = false
+      currentDirectory.eachFileMatch(~/.*.aux/) { auxFile ->
+        if (auxFile.text =~ 'bibdata') {
+          executor.executable([ environment.bibtexCommand, *environment.bibtexOptions, auxFile.name ])
+          bibTeXRun = true
+        }
+      }
+      if (bibTeXRun) {
+        runLaTeX()
+        if (conditionallyRunLaTeX()) { conditionallyRunLaTeX() }
+      }
+      def makeindexRun = false
+      currentDirectory.eachFileMatch(~/.*.idx/) { idxFIle ->
+        executor.executable([ environment.bibtexCommand, *environment.bibtexOptions, idxFile.name ])
+        makeindexRun = true
+      }
+      if (makeindexRun) { runLaTeX() }
+      runLaTeX()
+      if (conditionallyRunLaTeX()) {
+        if (! conditionallyRunLaTeX()) {
+          throw new RuntimeException('#### Something SERIOUSLY Wrong. ###')
+        }
+      }
+    }
+  }
+  /**
+   *  Create a PDF file from a LaTeX source.
+   *
+   *  @param arguments a <code>Map</code> of options to add to the build environment.
+   */
+  public void generatePDF(Map<String,String> arguments) {
+    arguments.each{key, value -> environment[key] = value}
+    environment.latexCommand = 'pdflatex'
+    executeLaTeX()
+  }
+  /**
+   *   Create a PostScript file from a LaTeX source.
+   *
+   *  @param arguments a <code>Map</code> of options to add to the build environment.
+   */
+  public void generatePS(Map<String,String> arguments) {
+    arguments.each{key, value -> environment[key] = value}
+    environment.latexCommand = 'latex'
+    executeLaTeX()
+    def dviFile = new File((String) environment.root + dviExtension)
+    def psFile = new File((String) environment.root + psExtension)
+    if ((! psFile.exists()) || (dviFile.lastModified() > psFile.lastModified())) {
+      executor.executable([ environment.dvipsCommand, * environment.dvipsOptions, '-o', psFile.name, dviFile.name ])
+    }
+  }
+}
diff --git a/src/main/groovy/gant/tools/Subdirectories.groovy b/src/main/groovy/gant/tools/Subdirectories.groovy
new file mode 100644
index 0000000..7b34669
--- /dev/null
+++ b/src/main/groovy/gant/tools/Subdirectories.groovy
@@ -0,0 +1,76 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2009, 2010, 2013  Russel Winder
+//
+//  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 gant.tools
+
+import org.codehaus.gant.GantBinding
+import org.codehaus.gant.GantState
+
+/**
+ *  Provides methods for executing processes in all subdirectories of the working directory.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Subdirectories {
+  private final GantBinding binding ;
+  /**
+   *  Constructor for the "includeTool <<" usage.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   */
+  Subdirectories(final GantBinding binding) { this.binding = binding ; }
+  /**
+   *  Constructor for the "includeTool **" usage.  It is assumed that the <code>Map</code> entry provides a
+   *  filename or a list of filenames of Ant XML files to load.
+   *
+   *  @param binding The <code>GantBinding</code> to bind to.
+   *  @param map The <code>Map</code> of initialization parameters.
+   */
+  Subdirectories(final GantBinding binding , final Map<String,String> map) { this.binding = binding ; }
+  /**
+   *  Run a shell command in a named directory.
+   *
+   *  @param command The shell command to execute.
+   *  @param directory Path of the directory in which to execute the shell command.
+   */
+  void runSubprocess(final String command , final File directory) {
+    binding.ant.project.log("\n============ ${directory} ================" , GantState.VERBOSE)
+    def process = command.execute(null , directory)
+    if (GantState.verbosity >= GantState.NORMAL) {
+      new InputStreamReader(process.err).eachLine{line -> System.err.println(line)}
+      new InputStreamReader(process.in).eachLine{line -> println(line)}
+    }
+    process.waitFor()
+  }
+  /**
+   *  Run a shell command in all the subdirectories of this one.
+   *
+   *  @param command The shell command to execute.
+   */
+  void forAllSubdirectoriesRun(final String command) {
+    new File('.').eachDir{directory -> runSubprocess(command , directory)}
+  }
+  /**
+   *  Execute an Ant target in all the subdirectories of this one.
+   *
+   *  @param target The target to execute.
+   */
+  void forAllSubdirectoriesAnt(final String target) { forAllSubdirectoriesRun('ant ' + target) }
+  /**
+   *  Execute a Gant target in all the subdirectories of this one.
+   *
+   *  @param target The target to execute.
+   */
+  void forAllSubdirectoriesGant(final String target) { forAllSubdirectoriesRun('gant ' + target) }
+}
diff --git a/src/main/groovy/gant/tools/package.html b/src/main/groovy/gant/tools/package.html
new file mode 100644
index 0000000..5f6c76f
--- /dev/null
+++ b/src/main/groovy/gant/tools/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>gant.tools</title>
+  </head>
+
+  <body>
+    <p>
+      This package contains classes that can be used as parameters to <code>includeTool</code> in a Gant
+      scripts.
+    </p>
+    <p>
+      Classes in this package provide tools for use in Gant scripts.  These are basically just standard
+      support features to abstract common actions and hence make Gant scripts simpler.
+    </p>
+ 
+    <hr>
+    <address><a href="mailto:russel at winder.org.uk">Russel Winder</a></address>
+    Last modified: 2010-04-05T08:30+01:00
+  </body>
+</html>
diff --git a/src/main/groovy/org/codehaus/gant/AbstractInclude.groovy b/src/main/groovy/org/codehaus/gant/AbstractInclude.groovy
new file mode 100644
index 0000000..681405f
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/AbstractInclude.groovy
@@ -0,0 +1,172 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant
+
+/**
+ *  This class is for code sharing between classes doing include activity.
+ *
+ *  @see IncludeTargets
+ *  @see IncludeTool
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+abstract class AbstractInclude {
+  /**
+   *  The <code>GantBinding</code> for this run.
+   */
+  protected Binding binding
+  /**
+   *  The list of loaded classes.
+   */
+  protected final List<Class<?>> loadedClasses = []
+  /**
+   *  When using the ** * operator there is a need to not instantiate the class immediately so information
+   *  has to be buffered.  This variable  holds a reference to the class ready for instantiation once all the
+   *  constructor parameters are known.
+   */
+  protected Class<?> pendingClass = null
+  /**
+   *  Constructor.
+   *
+   *  @param binding The <code>GantBinding</code> to associate with.
+   */
+  protected AbstractInclude(final GantBinding binding) { this.binding = binding }
+  /**
+   *  Implementation of the << operator taking a <code>Class</code> parameter.
+   *
+   *  @param theClass The <code>Class</code> to load and instantiate.
+   *  @return The includer object to allow for << chaining.
+   */
+  public abstract leftShift(Class<?> theClass)
+  /**
+   *  Implementation of the << operator taking a <code>File</code> parameter.
+   *
+   *  @param file The <code>File</code> to load, compile, and instantiate.
+   *  @return The includer object to allow for << chaining.
+   */
+  public abstract leftShift(File file)
+  /**
+   *  Implementation of the << operator taking a <code>String</code> parameter.
+   *
+   *  @param s The <code>String</code> to compile and instantiate.
+   *  @return The includer object to allow for << chaining.
+   */
+  public abstract leftShift(String s)
+  /**
+   *  Implementation of the << operator taking a <code>List</code> parameter.
+   *
+   *  @param l The <code>List</code> of things to load (, compile) and instantiate.
+   *  @return The includer object to allow for << chaining.
+   */
+  public leftShift(final List<?> l) { l.each { item -> this << item } ; this }
+  /**
+   *  Implementation of the << operator taking a <code>Object</code> parameter.  This always throws an
+   *  exception, it is here to avoid using a type other than <code>Class</code>, <code>File</code>,
+   *  <code>String</code> or <code>List</code> (of <code>Class</code>, <code>File</code>, or
+   *  <code>String</code>).
+   *
+   *  @param theClass The <code>Class</code> to load and instantiate.
+   *  @throw RuntimeException always.
+   */
+  public leftShift(final Object o) { throw new RuntimeException('Ignoring include of type ' + o.class.name) }
+  /**
+   *  Implementation of the ** operator taking a <code>Class</code> parameter.
+   *
+   *  @param theClass The <code>Class</code> to load and instantiate.
+   *  @return The includer object to allow for * operator.
+   */
+  public power(final Class<?> theClass) { pendingClass = theClass ; this }
+  /**
+   *  Implementation of the * operator taking a <code>Map</code> parameter.  This operator only makes
+   *  sense immediately after a ** operator, since only then is there a <code>Class</code> to instantiate.
+   *
+   *  @param keywordParameter The <code>Map</code> of parameters to the constructor.
+   *  @return The includer object to allow for ** * operator chaining.
+   */
+  public abstract multiply(Map<String,String> keywordParameters)
+  /**
+   *  Create an instance of a class included using the << operator.
+   *
+   *  @param theClass The <code>Class</code> to instantiate.
+   *  @throws NoSuchMethodException if the required constructor cannot be found.
+   */
+  protected createInstance(Class<?> theClass) {
+    if (Script.isAssignableFrom(theClass)) {
+      // We need to ensure that the script runs so that it populates the binding.
+      def script = theClass.newInstance()
+      script.binding = binding
+      script.run()
+      return script
+    }
+    else {
+      try { return theClass.getConstructor(GantBinding).newInstance([ binding ] as Object[]) }
+      catch (NoSuchMethodException nsme) { throw new RuntimeException('Could not initialize ' + theClass.name, nsme) }
+    }
+    null // Be explicit about the return value to keep IntelliJ IDEA's inspectors happy.
+  }
+  /**
+   *  Create an instance of a class included with the ** * operator.
+   *
+   *  @param theClass The <code>Class</code> to instantiate.
+   *  @param keywordParameter The <code>Map</code> containing the parameters for construction.
+   *  @throws NoSuchMethodException if the required constructor cannot be found.
+   */
+  protected createInstance(Class<?> theClass, Map<?,?> keywordParameters) {
+    try { return theClass.getConstructor(GantBinding, Map).newInstance([ binding, keywordParameters ] as Object[]) }
+    catch (NoSuchMethodException nsme) { throw new RuntimeException('Could not initialize ' + theClass.name, nsme) }
+  }
+  /**
+   *  Make an attempt to evaluate a file, possible as a class.
+   *
+   *  @param file The <code>File</code> to read.
+   *  @param asClass Specify whether the file is to be treated as a class.
+   *  @return The class read or null if the file is not to be treated as a class.
+   */
+  private attemptEvaluate(File file, boolean asClass) {
+    if (asClass) { return binding.groovyShell.evaluate(file.text + " ; return ${file.name.replace('.groovy', '')}") }
+    //
+    //  GANT-58 raised the issue of reporting errors correctly.  This means catching and processing
+    //  exceptions so as to capture the original location of the error.
+    //
+    try { binding.groovyShell.evaluate(file) }
+    catch (Exception e) {
+      def errorSource = ''
+      for (stackEntry in e.stackTrace) {
+        if ((stackEntry.fileName == file.name) && (stackEntry.lineNumber  != -1)) {
+          errorSource += file.absolutePath + ', line ' + stackEntry.lineNumber + ' -- '
+        }
+      }
+      throw new RuntimeException(errorSource + e.toString(), e)
+    }
+    null
+  }
+  /**
+   *  Read a file which may or may not be a class, searching the Gant library path if the file cannot
+   *  be found at first.
+   *
+   *  @param file The <code>File</code> to read.
+   *  @param asClass Specify whether this is supposed to be a class.
+   *  @throws FileNotFoundException when the file cannot be found.
+   */
+  protected readFile(File file, boolean asClass = false) {
+    try { return attemptEvaluate(file, asClass) }
+    catch (FileNotFoundException fnfe) {
+      for (directory in binding.gantLib) {
+        def possible = new File((String)directory, file.name)
+        if (possible.isFile() && possible.canRead()) { return attemptEvaluate(possible, asClass) }
+      }
+      throw fnfe
+    }
+  }
+}
diff --git a/src/main/groovy/org/codehaus/gant/GantBinding.groovy b/src/main/groovy/org/codehaus/gant/GantBinding.groovy
new file mode 100644
index 0000000..2916f42
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/GantBinding.groovy
@@ -0,0 +1,306 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008--2011, 2013 Russel Winder
+//
+//  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.codehaus.gant
+
+import org.apache.tools.ant.BuildListener
+import org.apache.tools.ant.Project
+import org.apache.tools.ant.Target
+
+/**
+ *  This class is a sub-class of <code>groovy.lang.Binding</code> to provide extra capabilities.  In
+ *  particular, all the extra bits needed in the binding for Gant to actually work at all.  Handle this as a
+ *  separate class to avoid replication of initialization if binding objects are cloned.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+public class GantBinding extends Binding implements Cloneable {
+  /**
+   *  Determine whether we are initializing an instance and so are able to define the read-only items.
+   */
+  private boolean initializing = true
+  /**
+   * A List of BuildListener instances that Gant sends events to.
+   */
+  private List<BuildListener> buildListeners = []
+  /**
+   *  Default constructor.
+   */
+  public GantBinding() {
+    setVariable('ant', new GantBuilder())
+    initializeGantBinding()
+  }
+  /**
+   *  Constructor taking an explicit <code>Binding</code> as parameter.
+   *
+   *  @param binding The <code>Binding</code> to use as a base of maplets to initialize the
+   *  <code>GantBinding</code> with.
+   */
+  public GantBinding(final Binding binding) {
+    super(binding.variables)
+    setVariable('ant', new GantBuilder())
+    initializeGantBinding()
+  }
+  /**
+   *  Constructor taking an explicit <code>Project</code> as parameter.
+   *
+   *  @param p The <code>Project</code> to use when initializing the <code>GantBuilder</code>.
+   */
+  public GantBinding(final Project p) {
+    setVariable('ant', new GantBuilder(p))
+    initializeGantBinding()
+  }
+  /**
+   *  Adds a <code>BuildListener</code> instance to this <code>Gant</code> instance
+   */
+  public synchronized void addBuildListener(final BuildListener buildListener) {
+    if (buildListener) {
+      buildListeners << buildListener
+      ant.antProject.addBuildListener(buildListener)
+    }
+  }
+  /**
+   *  Removes a <code>BuildListener</code> instance from this <code>Gant</code> instance
+   */
+  public synchronized void removeBuildListener(final BuildListener buildListener) {
+    buildListeners.remove(buildListener)
+    ant.antProject.removeBuildListener(buildListener)
+  }
+  /**
+   *  Call a target wrapped in <code>BuildListener</code> event handler.
+   */
+  private withTargetEvent(targetName, targetDescription, Closure callable) {
+    final antTarget = new Target(name : targetName, project : ant.antProject, description : targetDescription)
+    final event = new GantEvent(antTarget, this)
+    def targetResult = null
+    try {
+      buildListeners.each{BuildListener b -> b.targetStarted(event)}
+      targetResult = callable.call()
+      buildListeners.each{BuildListener b -> b.targetFinished(event)}
+    }
+    catch (Exception e) {
+      event.exception = e
+      buildListeners.each{BuildListener b -> b.targetFinished(event)}
+      throw e
+    }
+    return targetResult
+  }
+  /**
+   *  Method holding all the code common to all construction.
+   */
+  private void initializeGantBinding() {
+    //  Do not allow the output of the ant.property call to escape.  If the output is allowed out then Ant,
+    //  Gant, Maven, Eclipse and IntelliJ IDEA all behave slightly differently.  This makes testing nigh on
+    //  impossible.  Also the user doesn't need to know about these.
+    ant.logger.messageOutputLevel = GantState.SILENT
+    ant.property(environment : 'environment')
+    ant.logger.messageOutputLevel = GantState.verbosity
+    super.setVariable('includeTargets', new IncludeTargets(this))
+    super.setVariable('includeTool', new IncludeTool(this))
+    super.setVariable('globalPreHook', null)
+    super.setVariable('globalPostHook', null)
+    super.setVariable('terminateHook', {int returnValue, String elapseTime ->
+        owner.ant.project.log('\nBUILD ' +(returnValue == 0 ? 'SUCCESSFUL' : 'FAILED'))
+        owner.ant.project.log('Total time: ' + elapseTime)
+      })
+    super.setVariable('listOfTargetMapsDeclared', [ ])
+    super.setVariable('target', {Map<String, String> map, Closure closure ->
+        def targetName = ''
+        def targetDescription = ''
+        def nameKey = 'name'
+        def descriptionKey = 'description'
+        Map targetMap = [:]
+        if  (! map || map.size() == 0) { throw new RuntimeException('Target specified without a name.') }
+        //  target(name : 'flob') is treated as a specification of target flob.
+        if (map.size() == 1 &&  ! map[nameKey]) {
+          // Implicit style of specifying a target and description.
+          targetName = map.keySet().iterator().next()
+          targetDescription = map[targetName]
+          // Create fake name/description entries in the map so that targets closures can still take
+          // advantage of it.name and it.description
+          targetMap[nameKey] = targetName
+          targetMap[descriptionKey] = targetDescription
+        }
+        else {
+          // Explicit style of specifying target name (and possibly description)
+          targetName = map[nameKey]
+          targetDescription = map[descriptionKey]
+          targetMap.putAll(map)
+        }
+        if (! targetName) { throw new RuntimeException('Target specified without a name.') }
+        try {
+          owner.getVariable((String)targetName)
+          //
+          //  Exceptions thrown in this Closure appear not to cause execution to enter an error path.  Must
+          //  find out how to throw an exception from a Closure.
+          //
+          //throw new RuntimeException("Attempt to redefine " + targetName)
+          //
+          owner.binding.ant.project.log('Warning, target causing name overwriting of name ' + targetName, Project.MSG_WARN)
+          //System.exit(-101)
+        }
+        catch (MissingPropertyException mpe) { /* Intentionally empty */ }
+        if (targetDescription) { targetDescriptions.put(targetName, targetDescription) }
+        closure.metaClass = new GantMetaClass(closure.metaClass, owner)
+        if (! targetMap.containsKey('prehook')) { targetMap.prehook = [{-> owner.ant.project.log(targetName + ':')}] }
+        if (! targetMap.containsKey('posthook')) { targetMap.posthook = [{-> owner.ant.project.log('------ ' + targetName)}] }
+        if (targetMap.containsKey('addprehook')) {
+          if (targetMap.prehook instanceof Closure) { targetMap.prehook = [targetMap.prehook] }
+          if (targetMap.addprehook instanceof List) { targetMap.prehook += targetMap.addprehook }
+          else { targetMap.prehook += [targetMap.addprehook] }
+        }
+        if (targetMap.containsKey('addposthook')) {
+          if (targetMap.posthook instanceof Closure) { targetMap.posthook = [targetMap.posthook] }
+          if (targetMap.addposthook instanceof List) { targetMap.posthook = targetMap.addposthook + targetMap.posthook }
+          else { targetMap.posthook = [targetMap.addposthook] + targetMap.posthook }
+        }
+        final targetClosure =  {
+          def returnCode = 0
+          def runHooks = {hook, String label ->
+            if (hook) {
+              if (hook instanceof Closure) { hook.call() }
+              else if (hook instanceof List) {
+                for (item in hook) {
+                  if (item instanceof Closure) { item.call() }
+                  else { owner.ant.project.log(label + ' list item is not a closure.', Project.MSG_ERR) }
+                }
+              }
+              else { owner.ant.project.log(label + ' not a closure or list (of closures).', Project.MSG_ERR) }
+            }
+          }
+          runHooks(owner.globalPreHook, 'Global prehook')
+          runHooks(targetMap.prehook, 'Target prehook')
+          withTargetEvent(targetName, targetDescription) { returnCode = closure(targetMap) }
+          runHooks(targetMap.posthook, 'Target posthook')
+          runHooks(owner.globalPostHook, 'Global posthook')
+          returnCode
+        }
+        owner.setVariable((String) targetName, targetClosure)
+        owner.setVariable(targetName + '_description', targetDescription)  //  For backward compatibility.
+        owner.getVariable('listOfTargetMapsDeclared') << targetMap
+     })
+    super.setVariable('setAllPerTargetPreHooks', { item ->
+      for (tgt in listOfTargetMapsDeclared) { tgt.prehook = item }
+    })
+    super.setVariable('setAllPerTargetPostHooks', { item ->
+      for (tgt in listOfTargetMapsDeclared) { tgt.posthook = item }
+    })
+    super.setVariable('addAllPerTargetPreHooks', { item ->
+      for (tgt in listOfTargetMapsDeclared) { tgt.prehook << item }
+    })
+    super.setVariable('addAllPerTargetPostHooks', { item ->
+      for (tgt in listOfTargetMapsDeclared) { tgt.posthook << item }
+    })
+    super.setVariable('task', {Map<String, String> map, Closure closure ->
+      owner.ant.project.log('task has now been removed from Gant, please update your Gant files to use target instead of task.', Project.MSG_ERR)
+      System.exit(-99) ;
+    })
+    super.setVariable('targetDescriptions', new TreeMap())
+    super.setVariable('message', {String tag, Object message ->
+        def padding = 9 - tag.length()
+        if (padding < 0) { padding = 0 }
+        owner.ant.project.log("           ".substring(0, padding) + '[' + tag + '] ' + message)
+      })
+    super.setVariable('setDefaultTarget', {defaultTarget -> // Deal with Closure or String arguments.
+         switch (defaultTarget.class) {
+          case Closure :
+           String defaultTargetName = null
+           owner.variables.each{key, value -> if (value.is(defaultTarget)) { defaultTargetName = key }}
+           if (defaultTargetName == null) { throw new RuntimeException('Parameter to setDefaultTarget method is not a known target.') }
+           else { owner.forcedSettingOfVariable('defaultTarget', defaultTargetName) }
+           break
+          case String :
+           owner.forcedSettingOfVariable('defaultTarget', defaultTarget)
+           break
+          default :
+           throw new RuntimeException('Parameter to setDefaultTarget is of the wrong type -- must be a target reference or a string.')
+         }
+      })
+    super.setVariable('defaultTarget', 'default')
+    super.setVariable('setFinalizeTarget', {finalizeTarget -> // Deal with Closure or String arguments.
+         switch (finalizeTarget.class) {
+          case Closure :
+           String finalizeTargetName = null
+           owner.variables.each{key, value -> if (value.is(finalizeTarget)) { finalizeTargetName = key }}
+           if (finalizeTargetName == null) { throw new RuntimeException('Parameter to setFinalizeTarget method is not a known target.') }
+           else { owner.forcedSettingOfVariable('finalizeTarget', finalizeTargetName) }
+           break
+          case String :
+           owner.forcedSettingOfVariable('finalizeTarget', finalizeTarget)
+           break
+          default :
+           throw new RuntimeException('Parameter to setFinalizeTarget is of the wrong type -- must be a target reference or a string.')
+         }
+      })
+    super.setVariable('finalizeTarget', 'finalize')
+    super.setVariable('cacheEnabled', false)
+    final item = System.getenv().GANTLIB ;
+    if (item == null) { gantLib = [] }
+    else { gantLib = Arrays.asList(item.split(System.properties.'path.separator')) }
+    initializing = false
+  }
+  /**
+   *  The method for getting values from the binding.  Ensures that Ant properties appear to be in the binding object.
+   */
+  Object getVariable(final String name) {
+    def returnValue
+    try { returnValue = super.getVariable(name) }
+    catch (final MissingPropertyException mpe) {
+      returnValue = super.getVariable('ant')?.project?.getProperty(name)
+      if (returnValue == null) { throw mpe }
+    }
+    returnValue
+  }
+  /**
+   *  The method for setting values in the binding.  Ensures that read-only values cannot be reset after
+   *  initialization.
+   *
+   *  @param name The symbol to define.
+   *  @param value The value to associate with the name.
+   */
+  void setVariable(final String name, final Object value) {
+    if (! initializing && [
+                            'target',
+                            'message',
+                            'ant',
+                            'includeTargets',
+                            'includeTool',
+                            'targetDescriptions',
+                            'setDefaultTarget',
+                            'initiatingTarget',
+                            'targets',
+                            'defaultTarget',
+                            'finalizeTarget',
+                            'listOfTargetMapsDeclared',
+                            'setAllPerTargetPreHooks',
+                            'setAllPerTargetPostHooks',
+                            'addAllPerTargetPreHooks',
+                            'addAllPerTargetPostHooks'
+                            ].contains(name)) { throw new RuntimeException('Cannot redefine symbol ' + name) }
+    super.setVariable(name, value)
+  }
+  /**
+   *  <code>setVariable</code> includes tests for certain names so as to make them read only as far as the
+   *  Gant script is concerned.  However the implementation code needs to be able to circumvent that
+   *  checking, and so we provide this method for implementation code to force things at times other than
+   *  initialization.  This need came about in realizing GANT-44.
+   *
+   *  @param ant the <code>GantBuilder</code> to assign to the 'ant' entry in the binding.
+   */
+  void forcedSettingOfVariable(final String name, final Object value) { super.setVariable(name, value) }
+  /**
+   *  Getter for the list of build listeners.  Used in {@code gant.Gant.withBuildListeners}.
+   */
+  List<BuildListener> getBuildListeners() { buildListeners }
+}
diff --git a/src/main/groovy/org/codehaus/gant/GantBuilder.java b/src/main/groovy/org/codehaus/gant/GantBuilder.java
new file mode 100644
index 0000000..a32ae89
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/GantBuilder.java
@@ -0,0 +1,111 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2011, 2013 Russel Winder
+//
+//  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.codehaus.gant;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+//  In Groovy 1.7.x Closure was a type, in Groovy 1.8.x Closure is a parameterized type.
+//  To support compilation against both versions of Groovy with the same source,
+//  suffer the "raw type" warnings that Eclipse issues.
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+import groovy.lang.Closure;
+import groovy.util.AntBuilder;
+
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.BuildLogger;
+import org.apache.tools.ant.Project;
+
+/**
+ *  This class is a sub-class of {@code AntBuilder} to provide extra capabilities.  In particular, a
+ *  dry-run capability, and things to help support interaction between Gant and the underlying
+ *  {@code Project}.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+public class GantBuilder extends AntBuilder {
+  /**
+   *  Constructor that uses the default project.
+   */
+  public GantBuilder() { }
+  /**
+   *  Constructor that specifies which {@code Project} to be associated with.
+   *
+   *  <p>If execution is from a command line Gant or call from a Groovy script then the class loader for all
+   *  objects is a single instance of {@code org.codehaus.groovy.tools.RootLoader}, which already has
+   *  Ant and Groovy jars in the classpath.  If, however, execution is from an Ant execution via the Gant
+   *  Ant Task, then the classloader for the instance is an instance of
+   *  {@code org.apache.tools.ant.AntClassLoader} with Ant and Groovy jars on the classpath BUT the
+   *  class loader for the {@code Project} instance is a simple {@code java.net.URLClassLoader}
+   *  and does not have the necessary jars on the classpath.  When using Ant, the Ant jar has been loaded
+   *  before the Groovy aspects of the classpath have been set up.  So we must allow for a specialized
+   *  constructor (this one) taking a preprepared {@code Project} to handle this situation.</p>
+   *
+   *  @param project The {@code Project} to be associated with.
+   */
+  public GantBuilder(final Project project) { super(project); }
+  /**
+   *  Invoke a method.
+   *
+   *  @param name The name of the method to invoke.
+   *  @param arguments The parameters to the method call.
+   *  @return The value returned by the method call or null if no value is returned.
+   */
+  @Override public Object invokeMethod(final String name, final Object arguments) {
+    if (GantState.dryRun) {
+      if (GantState.verbosity > GantState.SILENT) {
+        final StringBuilder sb = new StringBuilder();
+        int padding = 9 - name.length();
+        if (padding < 0) { padding = 0; }
+        sb.append("         ".substring(0, padding) + '[' + name + "] ");
+        final Object[] args = (Object[]) arguments;
+        if (args[0] instanceof Map<?,?>) {
+          //////////////////////////////////////////////////////////////////////////////////////////////////////////
+          // Eclipse and IntelliJ IDEA warn that (Map) is not a proper cast but using the
+          // cast (Map<?,?>) causes a type check error due to the capture algorithm.
+          //
+          //  TODO : Fix this rather than use a SuppressWarnings.
+          //////////////////////////////////////////////////////////////////////////////////////////////////////////
+          @SuppressWarnings({ "unchecked", "rawtypes" } ) final Iterator<Map.Entry<?,?>> i =((Map) args[0]).entrySet().iterator();
+          while (i.hasNext()) {
+            final Map.Entry<?,?> e = i.next();
+            sb.append(e.getKey() + " : '" + e.getValue() + '\'');
+            if (i.hasNext()) { sb.append(", "); }
+          }
+          sb.append('\n');
+          getProject().log(sb.toString());
+          if (args.length == 2) {((Closure<?>) args[1]).call(); }
+        }
+        else if (args[0] instanceof Closure) { ((Closure<?>) args[0]).call(); }
+        else { throw new RuntimeException("Unexpected type of parameter to method " + name); }
+      }
+      return null;
+    }
+    return super.invokeMethod(name, arguments);
+  }
+  /**
+   *  Accessor for the logger associated with the {@code Project}.
+   *
+   *  @return The {@code BuildLogger}.
+   */
+  public BuildLogger getLogger() {
+    @SuppressWarnings("unchecked") final List<? extends BuildListener> listeners = getProject().getBuildListeners();
+    assert listeners.size() > 0;
+    return (BuildLogger)listeners.get(0);
+  }
+}
diff --git a/src/main/groovy/org/codehaus/gant/GantEvent.groovy b/src/main/groovy/org/codehaus/gant/GantEvent.groovy
new file mode 100644
index 0000000..445e61f
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/GantEvent.groovy
@@ -0,0 +1,45 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright  © 2008, 2013  Russel Winder
+//
+//  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.codehaus.gant
+
+import org.apache.tools.ant.BuildEvent
+import org.apache.tools.ant.Project
+import org.apache.tools.ant.Target
+import org.apache.tools.ant.Task
+
+/**
+ *  Extended version of the <code>BuildEvent</code> class that provides access to the
+ *  <code>GantBinding</code>.
+ *
+ *  @author Graeme Rocher
+ *  @since 1.6
+ *
+ *  Created: 2008-12-18
+ */
+public class GantEvent extends BuildEvent {
+  private GantBinding binding
+  public GantEvent(final Project project, final GantBinding binding) {
+    super(project)
+    this.binding = binding
+  }
+  public GantEvent(final Target target, final GantBinding binding) {
+    super(target)
+    this.binding = binding
+  }
+  public GantEvent(final Task task, final GantBinding binding) {
+    super(task)
+    this.binding = binding
+  }
+}
diff --git a/src/main/groovy/org/codehaus/gant/GantMetaClass.java b/src/main/groovy/org/codehaus/gant/GantMetaClass.java
new file mode 100644
index 0000000..da13584
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/GantMetaClass.java
@@ -0,0 +1,209 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2011, 2013  Russel Winder
+//
+//  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.codehaus.gant;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+//  In Groovy 1.7.x Closure was a type, in Groovy 1.8.x Closure is a parameterized type.
+//  To support compilation against both versions of Groovy with the same source,
+//  suffer the "raw type" warnings that Eclipse issues.
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+import groovy.lang.Closure;
+import groovy.lang.DelegatingMetaClass;
+import groovy.lang.GString;
+import groovy.lang.MetaClass;
+import groovy.lang.MissingMethodException;
+import groovy.lang.MissingPropertyException;
+import groovy.lang.Tuple;
+
+import org.codehaus.groovy.runtime.MetaClassHelper;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ *  This class is the metaclass used for target {@code Closure}s, and any enclosed {@code Closures}.
+ *
+ *  <p>This metaclass deals with {@code depends} method calls and redirects unknown method calls to the
+ *  instance of {@code GantBuilder}.  To process the {@code depends} all closures from the
+ *  binding called during execution of the Gant specification must be logged so that when a depends happens
+ *  the full closure call history is available.</p>
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+public class GantMetaClass extends DelegatingMetaClass {
+  /**
+   *  The set of all targets that have been called.  This is a global variable shared by all instances of
+   *  {@code GantMetaClass}.
+   *
+   *  <p>TODO : This code is a long way from thread safe, and so it needs fixing.  Should this variable be
+   *  moved to the GantState class, which is the class that holds other bits of the internal shared state?
+   *  Should a different data structure be used, one that is a bit more thread safe?  Arguably it is
+   *  reasonable for this to be a synchronized object.</p>
+   */
+  private static final Set<Closure<?>> methodsInvoked = new HashSet<Closure<?>>();
+  /**
+   *  The binding (aka global shared state) that is being used.
+   */
+  private final GantBinding binding;
+  /*
+   */
+  public GantMetaClass(final MetaClass metaClass, final GantBinding binding) {
+    super(metaClass);
+    this.binding = binding;
+  }
+  /**
+   *  Execute a {@code Closure} only if it hasn't been executed previously.  If it is executed, record
+   *  the execution.  Only used for processing a {@code depends} call.
+   *
+   *  @param closure The {@code Closure} to potentially call.
+   *  @return the result of the {@code Closure} call, or {@code null} if the closure was not
+   *  called.
+   */
+  private Object processClosure(final Closure<?> closure) {
+    if (! methodsInvoked.contains(closure)) {
+      methodsInvoked.add(closure);
+      return closure.call();
+    }
+    return null;
+  }
+  /**
+   *  Process the argument to a {@code depends} call.  If the parameter is a {@code Closure} just
+   *  process it. If it is a {@code String} then do a lookup for the {@code Closure} in the
+   *  binding, and if found process it.
+   *
+   *  @param argument The argument.
+   *  @return The result of the {@code Closure}.
+   */
+  private Object processArgument(final Object argument) {
+    final Object returnObject;
+    if (argument instanceof Closure) { returnObject = processClosure((Closure<?>) argument); }
+    else {
+      final String errorReport = "depends called with an argument (" + argument + ") that is not a known target or list of targets.";
+      Object theArgument = argument;
+      if (theArgument instanceof GString) { theArgument = theArgument.toString(); }
+      if (theArgument instanceof String) {
+        final Object entry = binding.getVariable((String) theArgument);
+        if ((entry != null) && (entry instanceof Closure)) { returnObject = processClosure((Closure<?>) entry); }
+        else { throw new RuntimeException(errorReport); }
+      }
+      else { throw new RuntimeException(errorReport); }
+    }
+    return returnObject;
+  }
+  /**
+   *  Invokes a method on the given object with the given name and arguments. The {@code MetaClass}
+   *  will attempt to pick the best method for the given name and arguments. If a method cannot be invoked a
+   *  {@code MissingMethodException} will be thrown.
+   *
+   *  @see MissingMethodException
+   *  @param object The instance on which the method is invoked.
+   *  @param methodName The name of the method.
+   *  @param arguments The arguments to the method.
+   *  @return The return value of the method which is {@code null} if the return type is
+   *  {@code void}.
+   */
+  @Override public Object invokeMethod(final Object object, final String methodName, final Object[] arguments) {
+    Object returnObject = null;
+    if (methodName.equals("depends")) {
+      for (final Object argument : arguments) {
+        if (argument instanceof List<?>) {
+          for (final Object item : (List<?>) argument) { returnObject = processArgument(item); }
+        }
+        else { returnObject = processArgument(argument); }
+      }
+    }
+    else {
+      try {
+        returnObject = super.invokeMethod(object, methodName, arguments);
+        try {
+          final Closure<?> closure = (Closure<?>) binding.getVariable(methodName);
+          if (closure != null) { methodsInvoked.add(closure); }
+        }
+        catch (final MissingPropertyException mpe) { /* Purposefully empty */ }
+      }
+      catch (final MissingMethodException mme) {
+        try { returnObject = ((GantBuilder)(binding.getVariable("ant"))).invokeMethod(methodName, arguments); }
+        catch (final BuildException be) {
+          //  This BuildException could be a real exception due to a failed execution of a found Ant task
+          //  (in which case it should be propagated), or it could be due to a failed name lookup (in which
+          //  case the MissingMethodException should be propagated).  The big problem is distinguishing the
+          //  various uses of Build Exception here -- for now use string search of the exception message to
+          //  distinguish the cases.  NB GANT-49 and GANT-68 are the main conflicting issues here :-(
+          if (be.getMessage().startsWith("Problem: failed to create task or type")) { throw mme; }
+          else { throw be; }
+        }
+        catch (final Exception e) { throw mme; }
+      }
+    }
+    return returnObject;
+  }
+  /**
+   *  Invokes a method on the given object, with the given name and single argument.
+   *
+   *  @see #invokeMethod(Object, String, Object[])
+   *  @param object The Object to invoke the method on
+   *  @param methodName The name of the method
+   *  @param arguments The argument to the method
+   *  @return The return value of the method which is null if the return type is void
+   */
+  @Override public Object invokeMethod(final Object object, final String methodName, final Object arguments) {
+    if (arguments == null) { return invokeMethod(object, methodName, MetaClassHelper.EMPTY_ARRAY); }
+    else if (arguments instanceof Tuple) { return invokeMethod(object, methodName,((Tuple)arguments).toArray()); }
+    else if (arguments instanceof Object[]) { return invokeMethod(object, methodName, (Object[])arguments); }
+    else { return invokeMethod(object, methodName, new Object[] { arguments }); }
+  }
+  /**
+   *  Invoke the given method.
+   *
+   *  @param name the name of the method to call
+   *  @param args the arguments to use for the method call
+   *  @return the result of invoking the method
+   */
+  @Override public Object invokeMethod(final String name, final Object args) {
+    return invokeMethod(this, name, args);
+  }
+  //////////////////////////////////////////////////////////////////////////////////////////////////////////
+  //  As at 2012-05-31 it is believed that groovy.lang.DelegatingMetaClass (the invokeMethod method
+  //  anyway) has not been marked up for Java generics in any branch of Groovy (1.8, 2.0, master).
+  //  This leads to the problem that blah(Class<?>) does not override blah(Class). So we must leave
+  //  the Class type without a type parameter and suffer the compilation warning.
+  //
+  //  TODO : Class -> Class<?> when the Eclipse plugin and the Groovy code base allow.
+  //////////////////////////////////////////////////////////////////////////////////////////////////////////
+  /**
+   *  Invoke a method on the given receiver for the specified arguments. The sender is the class that
+   *  invoked the method on the object.  Attempt to establish the method to invoke based on the name and
+   *  arguments provided.
+   *
+   *  <p>The {@code isCallToSuper} and {@code fromInsideClass} help the Groovy runtime perform
+   *  optimizations on the call to go directly to the superclass if necessary.</p>
+   *
+   *  @param sender The {@code java.lang.Class} instance that invoked the method.
+   *  @param receiver The object which the method was invoked on.
+   *  @param methodName The name of the method.
+   *  @param arguments The arguments to the method.
+   *  @param isCallToSuper Whether the method is a call to a superclass method.
+   *  @param fromInsideClass Whether the call was invoked from the inside or the outside of the class.
+   *  @return The return value of the method
+   */
+  @SuppressWarnings("rawtypes")
+  @Override public Object invokeMethod(final Class sender, final Object receiver, final String methodName, final Object[] arguments, final boolean isCallToSuper, final boolean fromInsideClass) {
+    return invokeMethod(receiver, methodName, arguments);
+  }
+}
diff --git a/src/main/groovy/org/codehaus/gant/GantState.java b/src/main/groovy/org/codehaus/gant/GantState.java
new file mode 100644
index 0000000..74f4402
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/GantState.java
@@ -0,0 +1,83 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant;
+
+import org.apache.tools.ant.Project;
+
+/**
+ *  A class to hold the shared global state for a run of Gant, also a variety of general-use constants are
+ *  defined here.
+ *
+ *  <p>This class was originally needed because parts of Gant are written in Java and parts in Groovy and it
+ *  was not possible to compile them all at the same time.  All references to Groovy classes had to be
+ *  avoided in the Java classes so that the Java could be compiled and then the Groovy compiled.  This class
+ *  contains things that should be in the {@code Gant} class but could not be.  All this is no longer
+ *  true, so the material could go back into the {@code Gant} class.</p>
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+public class GantState {
+
+  //  Ant's Project message priority levels are good for specifying the priority of a message sent to the
+  //  log but present an awkward way of specifying the level of verbosity.  We therefore create some aliases
+  //  to make code a little more self-documenting.
+  //
+  //  Ant appears not to have a silent mode.  Gant allows for a silent mode by adding an extra verbosity
+  //  level.  We have to be aware that the constants from Project are effectively an enumeration -- integer
+  //  values starting at 0 -- and that the larger the number, the lower the priority of the message.  Thus
+  //  if we set the priority of the logger less than MSG_ERR, no messages will be output.
+  //
+  //  NB Ant appears to output errors to the error channel (System.err by default) and all other messages to
+  //  the standard output (System.out by default).  Gant's behaviour to date (i.e. up to version 1.6.1) has
+  //  been to output all information to System.out.  For the moment then error information is logged at
+  //  MSG_WARN priority, and MSG_ERR is unused.
+
+  /**
+   *  Output no information ever.
+   */
+  public static final int SILENT = Project.MSG_ERR - 1;
+  /**
+   *  Output only information about errors.
+   */
+  public static final int ERRORS_ONLY = Project.MSG_ERR;
+  /**
+   *  Output only the meagrest of information.
+   */
+  public static final int WARNINGS_AND_ERRORS = Project.MSG_WARN;
+  /**
+   *  Output information about which task is executing, and other things.
+   */
+  public static final int NORMAL = Project.MSG_INFO;
+  /**
+   *  Output lots of information about what is going on.
+   */
+  public static final int VERBOSE = Project.MSG_VERBOSE;
+  /**
+   *  Output huge amounts of information about what is going on.
+   */
+  public static final int DEBUG = Project.MSG_DEBUG;
+  /**
+   *  The current state of the verbosity of execution -- default is {@code NORMAL}.
+   */
+  public static int verbosity = NORMAL;
+  /**
+   *  Whether this is a dry drun, i.e. no actual execution occur.
+   */
+  public static boolean dryRun = false;
+  /**
+   *  We never want an instance of this class, so the constructor is made private.
+   */
+  private GantState() {}
+}
diff --git a/src/main/groovy/org/codehaus/gant/IncludeTargets.groovy b/src/main/groovy/org/codehaus/gant/IncludeTargets.groovy
new file mode 100644
index 0000000..bc68fc3
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/IncludeTargets.groovy
@@ -0,0 +1,91 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2008, 2010, 2013  Russel Winder
+//
+//  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.codehaus.gant
+
+/**
+ *  An instance of this class is provided to each Gant script for including targets.  Targets can be
+ *  provided by Gant (sub)scripts, Groovy classes, or Java classes.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ *  @author Graeme Rocher <graeme.rocher at gmail.com>
+ */
+class IncludeTargets extends AbstractInclude {
+  /**
+   *  Constructor.
+   *
+   *  @param binding The <code>GantBinding</code> to associate with.
+   */
+  IncludeTargets(GantBinding binding) { super(binding) }
+  /**
+   *  Implementation of the << operator taking a <code>Class</code> parameter.
+   *
+   *  @param theClass The <code>Class</code> to load and instantiate.
+   *  @return The includer object to allow for << chaining.
+   */
+  def leftShift(final Class<?> theClass) {
+    def className = theClass.name
+    if (!(className in loadedClasses)) {
+      createInstance(theClass)
+      loadedClasses << className
+    }
+    this
+  }
+  /**
+   *  Implementation of the << operator taking a <code>File</code> parameter.
+   *
+   *  @param file The <code>File</code> to load, compile, and instantiate.
+   *  @return The includer object to allow for << chaining.
+   */
+  def leftShift(final File file) {
+    def className = file.name
+    if (!(className in loadedClasses)) {
+      if (binding.cacheEnabled) {
+        //  Class name will likely have packages, but this is not acceptable for a single name in the
+        //  binding, so convert any dots to underscores.
+        def script = binding.loadClassFromCache.call(className.replaceAll(/\./, '_'), file.lastModified(), file)
+        script.binding = binding
+        script.run()
+      }
+      else { readFile(file) }
+      loadedClasses << className
+    }
+    this
+  }
+  /**
+   *  Implementation of the << operator taking a <code>String</code> parameter.
+   *
+   *  @param s The <code>String</code> to compile and instantiate.
+   *  @return The includer object to allow for << chaining.
+   */
+  def leftShift(final String s) { binding.groovyShell.evaluate(s); this }
+  /**
+   *  Implementation of the * operator taking a <code>Map</code> parameter.  This operator only makes
+   *  sense immediately after a ** operator, since only then is there a <code>Class</code> to instantiate.
+   *
+   *  @param keywordParameter The <code>Map</code> of parameters to the constructor.
+   *  @return The includer object to allow for ** * operator chaining.
+   */
+  def multiply(final Map<String,String> keywordParameters) {
+    if (pendingClass != null) {
+      def className = pendingClass.name
+      if (!(className in loadedClasses)) {
+        createInstance(pendingClass, keywordParameters)
+        loadedClasses << className
+      }
+      pendingClass = null
+    }
+    this
+  }
+}
diff --git a/src/main/groovy/org/codehaus/gant/IncludeTool.groovy b/src/main/groovy/org/codehaus/gant/IncludeTool.groovy
new file mode 100644
index 0000000..a3622c9
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/IncludeTool.groovy
@@ -0,0 +1,122 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2008, 2010, 2013  Russel Winder
+//
+//  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.codehaus.gant
+
+/**
+ *  An instance of this class is provided to each Gant script for including tools.  A tool is a class that
+ *  provides Gant related facilities.  The class must have a single parameter constructor which is a
+ *  <code>Map</code>.  The map contains a binding of various useful things, in particular there is always an
+ *  entry 'Ant' to give access to the global static instance of <code>AntBuilder</code>.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+class IncludeTool extends AbstractInclude {
+  /**
+   *  Constructor.
+   *
+   *  @param binding The <code>GantBinding</code> to associate with.
+   */
+  IncludeTool(GantBinding binding) { super(binding ) }
+  /**
+   *  Implementation of the << operator taking a <code>Class</code> parameter.
+   *
+   *  @param theClass The <code>Class</code> to load and instantiate.
+   *  @return The includer object to allow for << chaining.
+   */
+  def leftShift(Class<?> theClass) {
+    def className = theClass.name
+    if (!(className in loadedClasses)) {
+      def index = className.lastIndexOf('.') + 1
+      makeBindingEntry(className[index..-1], createInstance(theClass))
+      loadedClasses << className
+    }
+    this
+  }
+  /**
+   *  Implementation of the << operator taking a <code>File</code> parameter.
+   *
+   *  @param file The <code>File</code> to load, compile, and instantiate.
+   *  @return The includer object to allow for << chaining.
+   */
+  def leftShift(File file) {
+    def className = file.name
+    if (!(className in loadedClasses)) {
+      className = className[ 0 ..< className.lastIndexOf('.') ]
+      def theClass = readFile(file, true)
+      makeBindingEntry(className, createInstance(theClass))
+      loadedClasses << className
+    }
+    this
+  }
+  /**
+   *  Implementation of the << operator taking a <code>String</code> parameter.
+   *
+   *  @param s The <code>String</code> to compile and instantiate.
+   *  @return The includer object to allow for << chaining.
+   */
+  def leftShift(String script) {
+    def className = ''
+    final javaIdentifierRegexAsString = /\b\p{javaJavaIdentifierStart}(?:\p{javaJavaIdentifierPart})*\b/
+    final javaQualifiedNameRegexAsString = /\b${javaIdentifierRegexAsString}(?:[.\/]${javaIdentifierRegexAsString})*\b/
+    script.eachMatch(/(?:(?:public|final))*[ \t\r\n]*class[ \t\r\n]*(${javaIdentifierRegexAsString})[ \t\r\n]*(?:extends[ \t\r\n]*${javaQualifiedNameRegexAsString})*[ \t\r\n]*\{/) { opening, name ->
+      //  There has to be a better way of doing this.  Assume that the first instance of the class
+      //  declaration is the one we want and that any later ones are not an issue.
+      if (className == '') { className = name }
+    }
+    if (!(className in loadedClasses)) {
+      loadedClasses << className
+      def theClass = binding.groovyShell.evaluate(script + " ; return ${className}")
+      makeBindingEntry(className, createInstance(theClass))
+    }
+    this
+  }
+  /**
+   *  Implementation of the * operator taking a <code>Map</code> parameter.  This operator only makes
+   *  sense immediately after a ** operator, since only then is there a <code>Class</code> to instantiate.
+   *
+   *  @param keywordParameter The <code>Map</code> of parameters to the constructor.
+   *  @return The includer object to allow for ** * operator chaining.
+   */
+  def multiply(Map<String,String> keywordParameters) {
+    if (pendingClass != null) {
+      def className = pendingClass.name
+      if (!(className in loadedClasses)) {
+        def index = className.lastIndexOf('.') + 1
+        makeBindingEntry(className[index..-1], createInstance(pendingClass, keywordParameters))
+        loadedClasses << className
+      }
+      pendingClass = null
+    }
+    this
+  }
+  /**
+   *  Make an entry in the binding for an instance of a class where the entry in the binding is the same as
+   *  the name of the class but with an initial lowercase letter instead of uppercase letter.
+   *
+   *  @param name The label to use in the binding.
+   *  @param object The object for name to refer to.
+   */
+  private void makeBindingEntry(String name, object) {
+    def initialLetter = name[0] as Character
+    def transformedName = (Character.toLowerCase(initialLetter) as String) + name[1..-1]
+    try {
+      binding.getVariable(transformedName)
+      throw new RuntimeException("Attempt to redefine name " + transformedName)
+    }
+    catch (MissingPropertyException nspe) {
+      binding.setVariable(transformedName, object)
+    }
+  }
+}
diff --git a/src/main/groovy/org/codehaus/gant/ant/Gant.java b/src/main/groovy/org/codehaus/gant/ant/Gant.java
new file mode 100644
index 0000000..3d491b6
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/ant/Gant.java
@@ -0,0 +1,214 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2009, 2013  Russel Winder
+//
+//  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.codehaus.gant.ant;
+
+import java.io.File;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+import org.codehaus.gant.GantBinding;
+import org.codehaus.gant.GantBuilder;
+
+/**
+ *  Execute a Gant script.
+ *
+ *  <p>This Ant task provides a Gant calling capability. The original intention behind this was to support
+ *  continuous integration systems that do not directly support Gant but only Ant.  However it also allows
+ *  for gradual evolution of an Ant build into a Gant build.</p>
+ *
+ *  <p>Possible attributes are:</p>
+ *
+ *  <ul>
+ *    <li>file – the path of the Gant script to execute.</li>
+ *    <li>target – the target to execute; must be a single target name.  For specifying than a
+ *        single target, use nested gantTarget tags.</li>
+ *  </ul>
+ *
+ *  <p>Both of these are optional.  The file 'build.gant' and the default target are used by default.  An
+ *  error results if there is no default target and no target is specified.</p>
+ *
+ *  <p>Definitions, if needed, are specified using nested <code>definition</code> tags, one for each symbol
+ *  to be defined.  Each <code>definition</code> tag takes a compulsory <code>name</code> attribute and an
+ *  optional <code>value</code> attribute.</p>
+ *
+ * @author Russel Winder
+ */
+public class Gant extends Task {
+  /**
+   *  The path to the file to use to drive the Gant build.  The default is build.gant.  This path is
+   *  relative to the basedir of the Ant project if it is set, or the directory in which the job was started
+   *  if the basedir is not set.
+   */
+  private String file = "build.gant";
+  /**
+   *  Flag determining whether properties are inherited from the parent project.
+   */
+  private boolean inheritAll = false;
+  /**
+   *  A class representing a nested definition tag.
+   */
+  public static final class Definition {
+    private String name;
+    private String value;
+    public void setName(final String s) { name = s; }
+    public String getName() { return name; }
+    public void setValue(final String s) { value = s; }
+    public String getValue() { return value; }
+  }
+  /**
+   *  A list of definitions to be set in the Gant instance.
+   */
+  private final List<Definition> definitions = new ArrayList<Definition>();
+  /**
+   *  A class representing a nested target tag.
+   */
+  public static final class GantTarget {
+    private String value;
+    public void setValue(final String s) { value = s; }
+    public String getValue() { return value; }
+  }
+  /**
+   *  A list of targets to be achieved by the Gant instance.
+   */
+  private final List<GantTarget> targets = new ArrayList<GantTarget>();
+  /**
+   *  Set the name of the build file to use.  This path is relative to the basedir of the Ant project if it
+   *  is set, or the directory in which the job was started if the basedir is not set.
+   *
+   *  @param f The name of the file to be used to drive the build.
+   */
+  public void setFile(final String f) { file = f; }
+  /**
+   *  Set the target to be achieved.
+   *
+   *  @param t The target to achieve.
+   */
+  public void setTarget(final String t) {
+    final GantTarget gt = new GantTarget();
+    gt.setValue(t);
+    targets.add(gt);
+  }
+  /**
+   *  Create a node to represent a nested <code>gantTarget</code> tag.
+   *
+   *  @return a new <code>GantTarget</code> instance ready for values to be added.
+   */
+  public GantTarget createGantTarget() {
+    final GantTarget gt = new GantTarget();
+    targets.add(gt);
+    return gt;
+  }
+  /**
+   *  Create a node to represent a nested <code>definition</code> tag.
+   *
+   *  @return a new <code>Definition</code> instance ready for values to be added.
+   */
+  public Definition createDefinition() {
+    final Definition definition = new Definition();
+    definitions.add(definition);
+    return definition;
+  }
+  /**
+   *  If true, pass all properties to the new Ant project.
+   *
+   *  @param value if true pass all properties to the new Ant project.
+   */
+  public void setInheritAll(final boolean value) { inheritAll = value; }
+  /**
+   * Load the file and then execute it.
+   */
+  @Override public void execute() throws BuildException {
+    //
+    //  At first it might seem appropriate to use the Project object from the calling Ant instance as the
+    //  Project object used by the AntBuilder object and hence GantBuilder object associated with the Gant
+    //  instance we are going to create here.  However, if we just use that Project object directly then
+    //  there are problems with proper annotation of the lines of output, so it isn't really an option.
+    //  Therefore create a new Project instance and set the things appropriately from the original Project
+    //  object.
+    //
+    //  Issues driving things here are GANT-50 and GANT-80.  GANT-50 is about having the correct base
+    //  directory for operations, GANT-80 is about ensuring that all output generation actually generated
+    //  observable output.
+    //
+    //  NB As this class is called Gant, we have to use fully qualified name to get to the Gant main class.
+    //
+    final Project antProject =  getOwningTarget().getProject();
+    final Project newProject = new Project();
+    newProject.init();
+    //  Deal with GANT-80 by getting all the the loggers from the Ant instance Project object and adding
+    //  them to the new Project Object.  This was followed up by GANT-91 so the code was amended to copying
+    //  over all listeners except the class loader if present.
+    for (final Object o : antProject.getBuildListeners()) {
+      final BuildListener listener = (BuildListener) o;
+      if (!(listener instanceof AntClassLoader)) { newProject.addBuildListener(listener); }
+    }
+    //  Deal with GANT-50 by getting the base directory from the Ant instance Project object and use it for
+    //  the new Project object.  GANT-93 leads to change in the way the Gant file is extracted.
+    newProject.setBaseDir(antProject.getBaseDir());
+    //  Deal with GANT-110 by using the strategy proposed by Eric Van Dewoestine.
+    if (inheritAll) { addAlmostAll(newProject, antProject); }
+    final File gantFile = newProject.resolveFile(file);
+    if (! gantFile.exists()) { throw new BuildException("Gantfile does not exist.", getLocation()); }
+    final GantBuilder ant = new GantBuilder(newProject);
+    final Map<String,String> environmentParameter = new HashMap<String,String>();
+    environmentParameter.put("environment", "environment");
+    ant.invokeMethod("property", new Object[] { environmentParameter });
+    final GantBinding binding = new GantBinding();
+    binding.forcedSettingOfVariable("ant", ant);
+    for (final Definition definition : definitions) {
+      final Map<String,String> definitionParameter = new HashMap<String,String>();
+      definitionParameter.put("name", definition.getName());
+      definitionParameter.put("value", definition.getValue());
+      ant.invokeMethod("property", new Object[] { definitionParameter });
+    }
+    final gant.Gant gant = new gant.Gant(binding);
+    gant.loadScript(gantFile);
+    final List<String> targetsAsStrings = new ArrayList<String>();
+    for (final GantTarget g : targets) { targetsAsStrings.add(g.getValue()); }
+    final int returnCode =  gant.processTargets(targetsAsStrings);
+    if (returnCode != 0) { throw new BuildException("Gant execution failed with return code " + returnCode + '.', getLocation()); }
+  }
+  /**
+   *  Copy all properties from the given project to the new project -- omitting those that have already been
+   *  set in the new project as well as properties named basedir or ant.file. Inspired by the {@code
+   *  org.apache.tools.ant.taskdefs.Ant} source.
+   *
+   *  @param newProject the {@code Project} to copy into.
+   *  @param oldProject the {@code Project} to copy properties from.
+   */
+  //  Russel Winder rehacked the code provided by Eric Van Dewoestine.
+  private void addAlmostAll(final Project newProject, final Project oldProject) {
+    final Hashtable<String,Object> properties = oldProject.getProperties();
+    final Enumeration<String> e = properties.keys();
+    while (e.hasMoreElements()) {
+      final String key = e.nextElement();
+      if (!(MagicNames.PROJECT_BASEDIR.equals(key) || MagicNames.ANT_FILE.equals(key))) {
+        if (newProject.getProperty(key) == null) { newProject.setNewProperty(key, (String)properties.get(key)); }
+      }
+    }
+  }
+}
diff --git a/src/main/groovy/org/codehaus/gant/ant/package.html b/src/main/groovy/org/codehaus/gant/ant/package.html
new file mode 100644
index 0000000..e3eb2a2
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/ant/package.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>org.codehaus.gant.ant</title>
+  </head>
+
+  <body>
+    <p>
+      This package has all the implementation classes for Ant support in Gant.
+    </p>
+
+    <hr>
+    <address><a href="mailto:russel at winder.org.uk">Russel Winder</a></address>
+    Last modified: 2010-04-05T08:30+01:00
+  </body>
+</html>
diff --git a/src/main/groovy/org/codehaus/gant/package.html b/src/main/groovy/org/codehaus/gant/package.html
new file mode 100644
index 0000000..7660446
--- /dev/null
+++ b/src/main/groovy/org/codehaus/gant/package.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>org.codehaus.gant</title>
+  </head>
+
+  <body>
+    <p>
+      This package has all the internal implementation classes for Gant.
+    </p>
+
+    <hr>
+    <address><a href="mailto:russel at winder.org.uk">Russel Winder</a></address>
+    Last modified: 2010-04-05T08:30+01:00
+  </body>
+</html>
diff --git a/src/site/site.xml b/src/site/site.xml
new file mode 100644
index 0000000..80ff4c1
--- /dev/null
+++ b/src/site/site.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Gant - A Groovy way of scripting Ant tasks.
+
+Copyright © 2007,2010 Russel Winder.
+
+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 : Russel Winder <russel at winder.org.uk>
+-->
+
+<project name="${project.name}">
+  
+  <bannerLeft>
+    <name>Groovy</name>
+    <src>http://media.xircles.codehaus.org/_projects/groovy/_logos/medium.png</src>
+    <href>http://groovy.codehaus.org</href>
+  </bannerLeft>
+
+  <bannerRight>
+    <name>Codehaus</name>
+    <src>http://mojo.codehaus.org/images/codehaus-small.png</src>
+    <href>http://codehaus.org</href>
+  </bannerRight>
+
+  <publishDate format="yyyy-MM-dd" position="left"/>
+
+  <version position="left"/>
+  
+  <body>
+    <links>
+      <item name="Gant" href="http://groovy.codehaus.org/Gant/"/>
+      <item name="Groovy" href="http://groovy.codehaus.org/"/>
+    </links>
+
+    ${parentProject}
+
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+    </menu>
+    
+    ${modules}
+    
+    ${reports}
+  </body>
+</project>
diff --git a/src/test/groovy/gant/targets/tests/Clean_Test.groovy b/src/test/groovy/gant/targets/tests/Clean_Test.groovy
new file mode 100644
index 0000000..13e78f7
--- /dev/null
+++ b/src/test/groovy/gant/targets/tests/Clean_Test.groovy
@@ -0,0 +1,117 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2007–2010, 2013  Russel Winder
+//
+//  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 gant.targets.tests
+
+import org.codehaus.gant.tests.GantTestCase
+
+/**
+ *  A test to ensure that the Clean targets are not broken.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Clean_Test extends GantTestCase {
+  final targetName = 'targetName'
+  void testCleanDirectoryString() {
+    script = """
+includeTargets << gant.targets.Clean
+cleanDirectory << 'target'
+target(${targetName}: '') { println(cleanDirectory) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[target]\n'), output)
+    assertEquals('', error)
+  }
+  void testCleanDirectoryList() {
+    script = """
+includeTargets << gant.targets.Clean
+cleanDirectory << ['target_a', 'target_b']
+target(${targetName}: '') { println(cleanDirectory) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[[target_a, target_b]]\n'), output)
+    assertEquals('', error)
+  }
+  void testCleanPatternString() {
+    script = """
+includeTargets << gant.targets.Clean
+cleanPattern << '**/*~'
+target(${targetName}: '') {println(cleanPattern) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[**/*~]\n'), output)
+    assertEquals('', error)
+  }
+  void testCleanPatternList() {
+    script = """
+includeTargets << gant.targets.Clean
+cleanPattern << ['**/*~', '**/*.bak']
+target(${targetName}: '') { println(cleanPattern) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[[**/*~, **/*.bak]]\n'), output)
+    assertEquals('', error)
+  }
+  void testClobberDirectoryString() {
+    script = """
+includeTargets << gant.targets.Clean
+clobberDirectory << 'target'
+target(${targetName}: '') { println(clobberDirectory) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[target]\n'), output)
+    assertEquals('', error)
+  }
+  void testClobberDirectoryList() {
+    script = """
+includeTargets << gant.targets.Clean
+clobberDirectory << ['target_a', 'target_b']
+target(${targetName}: '') { println(clobberDirectory) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[[target_a, target_b]]\n'), output)
+    assertEquals('', error)
+  }
+  void testClobberPatternString() {
+    script = """
+includeTargets << gant.targets.Clean
+clobberPattern << '**/*~'
+target(${targetName}: '') {
+  println(clobberPattern)
+}
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[**/*~]\n'), output)
+    assertEquals('', error)
+  }
+  void testClobberPatternList() {
+    script = """
+includeTargets << gant.targets.Clean
+clobberPattern << ['**/*~', '**/*.bak']
+target(${targetName}: '') { println(clobberPattern) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[[**/*~, **/*.bak]]\n'), output)
+    assertEquals('', error)
+  }
+  void testParameterizedInclude() {
+   script = """
+includeTargets ** gant.targets.Clean * [cleanDirectory: 'target']
+target(${targetName}: '') { println(cleanDirectory) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[target]\n'), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/gant/targets/tests/Maven_Test.groovy b/src/test/groovy/gant/targets/tests/Maven_Test.groovy
new file mode 100644
index 0000000..b53c004
--- /dev/null
+++ b/src/test/groovy/gant/targets/tests/Maven_Test.groovy
@@ -0,0 +1,165 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2007--2011, 2013  Russel Winder
+//
+//  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 gant.targets.tests
+
+import org.codehaus.gant.GantBuilder
+import org.codehaus.gant.GantState
+
+import org.codehaus.gant.tests.GantTestCase
+
+/**
+ *  A test to ensure that the Maven targets are not broken.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Maven_Test extends GantTestCase {
+  void testLoadingTargets() {
+    script = """
+includeTargets << gant.targets.Maven
+"""
+    assertEquals(0, processCmdLineTargets('initialize'))
+    assertEquals('initialize:\n' + exitMarker + 'initialize\n', output)
+    assertEquals('', error)
+  }
+  void testCompileTargetInDirectoryOtherThanTheCurrentBuildDirectory() {
+    final mavenTargetSetTestDirectory = new File('mavenTargetsSetTest')
+    final sourceDirectory = new File(mavenTargetSetTestDirectory, 'src')
+    final javaFileDirectory = new File(sourceDirectory, 'main/java')
+    final targetDirectory = new File(mavenTargetSetTestDirectory, 'target')
+    final compiledClassesDirectory = new File(targetDirectory, 'classes')
+    final root = 'hello'
+    final gantBuilder = new GantBuilder()
+    gantBuilder.logger.messageOutputLevel = GantState.SILENT
+    gantBuilder.delete(dir: mavenTargetSetTestDirectory.path)
+    gantBuilder.mkdir(dir: javaFileDirectory.path)
+   (new File(javaFileDirectory, root + '.java')).write("class ${root} { }")
+    final targetName = 'compile'
+    //  Java 7 introduces a new warning message about setting bootclasspath when setting a source level
+    //  lower than the current Java version.  Circumvent this for all cases by enforcing not using the
+    //  default of 5, but the same version as the running version.
+    final versionNumber = System.getProperty('java.version')[2]
+    script = """
+includeTargets ** gant.targets.Maven * [
+    sourcePath: '${sourceDirectory.path}',
+    targetPath: '${targetDirectory.path}',
+    javaCompileProperties: [ source: '${versionNumber}', target: '${versionNumber}', debug: 'false' ],
+
+]
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, resultString('initialize', '') + """    [mkdir] Created dir: ${compiledClassesDirectory.absolutePath}
+    [javac] : warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
+    [javac] Compiling 1 source file to ${compiledClassesDirectory.absolutePath}
+"""), output)
+    assertTrue(( new File(compiledClassesDirectory, root + '.class')).isFile())
+    assertEquals('', error)
+    gantBuilder.delete(dir: mavenTargetSetTestDirectory.path)
+    assertFalse(mavenTargetSetTestDirectory.exists())
+  }
+  void testPackageNoGroupIdLeftShift() {
+    final targetName = 'package'
+    script = """
+includeTargets << gant.targets.Maven
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n', output)
+    assertEquals('java.lang.RuntimeException: maven.groupId must be set to achieve target package.\n', error)
+  }
+  void testPackageNoGroupIdPower() {
+    def targetName = 'package'
+    script = """
+includeTargets ** gant.targets.Maven * [: ]
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n', output)
+    assertEquals('java.lang.RuntimeException: maven.groupId must be set to achieve target package.\n', error)
+  }
+  void testPackageNoArtifactIdLeftShift() {
+    final targetName = 'package'
+    script = """
+includeTargets << gant.targets.Maven
+maven.groupId = 'flob'
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n', output)
+    assertEquals('java.lang.RuntimeException: maven.artifactId must be set to achieve target package.\n', error)
+  }
+  void testPackageNoArtifactIdPower() {
+    def targetName = 'package'
+    script = """
+includeTargets ** gant.targets.Maven * [ groupId: 'flob' ]
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n', output)
+    assertEquals('java.lang.RuntimeException: maven.artifactId must be set to achieve target package.\n', error)
+  }
+  void testPackageVersionLeftShift() {
+    final targetName = 'package'
+    script = """
+includeTargets << gant.targets.Maven
+maven.groupId = 'flob'
+maven.artifactId = 'adob'
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n', output)
+    assertEquals('java.lang.RuntimeException: maven.version must be set to achieve target package.\n', error)
+  }
+  void testPackageVersionPower() {
+    final targetName = 'package'
+    script = """
+includeTargets ** gant.targets.Maven * [ groupId: 'flob', artifactId: 'adob' ]
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n', output)
+    assertEquals('java.lang.RuntimeException: maven.version must be set to achieve target package.\n', error)
+  }
+  void testBindingPropertyIsReadOnlyLeftShift() {
+    script = """
+includeTargets << gant.targets.Maven
+maven.binding = new Binding()
+"""
+    assertEquals(-4, processCmdLineTargets('initialize'))
+    assertEquals('', output)
+    assertEquals('Standard input, line 3 -- Error evaluating Gantfile: Cannot amend the property binding.\n', error)
+  }
+  void testBindingPropertyIsReadOnlyPower() {
+    script = """
+includeTargets ** gant.targets.Maven * [ binding: new Binding() ]
+"""
+    assertEquals(-4, processCmdLineTargets('initialize'))
+    assertEquals('', output)
+    assertEquals('Standard input, line 2 -- Error evaluating Gantfile: Cannot amend the property binding.\n', error)
+  }
+  void testAdditionalTarget() {
+    final targetName = 'sayHello'
+    script = """
+includeTargets << gant.targets.Maven
+target(${targetName}: '') { println('Hello.') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, 'Hello.\n'), output)
+    assertEquals('', error)
+  }
+  void testAdditionalTargetError() {
+    final targetName = 'sayHello'
+    script = """
+includeTargets << gant.targets.Maven
+target(${targetName}, '') { println('Hello.') }
+"""
+    assertEquals(-4, processCmdLineTargets(targetName))
+    assertEquals('', output)
+    assertEquals('Standard input, line 3 -- Error evaluating Gantfile: No such property: sayHello for class: standard_input\n', error)
+  }
+}
diff --git a/src/test/groovy/gant/tools/tests/AntFile_Test.groovy b/src/test/groovy/gant/tools/tests/AntFile_Test.groovy
new file mode 100644
index 0000000..e41edef
--- /dev/null
+++ b/src/test/groovy/gant/tools/tests/AntFile_Test.groovy
@@ -0,0 +1,109 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2010, 2013  Russel Winder
+//
+//  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 gant.tools.tests
+
+import org.codehaus.gant.tests.GantTestCase
+
+/**
+ *  A test to ensure that the AntFile tool is not broken.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class AntFile_Test extends GantTestCase {
+
+  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
+  ////  createTempFile delivers a File object that delivers a string for the path that is platform specific.
+  ////  Cannot use // to delimit the strings in the Gant script being created since / is the file separator
+  ////  on most OSs.  Have to do something to avoid problems on Windows since '' strings still interpret \.
+  ////  Fortunately Windows will accept / as the path separator, so transform all \ to / in all cases.
+  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private File temporaryFile
+  private String temporaryFilePath
+
+  void setUp() {
+    super.setUp()
+    temporaryFile = File.createTempFile('gant-antFile-',  '-executable')
+    temporaryFilePath = temporaryFile.path.replaceAll('\\\\', '/')
+    temporaryFile.write('''
+<project name="Gant Ant Use Test" default="execute">
+  <target name="execute" description="Do something.">
+    <echo message="Hello world."/>
+  </target>
+</project>
+''')
+  }
+  void tearDown() {
+    temporaryFile.delete()
+    super.tearDown()
+  }
+
+  private void performExecutableTest() {
+    assertEquals(0, processCmdLineTargets())
+    assertEquals('     [echo] Hello world.\n', output)
+    assertEquals('', error)
+  }
+  private void performListingTest() {
+    assertEquals(0, gant.processArgs(['-p', '-f', '-'] as String[]))
+    assertEquals('''
+ execute  Do something.
+
+Default target is execute.
+
+''', output)
+    assertEquals('', error)
+  }
+
+  private uninitializedScript = """
+includeTool << gant.tools.AntFile
+antFile.includeTargets('${-> temporaryFilePath}')
+setDefaultTarget('execute')
+"""
+  private initializedScriptString = """
+includeTool ** gant.tools.AntFile * [ filename: '${ -> temporaryFilePath}' ]
+setDefaultTarget('execute')
+"""
+  private initializedScriptList = """
+includeTool ** gant.tools.AntFile * [ filename: [ '${ -> temporaryFilePath}' ] ]
+setDefaultTarget('execute')
+"""
+
+  void testExecutableUninitialized() {
+    script = uninitializedScript
+    performExecutableTest()
+  }
+  void testListingUninitialized() {
+    script = uninitializedScript
+    performListingTest()
+  }
+
+  void testExecutableInitializedString() {
+    script = initializedScriptString
+    performExecutableTest()
+  }
+  void testListingInitializedString() {
+    script = initializedScriptString
+    performListingTest()
+  }
+
+  void testExecutableInitializedList() {
+    script = initializedScriptList
+    performExecutableTest()
+  }
+  void testListingInitializedList() {
+    script = initializedScriptList
+    performListingTest()
+  }
+}
diff --git a/src/test/groovy/gant/tools/tests/Execute_Test.groovy b/src/test/groovy/gant/tools/tests/Execute_Test.groovy
new file mode 100644
index 0000000..b53ced8
--- /dev/null
+++ b/src/test/groovy/gant/tools/tests/Execute_Test.groovy
@@ -0,0 +1,82 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2007–2010, 2013  Russel Winder
+//
+//  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 gant.tools.tests
+
+import org.codehaus.gant.tests.GantTestCase
+
+/**
+ *  A test to ensure that the Execute tool is not broken.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Execute_Test extends GantTestCase {
+  final targetName = 'testing'
+  void testExecutableString() {
+    final command = isWindows ? 'cmd /c echo 1': 'echo 1'
+    script = """includeTool << gant.tools.Execute
+target(${targetName}: '') { execute.executable('${command}') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '  [execute] ' + command + '\n1\n'), output)
+    assertEquals('', error)
+  }
+  void testExecutableListOfString() {
+    //  Format these correctly and they are both input and expected value.
+    final command = isWindows ? '["cmd", "/c", "echo", "1"]': '["echo", "1"]'
+    final expected = command.replaceAll('"', '')
+    script = """includeTool << gant.tools.Execute
+target(${targetName}: '') { execute.executable(${command}) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '  [execute] ' + expected + '\n1\n'), output)
+    assertEquals('', error)
+  }
+  void testShellString() {
+    script = """includeTool << gant.tools.Execute
+target(${targetName}: '') { execute.shell('echo 1') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '    [shell] echo 1\n1\n'), output)
+    assertEquals('', error)
+  }
+  void testExecuteReturnCodeCorrect() {
+    final command = isWindows ? 'cmd /c echo 1': 'echo 1'
+    script = """includeTool << gant.tools.Execute
+target(${targetName}: '') { assert execute.executable('${command}') == 0 }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '  [execute] ' + command + '\n1\n'), output)
+    assertEquals('', error)
+  }
+  void testExecuteReturnCodeError() {
+    //  TODO:  Find out what can be done in Windows to check this.
+    if (! isWindows) {
+      script = """includeTool << gant.tools.Execute
+target(${targetName}: '') { assert execute.executable('false') == 1 }
+"""
+      assertEquals(0, processCmdLineTargets(targetName))
+      assertEquals(resultString(targetName, '  [execute] false\n'), output)
+      assertEquals('', error)
+    }
+  }
+  void testParameterizedUsage() {
+    script = """includeTool ** gant.tools.Execute * [ command: 'echo 1' ]
+target(${targetName}: '') { execute.shell('echo 1') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '    [shell] echo 1\n1\n'), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/gant/tools/tests/LaTeX_Test.groovy b/src/test/groovy/gant/tools/tests/LaTeX_Test.groovy
new file mode 100644
index 0000000..df779ba
--- /dev/null
+++ b/src/test/groovy/gant/tools/tests/LaTeX_Test.groovy
@@ -0,0 +1,147 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2007–2010, 2013 Russel Winder
+//
+//  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 gant.tools.tests
+
+import org.codehaus.gant.tests.GantTestCase
+
+/**
+ *  A test to ensure that the LaTeX tool is not broken.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class LaTeX_Test extends GantTestCase {
+  def executablePresent = false
+  public LaTeX_Test() {
+    try { executablePresent = Runtime.runtime.exec('pdflatex -interaction=batchmode \\end' ).waitFor() == 0 }
+    catch(Exception io ) { }
+  }
+  def optionTestGantFile(name, key ) { """
+includeTool << gant.tools.LaTeX
+target(add${name}Option: '' ) {
+  laTeX.add${name}Option('-blah' )
+  println(laTeX.environment[ "${key}Options" ] )
+}
+"""
+  }
+  def optionListTestGantFile(name, key ) { """
+includeTool << gant.tools.LaTeX
+target(add${name}OptionList: '' ) {
+  laTeX.add${name}Option(['-blah', '--flobadob'] )
+  println(laTeX.environment["${key}Options"] )
+}
+"""
+  }
+
+  void testAddLaTeXOption() {
+    final targetName = 'addLaTeXOption'
+    script = optionTestGantFile('LaTeX', 'latex' )
+    assertEquals(0, processCmdLineTargets(targetName ) )
+    assertEquals(resultString(targetName, '[-interaction=nonstopmode, -halt-on-error, -blah]\n' ), output )
+    assertEquals('', error )
+  }
+  void testAddLaTeXOptionList() {
+    final targetName = 'addLaTeXOptionList'
+    script = optionListTestGantFile('LaTeX', 'latex' )
+    assertEquals(0, processCmdLineTargets(targetName ) )
+    assertEquals(resultString(targetName, '[-interaction=nonstopmode, -halt-on-error, -blah, --flobadob]\n' ), output )
+    assertEquals('', error)
+  }
+  void testAddBibTeXOption() {
+    final targetName = 'addBibTeXOption'
+    script = optionTestGantFile('BibTeX', 'bibtex')
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[-blah]\n'), output)
+    assertEquals('', error)
+  }
+  void testAddBibTeXOptionList() {
+    final targetName = 'addBibTeXOptionList'
+    script = optionListTestGantFile('BibTeX', 'bibtex')
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[-blah, --flobadob]\n'), output)
+    assertEquals('', error)
+  }
+  void testAddMakeindexOption() {
+    final targetName = 'addMakeindexOption'
+    script = optionTestGantFile('Makeindex', 'makeindex')
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[-blah]\n'), output)
+    assertEquals('', error)
+  }
+  void testAddMakeindexOptionList() {
+    final targetName = 'addMakeindexOptionList'
+    script = optionListTestGantFile('Makeindex', 'makeindex')
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[-blah, --flobadob]\n'), output)
+    assertEquals('', error)
+  }
+  void testAddDvipsOption() {
+    final targetName = 'addDvipsOption'
+    script = optionTestGantFile('Dvips', 'dvips')
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[-blah]\n'), output)
+    assertEquals('', error)
+  }
+  void testAddDvipsOptionList() {
+    final targetName = 'addDvipsOptionList'
+    script = optionListTestGantFile('Dvips', 'dvips')
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[-blah, --flobadob]\n'), output)
+    assertEquals('', error)
+  }
+  void testAddPs2pdfOption() {
+    final targetName = 'addPs2pdfOption'
+    script = optionTestGantFile('Ps2pdf', 'ps2pdf')
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[-blah]\n'), output)
+    assertEquals('', error)
+  }
+  void testAddPs2pdfOptionList() {
+    final targetName = 'addPs2pdfOptionList'
+    script = optionListTestGantFile('Ps2pdf', 'ps2pdf')
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[-blah, --flobadob]\n'), output)
+    assertEquals('', error)
+  }
+  void testEmptyFile() {
+    final buildScript = '''
+includeTool << gant.tools.LaTeX
+target("pdf": "") { laTeX.generatePDF(root: "TESTFILENAME") }
+includeTargets << gant.targets.Clean
+laTeX.intermediateExtensions.each { extension -> cleanPattern << '*' + extension }
+'''
+    if (executablePresent) {
+      final extension = '.ltx'
+      final filename = File.createTempFile('gantLaTeXTest_', extension, new File('.'))
+      script = buildScript.replace('TESTFILENAME', filename.name.replaceAll(extension, ''))
+      assertEquals(0, processCmdLineTargets('pdf'))
+      assertTrue(output.contains('[execute] [pdflatex, -interaction=nonstopmode, -halt-on-error, gantLaTeXTest_'))
+      assertTrue(output.contains('!  ==> Fatal error occurred, no output PDF file produced!'))
+      assertEquals('', error)
+      assertEquals(0, processCmdLineTargets('clean'))
+      filename.delete()
+    }
+    else { System.err.println('testEmptyFile not run since pdflatex executable is not available.') }
+  }
+  void testInitialized() {
+    final targetName = 'test'
+    script = """
+includeTool ** gant.tools.LaTeX * [ latexOptions: 'flobadob' ]
+target(${targetName}: "") { println(laTeX.environment['latexOptions']) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '[-interaction=nonstopmode, -halt-on-error, flobadob]\n'), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/ant/tests/Gant_Test.java b/src/test/groovy/org/codehaus/gant/ant/tests/Gant_Test.java
new file mode 100644
index 0000000..fe0bbea
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/ant/tests/Gant_Test.java
@@ -0,0 +1,120 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.ant.tests;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+
+/**
+ *  Unit tests for the Gant Ant task.  In order to test things appropriately this test must be initiated
+ *  without any of the Groovy, Gant or related jars in the class path.  Also of course it must be a JUnit
+ *  test with no connection to Groovy or Gant.
+ *
+ *  @author Russel Winder
+ */
+public class Gant_Test extends TestCase {
+  private final String separator = System.getProperty("file.separator");
+  private final String locationPrefix = "Gradle".equals(System.getProperty("buildFrameworkIdentifier")) ? ".." + separator : "";
+  private final String path; {
+    final StringBuilder sb = new StringBuilder();
+    sb.append("src");
+    sb.append(separator);
+    sb.append("test");
+    sb.append(separator);
+    sb.append("groovy");
+    sb.append(separator);
+    sb.append("org");
+    sb.append(separator);
+    sb.append("codehaus");
+    sb.append(separator);
+    sb.append("gant");
+    sb.append(separator);
+    sb.append("ant");
+    sb.append(separator);
+    sb.append("tests");
+    path = sb.toString();
+  }
+  private final String canonicalPath; {
+    try { canonicalPath = new File(locationPrefix + path).getCanonicalPath(); }
+    catch (final IOException ioe) { throw new RuntimeException("Path calculation failure.", ioe); }
+  }
+  private final File antFile =  new File(canonicalPath, "gantTest.xml");
+  private Project project;
+  //  This variable is assigned in the Gant script hence the public static.
+  public static String returnValue;
+
+  @Override protected void setUp() throws Exception {
+    super.setUp();
+    project = new Project();
+    project.init();
+    ProjectHelper.configureProject(project, antFile);
+    returnValue = "";
+  }
+
+  public void testDefaultFileDefaultTarget() {
+    project.executeTarget("gantTestDefaultFileDefaultTarget");
+    assertEquals("A test target in the default file.", returnValue);
+  }
+  public void testDefaultFileNamedTarget() {
+    project.executeTarget("gantTestDefaultFileNamedTarget");
+    assertEquals("Another target in the default file.", returnValue);
+  }
+  public void testNamedFileDefaultTarget() {
+    project.executeTarget("gantTestNamedFileDefaultTarget");
+    assertEquals("A test target in the default file.", returnValue);
+  }
+  public void testNamedFileNamedTarget() {
+    project.executeTarget("gantTestNamedFileNamedTarget");
+    assertEquals("Another target in the default file.", returnValue);
+  }
+  public void testGantWithParametersAsNestedTags() {
+    project.executeTarget("gantWithParametersAsNestedTags");
+    assertEquals("gant -Dflob=adob -Dburble gantParameters", returnValue);
+  }
+  public void testMultipleGantTargets() {
+    project.executeTarget("gantWithMultipleTargets");
+    assertEquals("A test target in the default file.Another target in the default file.", returnValue);
+  }
+  public void testUnknownTarget() {
+    try { project.executeTarget("blahBlahBlahBlah"); }
+    catch (final BuildException be) {
+      assertEquals("Target \"blahBlahBlahBlah\" does not exist in the project \"Gant Ant Task Test\". ", be.getMessage());
+      return;
+    }
+    fail("Should have got a BuildException.");
+  }
+  public void testMissingGantfile() {
+    try { project.executeTarget("missingGantfile"); }
+    catch (final BuildException be) {
+      assertEquals("Gantfile does not exist.", be.getMessage());
+      return;
+    }
+    fail("Should have got a BuildException.");
+  }
+  /*
+   *  Test for the taskdef-related verify error problem.  Whatever it was supposed to do it passes now,
+   *  2008-04-14.
+   */
+  public void testTaskdefVerifyError() {
+    project.executeTarget("gantTaskdefVerifyError");
+    assertEquals("OK.", returnValue);
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/ant/tests/build.gant b/src/test/groovy/org/codehaus/gant/ant/tests/build.gant
new file mode 100644
index 0000000..f68c597
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/ant/tests/build.gant
@@ -0,0 +1,81 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.ant.tests.Gant_Test
+
+//  For some reason there has to be an ant. here :-(
+ant.property(file: 'build.properties')
+
+target(test: 'A test target in the default file.') { Gant_Test.returnValue = Gant_Test.returnValue + test_description }
+
+target(blah: 'Another target in the default file.') { Gant_Test.returnValue = Gant_Test.returnValue + blah_description }
+
+//// This build file has to work in two contexts.  If GROOVY_HOME is set in the environment then the jars
+//// from that installation of Groovy should be used so as to ensure testing in the right context.  If the
+//// environment does not have a GROOVY_HOME set then grab some specific versions to make things work.
+
+target(gantTaskdefVerifyError: 'Check that a taskdef works.') {
+  final groovyHome = System.getenv().'GROOVY_HOME'
+  //  Just ensure that the environment variables really have been brought in.
+  assert groovyHome == ant.project.properties.'environment.GROOVY_HOME'
+  if (groovyHome != null) {
+    taskdef(name: 'groovyc', classname: 'org.codehaus.groovy.ant.Groovyc') {
+      classpath {
+        fileset(dir: groovyHome + '/lib', includes: 'groovy*.jar')
+        fileset(dir: groovyHome + '/lib', includes: 'commons-cli*.jar')
+      }
+    }
+  }
+  /*
+   *  With Gant now using Gradle for its build instead of Ant there is no need to have the Maven Ant task
+   *  jar in the repository as a bootstrap tool and the only other use of the jar is here for this one test.
+   *  Removing this test code allows for the removal of the jar with all the knock on consequences for the
+   *  distributions.
+   *
+   *  Clearly this has decimated this test, but it is not entirely obvious what about Gant is really being
+   *  tested here anyway.
+   *
+  //  Paths are relative to the directory in which this file resides.
+  def artifact = 'urn:maven-artifact-ant'
+  typedef(resource: 'org/apache/maven/artifact/ant/antlib.xml', uri: artifact) {
+    classpath { fileset(dir: toplevelDirectory + '/jarfiles', includes: 'maven-ant-tasks-*.jar') }
+  }
+  def dependencyClasspathId = 'dependencyClasspath'
+  "${artifact}:dependencies"(pathId: dependencyClasspathId) {
+    remoteRepository(id: 'Codehaus', url: 'http://repository.codehaus.org/')
+    dependency(groupId: 'org.codehaus.groovy', artifactId: 'groovy', version: System.getenv().GROOVY_ANT_TASK_TEST_VERSION)
+  }
+  taskdef(name: 'groovyc', classname: 'org.codehaus.groovy.ant.Groovyc', classpathref: dependencyClasspathId)
+  *
+  */
+  Gant_Test.returnValue = 'OK.'
+}
+
+target(gantParameters: '') {
+  Gant_Test.returnValue = 'gant' +(flob ? ' -Dflob=' + flob: '') +(burble ? ' -Dburble': '') + ' gantParameters'
+}
+
+//  For dealing with GANT-110 -- thanks to Eric Van Dewoestine for providing this.
+
+target(gantInheritAll: 'Check that a inheritAll works.') {
+  echo(message: '${gant.test.inheritAll}')
+}
+
+//  For dealing with GANT-111 -- thanks to Eric Van Dewoestine for providing this.
+
+target(testFail: ''){
+  fail(message: 'test fail message')
+}
+
+setDefaultTarget(test)
diff --git a/src/test/groovy/org/codehaus/gant/ant/tests/build.properties b/src/test/groovy/org/codehaus/gant/ant/tests/build.properties
new file mode 100644
index 0000000..d3de258
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/ant/tests/build.properties
@@ -0,0 +1 @@
+toplevelDirectory = ../../../../../../../..
diff --git a/src/test/groovy/org/codehaus/gant/ant/tests/commonBits.xml b/src/test/groovy/org/codehaus/gant/ant/tests/commonBits.xml
new file mode 100644
index 0000000..c087372
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/ant/tests/commonBits.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+   Gant - A Groovy way of scripting Ant tasks.
+
+   Copyright © 2009-10 Russel Winder
+
+   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 : Russel Winder <russel at winder.org.uk>
+-->
+
+<project name="Common Ant File Bits for Gant Ant Task Test" xmlns:artifact="urn:maven-artifact-ant" basedir="." >
+
+  <!--
+     Assume that all the Gant and Groovy classes are on the underlying classpath.
+
+     Currently do the needful with the environment variable GROOVY_ANT_TASK_TEST_VERSION.
+    -->
+
+  <target name="-defineGroovyTask">
+    <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" />
+  </target>
+
+  <target name="-defineGantTask">
+    <taskdef name="gant" classname="org.codehaus.gant.ant.Gant"/>
+  </target>
+  
+</project>
diff --git a/src/test/groovy/org/codehaus/gant/ant/tests/gantTest.xml b/src/test/groovy/org/codehaus/gant/ant/tests/gantTest.xml
new file mode 100644
index 0000000..20eae8b
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/ant/tests/gantTest.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+   Gant - A Groovy way of scripting Ant tasks.
+
+   Copyright © 2008-10 Russel Winder
+
+   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 : Russel Winder <russel at winder.org.uk>
+-->
+
+<project name="Gant Ant Task Test" default="gantTestDefaultFileDefaultTarget" basedir=".">
+
+  <import file="commonBits.xml"/>
+
+  <target name="gantTestDefaultFileDefaultTarget" depends="-defineGantTask">
+    <gant/>
+  </target>
+ 
+  <target name="gantTestDefaultFileNamedTarget" depends="-defineGantTask">
+    <gant target="blah"/>
+  </target>
+
+ <target name="gantTestNamedFileDefaultTarget" depends="-defineGantTask">
+    <gant file="build.gant"/>
+  </target>
+ 
+  <target name="gantTestNamedFileNamedTarget" depends="-defineGantTask">
+    <gant file="build.gant" target="blah"/>
+  </target>
+
+  <!--  Ensure there is no file of the name used in the Gant Ant task here. -->
+  <target name="missingGantfile" depends="-defineGantTask">
+    <gant file="blahBlahBlahBlah.blah"/>
+  </target>
+
+  <!--  Ensure there is no target called blahBlahBlahBlah. -->
+  <target name="gantTaskdefVerifyError" depends="-defineGantTask">
+    <gant file="build.gant" target="gantTaskdefVerifyError"/>
+  </target>
+
+  <target name="gantWithParametersAsNestedTags" depends="-defineGantTask">
+    <gant file="build.gant" target="gantParameters">
+      <definition name="flob" value="adob"/>
+      <definition name="burble"/>
+    </gant>
+  </target>
+
+  <target name="gantWithMultipleTargets" depends="-defineGantTask">
+    <gant>
+      <gantTarget value="test"/>
+      <gantTarget value="blah"/>
+    </gant>
+  </target>
+
+  <!-- For GANT-110.  Thanks to Eric Van Dewoestine for providing this. -->
+
+  <target name="gantTestInheritAll" depends="-defineGantTask">
+    <property name="gant.test.inheritAll" value="gantInheritAllWorks"/>
+    <gant file="build.gant" target="gantInheritAll"/>
+    <gant file="build.gant" target="gantInheritAll" inheritAll="false"/>
+    <gant file="build.gant" target="gantInheritAll" inheritAll="true"/>
+  </target>
+  
+  <!-- For GANT-111.  Thanks to Eric Van Dewoestine for providing this. -->
+
+  <target name="gantTestFail" depends="-defineGantTask">
+    <gant file="build.gant" target="testFail"/>
+  </target>
+  
+</project>
diff --git a/src/test/groovy/org/codehaus/gant/tests/BuildListener_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/BuildListener_Test.groovy
new file mode 100644
index 0000000..736dd6c
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/BuildListener_Test.groovy
@@ -0,0 +1,72 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright  © 2008, 2013  Graeme Rocher
+//
+//  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.codehaus.gant.tests
+
+import org.apache.tools.ant.BuildEvent
+import org.apache.tools.ant.BuildListener
+
+/**
+ * @author Graeme Rocher
+ * @since 1.6
+ *
+ * Created: 2008-12-17
+ */
+public class BuildListener_Test extends GantTestCase {
+  void testBuildListeners() {
+    DummyBuildListener listener = new DummyBuildListener()
+    gant.addBuildListener(listener)
+    script = '''
+target(main: "The main target.") { doMore() }
+target(doMore: "Another target.") {
+  foo = "bar"
+  ant.echo "do stuff"
+  ant.property name:"one", value:"two"
+}
+setDefaultTarget main
+'''
+    processTargets()
+    def starts = listener.targetStarts
+    assertEquals 2, starts.size()
+    assertEquals 2, listener.targetEnds.size()
+    assertEquals "main", starts[0].target.name
+    assertEquals "doMore", starts[1].target.name
+    assertEquals "bar", starts[1].binding.foo
+    assertEquals 1, listener.buildStarts.size()
+    assertEquals 1, listener.buildEnds.size()
+    assertEquals 2, listener.taskStarts.size()
+    assertEquals 2, listener.taskEnds.size()
+    starts = listener.taskStarts
+    assertEquals "echo", starts[0].task.taskName
+    assertEquals "property", starts[1].task.taskName
+  }
+}
+
+class DummyBuildListener implements BuildListener {
+  def targetStarts = []
+  def targetEnds = []
+  def buildStarts = []
+  def buildEnds = []
+  def taskStarts = []
+  def taskEnds = []
+  public void buildStarted(final BuildEvent event) { buildStarts << event }
+  public void buildFinished(final BuildEvent event) { buildEnds << event }
+  public void targetStarted(final BuildEvent event) { targetStarts << event }
+  public void targetFinished(final BuildEvent event) { targetEnds << event }
+  public void taskStarted(final BuildEvent event) { taskStarts << event }
+  public void taskFinished(final BuildEvent event) { taskEnds << event }
+  public void messageLogged(final BuildEvent event) {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/CallPrint_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/CallPrint_Test.groovy
new file mode 100644
index 0000000..67a5afc
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/CallPrint_Test.groovy
@@ -0,0 +1,45 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that using standard Groovy functions works.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class CallPrint_Test extends GantTestCase {
+  final outputString = 'Hello World.'
+  void testSystemOutPrintln() {
+    final targetName = 'systemOutPrintln'
+    script = "target(${targetName}: '') { System.out.println('${outputString}') }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, outputString + '\n'), output)
+    assertEquals('', error)
+  }
+  void testPrintln() {
+    final targetName = 'testPrintln'
+    script = "target(${targetName}: '') { println('${outputString}') }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, outputString + '\n'), output)
+    assertEquals('', error)
+  }
+  void testMessage() {
+    final targetName = 'testMessage'
+    script = "target(${targetName}: '') { message('message', '${outputString}') }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, "  [message] " + outputString + '\n'), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/CommentAccess_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/CommentAccess_Test.groovy
new file mode 100644
index 0000000..ecf5429
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/CommentAccess_Test.groovy
@@ -0,0 +1,39 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2007–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure access to the comment in a task works correctly.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class CommentAccess_Test extends GantTestCase {
+  void testcommentAccess() {
+    final targetName = 'commentAccess'
+    final success = 'Success.'
+    script = """
+theComment = 'Some comment.'
+target(${targetName}: theComment) {
+ //  This is old-style and should be deprecated.
+ assert commentAccess_description == theComment
+ assert it.description == theComment
+ println('${success}')
+}
+"""
+    assertEquals(0, processCmdLineTargets('commentAccess'))
+    assertEquals(resultString(targetName, success + '\n'), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/CustomClassLoader_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/CustomClassLoader_Test.groovy
new file mode 100644
index 0000000..971de96
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/CustomClassLoader_Test.groovy
@@ -0,0 +1,46 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2009, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  Tests that you can use a custom class loader with Gant.
+ *
+ *  @author Graeme Rocher
+ *  @author Russel Winder
+ */
+final class CustomClassLoader_Test extends GantTestCase {
+  final outputString = 'goodbye'
+  final introducer = 'Starting'
+  final ender = 'Finished'
+  final defaultTargetName = 'default'
+  void setUp() {
+    super.setUp()
+    def gcl = new GroovyClassLoader()
+    gcl.parseClass("package helloworld; class Hello { def say() { '${outputString}' } }")
+    script = """
+target('${defaultTargetName}': '') {
+	println '${introducer}'
+	println new helloworld.Hello().say()
+	println '${ender}'
+}
+"""
+    gant = new gant.Gant(null, gcl)
+  }
+  void testDefault() {
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultString(defaultTargetName, introducer + '\n' + outputString + '\n' + ender + '\n'), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/Depends_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/Depends_Test.groovy
new file mode 100644
index 0000000..2755895
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/Depends_Test.groovy
@@ -0,0 +1,254 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test for the depends processing, i.e. make sure the depends calls the method when appropriate and not
+ *  when appropriate.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Depends_Test extends GantTestCase {
+  final outputMessage = 'done.'
+  final targetName = 'getOnWithIt'
+  final outputFunction = 'outputFunction'
+   final caseA = 'caseA'
+   final caseB = 'caseB'
+   final caseC = 'caseC'
+  void testNone() {
+    script = """
+target(${outputFunction}: '') { println('${outputMessage}') }
+target(${caseA}: '') { ${outputFunction}() }
+target(${caseB}: '') { ${outputFunction}() }
+target(${caseC}: '') { ${outputFunction}() }
+target(${targetName}: '') { ${caseA}() ; ${caseB}() ; ${caseC}() }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName,
+                                  resultString(caseA, resultString(outputFunction, outputMessage + '\n'))
+                                  + resultString(caseB, resultString(outputFunction, outputMessage + '\n'))
+                                  + resultString(caseC, resultString(outputFunction, outputMessage + '\n'))
+                                 ), output)
+    assertEquals('', error)
+  }
+  void testMixed() {
+    script = """
+target(${outputFunction}: '') { println('${outputMessage}') }
+target(${caseA}: '') { depends(${outputFunction}) }
+target(${caseB}: '') { ${outputFunction}() }
+target(${caseC}: '') { depends(${outputFunction}) }
+target(${targetName}: '') { ${caseA}() ; ${caseB}() ; ${caseC}() }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName,
+                                  resultString(caseA, resultString(outputFunction, outputMessage + '\n'))
+                                  + resultString(caseB, resultString(outputFunction, outputMessage + '\n'))
+                                  + resultString(caseC, '')
+                                 ), output)
+    assertEquals('', error)
+  }
+  void testAll() {
+    script = """
+target(${outputFunction}: '') { println('${outputMessage}') }
+target(${caseA}: '') { depends(${outputFunction}) }
+target(${caseB}: '') { depends(${outputFunction}) }
+target(${caseC}: '') { depends(${outputFunction}) }
+target(${targetName}: '') { ${caseA}() ; ${caseB}() ; ${caseC}() }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName,
+                                  resultString(caseA, resultString(outputFunction, outputMessage + '\n'))
+                                  + resultString(caseB, '')
+                                  + resultString(caseC, '')
+                                 ), output)
+    assertEquals('', error)
+  }
+  void testMultiple() {
+    script = """
+target(${outputFunction}: '') { println('${outputMessage}') }
+target(${caseA}: '') { depends(${outputFunction}) }
+target(${caseB}: '') { depends(${outputFunction}) }
+target(${caseC}: '') { depends(${outputFunction}) }
+target(${targetName}: '') { depends(${caseA}, ${caseB}, ${caseC}) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName,
+                                  resultString(caseA, resultString(outputFunction, outputMessage + '\n'))
+                                  + resultString(caseB, '')
+                                  + resultString(caseC, '')
+                                 ), output)
+    assertEquals('', error)
+  }
+  void testList() {
+    script = """
+target(${outputFunction}: '') { println('${outputMessage}') }
+target(${caseA}: '') { depends(${outputFunction}) }
+target(${caseB}: '') { depends(${outputFunction}) }
+target(${caseC}: '') { depends(${outputFunction}) }
+target(${targetName}: '') { depends([ ${caseA}, ${caseB}, ${caseC} ]) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName,
+                                  resultString(caseA, resultString(outputFunction, outputMessage + '\n'))
+                                  + resultString(caseB, '')
+                                  + resultString(caseC, '')
+                                 ), output)
+    assertEquals('', error)
+  }
+  void testNotClosure() {
+    script = """
+datum = 1
+target(${targetName}: '') { depends(datum) }
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n', output)
+    assertEquals('java.lang.RuntimeException: depends called with an argument (1) that is not a known target or list of targets.\n', error)
+  }
+  void testNotListClosure() {
+    script = """
+datum = 1
+target(${targetName}: '') { depends([ datum ]) }
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n', output)
+    assertEquals('java.lang.RuntimeException: depends called with an argument (1) that is not a known target or list of targets.\n', error)
+  }
+  void testOutOfOrder() {
+    script = """
+target(${targetName}: '') { depends(${caseA}, ${caseB}, ${caseC}) }
+target(${caseC}: '') { depends(${outputFunction}) }
+target(${caseB}: '') { depends(${outputFunction}) }
+target(${caseA}: '') { depends(${outputFunction}) }
+target(${outputFunction}: '') { println('${outputMessage}') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName,
+                                  resultString(caseA, resultString(outputFunction, outputMessage + '\n'))
+                                  + resultString(caseB, '')
+                                  + resultString(caseC, '')
+                                 ), output)
+    assertEquals('', error)
+  }
+  void testOutOfOrderList() {
+    script = """
+target(${targetName}: '') { depends([ ${caseA}, ${caseB}, ${caseC} ]) }
+target(${caseC}: '') { depends(${outputFunction}) }
+target(${caseB}: '') { depends(${outputFunction}) }
+target(${caseA}: '') { depends(${outputFunction}) }
+target(${outputFunction}: '') { println('${outputMessage}') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName,
+                                  resultString(caseA, resultString(outputFunction, outputMessage + '\n'))
+                                  + resultString(caseB, '')
+                                  + resultString(caseC, '')
+                                 ), output)
+    assertEquals('', error)
+  }
+  void testSameTargetAndFileName() {
+    //  Having a target of the same name as the script being compiled is fine until the target name is used in
+    //  a depend.  At this point the class name not the name in the binding is picked up and all hell breaks
+    //  loose.  Standard input is compiled as class standard_input.
+    script = """
+target(standard_input, '') { println('${outputMessage}') }
+target(${targetName}, '') { depends(standard_input) }
+"""
+    assertEquals(-4, processCmdLineTargets(targetName))
+    assertTrue(error.startsWith('Standard input, line 2 -- Error evaluating Gantfile: No signature of method: '))
+  }
+  void testStringParameter() {
+    script = """
+target(${caseA}: '') { println('${outputMessage}') }
+target(${targetName}: '') { depends('${caseA}') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, resultString(caseA, outputMessage + '\n')), output)
+    assertEquals('', error)
+  }
+  void testStringListParameter() {
+    script = """
+target(${caseA}: '') { println('${outputMessage}') }
+target(${caseB}: '') { println('${outputMessage}') }
+target(${targetName}: '') { depends([ '${caseA}', '${caseB}' ]) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName,
+                                  resultString(caseA, outputMessage + '\n')
+                                  + resultString(caseB, outputMessage + '\n')
+                                 ), output)
+    assertEquals('', error)
+  }
+  void testMixedListParameter() {
+    script = """
+target(${caseA}: '') { println('${outputMessage}') }
+target(${caseB}: '') { println('${outputMessage}') }
+target(${targetName}: '') { depends([ ${caseA}, '${caseB}' ]) }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName,
+                                  resultString(caseA, outputMessage + '\n')
+                                  + resultString(caseB, outputMessage + '\n')
+                                 ), output)
+    assertEquals('', error)
+  }
+  void testCircularDependency() {
+    //  Should this actually fail? cf. GANT-9.  Current view is that it is fine as is.
+    script = '''
+target(A: '') { depends(B) ; println('A') }
+target(B: '') { depends(C)  ; println('B') }
+target(C: '') { depends(A)  ; println('C') }
+'''
+    assertEquals(0, processCmdLineTargets('A'))
+    assertEquals(resultString('A',
+                                  resultString('B',
+                                                 resultString('C',
+                                                                resultString('A', 'A\n')
+                                                                + 'C\n')
+                                                 + 'B\n')
+                                  + 'A\n'), output)
+    assertEquals('', error)
+  }
+  void testMultipleIndependentTargets() {
+    script = """
+target(${caseA}: '') { println('${caseA}') }
+target(${caseB}: '') { println('${caseB}') }
+"""
+    assertEquals(0, processCmdLineTargets([ caseA, caseB ]))
+    assertEquals(resultString(caseA, caseA + '\n') + resultString(caseB, caseB + '\n'), output)
+    assertEquals('', error)
+  }
+  void testEmbeddedDepend() {
+    script = """
+target(${caseA}: '') { println('${outputMessage}') }
+target(${targetName}: '') { (0..3).each { depends(${caseA}) } }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, resultString(caseA, outputMessage + '\n')), output)
+    assertEquals('', error)
+  }
+  //  cf. GANT-26
+  void testMultipleDependentTargets() {
+    script = """
+target(${caseA}: '') {
+  depends(${caseB})
+  println('${caseA}')
+}
+target(${caseB}: '') { println('${caseB}') }
+"""
+    assertEquals(0, processCmdLineTargets([ caseA, caseB ]))
+    assertEquals(resultString(caseA, resultString(caseB, caseB + '\n') + caseA + '\n') + resultString(caseB, caseB + '\n'), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/DryRun_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/DryRun_Test.groovy
new file mode 100644
index 0000000..0be529e
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/DryRun_Test.groovy
@@ -0,0 +1,53 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013 Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that the target listing works.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class DryRun_Test extends GantTestCase {
+  final something = 'something'
+  final somethingElse = 'somethingElse'
+  void setUp() {
+    super.setUp()
+    script = """
+target(${something}: '') { echo(message: '${something}') }
+target(${somethingElse}: '') { echo(message: '${somethingElse}') }
+"""
+  }
+  void testMissingDefault() {
+    assertEquals(-12, gant.processArgs(['-n',  '-f',  '-'] as String[]))
+    assertEquals('', output)
+    assertEquals('Target default does not exist.\n', error)
+  }
+  void testMissingNamedTarget() {
+    final missingTargetName = 'blah'
+    assertEquals(-11, gant.processArgs(['-n',  '-f',  '-' , missingTargetName] as String[]))
+    assertEquals('', output)
+    assertEquals("Target ${missingTargetName} does not exist.\n", error)
+  }
+  void testSomething() {
+    assertEquals(0, gant.processArgs(['-n',  '-f',  '-' , something] as String[]))
+    assertEquals(resultString(something, "     [echo] message : '${something}'\n"), output)
+    assertEquals('', error)
+  }
+  void testSomethingElse() {
+    assertEquals(0, gant.processArgs(['-n',  '-f',  '-' , somethingElse] as String[]))
+    assertEquals(resultString(somethingElse, "     [echo] message : '${somethingElse}'\n"), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/ExecutingTargets_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/ExecutingTargets_Test.groovy
new file mode 100644
index 0000000..9396e3f
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/ExecutingTargets_Test.groovy
@@ -0,0 +1,133 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that the target executing works.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class ExecutingTargets_Test extends GantTestCase {
+  final targetName = 'testing'
+  final clean = 'clean'
+  final something = 'something'
+  final somethingElse = 'somethingElse'
+  final coreScript = """
+target(${something}: '') { }
+target(${somethingElse}: '') { }
+"""
+  void testSomethingArgs() {
+    script = coreScript
+    assertEquals(0, gant.processArgs(['-f',  '-', something] as String[]))
+    assertEquals(resultString(something, ''), output)
+    assertEquals('', error)
+  }
+  void testSomethingTargets() {
+    script = coreScript
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultString(something, ''), output)
+    assertEquals('', error)
+  }
+  void testCleanAndSomethingArgs() {
+    script = 'includeTargets << gant.targets.Clean\n' + coreScript
+    assertEquals(0, gant.processArgs(['-f',  '-', clean, something] as String[]))
+    assertEquals(resultString(clean, '') + resultString(something, ''), output)
+    assertEquals('', error)
+  }
+  void testCleanAndSomethingTargets() {
+    script = 'includeTargets << gant.targets.Clean\n' + coreScript
+    assertEquals(0, processCmdLineTargets([ clean, something ]))
+    assertEquals(resultString(clean, '') + resultString(something, ''), output)
+    assertEquals('', error)
+  }
+
+ //  GANT-44 asks for targets to have access to the command line target list so that it can be processed in targets.
+
+  void testTargetsListIsAccessbileAnChangeable() {
+    script = """
+target(${targetName}: '') {
+  assert targets.class == ArrayList
+  assert targets.size() == 3
+  assert targets[0] == 'testing'
+  assert targets[1] == 'one'
+  assert targets[2] == 'two'
+  def x = targets.remove(1)
+  assert x == 'one'
+  assert targets.size() == 2
+  assert targets[0] == 'testing'
+  assert targets[1] == 'two'
+}
+"""
+    assertEquals(-11, processCmdLineTargets([ targetName, 'one', 'two' ]))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('Target two does not exist.\n', error)
+  }
+
+  //  GANT-81 requires that the target finalize is called in all circumstances if it is present.  If it
+  //  contains dependencies then they are ignored.
+
+  private final testingMessage =  'testing called'
+  private final finalizeMessage = 'finalize called'
+  private final finalize = 'finalize'
+  private final burble = 'burble'
+  void testFinalizeIsCalledNormally() {
+    script = """
+target(${targetName}: '') { println('${testingMessage}') }
+target(${finalize}: '') { println('${finalizeMessage}') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, testingMessage + '\n') + resultString(finalize, finalizeMessage + '\n'), output)
+    assertEquals('', error)
+  }
+  void testFinalizeIsCalledOnAnException() {
+    script = """
+target(${targetName}: '') { throw new RuntimeException('${testingMessage}') }
+target(${finalize}: '') { println('${finalizeMessage}') }
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n' + resultString(finalize, finalizeMessage + '\n'), output)
+    assertEquals("java.lang.RuntimeException: ${testingMessage}\n", error)
+  }
+  void testUsingSetFinalizerFinalizeIsCalledNormally() {
+    script = """
+target(${targetName}: '') { println('${testingMessage}') }
+target(burble: '') { println('${finalizeMessage}') }
+setFinalizeTarget(burble)
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, testingMessage + '\n') + resultString(burble, finalizeMessage + '\n'), output)
+    assertEquals('', error)
+  }
+  void testUsingSetFinalizerFinalizeIsCalledOnAnException() {
+    script = """
+target(${targetName}: '') { throw new RuntimeException('${testingMessage}') }
+target(burble: '') { println('${finalizeMessage}') }
+setFinalizeTarget(burble)
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n' + resultString(burble, finalizeMessage + '\n'), output)
+    assertEquals("java.lang.RuntimeException: ${testingMessage}\n", error)
+  }
+  void testReturnValueFromOneTargetReceivedByCaller() {
+    final called = 'called'
+    script = """
+target(${called}: '') { 17 }
+target(${targetName}: '') { assert ${called}() == 17 }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, resultString(called, '')), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/GantBinding_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/GantBinding_Test.groovy
new file mode 100644
index 0000000..4b9fc5e
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/GantBinding_Test.groovy
@@ -0,0 +1,313 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008--2011, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+import org.codehaus.gant.GantBinding
+import org.codehaus.gant.GantBuilder
+import org.codehaus.gant.IncludeTargets
+import org.codehaus.gant.IncludeTool
+
+/**
+ *  A test for the <code>GantBinding</code> class.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class GantBinding_Test extends GantTestCase {
+  final targetName = 'targetName'
+  final propertyToCheck = 'java.vm.specification.version'
+  final propertyValue = System.getProperty(propertyToCheck)
+  void testCreate() {
+    def object = new GantBinding()
+    assertTrue(object.ant instanceof GantBuilder)
+    assertTrue(object.includeTargets instanceof IncludeTargets)
+    assertTrue(object.includeTool instanceof IncludeTool)
+    assertTrue(object.target instanceof Closure)
+    assertTrue(object.targetDescriptions instanceof TreeMap)
+    assertTrue(object.message instanceof Closure)
+    assertTrue(object.setDefaultTarget instanceof Closure)
+    assertTrue(object.cacheEnabled instanceof Boolean)
+    assertTrue(object.gantLib instanceof List)
+  }
+  void testGantBindingIsActuallyUsedOutsideTarget() {
+    script = """
+assert binding instanceof org.codehaus.gant.GantBinding
+target(${targetName}: '') { }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+  void testGantBindingIsActuallyUsedInsideTarget() {
+    script = """
+target(${targetName}: '') {
+  assert binding instanceof org.codehaus.gant.GantBinding
+}
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+  void testAntPropertyAccessAsAntPropertyOutsideTarget() {
+    script = """
+assert ant.project.properties.'${propertyToCheck}' == '${propertyValue}'
+target(${targetName}: '') { }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+  void testAntPropertyAccessAsAntPropertyInsideTarget() {
+    script = """
+target(${targetName}: '') {
+  assert ant.project.properties.'${propertyToCheck}' == '${propertyValue}'
+}
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+  void testAntPropertyAccessAsBindingVariableOutsideTarget() {
+    script = """
+assert binding.'${propertyToCheck}' == '${propertyValue}'
+target(${targetName}: '') { }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+  void testAntPropertyAccessAsBindingVariableInsideTarget() {
+    script = """
+target(${targetName}: '') {
+  assert binding.'${propertyToCheck}' == '${propertyValue}'
+}
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+  void testAntPropertyAccessViaObjectSpecifierOutsideTarget() {
+    script = """
+assert this.'${propertyToCheck}' == '${propertyValue}'
+target(${targetName}: '') { }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+  void testAntPropertyAccessViaObjectSpecifierInsideTarget() {
+    script = """
+target(${targetName}: '') {
+  assert this.'${propertyToCheck}' == '${propertyValue}'
+  assert owner.'${propertyToCheck}' == '${propertyValue}'
+  assert delegate.'${propertyToCheck}' == '${propertyValue}'
+}
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+  void testPropertySettingWorksAsExpectedOutsideTarget() {
+    script = """
+final name = 'flobadob'
+final value = 'burble'
+assert null == ant.project.properties."\${name}"
+ant.property(name: name, value: value)
+assert value == ant.project.properties."\${name}"
+assert value == binding."\${name}"
+assert value == this."\${name}"
+target(${targetName}: '') {
+}
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+  void testPropertySettingWorksAsExpectedInTarget() {
+    script = """
+target(${targetName}: '') {
+  final name = 'flobadob'
+  final value = 'burble'
+  assert null == ant.project.properties."\${name}"
+  property(name: name, value: value)
+  assert value == ant.project.properties."\${name}"
+  assert value == binding."\${name}"
+  assert value == this."\${name}"
+  assert value == owner."\${name}"
+  assert value == delegate."\${name}"
+}
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+  void testPropertyAccessInsideCategory() {
+    final message = 'Hello World'
+    script = """
+target(${targetName}: '') {
+  use(groovy.xml.dom.DOMCategory) { println("${message}") }
+}
+"""
+    assertEquals(0, processTargets(targetName))
+    assertEquals(resultString(targetName, message + '\n'), output)
+    assertEquals('', error)
+  }
+
+  /*
+   *  Need a separate test method for each read-only attribute to ensure correct processing of the script.
+   *  It is a pity we cannot synthesize the methods as would be possible in interpreted Ruby.
+   */
+  private void undertakeTestingOfAReadOnlyEntryInBinding(String name) {
+    script = """
+${name} = null
+target('default': '') { println('This should never be printed.') }
+"""
+    assertEquals(-4, processCmdLineTargets())
+    assertEquals('', output)
+    assertEquals("Standard input, line 2 -- Error evaluating Gantfile: Cannot redefine symbol ${name}\n", error)
+  }
+  void testAttemptToAlterReadOnlyBindingEntriesCausesException_target() { undertakeTestingOfAReadOnlyEntryInBinding('target') }
+  void testAttemptToAlterReadOnlyBindingEntriesCausesException_message() { undertakeTestingOfAReadOnlyEntryInBinding('message') }
+  void testAttemptToAlterReadOnlyBindingEntriesCausesException_ant() { undertakeTestingOfAReadOnlyEntryInBinding('ant') }
+  void testAttemptToAlterReadOnlyBindingEntriesCausesException_includeTargets() { undertakeTestingOfAReadOnlyEntryInBinding('includeTargets') }
+  void testAttemptToAlterReadOnlyBindingEntriesCausesException_includeTool() { undertakeTestingOfAReadOnlyEntryInBinding('includeTool') }
+  void testAttemptToAlterReadOnlyBindingEntriesCausesException_targetDescriptions() { undertakeTestingOfAReadOnlyEntryInBinding('targetDescriptions') }
+  void testAttemptToAlterReadOnlyBindingEntriesCausesException_setDefaultTarget() { undertakeTestingOfAReadOnlyEntryInBinding('setDefaultTarget') }
+  void testAttemptToAlterReadOnlyBindingEntriesCausesException_initiatimgTarget() { undertakeTestingOfAReadOnlyEntryInBinding('initiatingTarget') }
+  void testAttemptToAlterReadOnlyBindingEntriesCausesException_targets() { undertakeTestingOfAReadOnlyEntryInBinding('targets') }
+
+  //  GANT-75 called for adding the properties gant.file and gant.version.
+
+  void testGantFilePropertyIsAccessble() {
+    script = "target(${targetName}: '') { println(binding.'gant.file') }"
+    assertEquals(0, processTargets(targetName))
+    assertEquals(resultString(targetName, '<stream>\n'), output)
+    assertEquals('', error)
+  }
+  void testGantVersionPropertyIsAccessible() {
+    script = "target(${targetName}: '') { println(binding.'gant.version') }"
+    assertEquals(0, processTargets(targetName))
+    assertEquals(resultString(targetName, gant.binding.'gant.version' + '\n'), output)
+    assertEquals('', error)
+  }
+
+  //  GANT-117 requires functions to be able to set or add to the per-target pre- and post-hooks.
+
+  def baseScript = '''
+target('one': '') { }
+target('two': '') { }
+'''
+
+  void testSetAllPerTargetPreHooks() {
+    script = baseScript + '''
+setAllPerTargetPreHooks({ -> println 'XXXX' })
+'''
+    assertEquals(0, processTargets('one'))
+    assertEquals("XXXX\n${exitMarker}one\n", output)
+    assertEquals('', error)
+    assertEquals(0, processTargets('two'))
+    assertEquals("XXXX\n${exitMarker}one\nXXXX\n${exitMarker}two\n", output)
+    assertEquals('', error)
+  }
+
+  void testSetAllPerTargetPostHooks() {
+      script = baseScript + '''
+setAllPerTargetPostHooks({ -> println 'XXXX' })
+'''
+      assertEquals(0, processTargets('one'))
+      assertEquals('one:\nXXXX\n', output)
+      assertEquals('', error)
+      assertEquals(0, processTargets('two'))
+      assertEquals('one:\nXXXX\ntwo:\nXXXX\n', output)
+      assertEquals('', error)
+    }
+
+  void testAddAllPerTargetPreHooks() {
+      script = baseScript + '''
+addAllPerTargetPreHooks({ -> println 'XXXX' })
+'''
+      assertEquals(0, processTargets('one'))
+      assertEquals("one:\nXXXX\n${exitMarker}one\n", output)
+      assertEquals('', error)
+      assertEquals(0, processTargets('two'))
+      assertEquals("one:\nXXXX\n${exitMarker}one\ntwo:\nXXXX\n${exitMarker}two\n", output)
+      assertEquals('', error)
+    }
+
+    void testAddAllPerTargetPostHooks() {
+      script = baseScript + '''
+addAllPerTargetPostHooks({ -> println 'XXXX' })
+'''
+      assertEquals(0, processTargets('one'))
+      assertEquals("one:\n${exitMarker}one\nXXXX\n", output)
+      assertEquals('', error)
+      assertEquals(0, processTargets('two'))
+      assertEquals("one:\n${exitMarker}one\nXXXX\ntwo:\n${exitMarker}two\nXXXX\n", output)
+      assertEquals('', error)
+    }
+
+  void testAddPreHookNotAClosure() {
+    script = baseScript + '''
+addAllPerTargetPreHooks([])
+'''
+    assertEquals(0, processTargets('one'))
+    assertEquals("one:\n${exitMarker}one\n", output)
+    assertEquals('Target prehook list item is not a closure.\n', error)
+  }
+
+  void testAddPostHookNotAClosure() {
+    script = baseScript + '''
+  addAllPerTargetPostHooks([])
+'''
+    assertEquals(0, processTargets('one'))
+    assertEquals("one:\n${exitMarker}one\n", output)
+    assertEquals('Target posthook list item is not a closure.\n', error)
+  }
+
+  //  Some tests stemming from the 1.9.4 regression investigation.
+
+  final regressionInvestigationOutput = 'The Default Target Is Running...'
+  final regressionInvestigationDecoratedOutput = "default:\n${regressionInvestigationOutput}\n${exitMarker}default\n"
+  final regressionInvestigationScript = """
+target(default: 'some default target') {
+    println('${regressionInvestigationOutput}')
+}
+"""
+  final regressionInvestigationKillHooks = """
+setAllPerTargetPreHooks({ })
+setAllPerTargetPostHooks({ })
+"""
+
+  void testNotSettingPreAndPostHooksOnDefaultTask() {
+    script = regressionInvestigationScript
+    assertEquals(0, processTargets())
+    assertEquals(regressionInvestigationDecoratedOutput, output)
+    assertEquals('', error)
+  }
+
+  void testSettingPreAndPostHooksToNothingBeforeDefaultTask() {
+    script = regressionInvestigationKillHooks + regressionInvestigationScript
+    assertEquals(0, processTargets())
+    assertEquals(regressionInvestigationDecoratedOutput, output)
+    assertEquals('', error)
+  }
+
+  void testSettingPreAndPostHooksToNothingAfterDefaultTask() {
+    script = regressionInvestigationScript + regressionInvestigationKillHooks
+    assertEquals(0, processTargets())
+    assertEquals(regressionInvestigationOutput + '\n', output)
+    assertEquals('', error)
+  }
+
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/GantBuilder_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/GantBuilder_Test.groovy
new file mode 100644
index 0000000..eb65a39
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/GantBuilder_Test.groovy
@@ -0,0 +1,53 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+import org.codehaus.gant.GantBuilder
+import org.codehaus.gant.GantState
+
+/**
+ *  A test for the <code>GantBuilder</code> class.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class GantBuilder_Test extends GantTestCase {
+  void testSetMessageOutputLevel() {
+    //  org.apache.tools.ant.BuildLogger appears to have no way of querying the message output level only of
+    //  setting it. This means we can only test that using the setMessageOutputLevel fails to fail.
+    assertEquals(GantState.NORMAL, GantState.verbosity)
+    final gantBuilder = new GantBuilder()
+    GantState.verbosity = GantState.VERBOSE
+    gantBuilder.logger.setMessageOutputLevel(GantState.verbosity)
+    assertEquals(GantState.VERBOSE, GantState.verbosity)
+  }
+  void testGroovycTaskFail() {
+    final targetName = 'hello'
+    final sourceDirectory = '.'
+    final destinationDirectory = '/tmp/tmp/tmp/tmp'
+    final expectedError = "groovy.lang.MissingMethodException: No signature of method: standard_input.groovyc() is applicable for argument types: (java.util.LinkedHashMap) values: [[srcdir:${sourceDirectory}, destdir:${destinationDirectory}]]\n"
+    //
+    //  This test may only be guaranteed to work if JUnit is operating in perTest fork mode since otherwise
+    //  another test may have caused the Groovyc task to be loaded which leads to a 0 return value.
+    //
+    script = """
+target(${targetName}: '') {
+  groovyc(srcdir: '${sourceDirectory}', destdir: '${destinationDirectory}')
+}
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n', output)
+    assertEquals(expectedError, error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/GantTestCase.java b/src/test/groovy/org/codehaus/gant/tests/GantTestCase.java
new file mode 100644
index 0000000..10b967b
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/GantTestCase.java
@@ -0,0 +1,182 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import groovy.util.GroovyTestCase;
+
+import gant.Gant;
+
+import org.codehaus.gant.GantState;
+
+/**
+ *  A Gant test case: Adds the required input stream manipulation features to avoid replication of code.
+ *  Also prepare a new instance of Gant for each test.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+public abstract class GantTestCase extends GroovyTestCase {
+  public static final String exitMarker = "------ ";
+  //
+  //  Groovy version numbering is complicated:
+  //
+  //  For released versions the number is x.y.z where x is the major number, y is the minor number, and z is
+  //  the bugfix number -- with all of them being integers.
+  //
+  //  For released pre-release versions the number depends on the state of the release.  Early on the
+  //  numbers are x.y-beta-z.  Later on they are x.y-rc-z.  Or as of 2009-11-27, they will be w.x.y-beta-z
+  //  or w.x.y-rc-z.
+  //
+  //  For branches from the repository basically add -SNAPSHOT to the number with z being one higher than
+  //  the last release.  So checkouts of maintenance branches will have x.y.z-SNAPSHOT, while from trunk
+  //  numbers will be like x.y-beta-z-SNAPSHOT or as of 2009-11-27 w.x.y-beta-z-SNAPSHOT.
+  //
+  public enum ReleaseType { RELEASED, RELEASED_SNAPSHOT, BETA, BETA_SNAPSHOT, RC, RC_SNAPSHOT }
+  public static final int groovyMajorVersion;
+  public static final int groovyMinorVersion;
+  public static final int groovyBugFixVersion;
+  public static final ReleaseType releaseType;
+  static {
+    //
+    //  Since Groovy 1.6 there has been a method groovy.lang.GroovySystem.getVersion for getting the version
+    //  string.  Prior to this, whilst there was a class groovy.lang.GroovySystem, it did not have the
+    //  appropriate method and the method org.codehaus.groovy.runtime.InvokerHelper.getVersion had to be
+    //  used.  Supporting versions of Groovy from 1.5 onwards therefore meant using reflection.  Now
+    //  (comment dated 2010-08-08) that the 1.6 series has been "end of life"d, we choose to remove support
+    //  for Groovy 1.5 from Gant.  In fact, Gant has failed to support Groovy 1.5 for a while so there is no
+    //  risk of problems in only allowing Groovy 1.6 onwards.
+    //
+    final String[] version = groovy.lang.GroovySystem.getVersion().split("[.-]");
+    switch (version.length) {
+     case 3 :
+       //
+       //  X.Y.Z
+       //
+       groovyBugFixVersion =  Integer.parseInt(version[2]);
+       releaseType = ReleaseType.RELEASED;
+       break;
+     case 4 :
+       //
+       //  X.Y.Z-SNAPSHOT
+       //  X.Y-rc-Z
+       //  X.Y-beta-Z
+       //
+       if (version[3].equals("SNAPSHOT")) {
+         groovyBugFixVersion =  Integer.parseInt(version[2]);
+         releaseType = ReleaseType.RELEASED_SNAPSHOT;
+       }
+       else {
+         groovyBugFixVersion =  Integer.parseInt(version[3]);
+         final String discriminator = version[2];
+         releaseType = (discriminator.equals("RC") || discriminator.equals("rc")) ? ReleaseType.RC : ReleaseType.BETA;
+       }
+       break;
+     case 5 :
+       //
+       //  X.Y.0-rc-Z
+       //  X.Y.0-beta-Z
+       //  X.Y-rc-Z-SNAPSHOT
+       //  X.Y-beta-Z-SNAPSHOT
+       //
+       if (version[4].equals("SNAPSHOT")) {
+         groovyBugFixVersion =  Integer.parseInt(version[3]);
+         final String discriminator = version[2];
+         releaseType = (discriminator.equals("RC") || discriminator.equals("rc")) ? ReleaseType.RC_SNAPSHOT : ReleaseType.BETA_SNAPSHOT;
+       }
+       else {
+         assert version[2].equals("0");
+         groovyBugFixVersion =  Integer.parseInt(version[4]);
+         final String discriminator = version[3];
+         releaseType = (discriminator.equals("RC") || discriminator.equals("rc")) ? ReleaseType.RC : ReleaseType.BETA;
+       }
+       break;
+     case 6 : {
+       //
+       //  X.Y.0-rc-Z-SNAPSHOT
+       //  X.Y.0-beta-Z-SNAPSHOT
+       //
+       assert version[2].equals("0");
+       assert version[5].equals("SNAPSHOT");
+       groovyBugFixVersion =  Integer.parseInt(version[4]);
+       final String discriminator = version[3];
+       releaseType = (discriminator.equals("RC") || discriminator.equals("rc")) ? ReleaseType.RC_SNAPSHOT : ReleaseType.BETA_SNAPSHOT;
+       break;
+     }
+     default :
+      throw new RuntimeException("Groovy version number is not well-formed.");
+    }
+    groovyMajorVersion = Integer.parseInt(version[0]);
+    groovyMinorVersion = Integer.parseInt(version[1]);
+  }
+  public static final boolean isWindows;
+  static {
+    final String osName = System.getProperty("os.name");
+    isWindows = (osName.length() > 6) && osName.substring(0, 7).equals("Windows");
+  }
+  private ByteArrayOutputStream output;
+  private ByteArrayOutputStream error;
+  private PrintStream savedOut;
+  private PrintStream savedErr;
+  protected Gant gant;
+  protected String script;
+  @Override protected void setUp() throws Exception {
+    super.setUp();
+    savedOut = System.out;
+    savedErr = System.err;
+    output = new ByteArrayOutputStream();
+    error = new ByteArrayOutputStream();
+    System.setOut(new PrintStream(output));
+    System.setErr(new PrintStream(error));
+    gant = new Gant();
+    gant.setBuildClassName("standard_input");
+    script = "";
+    //
+    //  If the JUnit is run with fork mode 'perTest' then we do not have to worry about the static state.
+    //  However, when the fork mode is 'perBatch' or 'once' then we have to ensure that the static state
+    //  is reset to the normal state.
+    //
+    GantState.verbosity = GantState.NORMAL;
+    GantState.dryRun = false;
+  }
+  @Override protected void tearDown() throws Exception {
+    System.setOut(savedOut);
+    System.setErr(savedErr);
+    super.tearDown();
+  }
+  protected void setScript(final String s) { script = s; System.setIn(new ByteArrayInputStream(script.getBytes())); }
+  protected Integer processTargets() { gant.loadScript(System.in); return gant.processTargets(); }
+  protected Integer processTargets(final String s) { gant.loadScript(System.in); return gant.processTargets(s); }
+  protected Integer processTargets(final List<String> l) { gant.loadScript(System.in); return gant.processTargets(l); }
+  protected Integer processCmdLineTargets() { return gant.processArgs(new String[] {"-f", "-"}); }
+  protected Integer processCmdLineTargets(final String s) { return gant.processArgs(new String[] {"-f", "-", s}); }
+  protected Integer processCmdLineTargets(final List<String> l) {
+    final List<String> args = new ArrayList<String>(Arrays.asList("-f", "-"));
+    args.addAll(l);
+    return gant.processArgs(args.toArray(new String[0]));
+  }
+  protected String getOutput() { return output.toString().replace("\r", ""); }
+  protected String getError() { return error.toString().replace("\r", ""); }
+  protected String escapeWindowsPath(final String path) { return isWindows ? path.replace("\\",  "\\\\") : path; }
+  protected String resultString(final String targetName, final String result) {
+    return targetName + ":\n" + result + exitMarker + targetName + '\n';
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/Hooks_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/Hooks_Test.groovy
new file mode 100644
index 0000000..debbefe
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/Hooks_Test.groovy
@@ -0,0 +1,219 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2009–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test for the prehook and posthook interceptors.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Hooks_Test extends GantTestCase {
+  def targetName = 'trial'
+  def flobString = 'flobadob'
+  def targetString = 'weed'
+
+  def listItemNotAClosureErrorMessage(String item) { item + ' list item is not a closure.\n' }
+  def notAClosureOrListErrorMessage(String item) { item + ' not a closure or list (of closures).\n' }
+
+   //  __________________________________________________________________________
+   //
+   //  First test replacing the default (pre|post)hook.  This removes the logging.
+
+  void testDefinePrehookScalar() {
+    script = '''
+def flob = { println("''' + flobString + '''") }
+target(name: "''' + targetName + '''", prehook: flob) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(flobString + '\n' + targetString + '\n' + exitMarker + targetName + '\n', output)
+  }
+  void testDefinePrehookList() {
+    script = '''
+def flob = { println("''' + flobString + '''") }
+target(name: "''' + targetName + '''", prehook: [ flob ]) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(flobString + '\n' + targetString + '\n' + exitMarker + targetName + '\n', output)
+  }
+  void testDefinePosthookScalar() {
+    script = '''
+def flob = { println("''' + flobString + '''") }
+target(name: "''' + targetName + '''", posthook: flob) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(targetName + ':\n' + targetString + '\n' + flobString + '\n', output)
+  }
+  void testDefinePosthookList() {
+    script = '''
+def flob = { println("''' + flobString + '''") }
+target(name: "''' + targetName + '''", posthook: [ flob ]) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(targetName + ':\n' + targetString + '\n' + flobString + '\n', output)
+  }
+
+  //  __________________________________________________________________________
+  //
+  //  Now test appending to the (pre|post)hook list.  This preserves the standard logging.
+
+  void testAppendPrehookScalar() {
+    script = '''
+def flob = { println("''' + flobString + '''") }
+target(name: "''' + targetName + '''", addprehook: flob) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, flobString + '\n' + targetString + '\n'), output)
+  }
+  void testAppendPrehookList() {
+    script = '''
+def flob = { println("''' + flobString + '''") }
+target(name: "''' + targetName + '''", addprehook: [ flob ]) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, flobString + '\n' + targetString + '\n'), output)
+  }
+  void testAppendPosthookScalar() {
+    script = '''
+def flob = { println("''' + flobString + '''") }
+target(name: "''' + targetName + '''", addposthook: flob) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, targetString + '\n' + flobString + '\n'), output)
+  }
+  void testAppendPosthookList() {
+    script = '''
+def flob = { println("''' + flobString + '''") }
+target(name: "''' + targetName + '''", addposthook: [ flob ]) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, targetString + '\n' + flobString + '\n'), output)
+  }
+
+  //  __________________________________________________________________________
+  //
+  //  Try various errors.
+
+  void testPrehookScalarWrongTypeError() {
+    script = '''
+def flob = 1
+target(name: "''' + targetName + '''", prehook: flob) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(notAClosureOrListErrorMessage('Target prehook'), error)
+    assertEquals(targetString + '\n' + exitMarker + targetName + '\n', output)
+  }
+void testPrehookListWrongTypeError() {
+    script = '''
+def flob = 1
+target(name: "''' + targetName + '''", prehook: [ flob ]) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(listItemNotAClosureErrorMessage('Target prehook'), error)
+    assertEquals(targetString + '\n' + exitMarker + targetName + '\n', output)
+  }
+  void testPosthookScalarWrongTypeError() {
+    script = '''
+def flob = 1
+target(name: "''' + targetName + '''", posthook: flob) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(notAClosureOrListErrorMessage('Target posthook'), error)
+    assertEquals(targetName + ':\n' + targetString + '\n', output)
+  }
+void testPosthookListWrongTypeError() {
+    script = '''
+def flob = 1
+target(name: "''' + targetName + '''", posthook: [ flob ]) { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(listItemNotAClosureErrorMessage('Target posthook'), error)
+    assertEquals(targetName + ':\n' + targetString + '\n', output)
+  }
+
+  //  __________________________________________________________________________
+  //
+  //  Introduce the global hooks.
+
+  void testSetGlobalPreHook() {
+    def extraStuff = 'prehook'
+    script = '''
+globalPreHook = {-> println("''' + extraStuff + '''") }
+target(''' + targetName + ''': '') { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(extraStuff + '\n' + resultString(targetName, targetString + '\n'), output)
+  }
+  void testSetGlobalPostHook() {
+    def extraStuff = 'posthook'
+    script = '''
+globalPostHook = {-> println("''' + extraStuff + '''") }
+target(''' + targetName + ''': '') { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, targetString + '\n') + extraStuff + '\n', output)
+  }
+
+  //  __________________________________________________________________________
+  //
+  //  Try various errors.
+
+  void testGlobalPrehookScalarWrongTypeError() {
+    script = '''
+globalPreHook= 1
+target(''' + targetName + ''': '') { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(notAClosureOrListErrorMessage('Global prehook'), error)
+    assertEquals(resultString(targetName, targetString + '\n'), output)
+  }
+void testGlobalPrehookListWrongTypeError() {
+    script = '''
+globalPreHook = [ 1 ]
+target(''' + targetName + ''': '') { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(listItemNotAClosureErrorMessage('Global prehook'), error)
+    assertEquals(resultString(targetName, targetString + '\n'), output)
+  }
+  void testGlobalPosthookScalarWrongTypeError() {
+    script = '''
+globalPostHook = 1
+target(''' + targetName + ''': '') { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(notAClosureOrListErrorMessage('Global posthook'), error)
+    assertEquals(resultString(targetName, targetString + '\n'), output)
+  }
+void testGlobalPosthookListWrongTypeError() {
+    script = '''
+globalPostHook = [ 1 ]
+target(''' + targetName + ''': '') { println("''' + targetString + '''") }
+'''
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(listItemNotAClosureErrorMessage('Global posthook'), error)
+    assertEquals(resultString(targetName,  targetString + '\n'), output)
+  }
+
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/Include_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/Include_Test.groovy
new file mode 100644
index 0000000..fff5852
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/Include_Test.groovy
@@ -0,0 +1,591 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013, 2014  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that the various include mechanisms work as they should.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Include_Test extends GantTestCase {
+
+  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
+  ////  NB Instance initializers do not work properly in Groovy.  This means that fields that depend on the
+  ////  name of the temporary file must be initialized in the constructor.  Remember, variables in GStrings
+  ////  are bound at definition time even though expression execution only occurs at use time.  This means
+  ////  any GString depending on the name of the temporary directory must also be initialized in the
+  ////  constructor to avoid having the variable bound to null.
+  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private final File temporaryDirectory
+  private final toolClassName = 'ToolClass'
+  private final toolBindingName = 'toolClass'
+  private final String toolClassFilePath
+  private final flobbed = 'flobbed.'
+  private final flob = 'flob'
+  private final burble = 'burble'
+  private final something = 'something'
+  private final defaultTarget = 'default'
+  private final toolClassText =  """
+import org.codehaus.gant.GantBinding
+class ${toolClassName} {
+  ${toolClassName}(GantBinding binding) { }
+  void ${flob}() { println('${flobbed}') }
+}
+"""
+  private final toolBuildScriptBase =  """
+target(${something}: '') { ${toolBindingName}.${flob}() }
+target('${defaultTarget}': '') { ${something}() }
+"""
+  private final toolBuildScriptClass =  "includeTool <<  groovyShell.evaluate('''${toolClassText} ; return ${toolClassName}''')\n" + toolBuildScriptBase
+  private final String toolBuildScriptFile
+  private final toolBuildScriptString =  "includeTool <<  '''${toolClassText}'''\n" + toolBuildScriptBase
+  private final String targetsScriptFilePath
+  private final targetsScriptText =  """
+target(${flob}: '') { println('${flobbed}') }
+"""
+  private final targetsClassName = 'TargetsClass'
+  private final String targetsClassFilePath
+  private final targetsClassText =  """
+import org.codehaus.gant.GantBinding
+class ${targetsClassName} {
+  ${targetsClassName}(GantBinding binding) { binding.target.call(${flob}: '') { println('${flobbed}') } }
+}
+"""
+  private final targetsBuildScriptBase =  """
+target(${something}: '') { ${flob}() }
+target('${defaultTarget}': '') { ${something}() }
+"""
+  //  Source containing just a class and not a complete script must be turned into a script that
+  //  instantiates the class.  Test both correct and errorful behaviour.  Actually the errorful behaviour
+  //  causes a null to be returned, so perhaps rather than the evaluate as is we should just use null to
+  //  make things really explicit.  As it is though, we are testing that the evaluate really does return
+  //  null as well, so maybe leave as is.
+   //
+   //  Now to the problem of 2009-10-01: Sometime in the last couple of days, in the run up to the Groovy
+   //  1.6.5 release, a change was made to the way null.class got processed.  Instead of throwing a NPE it
+   //  returns a NullObject.  This of course throwns the whole << overload seraching into new behaviour.
+   //  This is a huge change of semantics, and wholly inappropriate for a bug fix release.:-(((
+  private final targetsBuildScriptClass =  "includeTargets <<  groovyShell.evaluate('''${targetsScriptText} ; return ${targetsClassName}''', '${targetsClassName}')\n" + targetsBuildScriptBase
+  private final targetsErrorBuildScriptClass =  "includeTargets <<  groovyShell.evaluate('''${targetsScriptText}''', '${targetsClassName}')\n" + targetsBuildScriptBase
+  private final resultErrorEvaluatingScript = "Standard input, line 1 -- Error evaluating Gantfile: Cannot get property 'name' on null object\n"
+  private final String targetsBuildScriptFile
+  private final targetsBuildScriptString =  "includeTargets <<  '''${targetsScriptText}'''\n" + targetsBuildScriptBase
+  private final targetsBuildClassClass =  "includeTargets <<  groovyShell.evaluate('''${targetsClassText} ; return ${targetsClassName}''')\n" + targetsBuildScriptBase
+  //  Source containing just a class and not a complete script must be turned into a script that
+  //  instantiates the class.  Test both correct and errorful behaviour
+  private final String targetsBuildClassFile
+  private final targetsBuildClassString =  "includeTargets <<  '''${targetsClassText} ; binding.classInstanceVariable = new ${targetsClassName}(binding)'''\n" + targetsBuildScriptBase
+  private final String targetsErrorBuildClassFile
+  private final targetsErrorBuildClassString =  "includeTargets <<  '''${targetsClassText}'''\n" + targetsBuildScriptBase
+  private final resultErrorEvaluatingClass = "Standard input, line 1 -- Error evaluating Gantfile: java.lang.InstantiationException: ${targetsClassName}\n"
+  private final String nonExistentFilePath
+  Include_Test() {
+    //////////////////////////////////////////////////////////////////////////////////////////////////////////
+    ////  createTempFile delivers a File object that delivers a string for the path that is platform
+    ////  specific.  Cannot use // to delimit the strings in the Gant script being created since / is the
+    ////  file separator on most OSs.  Have to do something to avoid problems on Windows since '' strings
+    ////  still interpret \.  Fortunately Windows will accept / as the path separator, so transform all \ to
+    ////  / in all cases.
+    //////////////////////////////////////////////////////////////////////////////////////////////////////////
+    temporaryDirectory = File.createTempFile('gant-includeTest-',  '-directory')
+    def temporaryDirectoryPath = isWindows ? temporaryDirectory.path.replaceAll('\\\\', '/'): temporaryDirectory.path
+    toolClassFilePath = temporaryDirectoryPath + '/' + toolClassName + '.groovy'
+    toolBuildScriptFile =  "includeTool <<  new File('${toolClassFilePath}')\n" + toolBuildScriptBase
+    targetsScriptFilePath = temporaryDirectoryPath +'/targets.gant'
+    targetsClassFilePath = temporaryDirectoryPath + '/' + targetsClassName + '.groovy'
+    targetsBuildScriptFile =  "includeTargets <<  new File('${targetsScriptFilePath}')\n" + targetsBuildScriptBase
+    //  Files containing source code that is a class rahter than a script must be treated as a tool.
+    targetsBuildClassFile =  "includeTool <<  new File('${targetsClassFilePath}')\n" + targetsBuildScriptBase
+    targetsErrorBuildClassFile =  "includeTargets <<  new File('${targetsClassFilePath}')\n" + targetsBuildScriptBase
+    nonExistentFilePath = temporaryDirectoryPath + '/tmp' * 3
+  }
+  private final String resultFlob = resultString(flob, flobbed + '\n')
+  private final String resultSomething = resultString(something, flobbed + '\n')
+   private final String resultSomethingFlob = resultString(something, resultFlob)
+  private final String resultFlobbedTool(final String target) { resultString(target, resultSomething) }
+  private final String resultFlobbedTargets(final String target) { resultString(target, resultString(something, resultString(flob, flobbed + '\n'))) }
+  private resultTargetDoesNotExist(String target) { 'Target ' + target + ' does not exist.\n' }
+  void setUp() {
+    super.setUp()
+    temporaryDirectory.delete()
+    temporaryDirectory.mkdirs()
+    new File(toolClassFilePath).write(toolClassText)
+    new File(targetsScriptFilePath).write(targetsScriptText)
+    new File(targetsClassFilePath).write(targetsClassText)
+  }
+  void tearDown() {
+    new File(toolClassFilePath).delete()
+    new File(targetsScriptFilePath).delete()
+    new File(targetsClassFilePath).delete()
+    temporaryDirectory.delete()
+    super.tearDown()
+  }
+  void testToolDefaultClass() {
+    script = toolBuildScriptClass
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTool(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testToolDefaultFile() {
+    script = toolBuildScriptFile
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTool(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testToolDefaultString() {
+    script = toolBuildScriptString
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTool(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testToolFlobClass() {
+    script = toolBuildScriptClass
+    assertEquals(-11, processCmdLineTargets(flob))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(flob), error)
+  }
+  void testToolFlobFile() {
+    script = toolBuildScriptFile
+    assertEquals(-11, processCmdLineTargets(flob))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(flob), error)
+  }
+  void testToolFlobString() {
+    script = toolBuildScriptString
+    assertEquals(-11, processCmdLineTargets(flob))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(flob), error)
+  }
+  void testToolBurbleClass() {
+    script = toolBuildScriptClass
+    assertEquals(-11, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(burble), error)
+  }
+  void testToolBurbleFile() {
+    script = toolBuildScriptFile
+    assertEquals(-11, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(burble), error)
+  }
+  void testToolBurbleString() {
+    script = toolBuildScriptString
+    assertEquals(-11, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(burble), error)
+  }
+  void testToolSomethingClass() {
+    script = toolBuildScriptClass
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultSomething, output)
+    assertEquals('', error)
+  }
+  void testToolSomethingFile() {
+    script = toolBuildScriptFile
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultSomething, output)
+    assertEquals('', error)
+  }
+  void testToolSomethingString() {
+    script = toolBuildScriptString
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultSomething, output)
+    assertEquals('', error)
+  }
+  void testToolClassNoFile() {
+    script = toolBuildScriptFile.replace(toolClassFilePath, nonExistentFilePath)
+    def errorMessage = 'Standard input, line 1 -- Error evaluating Gantfile: java.io.FileNotFoundException: '
+    if(isWindows) { errorMessage += nonExistentFilePath.replaceAll('/', '\\\\') + ' (The system cannot find the path specified)\n' }
+    else { errorMessage += nonExistentFilePath + ' (No such file or directory)\n' }
+    assertEquals(-4, processCmdLineTargets(flob))
+    assertEquals('', output)
+    assertEquals(errorMessage, error)
+  }
+  void testTargetsDefaultClassClass() {
+    script = targetsBuildClassClass
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTargets(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testTargetsDefaultClassFile() {
+    script = targetsBuildClassFile
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTargets(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testErrorTargetsDefaultClassFile() {
+    script = targetsErrorBuildClassFile
+    assertEquals(-4, processCmdLineTargets())
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingClass, error)
+  }
+  void testTargetsDefaultClassString() {
+    script = targetsBuildClassString
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTargets(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testErrorTargetsDefaultClassString() {
+    script = targetsErrorBuildClassString
+    assertEquals(-4, processCmdLineTargets())
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingClass, error)
+  }
+  void testTargetsFlobClassClass() {
+    script = targetsBuildClassClass
+    assertEquals(0, processCmdLineTargets(flob))
+    assertEquals(resultFlob, output)
+    assertEquals('', error)
+  }
+  void testTargetsFlobClassFile() {
+    script = targetsBuildClassFile
+    assertEquals(0, processCmdLineTargets(flob))
+    assertEquals(resultFlob, output)
+    assertEquals('', error)
+  }
+  void testErrorTargetsFlobClassFile() {
+    script = targetsErrorBuildClassFile
+    assertEquals(-4, processCmdLineTargets(flob))
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingClass, error)
+  }
+  void testTargetsFlobClassString() {
+    script = targetsBuildClassString
+    assertEquals(0, processCmdLineTargets(flob))
+    assertEquals(resultFlob, output)
+    assertEquals('', error)
+  }
+  void testErrorTargetsFlobClassString() {
+    script = targetsErrorBuildClassString
+    assertEquals(-4, processCmdLineTargets(flob))
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingClass, error)
+  }
+  void testTargetsBurbleClassClass() {
+    script = targetsBuildClassClass
+    assertEquals(-11, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(burble), error)
+  }
+  void testTargetsBurbleClassFile() {
+    script = targetsBuildClassFile
+    assertEquals(-11, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(burble), error)
+  }
+  void testErrorTargetsBurbleClassFile() {
+    script = targetsErrorBuildClassFile
+    assertEquals(-4, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingClass, error)
+  }
+  void testTargetsBurbleClassString() {
+    script = targetsBuildClassString
+    assertEquals(-11, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(burble), error)
+  }
+  void testErrorTargetsBurbleClassString() {
+    script = targetsErrorBuildClassString
+    assertEquals(-4, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingClass, error)
+  }
+  void testTargetsSomethingClassClass() {
+    script = targetsBuildClassClass
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultSomethingFlob, output)
+    assertEquals('', error)
+  }
+  void testTargetsSomethingClassFile() {
+    script = targetsBuildClassFile
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultSomethingFlob, output)
+    assertEquals('', error)
+  }
+  void testErrorTargetsSomethingClassFile() {
+    script = targetsErrorBuildClassFile
+    assertEquals(-4, processCmdLineTargets(something))
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingClass, error)
+  }
+  void testTargetsSomethingClassString() {
+    script = targetsBuildClassString
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultSomethingFlob, output)
+    assertEquals('', error)
+  }
+  void testErrorTargetsSomethingClassString() {
+    script = targetsErrorBuildClassString
+    assertEquals(-4, processCmdLineTargets(something))
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingClass, error)
+  }
+  void testTargetsClassNoFile() {
+    script = targetsBuildClassFile.replace(targetsClassFilePath, nonExistentFilePath)
+    assertEquals(-4, processCmdLineTargets(flob))
+    //  The returned string is platform dependent and dependent on whether NFS is used to mount stores, or
+    //  even RAID.  We therefore choose not to check the output to avoid having large numbers of cases.
+  }
+  void testTargetsDefaultScriptClass() {
+    script = targetsBuildScriptClass
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTargets(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testErrorTargetsDefaultScriptClass() {
+    script = targetsErrorBuildScriptClass
+    assertEquals(-4, processCmdLineTargets())
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingScript, error)
+  }
+  void testTargetsDefaultScriptFile() {
+    script = targetsBuildScriptFile
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTargets(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testTargetsDefaultScriptString() {
+    script = targetsBuildScriptString
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTargets(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testTargetsFlobScriptClass() {
+    script = targetsBuildScriptClass
+    assertEquals(0, processCmdLineTargets(flob))
+    assertEquals(resultFlob, output)
+    assertEquals('', error)
+  }
+  void testErrorTargetsFlobScriptClass() {
+    script = targetsErrorBuildScriptClass
+    assertEquals(-4, processCmdLineTargets(flob))
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingScript, error)
+  }
+  void testTargetsFlobScriptFile() {
+    script = targetsBuildScriptFile
+    assertEquals(0, processCmdLineTargets(flob))
+    assertEquals(resultFlob, output)
+    assertEquals('', error)
+  }
+  void testTargetsFlobScriptString() {
+    script = targetsBuildScriptString
+    assertEquals(0, processCmdLineTargets(flob))
+    assertEquals(resultFlob, output)
+    assertEquals('', error)
+  }
+  void testTargetsBurbleScriptClass() {
+    script = targetsBuildScriptClass
+    assertEquals(-11, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(burble), error)
+  }
+  void testErrorTargetsBurbleScriptClass() {
+    script = targetsErrorBuildScriptClass
+    assertEquals(-4, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingScript, error)
+  }
+  void testTargetsBurbleScriptFile() {
+    script = targetsBuildScriptFile
+    assertEquals(-11, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(burble), error)
+  }
+  void testTargetsBurbleScriptString() {
+    script = targetsBuildScriptString
+    assertEquals(-11, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(burble), error)
+  }
+  void testTargetsSomethingScriptClass() {
+    script = targetsBuildScriptClass
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultSomethingFlob, output)
+    assertEquals('', error)
+  }
+  void testErrorTargetsSomethingScriptClass() {
+    script = targetsErrorBuildScriptClass
+    assertEquals(-4, processCmdLineTargets(something))
+    assertEquals('', output)
+    assertEquals(resultErrorEvaluatingScript, error)
+  }
+  void testTargetsSomethingScriptFile() {
+    script = targetsBuildScriptFile
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultSomethingFlob, output)
+    assertEquals('', error)
+  }
+  void testTargetsSomethingScriptString() {
+    script = targetsBuildScriptString
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultSomethingFlob, output)
+    assertEquals('', error)
+  }
+  void testTargetsScriptNoFile() {
+    script = targetsBuildScriptFile.replace(targetsScriptFilePath, nonExistentFilePath)
+    assertEquals(-4, processCmdLineTargets(flob))
+    //  The returned string is platform dependent and dependent on whether NFS is used to mount stores, or
+    //  even RAID.  We therefore choose not to check the output to avoid having large numbers of cases.
+  }
+
+  ////////  Test multiple include of the same targets.
+
+  void testTargetsMultipleIncludeDefaultScriptFile() {
+    script = "includeTargets <<  new File('${targetsScriptFilePath}')\n" + targetsBuildScriptFile
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTargets(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testTargetsMultipleIncludeDefaultScriptString() {
+    script = "includeTargets <<  '''${targetsScriptText}'''\n" + targetsBuildScriptString
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultFlobbedTargets(defaultTarget), output)
+    assertEquals('', error)
+  }
+  void testTargetsMultipleIncludeFlobScriptFile() {
+    script = "includeTargets <<  new File('${targetsScriptFilePath}')\n" + targetsBuildScriptFile
+    assertEquals(0, processCmdLineTargets(flob))
+    assertEquals(resultFlob, output)
+    assertEquals('', error)
+  }
+  void testTargetsMultipleIncludeFlobScriptString() {
+    script = "includeTargets <<  '''${targetsScriptText}'''\n" + targetsBuildScriptString
+    assertEquals(0, processCmdLineTargets(flob))
+    assertEquals(resultFlob, output)
+    assertEquals('', error)
+  }
+  void testTargetsMultipleIncludeBurbleScriptFile() {
+    def target = 'burble'
+    script = "includeTargets <<  new File('${targetsScriptFilePath}')\n" + targetsBuildScriptFile
+    assertEquals(-11, processCmdLineTargets(target))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(target), error)
+  }
+  void testTargetsMultipleIncludeBurbleScriptString() {
+    script = "includeTargets <<  '''${targetsScriptText}'''\n" + targetsBuildScriptString
+    assertEquals(-11, processCmdLineTargets(burble))
+    assertEquals('', output)
+    assertEquals(resultTargetDoesNotExist(burble), error)
+  }
+  void testTargetsMultipleIncludeSomethingScriptFile() {
+    script = "includeTargets <<  new File('${targetsScriptFilePath}')\n" + targetsBuildScriptFile
+    assertEquals(0, processCmdLineTargets(flob))
+    assertEquals(resultFlob, output)
+    assertEquals('', error)
+  }
+  void testTargetsMultipleIncludeSomethingScriptString() {
+    script = "includeTargets <<  '''${targetsScriptText}'''\n" + targetsBuildScriptString
+    assertEquals(0, processCmdLineTargets(flob))
+    assertEquals(resultFlob, output)
+    assertEquals('', error)
+  }
+  void testUsingParameterConstructor() {
+    final theToolClassName = 'TheTool'
+    final theToolBindingName = 'theTool'
+    final theToolClassText = """
+import org.codehaus.gant.GantBinding
+class ${theToolClassName} {
+  ${theToolClassName}(GantBinding binding, Map map) { }
+  void ${flob}() { println('${flobbed}') }
+}
+"""
+    script = """
+includeTool ** groovyShell.evaluate('''${theToolClassText} ; return ${theToolClassName}''') * [ flob: 'adob', foo: 'bar' ]
+target(${something}: '') { ${theToolBindingName}.${flob}() }
+"""
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultSomething, output)
+    assertEquals('', error)
+  }
+  //  cf. GANT-29
+  void testInlineToolClass() {
+    final targetName = 'doit'
+    final data = 'data'
+    script = """
+import org.codehaus.gant.GantBinding
+class SampleTool {
+  private final Map properties = [ name: '' ]
+  SampleTool(GantBinding binding) { properties.binding = binding }
+  def getProperty(String name) { properties[name] }
+  void setProperty(String name, value) { properties[name] = value }
+}
+includeTool << SampleTool
+target(${targetName}: '') {
+  sampleTool.name = '${data}'
+  println(sampleTool.name)
+}
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, data + '\n'), output)
+    assertEquals('', error)
+  }
+
+  //  Make sure that errors are correctly trapped.
+
+  void testErrorPowerNoMultiply() {
+    // ** without * is effectively a no-op due to the way things are processed.
+    script = """
+includeTargets ** gant.targets.Clean
+target(${something}: '') { }
+"""
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultString(something, ''), output)
+    assertEquals('', error)
+  }
+  void testErrorNoPower() {
+    // * instead of ** is an error because of the type of the right hand parameter.
+    script = """
+includeTargets * gant.targets.Clean
+target(${something}: '') { }
+"""
+    assertEquals(-4, processCmdLineTargets(something))
+    assertEquals('', output)
+    assertEquals('Standard input, line 2 -- Error evaluating Gantfile: No signature of method: org.codehaus.gant.IncludeTargets.multiply() is applicable for argument types: (java.lang.Class) values: [class gant.targets.Clean]\nPossible solutions: multiply(java.util.Map), multiply(java.util.Map)\n', error)
+  }
+  void testErrorNullPower() {
+    script = """
+includeTargets ** null * [ ]
+target(${something}: '') { }
+"""
+    assertEquals(-4, processCmdLineTargets(something))
+    assertEquals('', output)
+    assertEquals('Standard input, line 2 -- Error evaluating Gantfile: wrong number of arguments\n', error)
+  }
+
+  //  This test provided by Peter Ledbrook in order to test the change to Gant to allow Script objects to be
+  //  used to initialize a Gant object.
+
+  //  TODO:  There needs to be more testing of this feature.
+
+  void testIncludeCompiledScript() {
+    def script = '''
+testVar = 'Test'
+target(aTarget: '') {
+  println('Tested.')
+}
+'''
+    final gcl = new GroovyClassLoader()
+    final clazz = gcl.parseClass(script)
+    final binding = new org.codehaus.gant.GantBinding()
+    final includeTargets = new org.codehaus.gant.IncludeTargets(binding)
+    includeTargets << clazz
+    assertEquals('Test', binding.testVar)
+    assertNotNull(binding.aTarget)
+  }
+
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/ListingTargets_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/ListingTargets_Test.groovy
new file mode 100644
index 0000000..8082f3d
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/ListingTargets_Test.groovy
@@ -0,0 +1,266 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that the target listing works.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class ListingTargets_Test extends GantTestCase {
+  final coreScript = '''
+target(something: "Do something.") { }
+target(somethingElse: "Do something else.") { }
+'''
+  void testSomethingUsingP() {
+    script = coreScript
+    assertEquals(0, gant.processArgs(['-p',  '-f',  '-'] as String[]))
+    assertEquals('''
+ something      Do something.
+ somethingElse  Do something else.
+
+''', output)
+  }
+  void testSomethingAndCleanUsingP() {
+    script = 'includeTargets << gant.targets.Clean\n' + coreScript
+    assertEquals(0, gant.processArgs(['-p',  '-f',  '-'] as String[]))
+    assertEquals('''
+ clean          Action the cleaning.
+ clobber        Action the clobbering. Do the cleaning first.
+ something      Do something.
+ somethingElse  Do something else.
+
+''', output)
+  }
+  void testGStringsUsingP() {
+    script = '''
+def theWord = 'The Word'
+target(something: "Do ${theWord}.") { }
+target(somethingElse: "Do ${theWord}.") { }
+'''
+    assertEquals(0, gant.processArgs(['-p',  '-f',  '-'] as String[]))
+    assertEquals('''
+ something      Do The Word.
+ somethingElse  Do The Word.
+
+''', output)
+  }
+  void testDefaultSomethingUsingP() {
+    script = '''
+target(something: "Do something.") { }
+target(somethingElse: "Do something else.") { }
+target('default': "The default.") { something() }
+'''
+    assertEquals(0, gant.processArgs(['-p',  '-f',  '-'] as String[]))
+    assertEquals('''
+ default        The default.
+ something      Do something.
+ somethingElse  Do something else.
+
+Default target is default.
+
+''', output)
+  }
+  void testDefaultSomethingSetDefaultClosureUsingP() {
+    script = '''
+target(something: "Do something.") { }
+target(somethingElse: "Do something else.") { }
+setDefaultTarget(something)
+'''
+    assertEquals(0, gant.processArgs(['-p',  '-f',  '-'] as String[]))
+    assertEquals('''
+ something      Do something.
+ somethingElse  Do something else.
+
+Default target is something.
+
+''', output)
+  }
+  void testDefaultSomethingSetDefaultStringUsingP() {
+    script = '''
+target(something: "Do something.") { }
+target(somethingElse: "Do something else.") { }
+setDefaultTarget('something')
+'''
+    assertEquals(0, gant.processArgs(['-p',  '-f',  '-'] as String[]))
+    assertEquals('''
+ something      Do something.
+ somethingElse  Do something else.
+
+Default target is something.
+
+''', output)
+  }
+  void testDefaultSomethingSetDefaultFailUsingP() {
+    script = '''
+target(something: "Do something.") { }
+target(somethingElse: "Do something else.") { }
+setDefaultTarget('fail')
+'''
+    assertEquals(0, gant.processArgs(['-p',  '-f',  '-'] as String[]))
+    assertEquals('''
+ something      Do something.
+ somethingElse  Do something else.
+
+''', output)
+  }
+
+  // -------------------------------------------------------------------------------------------------
+
+  void testSomethingUsingT() {
+    script = coreScript
+    assertEquals(0, gant.processArgs(['-T',  '-f',  '-'] as String[]))
+    assertEquals('''
+ something      Do something.
+ somethingElse  Do something else.
+
+''', output)
+  }
+  void testSomethingAndCleanUsingT() {
+    script = 'includeTargets << gant.targets.Clean\n' + coreScript
+    assertEquals(0, gant.processArgs(['-T',  '-f',  '-'] as String[]))
+    assertEquals('''
+ clean          Action the cleaning.
+ clobber        Action the clobbering. Do the cleaning first.
+ something      Do something.
+ somethingElse  Do something else.
+
+''', output)
+  }
+  void testGStringsUsingT() {
+    script = '''
+def theWord = 'The Word'
+target(something: "Do ${theWord}.") { }
+target(somethingElse: "Do ${theWord}.") { }
+'''
+    assertEquals(0, gant.processArgs(['-T',  '-f',  '-'] as String[]))
+    assertEquals('''
+ something      Do The Word.
+ somethingElse  Do The Word.
+
+''', output)
+  }
+  void testDefaultSomethingUsingT() {
+    script = '''
+target(something: "Do something.") { }
+target(somethingElse: "Do something else.") { }
+target('default': "The default target.") { something() }
+'''
+    assertEquals(0, gant.processArgs(['-T',  '-f',  '-'] as String[]))
+    assertEquals('''
+ default        The default target.
+ something      Do something.
+ somethingElse  Do something else.
+
+Default target is default.
+
+''', output)
+  }
+  void testDefaultSomethingSetDefaultClosureUsingT() {
+    script = '''
+target(something: "Do something.") { }
+target(somethingElse: "Do something else.") { }
+setDefaultTarget(something)
+'''
+    assertEquals(0, gant.processArgs(['-T',  '-f',  '-'] as String[]))
+    assertEquals('''
+ something      Do something.
+ somethingElse  Do something else.
+
+Default target is something.
+
+''', output)
+  }
+  void testDefaultSomethingSetDefaultStringUsingT() {
+    script = '''
+target(something: "Do something.") { }
+target(somethingElse: "Do something else.") { }
+setDefaultTarget('something')
+'''
+    assertEquals(0, gant.processArgs(['-T',  '-f',  '-'] as String[]))
+    assertEquals('''
+ something      Do something.
+ somethingElse  Do something else.
+
+Default target is something.
+
+''', output)
+  }
+  void testDefaultSomethingSetDefaultFailUsingT() {
+    script = '''
+target(something: "Do something.") { }
+target(somethingElse: "Do something else.") { }
+setDefaultTarget('fail')
+'''
+    assertEquals(0, gant.processArgs(['-T',  '-f',  '-'] as String[]))
+    assertEquals('''
+ something      Do something.
+ somethingElse  Do something else.
+
+''', output)
+  }
+
+  // -------------------------------------------------------------------------------------------------
+
+  /*
+   *  In Gant 1.5.0 changes were made to the way the parameter to target was handled -- cf. GANT-56.
+   *  However, it seems no tests were introduced for printing things out.  GANT-71 raised this point.  The
+   *  following tests are directly the ones from GANT-71 by Jason Messmer -- possibly more tests needs
+   *  adding.  In the end, GANT-71 was "Not A Bug", the original failing case was erroneous, and the new
+   *  format worked fine -- despite not having any unit tests.
+   */
+
+  void test_GANT_71_oldFormatStillWorksUsingP() {
+    script = '''
+target(test: 'testing') { println("$it.name:") }
+'''
+    assertEquals(0, gant.processArgs(['-p', '-f', '-'] as String[]))
+    assertEquals('''
+ test  testing
+
+''', output)
+  }
+  void test_GANT_71_newFormatWorksUsingP() {
+    script = '''
+target(name: 'test', description: 'testing') { println("$it.name:") }
+'''
+    assertEquals(0, gant.processArgs(['-p', '-f', '-'] as String[]))
+    assertEquals('''
+ test  testing
+
+''', output)
+  }
+
+  void test_GANT_71_oldFormatStillWorksUsingT() {
+    script = '''
+target(test: 'testing') { println("$it.name:") }
+'''
+    assertEquals(0, gant.processArgs(['-T', '-f', '-'] as String[]))
+    assertEquals('''
+ test  testing
+
+''', output)
+  }
+  void test_GANT_71_newFormatWorksUsingT() {
+    script = '''
+target(name: 'test', description: 'testing') { println("$it.name:") }
+'''
+    assertEquals(0, gant.processArgs(['-T', '-f', '-'] as String[]))
+    assertEquals('''
+ test  testing
+
+''', output)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/NoAntObject_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/NoAntObject_Test.groovy
new file mode 100644
index 0000000..d91f0f9
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/NoAntObject_Test.groovy
@@ -0,0 +1,103 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2007–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that calling an Ant task without the Ant object works as required.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class NoAntObject_Test extends GantTestCase {
+  private final targetName = 'targetName'
+  private final message = 'Hello'
+  private final followUp = ' World'
+  private final replicationCount = 4
+  private String resultMessage = resultString(targetName, "     [echo] ${message}\n")
+  private String resultReplicated = resultString(targetName, "     [echo] ${message}\n" * replicationCount)
+  void testEchoAttribute() {
+    script = "target(${targetName}: '') { echo(message: '${message}') }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultMessage, output)
+  }
+  void testEchoText() {
+    script = "target(${targetName}: '') { echo { '${message}' } }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, ''), output)
+  }
+  void testEchoMixed() {
+    script = "target(${targetName}: '') { echo(message: '${message}') { ' ${followUp}' } }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultMessage, output)
+  }
+  //  cf. GANT-10
+  void testWithAntReferenceScriptLevel() {
+    script = """
+ant.echo(message: '${message}')
+target(${targetName}: '') { ant.echo(message: '${followUp}') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals("     [echo] ${message}\n" + resultString(targetName, "     [echo] ${followUp}\n"), output)
+  }
+  void testWithoutAntReferenceScriptLevel() {
+    script = """
+ant.echo(message: '${message}')
+target(${targetName}: '') { echo(message: '${followUp}') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals( "     [echo] ${message}\n" + resultString(targetName, "     [echo] ${followUp}\n"), output)
+  }
+  void testWithAntReferenceInClosure() {
+    script = "target(${targetName}: '') {(0..<${replicationCount}).each { ant.echo(message: '${message}') } }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultReplicated, output)
+  }
+  void testWithoutAntReferenceInClosure() {
+    script = "target(${targetName}: '') {(0..<${replicationCount}).each { echo(message: '${message}') } }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultReplicated, output)
+  }
+  void testWithoutAntReferenceInMapClosure() {
+    script = "target(${targetName}: '') { [ a: 'A', b: 'B' ].each { key, value -> echo(message: \"\${key}:\${value}\") } }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, '''     [echo] a:A
+     [echo] b:B
+'''), output)
+  }
+  void testClosureWithAnt() {
+    script = """
+closure = { ant.echo(message: '${message}') }
+target(${targetName}: '') {(0..<${replicationCount}).each closure }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultReplicated, output)
+  }
+  void testClosureWithoutAntWithExplictMetaClassSetting() {
+    script = """
+closure = { echo(message: '${message}') }
+closure.metaClass = new org.codehaus.gant.GantMetaClass(closure.metaClass, binding)
+target(${targetName}: '') {(0..<${replicationCount}).each closure }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultReplicated, output)
+  }
+  void testClosureWithoutAnt() {
+    script = """
+closure = { echo(message: '${message}') }
+target(${targetName}: '') {(0..<${replicationCount}).each closure }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultReplicated, output)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/Options_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/Options_Test.groovy
new file mode 100644
index 0000000..af42f89
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/Options_Test.groovy
@@ -0,0 +1,53 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2007–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure certain options get processed correctly.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Options_Test extends GantTestCase {
+  private final targetName = 'printDefinitions'
+  void testVersion() {
+    //  Gant gets its idea of version number from the manifest in the jar.  This means the tests have
+  	//  to run against the jar to get a non-null version number -- running the tests against the compiled
+  	//  classes will always give null as the version number.  The Gant and Ant builds perform the
+  	//  packaging then run the tests, the Gradle, Maven, Eclipse, and IntelliJ IDEA tests occur before the
+  	//  packaging.  To avoid getting a test fail with these fiddle with the expectations.
+    assertEquals(0, gant.processArgs([ '-V' ] as String[]))
+    assertEquals('Gant version ' +(gant.binding.'gant.version' == null ? '<unknown>': gant.binding.'gant.version'), output.trim())
+  }
+  void testDefinitions() {
+    script = """
+target(${targetName}: '') {
+  println(first)
+  println(second)
+  println(third)
+}
+"""
+    assertEquals(0, gant.processArgs([ '-f', '-', '-Dfirst=tsrif', '-Dsecond=dnoces', '-Dthird=driht', targetName ] as String[]))
+    assertEquals(resultString(targetName, '''tsrif
+dnoces
+driht
+'''), output)
+  }
+  void testFileOptionLong() {
+    final message = 'Hello.'
+    script = "target(${targetName}: '') { println('${message}') }"
+    assertEquals(0, gant.processArgs([ '--file', '-', targetName ] as String[]))
+    assertEquals(resultString(targetName, message + '\n'), output)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/ReturnValue_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/ReturnValue_Test.groovy
new file mode 100644
index 0000000..559d0c1
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/ReturnValue_Test.groovy
@@ -0,0 +1,70 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that the return value of Gant is reasonable.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class ReturnValue_Test extends GantTestCase {
+  void testMissingMethodInDefaultTarget() {
+    script = '''
+target('default': '') { blah() }
+'''
+    assertEquals(-13, processCmdLineTargets())
+  }
+  void testMissingMethodInNonDefaultTarget() {
+    script = '''
+target(doit: '') { blah() }
+'''
+    assertEquals(-13, processCmdLineTargets('doit'))
+  }
+  void testMissingPropertyInDefaultTarget() {
+    script = '''
+target('default': '') { x = blah }
+'''
+    assertEquals(-12, processCmdLineTargets())
+  }
+  void testMissingPropertyInNonDefaultTarget() {
+    script = '''
+target(doit: '') { x = blah }
+'''
+    assertEquals(-11, processCmdLineTargets('doit'))
+  }
+  void testExplicitReturnCodeInDefaultTarget() {
+    def code = 27
+    script = """
+target('default': '') { ${code} }
+"""
+    assertEquals(code, processCmdLineTargets())
+  }
+  void testExplicitReturnCodeInNonDefaultTarget() {
+    def code = 28
+    script = """
+target(doit: '') { ${code} }
+"""
+    assertEquals(code, processCmdLineTargets('doit'))
+  }
+  void testScriptCompilationError() {
+    script = '''
+this is definitely not a legal script.
+'''
+    assertEquals(-2, processCmdLineTargets())
+  }
+  void testCannotFindScript() {
+    assertEquals(-3,(new gant.Gant()).processArgs([ '-f', 'blah_blah_blah_blah' ] as String[]))
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/SubGant_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/SubGant_Test.groovy
new file mode 100644
index 0000000..684e9a8
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/SubGant_Test.groovy
@@ -0,0 +1,81 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that creating a new Gant object and using works.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class SubGant_Test extends GantTestCase {
+  private final targetName = 'targetName'
+  private final internalTarget = 'doTarget'
+  private final resultMessage = 'Do thing.'
+  private File buildFile
+  public void setUp() {
+    super.setUp()
+    buildFile = File.createTempFile('gant_', '_SubGant_Test') // Must ensure name is a valid Java class name.
+  }
+  public void tearDown() {
+    super.tearDown()
+    buildFile.delete()
+  }
+  public void testSimple() {
+    final buildScript = """
+target(${internalTarget}: '') { println('${resultMessage}') }
+target(${targetName}: '') {
+  subGant = new gant.Gant()
+  subGant.loadScript(new File('${escapeWindowsPath(buildFile.path)}'))
+  subGant.processTargets('${internalTarget}')
+}
+"""
+    buildFile.write(buildScript)
+    script = buildScript
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, resultString(internalTarget, resultMessage + '\n')), output)
+  }
+  public void testWithBinding() {
+    final buildScript = """
+target(${internalTarget}: '') { println('${resultMessage}') }
+target(${targetName}: '') {
+  subGant = new gant.Gant(binding.clone())
+  subGant.loadScript(new File('${escapeWindowsPath(buildFile.path)}'))
+  subGant.processTargets('${internalTarget}')
+}
+"""
+    buildFile.write(buildScript)
+    script = buildScript
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, resultString(internalTarget, resultMessage + '\n')), output)
+  }
+  public void testSettingBindingVariable() {
+    final flobadob = 'flobadob'
+    final weed = 'weed'
+    final buildScript = """
+target(${internalTarget}: '') { println('${flobadob} = ' + ${flobadob}) }
+target(${targetName}: '') {
+  def newBinding = binding.clone()
+  newBinding.${flobadob} = '${weed}'
+  subGant = new gant.Gant(newBinding)
+  subGant.loadScript(new File('${escapeWindowsPath(buildFile.path)}'))
+  subGant.processTargets('${internalTarget}')
+}
+"""
+    buildFile.write(buildScript)
+    script = buildScript
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, resultString(internalTarget, flobadob + ' = ' + weed + '\n')), output)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/TargetMetaClassLookup_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/TargetMetaClassLookup_Test.groovy
new file mode 100644
index 0000000..62b4d5f
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/TargetMetaClassLookup_Test.groovy
@@ -0,0 +1,64 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that the targets method lookup works.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class TargetMetaClassLookup_Test extends GantTestCase {
+  private final something = 'something'
+  private final message = 'message'
+  void setUp() {
+    super.setUp()
+    script = """
+includeTargets << gant.targets.Clean
+cleanPattern << '**/*~'
+target(${something}: '') { ant.echo(message: '${message}') }
+setDefaultTarget(${something})
+"""
+  }
+
+  //  It seems that the same gant.targets.Clean instance is used for all tests in this class which is a bit
+  //  sad because it means that there is an accumulation of **/*~ patterns, one for each test method as
+  //  addCleanPattern gets executed for each test.  So it is crucial to know when testClean is run to know
+  //  what the output will be.  Put it first in the hope it will be run first.
+
+  void testClean() {
+    //  Have to do this dry run or the result is indeterminate.
+    assertEquals(0, gant.processArgs(['-n', '-f',  '-' , 'clean'] as String[]))
+    assertEquals(resultString('clean', '''   [delete] quiet : 'false'
+  [fileset] dir : '.', includes : '**/*~', defaultexcludes : 'false'
+'''), output) //// */ Emacs fontlock fixup.
+    assertEquals('', error)
+  }
+  void testDefault() {
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultString(something, "     [echo] ${message}\n"), output)
+    assertEquals('', error)
+  }
+  void testMissingTarget() {
+    final missingTarget = 'blah'
+    assertEquals(-11, processCmdLineTargets(missingTarget))
+    assertEquals('', output)
+    assertEquals("Target ${missingTarget} does not exist.\n", error)
+  }
+  void testSomething() {
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultString(something, "     [echo] ${message}\n"), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/Targets_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/Targets_Test.groovy
new file mode 100644
index 0000000..4619067
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/Targets_Test.groovy
@@ -0,0 +1,243 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013, 2014  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that the target specification works.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Targets_Test extends GantTestCase {
+  private final targetName = 'targetname'
+  private final ok = 'OK.'
+  private final result = resultString(targetName, ok)
+  void testNoDescription() {
+    script = "target(${targetName}: '') { print('${ok}') }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(result, output)
+    assertEquals('', error)
+  }
+  void testWithDescription() {
+    script = "target(${targetName}: 'Blah blah') { print('${ok}') }"
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(result, output)
+    assertEquals('', error)
+  }
+  void testEmptyMap() {
+    script = "target([: ]) { print('${ok}') }"
+    assertEquals(-4, processCmdLineTargets(targetName))
+    assertEquals('', output)
+    assertEquals('Standard input, line 1 -- Error evaluating Gantfile: Target specified without a name.\n', error)
+  }
+  void testMultipleEntries() {
+    script = "target(fred: '', debbie: '') { print('${ok}') }"
+    assertEquals(-4, processCmdLineTargets(targetName))
+    assertEquals('', output)
+    assertEquals('Standard input, line 1 -- Error evaluating Gantfile: Target specified without a name.\n', error)
+  }
+  void testOverwriting() {
+    //
+    //  TODO: Fix the problem of overwriting targets.  Until changed, creating a new symbol in the binding
+    //  using a target overwrites the old symbol.  This is clearly wrong behaviour and needs amending.
+    //
+    script = """
+target(${targetName}: '') { println('Hello 1') }
+target(${targetName}: '') { println('Hello 2') }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, 'Hello 2\n'), output)
+    assertEquals('', error)
+  }
+  void testForbidRedefinitionOfTarget() {
+    script = """
+target(${targetName}: '') { }
+target = 10
+"""
+    assertEquals(-4, processCmdLineTargets(targetName))
+    assertEquals('', output)
+    assertEquals('Standard input, line 3 -- Error evaluating Gantfile: Cannot redefine symbol target\n', error)
+  }
+  void testStringParameter() {
+    script = "target('${targetName}') { print('${ok}') }"
+    assertEquals(-4, processCmdLineTargets(targetName))
+    assertEquals('', output)
+    assertTrue(error.contains('Standard input, line 1 -- Error evaluating Gantfile: No signature of method: org.codehaus.gant.GantBinding$_initializeGantBinding_closure'))
+  }
+  void testStringSequenceParameter() {
+    script = "target('${targetName}', 'description') { print('${ok}') }"
+    assertEquals(-4, processCmdLineTargets(targetName))
+    assertEquals('', output)
+    assertTrue(error.startsWith('Standard input, line 1 -- Error evaluating Gantfile: No signature of method: org.codehaus.gant.GantBinding$_initializeGantBinding_closure'))
+  }
+  void testMissingTargetInScriptExplicitTarget() {
+    script = "setDefaultTarget(${targetName})"
+    assertEquals(-4, processCmdLineTargets(targetName))
+    assertEquals('', output)
+    assertEquals("Standard input, line 1 -- Error evaluating Gantfile: No such property: ${targetName} for class: standard_input\n", error)
+  }
+  void testMissingTargetInScriptDefaultTarget() {
+    script = "setDefaultTarget(${targetName})"
+    assertEquals(-4, processCmdLineTargets())
+    assertEquals('', output)
+    assertEquals("Standard input, line 1 -- Error evaluating Gantfile: No such property: ${targetName} for class: standard_input\n", error)
+  }
+  void testFaultyScript() {
+    script = 'XXXXX: YYYYY ->'
+    assertEquals(-2, processCmdLineTargets())
+    assertEquals('', output)
+    //  Error messages seem to get changed at bizarre parts of the lifecycle of Groovy.  Ho humm...
+    assertEquals('''Error evaluating Gantfile: startup failed:
+standard_input: 1: expecting EOF, found '->' @ line 1, column 14.
+   XXXXX: YYYYY ->
+                ^
+
+1 error
+''', error)
+  }
+
+  //  Tests resulting from GANT-45.
+
+  final testScript = """
+target(${targetName}: '') { println(home) }
+setDefaultTarget(${targetName})
+"""
+  final expectedOutput = 'Standard input, line 2 -- Error evaluating Gantfile: No such property: home for class: standard_input\n'
+  void test_GANT_45_MessageBugDefaultTarget() {
+    script = testScript
+    assertEquals(-12, processCmdLineTargets())
+    assertEquals(targetName + ':\n', output)
+    assertEquals(expectedOutput, error)
+  }
+  void test_GANT_45_MessageBugExplicitTarget() {
+    script = testScript
+    assertEquals(-11, processCmdLineTargets(targetName))
+    assertEquals(targetName + ':\n', output)
+    assertEquals(expectedOutput, error)
+  }
+
+  //  Test relating to GStrings as target names
+
+  void testGStringWorkingAsATargetName() {
+    script = """
+def name = '${targetName}'
+target("\${name}": '') { println("\${name}") }
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, targetName + '\n'), output)
+    assertEquals('', error)
+  }
+
+  //  Tests resulting from GANT-55 -- GString as a parameter to depends call causes problems.
+  //
+  //  GANT-61 turns out to be a replica of GANT-55.
+
+  private final profileTag = '.profile'
+  private final compileTag = '.compile'
+  private final expectedGant55Result =  resultString(targetName + compileTag, resultString(targetName + profileTag, "Profile for ${targetName}\n") + "Compile for ${targetName}\n")
+  void test_GANT_55_original_usingGStringKeys() {
+    script = """
+def tag = '${targetName}'
+target("\${tag}${profileTag}": '') { println("Profile for \$tag") }
+target("\${tag}${compileTag}": '') {
+  depends("\${tag}${profileTag}")
+  println("Compile for \$tag")
+}
+"""
+    /*
+     *  The original behaviour:
+     *
+    assertEquals(-13, processCmdLineTargets('test.compile'))
+    assertEquals('depends called with an argument (test.profile) that is not a known target or list of targets.\n', output)
+    *
+    *  Is now fixed:
+    */
+    assertEquals(0, processCmdLineTargets("${targetName}${compileTag}")) // NB parameter must be a String!
+    assertEquals(expectedGant55Result, output)
+    assertEquals('', error)
+  }
+  void test_GANT_55_usingStringKeys() {
+    script = """
+target('${targetName}${profileTag}': '') { println('Profile for $targetName') }
+target('${targetName}${compileTag}': '') {
+  depends('${targetName}${profileTag}')
+  println('Compile for $targetName')
+}
+"""
+    assertEquals(0, processCmdLineTargets(targetName + compileTag))
+    assertEquals(expectedGant55Result, output)
+    assertEquals('', error)
+  }
+
+  //  Tests to ensure the patch of GANT-56 doesn't do nasty things.  A couple of tests from earlier change
+  //  their purpose.
+
+  void test_GANT_56() {
+    script = """
+targetName = '${targetName}'
+targetDescription = 'Some description or other'
+target(name: targetName, description: targetDescription) {
+  assert it.name == targetName
+  assert it.description == targetDescription
+}
+setDefaultTarget(targetName)
+"""
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultString(targetName, ''), output)
+    assertEquals('', error)
+  }
+
+  void test_nameAsATargetNameImpliesExplicitDefinitionStyle() {
+    final bar = 'bar'
+    script = """
+targetName = '${bar}'
+target(name: targetName) {
+  assert it.name == targetName
+  assert it.description == null
+}
+setDefaultTarget(targetName)
+"""
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultString(bar, ''), output)
+    assertEquals('', error)
+  }
+
+  //  Phil Swenson asked for the name of the target being completed to be available -- see the email on the Gant
+  //  Developer list dated 2009-09-26 20:48+00:00
+
+  private final one = 'one'
+  private final two = 'two'
+  private final initiatingTargetScript = """
+target(${one}: '') {
+  println(initiatingTarget)
+}
+target(${two}: '') {
+  depends(${one})
+  println(initiatingTarget)
+}
+"""
+  void testInitiatingTargetAvailableToScript() {
+    script = initiatingTargetScript
+    assertEquals(0, processCmdLineTargets(two))
+    assertEquals(resultString(two, resultString(one, two + '\n') + two + '\n'), output)
+    assertEquals('', error)
+  }
+  void testEachInitiatingTargetOfASequenceAvailableToScript() {
+    script = initiatingTargetScript
+    assertEquals(0, processCmdLineTargets([ one, two ]))
+    assertEquals(resultString(one, one + '\n') + resultString(two, resultString(one, two + '\n') + two + '\n'), output)
+    assertEquals('', error)
+  }
+
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/ToolMetaClassLookup_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/ToolMetaClassLookup_Test.groovy
new file mode 100644
index 0000000..2681617
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/ToolMetaClassLookup_Test.groovy
@@ -0,0 +1,61 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2006–2010, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+import org.codehaus.gant.GantBuilder
+import org.codehaus.gant.GantState
+
+/**
+ *  A test to ensure that the target listing works.
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class ToolMetaClassLookup_Test extends GantTestCase {
+  private final something = 'something'
+  private final subdirectory = new File('aSubdirectoryOfTheCurrentOneThatIsUnlikelyToExist')
+  private final gantBuilder = new GantBuilder() ; {
+    gantBuilder.logger.setMessageOutputLevel(GantState.SILENT)
+  }
+  private final message = 'yes'
+  void setUp() {
+    super.setUp()
+    if(subdirectory.exists()) { fail('The name "' + directory.name + '" is in use.') }
+    gantBuilder.mkdir(dir: subdirectory.name)
+    def command =(isWindows ? 'cmd /c echo ': 'echo ') + message
+    script = """
+includeTool << gant.tools.Subdirectories
+target(${something}: '') { subdirectories.runSubprocess('${command}', new File('${subdirectory.name}')) }
+setDefaultTarget(${something})
+"""
+  }
+  void tearDown() { gantBuilder.delete(dir: subdirectory.name, quiet: 'true') }
+
+  void testDefault() {
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultString(something, message + '\n'), output)
+    assertEquals('', error)
+  }
+  void testTargetNotPresent() {
+    final targetName = 'blah'
+    assertEquals(-11, processCmdLineTargets(targetName))
+    assertEquals('', output)
+    assertEquals("Target ${targetName} does not exist.\n", error)
+  }
+  void testSomething() {
+    assertEquals(0, processCmdLineTargets(something))
+    assertEquals(resultString(something, message + '\n'), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/XMLProcessing_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/XMLProcessing_Test.groovy
new file mode 100644
index 0000000..80c9af0
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/XMLProcessing_Test.groovy
@@ -0,0 +1,57 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2012, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests
+
+/**
+ *  A test to ensure that XML processing works.
+ *
+ *  <p>This test stems from a mis-feature report made on the Groovy/Gant user mailing list by Mike
+ *  Nooney.</p>
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class XMLProcessing_Test extends GantTestCase {
+  public void testMikeNooneyXMLExampleToEnsureNoProblemWithXMLJars() {
+    def xmlScript = '''<Document>
+    <Sentence code="S0001" format="Document.Title"/>
+    <Sentence code="S0002" format="Section.Title"/>
+    <Sentence code="S0003" format="Subsection.Title"/>
+    <Sentence code="S0004" format="Sentence"/>
+    <Sentence code="S0005" format="Sentence"/>
+    <Sentence code="S0006" format="Subsection.Title"/>
+    <Sentence code="S0007" format="Sentence"/>
+</Document>
+'''
+    def targetName = 'testing'
+    script = """
+target(${targetName}: '') {
+  def testClass = new GroovyShell(binding).evaluate('''
+class Test {
+	public static void test() {
+		def reader = new StringReader(\\\'\\\'\\\'${xmlScript}\\\'\\\'\\\')
+		def xmlData = groovy.xml.DOMBuilder.parse(reader)
+		def rootElement = xmlData.documentElement
+		println('root element:' + rootElement)
+	}
+}
+return Test
+''' )
+  testClass.test()
+}
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, 'root element:<?xml version="1.0" encoding="UTF-8"?>' + xmlScript + '\n'), output)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/bugs/Assorted_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/bugs/Assorted_Test.groovy
new file mode 100644
index 0000000..6fbccc6
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/bugs/Assorted_Test.groovy
@@ -0,0 +1,206 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2009–2010, 2013, 2014  Russel Winder
+//
+//  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: Russel Winder <russel at winder.org.uk>
+
+//  This file contains the individual tests resulting from specific bug reports that do not require their
+//  own test class (because there are not a set of tests), and they do not obviously belong in another test
+//  class.
+
+package  org.codehaus.gant.tests.bugs
+
+import org.codehaus.gant.tests.GantTestCase
+
+class Assorted_Test extends GantTestCase {
+  private final targetName = 'targetName'
+
+  void test_GANT_29_ensureCaseChangeWorks() {
+    final result = 'some string or other'
+    script = """
+import org.codehaus.gant.tests.bugs.subPackage.GANT_29_SampleTool
+includeTool << GANT_29_SampleTool
+target(${targetName}: '') {
+  gANT_29_SampleTool.name = '${result}'
+  println(gANT_29_SampleTool.name)
+}
+setDefaultTarget(${targetName})
+"""
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, result + '\n'), output)
+    assertEquals('', error)
+  }
+
+  void test_GANT_32_singleFileFailsCorrectly() {
+    script = """
+target(${targetName}: '') { foo }
+def foo { badvariable }
+"""
+    assertEquals(-2, processCmdLineTargets( targetName))
+    assertEquals('', output)
+    assertEquals('''Error evaluating Gantfile: startup failed:
+standard_input: 3: unexpected token: foo @ line 3, column 5.
+   def foo { badvariable }
+       ^
+
+1 error
+''', error)
+  }
+  void test_GANT_32_multipleFilesFailsCorrectly() {
+    final file = File.createTempFile('gant-', '-GANT_32.groovy')
+    file.write("""target(${targetName}: '') { foo }
+def foo { badvariable }
+""")
+    script = "includeTargets << new File('${escapeWindowsPath(file.path)}')"
+    try { assertEquals(-4, processCmdLineTargets(targetName)) }
+    finally { file.delete() }
+    assertEquals('', output)
+    assertTrue(error.startsWith('Standard input, line 1 -- Error evaluating Gantfile: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:\n'))
+    assertTrue(error.endsWith('''GANT_32.groovy: 2: unexpected token: foo @ line 2, column 5.
+   def foo { badvariable }
+       ^
+
+1 error
+'''))
+  }
+
+  void test_GANT_34_originalIvycachePathProblemFixed() {
+    script = '''
+includeTool << gant.tools.Ivy
+target('default': '') {
+  ivy.cachepath(organisation: 'commons-lang',
+                  module: 'commons-lang',
+                  revision: '2.3',
+                  pathid: 'clpath',
+                  inline: true)
+}
+'''
+    assertEquals(0, processCmdLineTargets())
+    //  The output is not tested since it is extensive and it is not clear that it is guaranteed to be the
+    //  same on all platforms: it contains the Ivy jar version number and some timings.
+    assertEquals('', error)
+  }
+
+  void test_GANT_49_builderBug() {
+    //
+    //  NB Codehaus Bamboo execution is not in a context such that
+    //  org.codehaus.groovy.runtime.HandleMetaClass exists since it is running against Groovy 1.5.6 rather
+    //  than 1.6 or later.
+    //
+    script = """
+import groovy.xml.MarkupBuilder
+target(${targetName}: '') {
+  def builder = new MarkupBuilder()
+
+  //assert builder.metaClass instanceof org.codehaus.groovy.runtime.HandleMetaClass
+  assert this.is(owner)
+  assert this.is(delegate)
+  //assert this.metaClass instanceof org.codehaus.groovy.runtime.HandleMetaClass
+  assert binding instanceof org.codehaus.gant.GantBinding
+  //assert binding.metaClass instanceof org.codehaus.groovy.runtime.HandleMetaClass
+
+  def outerThis = this
+
+   builder.beans {
+
+    assert outerThis.is(this)
+    assert delegate.is(builder)
+    assert owner instanceof Closure
+    assert owner.metaClass instanceof org.codehaus.gant.GantMetaClass
+
+    resourceHolder('Something 1')
+    container {
+      item('1')
+      item('2')
+      item('3')
+    }
+  }
+}
+setDefaultTarget('${targetName}')
+"""
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultString(targetName, '''<beans>
+  <resourceHolder>Something 1</resourceHolder>
+  <container>
+    <item>1</item>
+    <item>2</item>
+    <item>3</item>
+  </container>
+</beans>'''), output)
+    assertEquals('', error)
+  }
+
+  void test_GANT_58_singleFileFailsCorrectly() {
+    def file = File.createTempFile('gant_', '_GANT_58_Test.groovy')
+    file.write('''
+def a = 1
+def b = 0
+def c = a / b
+''')
+    script = """
+includeTargets << new File('${escapeWindowsPath(file.path)}')
+target('default', '') { }
+"""
+    try {
+      assertEquals(-4, processCmdLineTargets())
+      assertEquals('', output)
+      assertEquals("Standard input, line 2 -- Error evaluating Gantfile: ${file.path}, line 4 -- java.lang.ArithmeticException: Division by zero\n", error)
+    }
+    finally { file.delete() }
+  }
+
+  void test_GANT_63_exceptionFailsCorrectly() {
+    script = """
+target(${targetName}: '') {
+  def f = new File('blahblahblahblahblah')
+  println('before')
+  f.eachDir { println(it) }
+  println('after')
+}
+setDefaultTarget(${targetName})
+"""
+    assertEquals(-13, processCmdLineTargets())
+    assertEquals("${targetName}:\nbefore\n", output)
+    assertTrue(error.startsWith('java.io.FileNotFoundException: '))
+    assertTrue(error.endsWith('blahblahblahblahblah\n'))
+  }
+
+  void test_GANT_68_getReasonableErrorMessageForMissingDestination() {
+    //  Use a preexisting directory as the source directory and make sure the build directory doesn't exist!
+    final sourceDirectory = 'src/test/groovy/org/codehaus/gant/tests/bugs'
+    final destinationDirectory = 'destinationDirectoryOfSomeObscureNameThatDoesntExist'
+    script = """
+sourceDirectory = '${sourceDirectory}'
+destinationDirectory = '${destinationDirectory}'
+target(${targetName}: '') {
+  delete(dir: destinationDirectory)
+  javac(srcdir: sourceDirectory, destdir: destinationDirectory, fork: 'true', failonerror: 'true', source: '5', target: '5', debug: 'on', deprecation: 'on')
+}
+"""
+    assertEquals(-13, processCmdLineTargets(targetName))
+    assertEquals("${targetName}:\n", output)
+    assertEquals(": destination directory \"${(new File(destinationDirectory)).absolutePath }\" does not exist or is not a directory\n", error)
+  }
+
+  void test_GANT_131_commandLineParsingOfDValuesWithEquals() {
+    final targetName = 'someNameOrOther'
+    script = """
+target(name: '${targetName}') {
+  println 'key: ' + key
+}
+"""
+    assertEquals(0, processCmdLineTargets(['-Dkey="xxx=yyy"', targetName]))
+    assertEquals(resultString(targetName, 'key: xxx=yyy\n'), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/bugs/GANT_108_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/bugs/GANT_108_Test.groovy
new file mode 100644
index 0000000..9f5d82f
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/bugs/GANT_108_Test.groovy
@@ -0,0 +1,99 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2009–2010, 2013  Russel Winder
+//
+//  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: Russel Winder <russel at winder.org.uk>
+
+package  org.codehaus.gant.tests.bugs
+
+import org.codehaus.gant.tests.GantTestCase
+
+class GANT_108_Test extends GantTestCase {
+  private testString = 'Hello.'
+  private targetName = 'doit'
+  private problemTargetBodyString = """
+def writer = new StringWriter()
+def xml = new MarkupBuilder(writer)
+xml.Configure { Set { println('${testString}') } }
+println(writer.toString())
+"""
+   private workingTargetBodyString = problemTargetBodyString.replace('Set', 'xml.Set')
+   private resultString = '''
+<Configure>
+  <Set />
+</Configure>
+'''
+
+//  TODO: Enable the tests that show the GANT-108 problems.
+
+  void X_test_inTargetProblem() {
+    script = 'import groovy.xml.MarkupBuilder ; target(' + targetName + ': "") { ' + problemTargetBodyString + ' }'
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, testString + resultString), output)
+  }
+  void test_inTargetWorking() {
+    script = 'import groovy.xml.MarkupBuilder ; target(' + targetName + ': "") { ' + workingTargetBodyString + ' }'
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, testString + resultString), output)
+  }
+  void X_test_inFunctionProblem() {
+    script = 'import groovy.xml.MarkupBuilder ; def doMarkup() { ' + problemTargetBodyString + ' } ; target(' + targetName + ': "") { doMarkup() }'
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, testString + resultString), output)
+  }
+  void test_inFunctionWorking() {
+    script = 'import groovy.xml.MarkupBuilder ; def doMarkup() { ' + workingTargetBodyString + ' } ; target(' + targetName + ': "") { doMarkup() }'
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, testString + resultString), output)
+  }
+  void X_test_inLocalClosureProblem() {
+    script = 'import groovy.xml.MarkupBuilder ; def doMarkup = { ' + problemTargetBodyString + ' } ; target(' + targetName + ': "") { doMarkup() }'
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, testString + resultString), output)
+  }
+  void test_inLocalClosureWorking() {
+    script = 'import groovy.xml.MarkupBuilder ; def doMarkup = { ' + workingTargetBodyString + ' } ; target(' + targetName + ': "") { doMarkup() }'
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, testString + resultString), output)
+  }
+  void X_test_inBindingClosureProblem() {
+    script = 'import groovy.xml.MarkupBuilder ; doMarkup = { ' + problemTargetBodyString + ' } ; target(' + targetName + ': "") { doMarkup() }'
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, testString + resultString), output)
+  }
+  void test_inBindingClosureWorking() {
+    script = 'import groovy.xml.MarkupBuilder ; doMarkup = { ' + workingTargetBodyString + ' } ; target(' + targetName + ': "") { doMarkup() }'
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, testString + resultString), output)
+  }
+  void test_evaluatedNeverWasAProblemWithProblem() {
+    script = 'evaluate("""import groovy.xml.MarkupBuilder ; doMarkup = { ' + problemTargetBodyString + ' }""") ; target(' + targetName + ': "") { doMarkup() }'
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, testString + resultString), output)
+  }
+  void test_evaluatedNeverWasAProblemWithWorking() {
+    script = 'evaluate("""import groovy.xml.MarkupBuilder ; doMarkup = { ' + workingTargetBodyString + ' }""") ; target(' + targetName + ': "") { doMarkup() }'
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals('', error)
+    assertEquals(resultString(targetName, testString + resultString), output)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/bugs/GANT_33_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/bugs/GANT_33_Test.groovy
new file mode 100644
index 0000000..e5fd8f8
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/bugs/GANT_33_Test.groovy
@@ -0,0 +1,118 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2011, 2013, 2014  Russel Winder
+//
+//  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.codehaus.gant.tests.bugs
+
+import org.codehaus.gant.tests.GantTestCase
+
+/**
+ *  A test to ensure that Gant objects are garbage collected appropriately.
+ *
+ *  <p>Original idea for the test due to Peter Ledbrook.</p>
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class GANT_33_Test extends GantTestCase {
+  private final buildScript =  '''
+function = { -> }
+target(main: 'simpleTest') {
+  println('Main target executing...')
+  function()
+}
+'''
+  private final scriptTemplate = '''
+import gant.Gant
+import java.lang.ref.PhantomReference
+import java.lang.ref.ReferenceQueue
+def refQueue = new ReferenceQueue()
+def phantomRefs = new HashSet()
+output = [ ] // Must be in the binding.
+Thread.startDaemon {
+  while(true) {
+    def obj = refQueue.remove()
+    if(obj != null) {
+      output << obj.toString()
+      phantomRefs.remove(obj)
+    }
+  }
+}
+def buildScript = '__BUILDSCRIPT_PATH__'
+def target = 'main'
+def gant = __CREATE_GANT__
+def refA = new PhantomReference(gant, refQueue)
+phantomRefs << refA
+output << refA.toString()
+__LOAD_SCRIPT__
+__PROCESS_TARGET__
+System.gc()
+gant = __CREATE_GANT__
+def refB = new PhantomReference(gant, refQueue)
+phantomRefs << refB
+output << refB.toString()
+__LOAD_SCRIPT__
+__PROCESS_TARGET__
+System.gc()
+Thread.sleep(500) //  Give time for the reference queue monitor to report in.
+'''
+  private File buildScriptFile
+  private fileNamePrefix =  'gant_'
+private fileNameSuffix = '_GANT_33_Test'
+  void setUp() {
+    super.setUp()
+    buildScriptFile = File.createTempFile(fileNamePrefix, fileNameSuffix)
+    buildScriptFile.write(buildScript)
+  }
+  void tearDown() {
+    buildScriptFile.delete()
+    //  Need to ensure that this cache directory actually is the real cache directory as listed in gant.Gant.
+    new AntBuilder().delete {
+      fileset(dir: [System.properties.'user.home', '.gant', 'cache'].join(System.properties.'file.separator'), includes: fileNamePrefix + '*' + fileNameSuffix + '*')
+    }
+  }
+  //////////////////////////////////////////////////////////////////////////////////////////////
+  //  On Windows the string returned by createTempFile must have \ reprocessed before being used for other
+  //  purposes.
+  //////////////////////////////////////////////////////////////////////////////////////////////
+  void testCorrectCollection() {
+    //  Creates two Gant instances, one of which should be garbage collected, so the result of execution is
+    //  a list of 3 items, the addresses of the two created objects and the address of the collected object
+    //  -- which should be the same as the address of the first created object.
+    final binding = new Binding(output: '')
+    final groovyShell = new GroovyShell(binding)
+    groovyShell.evaluate (
+                          scriptTemplate
+                          .replace('__BUILDSCRIPT_PATH__', escapeWindowsPath(buildScriptFile.path))
+                          .replace('__CREATE_GANT__', 'new Gant()')
+                          .replace('__LOAD_SCRIPT__', 'gant.loadScript(new File(buildScript))')
+                          .replace('__PROCESS_TARGET__', 'gant.processTargets(target)')
+                         )
+    assertEquals(3, binding.output.size())
+    //  if there is a garbage collected object then it should be the one we expect.
+    if (binding.output.size() > 2) { assertEquals(binding.output[0], binding.output[2]) }
+  }
+  void testNoCollection() {
+    //  Creates two Gant instances neither of which are garbage collected.  This is showing the presence of the "memory leak".
+    final binding = new Binding(output: '')
+    final groovyShell = new GroovyShell(binding)
+    System.err.println('testNoCollection:  This test succeeds incorrectly, it is showing the presence of the bug.')
+    groovyShell.evaluate (
+                          scriptTemplate
+                          .replace('__BUILDSCRIPT_PATH__', escapeWindowsPath(buildScriptFile.path))
+                          .replace('__CREATE_GANT__', 'new Gant()')
+                          .replace('__LOAD_SCRIPT__', '')
+                          .replace('__PROCESS_TARGET__', 'gant.processArgs([ "-f", new File(buildScript).absolutePath, "-c", target ] as String[])')
+                         )
+    assertEquals(2, binding.output.size())
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/bugs/GANT_4_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/bugs/GANT_4_Test.groovy
new file mode 100644
index 0000000..50be278
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/bugs/GANT_4_Test.groovy
@@ -0,0 +1,90 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2008–2009, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests.bugs
+
+import org.codehaus.gant.tests.GantTestCase
+
+class GANT_4_Test extends GantTestCase {
+  final theScript = '''
+target(target1: 'This has no properties.') {
+	println "Target One"
+}
+target(target2: 'with command line properties') {
+	println "Target Two"
+	println "p1=${p1}"
+}
+target('default': 'The default target.') {
+	println "Default Target"
+}
+'''
+  void testDefaultTarget() {
+    script = theScript
+    assertEquals(0, processCmdLineTargets())
+    assertEquals(resultString('default', 'Default Target\n'), output)
+    assertEquals('', error)
+  }
+  void testTarget1() {
+    final targetName = 'target1'
+    script = theScript
+    assertEquals(0, processCmdLineTargets(targetName))
+    assertEquals(resultString(targetName, 'Target One\n'), output)
+    assertEquals('', error)
+  }
+  void testTarget2() {
+    final targetName = 'target2'
+    script = theScript
+    assertEquals(-11, processCmdLineTargets(targetName))
+    assertEquals("${targetName}:\nTarget Two\n", output)
+    assertEquals("Standard input, line 7 -- Error evaluating Gantfile: No such property: p1 for class: standard_input\n", error)
+  }
+  void testDefaultTargetCommandLine() {
+    script = theScript
+    assertEquals(0, gant.processArgs(['-f', '-'] as String[]))
+    assertEquals(resultString('default', 'Default Target\n'), output)
+    assertEquals('', error)
+  }
+  void testTarget1CommandLine() {
+    final targetName = 'target1'
+    script = theScript
+    assertEquals(0, gant.processArgs(['-f', '-', targetName] as String[]))
+    assertEquals(resultString(targetName, 'Target One\n'), output)
+    assertEquals('', error)
+  }
+  void testTarget2CommandLine() {
+    final targetName = 'target2'
+    script = theScript
+    assertEquals(-11, gant.processArgs(['-f', '-', targetName] as String[]))
+    assertEquals("${targetName}:\nTarget Two\n", output)
+    assertEquals("Standard input, line 7 -- Error evaluating Gantfile: No such property: p1 for class: standard_input\n", error)
+  }
+  void testTarget2CommandLineWithDefinitionNoSpace() {
+    final targetName = 'target2'
+    script = theScript
+    assertEquals(0, gant.processArgs(['-Dp1=MyVal', '-f', '-', targetName] as String[]))
+    assertEquals (resultString(targetName,  '''Target Two
+p1=MyVal
+'''), output)
+    assertEquals('', error)
+  }
+  void testTarget2CommandLineWithDefinitionWithSpace() {
+    final targetName = 'target2'
+    script = theScript
+    assertEquals(0, gant.processArgs(['-D', 'p1=MyVal', '-f', '-', targetName] as String[]))
+    assertEquals(resultString(targetName, '''Target Two
+p1=MyVal
+'''), output)
+    assertEquals('', error)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/bugs/Regression_1_9_4_Test.groovy b/src/test/groovy/org/codehaus/gant/tests/bugs/Regression_1_9_4_Test.groovy
new file mode 100644
index 0000000..b4c7696
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/bugs/Regression_1_9_4_Test.groovy
@@ -0,0 +1,80 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright © 2011, 2013  Russel Winder
+//
+//  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.codehaus.gant.tests.bugs
+
+import org.codehaus.gant.tests.GantTestCase
+
+/**
+ *  At some point during the 1.9.4 release cycle there was a regression of behaviour critical to Grails.
+ *
+ *  <p>Original idea for the test due to Jeff Brown.</p>
+ *
+ *  @author Russel Winder <russel at winder.org.uk>
+ */
+final class Regression_1_9_4_Test extends GantTestCase {
+  final theMessage = 'The Default Target Is Running...'
+  final expectedOutput = theMessage + '\n'
+  final expectedDecoratedOutput = "default:\n${expectedOutput}${exitMarker}default\n"
+  final groovyScript = """
+target(default: 'some default target') {
+    println('${theMessage}')
+}
+"""
+  final groovyProgramTemplate = """
+import gant.Gant
+doNothingClosure = { }
+gant = new Gant()
+gant.loadScript ('''
+${groovyScript}
+''')
+gant.prepareTargets()
+__ITEM__
+gant.executeTargets()
+"""
+  void testForExpectedBehaviourOfBaseProgram() {
+    final groovyShell = new GroovyShell()
+    groovyShell.evaluate(groovyProgramTemplate.replace('__ITEM__', ''))
+    assertEquals(expectedDecoratedOutput, output)
+  }
+  void testForPresenceOfTheRegression() {
+    final groovyProgram = groovyProgramTemplate.replace('__ITEM__', '''
+gant.setAllPerTargetPostHooks(doNothingClosure)
+gant.setAllPerTargetPreHooks(doNothingClosure)
+''')
+    final groovyShell = new GroovyShell()
+    groovyShell.evaluate(groovyProgram)
+    assertEquals(expectedOutput, output)
+  }
+  void testForCorrectBehaviourOfScript() {
+    script = groovyScript
+    assertEquals(0, processTargets())
+    assertEquals(expectedDecoratedOutput, output)
+  }
+
+  final switchOffHooks = """
+setAllPerTargetPreHooks({ })
+setAllPerTargetPostHooks({ })
+"""
+  void testForExpectedBehaviourOfPreAmendedScript() {
+    script = switchOffHooks + groovyScript
+    assertEquals(0, processTargets())
+    assertEquals(expectedDecoratedOutput, output)
+  }
+  void testForExpectedBehaviourOfPostAmendedScript() {
+    script = groovyScript + switchOffHooks
+    assertEquals(0, processTargets())
+    assertEquals(expectedOutput, output)
+  }
+}
diff --git a/src/test/groovy/org/codehaus/gant/tests/bugs/subPackage/GANT_29_SampleTool.groovy b/src/test/groovy/org/codehaus/gant/tests/bugs/subPackage/GANT_29_SampleTool.groovy
new file mode 100644
index 0000000..10b32a4
--- /dev/null
+++ b/src/test/groovy/org/codehaus/gant/tests/bugs/subPackage/GANT_29_SampleTool.groovy
@@ -0,0 +1,24 @@
+//  Gant -- A Groovy way of scripting Ant tasks.
+//
+//  Copyright  © 2013  Russel Winder
+//
+//  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.codehaus.gant.tests.bugs.subPackage
+
+import org.codehaus.gant.GantBinding
+
+class GANT_29_SampleTool {
+  private final Map<String,String> properties = [name: '']
+  GANT_29_SampleTool(GantBinding binding) { properties.binding = binding }
+  public getProperty(String name) { properties[name] }
+  public void setProperty(String name, value) { properties[name] = value }
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/gant.git



More information about the pkg-java-commits mailing list