[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