Ant4Eclipse provides a set of Ant-tasks that you can use to access and process your Eclipse project settings from your Ant buildfiles. Using ant4eclipse you can write build scripts that are driven by the configuration you made for your projects in Eclipse without to duplicate your configuration (like a projects classpath, its output- and source folders) in Eclipse and in Ant.
The Ant4Eclipse task can be grouped into three categories:
if
-task, that is part of the antcontrib project.
In additions to the tasks mentioned above ant4eclipse comes with a set of macros that provide out-of-the-box-solutions for some common tasks (like compiling a whole java project or building a plug-in). The macros can be found in several xml-files inside the "macros" subfolder in the ant4eclipse distribution. (Note: of course the macros are using the ant4eclipse tasks so they are a good demonstration of their usage).
Ant4Eclipse directly works with your project configuration thus eliminating the need of re-configuration your setup in your build file. Your Eclipse project setting completely drives your build. But there are some configurations that are not part of your project, but part of the workspace or Eclipse preferences. The JREs you define in Eclipse for example are stored in the .metadata
directory in your workspace. If you make a clean checkout of your project (for example in a nightly build), these informations are not available (to ant4eclipse) and need to be re-configured in ant4eclipse. Anyway that is pretty straight forward and we’ll show you in the following sections how you do this.
An Executor is a special kind of an Ant task. Executors "executing" a project artifact (like a Team Project Set, a Project, or a Launch configuration). Executing means that the executors parses the artifact and calls several callbacks targets, passing in the information just parsed (like the name of a project, it's classpath, it's source- and output folder, the main class to launch etc). The potential call back targets are executor-specific and are implemented in your build file as a sub element to the executor task.
The usage of Executors has several advantages including:
scoped
, that is they are only valid while the Executor resp. one of its call back targets is executed. Ant4eclipse makes sure that you always see what's relevant for your target. You don't need to manage the properties etc. yourself.Let's have a look at an example. Imagine you want to iterate over all projects contained in a Team Project Set (psf) file, for example to build those projects In the first step you have to iterate over all projects of that file. For this task ant4eclipse provides the executeProjectSet-Executor. This executor calculates the correct dependency hierarchy of the projects (for example according to their classpathes) and invokes the forEachProject
subtask for each project in the psf-file. In each iteration ant4eclipse passes some properties and references to the subtask describing the current project (for example it's name). The following snippet echoes the name of all project names in their correct build order:
<ant4eclipse:executeProjectSet workspace="c:/myworkspace" teamprojectset="my-project.psf" projectReferenceTypes="jdt"> <ant4eclipse:forEachProject> <!-- Note that ${executeProjectSet.project.name} is passed in by ant4eclipse --> <echo>Project that should be build: ${executeProjectSet.project.name}</echo> </ant4eclipse:forEachProject> </ant4eclipse:executeProjectSet>
It is even possible to use Executors within other Executors. We could enhance the previous example with the executeJdtProject-Executor, that works on an JDT-project and provides among others information about the classpath, source- and output-folders of a project. Let's dump the classpathes of all Projects:
<ant4eclipse:executeProjectSet workspace="c:/myworkspace" teamprojectset="my-project.psf" projectReferenceTypes="jdt"> <ant4eclipse:forEachProject> <!-- Note that ${executeProjectSet.project.name} is passed in by ant4eclipse --> <echo>Project that should be build: ${executeProjectSet.project.name}</echo> <ant4eclipse:executeJdtProject workspace="c:/myworkspace" projectName="${executeProjectSet.project.name}" <ant4eclipse:forProject> <echo>Classpath of project: ${executeJdtProject.classpath.absolute.compiletime}</echo> </ant4eclipse:forProject> </ant4eclipse:executeJdtProject> </ant4eclipse:forEachProject> </ant4eclipse:executeProjectSet>
Note that the allowed sub-tasks of an Executor can be used in any order and they are allowed to implement them as often as you need them. You could for example use the forEachOutputDirectory
sub-task of the executeJdtProject
-Executor at the beginning to clean the output directory before compiling. Then you use the forProject
sub-task to compile your project. In the last step you could again use forEachOutputDirectory
to instrument classes you just compiled:
<ant4eclipse:executeJdtProject workspace="c:/myworkspace" projectName="${executeProjectSet.project.name}"> <!-- 1. step: clean up all output directories --> <ant4eclipse:forEachOutputDirectory> ... </ant4eclipse:forEachOutputDirectory> <!-- 2. step: build the whole project --> <ant4eclipse:forProject> ... </ant4eclipse:forProject> <!-- 3. step: instrument the compiled classes --> <ant4eclipse:forEachOutputDirectory> ... </ant4eclipse:forEachOutputDirectory> </ant4eclipse:executeJdtProject>
Note: more real-world examples of Executors can be found in our ant4eclipse build-file.
We just have seen that some Executors iterate over a set of items, for example a list of projects or a list of output folders etc. Sometimes it's desired to filter such a list according to some criterias.
if
and unless
The easiest way to filter is to use the if
or unless
attributes on the sub-tasks of an executor. You can pass in a variable that expands to true
or false
. If the variable evaluates to true
the sub-tasks gets executed (if using the if
attribute) or is skipped (if using the unless
attribute) and vice versa. This is quite common to the if
and unless
attribute that some built-in ant tasks provides. In the following example the second forEachOutputDirectory
only gets invoked if the variable instrumentProjectClasses
is set to true
:
<ant4eclipse:executeJdtProject workspace="c:/myworkspace" projectName="${executeProjectSet.project.name}"> <!-- 1. step: clean up all output directories --> <ant4eclipse:forEachOutputDirectory> ... </ant4eclipse:forEachOutputDirectory> <!-- 2. step: build the whole project --> <ant4eclipse:forProject> ... </ant4eclipse:forProject> <!-- 3. step: instrument the compiled classes (only when 'instrumentProjectClasses' is set to 'true' --> <ant4eclipse:forEachOutputDirectory if="${instrumentProjectClasses}"> ... </ant4eclipse:forEachOutputDirectory> </ant4eclipse:executeJdtProject>
filter
While this approach allows you some simple filtering in some circumstances it's not enough. In the example above instrumentProjectClasses
is a regular static Ant variable. It's value doesn't change from one invocation of forEachOutputDirectory
to another. But what if you want to instrument the classes in the output directory depending on the name of the current (for example if you want to instrument only those directories whose name don't end with .test
)? For such cases ant4eclipse providers another, more powerful and flexible option: filters. All sub-tasks provide a filter
element that can be used to specify an LDAP-like query expression. Within this query you can access all scoped properties that are provided by the sub-task and it's parent Executor and compare them with your desired values.
Let's consider the example mentioned above, where you want to only instrument directories whose names not ending with .test
. In this case you could use the following filter:
<ant4eclipse:executeJdtProject workspace="c:/myworkspace" projectName="${executeProjectSet.project.name}"> <!-- 1. step: clean up all output directories --> <ant4eclipse:forEachOutputDirectory> ... </ant4eclipse:forEachOutputDirectory> <!-- 2. step: build the whole project --> <ant4eclipse:forProject> ... </ant4eclipse:forProject> <!-- 3. step: instrument the compiled classes (only when directory name doesn't end with '.test' --> <ant4eclipse:forEachOutputDirectory filter="(!(output.directory=*.text))"> ... </ant4eclipse:forEachOutputDirectory> </ant4eclipse:executeJdtProject>
Filter syntax
Filter expressions are based on the RCF 1960 "A String Representation of LDAP Search Filters". A filter is built of one ore more Criterias where each criteria defines a request to an attribute, that must be the name of a scoped property from the enclosing executor or it's sub-task, where you specify the filter. The specified value can contain an asterisk (*) to specify a wildcard that matches any set of characters. The following criterias are possible:
Several criterias can be combined using Operators. An operator is written before the criteria. Both, the operator and the criteria are surrounded by parenthesis. Ant4Eclipse supports the following operators:
(& (criteria-1)(criteria-2))
. It's even possible to specifiy more than two criterias: (& (criteria-1)(criteria-2)(criteria-n))
(| (criteria-1) (criteria-2)
. It's even possible to specifiy more than two criterias: (| (criteria1)(criteria2)(criteria-n)
(! (criteria-1)
Example
A filter that checks whether the scoped property project.name
starts with "org." or "net." would look like this:
(|(project.name=org.*)(project.name=net.*))
Since Eclipse is a platform that is not only used for developing Java applications but that works as a basis for development environments for several languages (for example C/C++, Python, PHP) and use cases (for example Web Development, Plug-in Development, Database development) it has an extensible concept of projects. There is not the one project type that is identical for all purposes. The most simple project type is the General Project that is defined in Eclipse' platform layer and that is more or less a "container" for files. A General Project doesn't know anything about programing languages, compilers etc. It just have a name and a location and it can be managed by the version control system features Eclipse provides (CVS, Subversion etc).
To support more than the General Project type, projects can get several natures assigned. A nature is a unique identifier (typically provided by a Plug-in) that is stored in the project's .project
file. Plug-ins (and Features) installed in Eclipse (for example the Java Tooling or the Plug-in dev. env) can access the natures of a project and can deceide if they need to participate in someway in that project. Some Plug-ins need more configuration options (like a classpath) that cannot be stored inside the .project
. Such Plug-ins typically work in addition with proprietary config files that are stored in the project (often as hidden files or directories starting with a .
). An example is the .classpath
file that specifies the Java classpath of a JDT/Java project. Of course it's possible that projects have more than one nature assigned. A Plug-in project from the Plug-in development environment (PDE) for example contains among the javanature
it's own org.eclipse.pde.PluginNature
.
Ant4Eclipse' tasks are grouped in layers that are related to a specific feature (as they are in Eclipse).