Check if executable command exists using ant - ant

Is it possible to check if a command exists as part of an ant task. For example, I want to ensure the "yasm" command is present as part of the ant task. Is this possible? If so, can you provide an example?

The following idiom can be used to find an executable somewhere in the environment's PATH.
<property environment="env" />
<available file="commandname"
filepath="${env.PATH}"
property="commandname.present"/>

The best way I can think of to do this is by using the available task combined with an if in a subsequent target. If you take a look at that task page you will see that you can check to see if something exists then set a property. For example:
<available file="/path/to/my/file" type="file" property="file.present"/>
Then in the target you would say something like <target name='foo' if='file.present'>
That doesn't check for executable permissions but it will get much closer. If a task exists to check for the executable permission specifically you would still probably combine it with the if in the target.
Original answer
It is better to use the ant copy task instead of trying to execute cp yourself. This keeps its platform independent.
<copy todir"/some/target">
<fileset dir="/some/src"/>
</copy>
More usage on the Ant documentation for the copy task.

Related

ANT- How to recursively build the iOS project for different environments?

I am using ANT script to automate my iOS build and packaging tasks. As per my current build script, I am passing the desired environment from command line and the script will generate a IPA file for that particular environment.
Basically, it will run the following targets- ValidateParameters, SetupBuildProperties, SetupXcodeSettings, clean, archive & package.
I have to create builds for Dev, QA & UAT. So, I have to run the script 3 times to have 3 different IPA files. When I pass the environment from command line, I store the same in a ANT property and that will be used in almost all the targets. Because, a property is immutable, that doesn't help me either.
Now, is there any way I can generate all the 3 builds by running the script only once? Not sure how to reset the environment property !!
Please help me.
One solution is to create a target called something like "buildForAllEnvs" where you invoke a subproject build using antcall for each target environment and passing its property as a nested element:
<target name="buildForAllEnvs">
<antcall target="runBuild">
<param name="targetEnv" value="Dev"/>
</antcall>
<antcall target="runBuild">
<param name="targetEnv" value="QA"/>
</antcall>
<antcall target="runBuild">
<param name="targetEnv" value="UAT"/>
</antcall>
</target>
Note that there are many ways to override or reset properties in Ant. See How to over-write the property in Ant?:
Using Ant-Contrib's var task (requires adding Ant-Contrib to your classpath, which also introduces a bunch of useful tasks for conditional execution using if and looping using for).
Using macrodefs to reuse the same build with different parameters.
Manually overriding the property using the project API (hacky though).

how to create dynamic path/fileset elements or other random XML nodes in a build.xml file

I have a project with a number of compile-time dependencies on other projects (of the same code-base).
So the compile classpath is defined somewhat like the following:
<path id = "compile.classpath">
<fileset dir="${dependency-a.dist.dir}">
<include name ="*.jar"/>
</fileset>
<fileset dir="${dependency-b.dist.dir}">
<include name ="*.jar"/>
</fileset>
<fileset dir="${dependency-c.dist.dir}">
<include name ="*.jar"/>
</fileset>
<fileset dir="${dependency-d.dist.dir}">
<include name ="*.jar"/>
</fileset>
</path>
Also, you can image the corresponding build targets for the dependencies and so on.
To reduce repetition I need to somehow generate those structures dynamically.
I thought that one Ant-friendly way to capture those dependencies might be to create a deps directory and add sym-links to all the compile-time dependencies of my project.
So the question is: is there an Ant way to write a macrodef or a custom Ant task that would scan that directory (or, alternatively, read a configuration file) and expand into/generate the necessary filesets / build targets automatically, in effect changing the XML nodes of the build.xml file at runtime? I am looking for a generic Ant way to do that (if such exist) so I don't have to use the more disruptive way of generating myself the build.xml file in its entirety from some other configuration. I am not asking how to use subant etc. as I am wondering whether there might exist a more sweeping capability of extending/enriching the Ant build file at runtime that would also apply to other cases not involving building dependencies.
Writing a task that builds the paths would be pretty easy, but Ant targets are fixed once the build file has been parsed. Ant builds a directed graph of the targets and then executes them.
It is possible to add new targets via a task that is outside of any target itself. include is such a task. It might be possible to generate a build file snippet containing the paths and targets you need via a custom task later include it. Unfortunately include won't allow you to embed it in a macrodef so the two steps had to appear in pairs.
Of course you can use Ant's API rather than include in order to add the paths and targets. You'd get hold of an existing Path using getReference on the Project instance you've received and add you filesets to it. Completely new data types use addReference, addTarget is for targets.
Have you considered using ivy? It's a dependency manager that provides a set of ANT tasks that can be used control classpaths but it can also download jars from managed repositories (like Maven).
The following answers can give your a flavour of how ivy is used:
sample example which explain how to use filesystem resolver
How to avoid copying dependencies with Ivy
Ivy provides a more powerful solution because it also prevents conflicting versions of the same jar. For example where several dependencies all contain a copy of a common jar like log4j.
In conclusion ivy may appear complex at first glance, but I can assure you that it's solving a complex problem.

In ant, how to apply a target on a list of files (without ant-contrib)?

Basically, I would like to mimic apply task but instead of passing to it anexecutable, I would like to pass an ant task and come up with something like:
<project>
<target name="my-task">
<!--target definition-->
<target/>
<target name="my-task-on-files">
<apply task="my-task">
<srcfile/>
<targetfile/>
<fileset dir="." includes="*.xml"/>
</apply>
</target>
</project>
The problem is that apply has to task attribute but only executable.
I need a solution that doesn't require ant-contrib.
No native solution in ANT. This is the sort of problem ant-contrib was invented to solve :-(
Basically, ANT was designed to be extended by writing custom tasks to solve non-standard build problems....
Personally, I think once your build needs complex logic, it's time to embed a full blown programming language. My tool of choice is groovy, due to it's tight integration with ANT. Furthermore, I use ivy to manage my build's 3rd party dependencies, so automatically adding groovy to the classpath is no hardship.

What are some good ways to distribute a common ant file to be included in builds?

I work in a group where we produce many small apps, and use ANT for our build processes.
We would like to have some of our commonly used directives housed in a common way. Currently, we require a mapped drive to a common location, and use
<import file="${env.MAPPED_DRIVE}/common_directive.xml">
There must be a better way to distribute a common ant file to include in many projects without having to map a drive. Do you have any other suggestions?
Import is a "top level" directive, which means it won't work inside of a target. Therefore, I cannot simply create a target that downloads the file, and then import it.
If you are using ANT 1.8+, you could specify a URL and host the common build fragment on a website.
Since Ant 1.8.0 the task can also
import resources from URLs or
classpath resources (which are URLs,
really). If you need to know whether
the current build file's source has
been a file or an URL you can consult
the property ant.file.type.projectname
(using the same example as above
ant.file.type.builddocs) which either
have the value "file" or "url".
I've worked out a solution that creates a jar file containing our reusable build scripts in a directory, say com/example/ant/sharedbuild, which can be imported in Ant 1.8:
<project>
<import>
<javaresource name="com/example/ant/sharedbuild/java.xml">
<classpath location="../../../../target/ant-shared-build.jar" />
</javaresource>
</import>
</project>
In my case this defines all of the "public" targets for the project to do a java-based build.
The syntax is a little verbose, especially as I add more and more include files (say, to add the ability to create an OSGi jar). By adding an antlib.xml that contains a combination of a macrodef and scriptdef to the jar file (in the same directory as the shared build scripts), the build file can now look like this (and now also creating an OSGi jar bundle):
<project xmlns:build="antlib:com.example.ant.sharedbuild">
<taskdef uri="antlib:com.example.ant.sharedbuild"
classpath="../../../../target/ant-shared-build.jar" />
<build:build using="java, jar, bundle" />
</project>
Unfortunately, I can't share the code in the macrodef or scriptdef, but really it isn't hard: a little javascript to parse the using attribute and loop over each, derive a file name from it, and import.
I reference the jar file in a fixed location (relative to my project) on my hard drive. I think we can do better. Ideally, I'd like to fetch a (versioned!) jar file from a central location. Since we're already using Ivy (with an HTTP repository) we can publish the jar file there (again, with a version) and fetch it directly from there:
<project xmlns:build="antlib:com.example.ant.sharedbuild">
<property name="ant.shared.build.jar.file"
location="${user.home}/ant/ant-shared-build-1.5.3.jar" />
<get src="http://repo.example.com/.../ant-shared-build-1.5.3.jar"
dest="${ant.shared.build.jar.file}"
skipexisting="true" />
<taskdef uri="antlib:com.example.ant.sharedbuild"
classpath="${ant.shared.build.jar.file}" />
<build:build using="java, jar, bundle" />
</project>
There are some problems with this:
It's getting verbose again.
The verbosity is repeated for every build.xml.
There's a lot of repeated boilerplate, especially the version number.
To mitigate these problems, in each directory containing a build.xml I also have a bootstrap.xml (the name doesn't really matter). Each build.xml then includes this file:
<project xmlns:build="antlib:com.example.ant.sharedbuild">
<include file="bootstrap.xml" />
<build:build using="java, jar, bundle" />
</project>
Each bootstrap.xml, at a minimum, includes it's parent's bootstrap.xml:
<project>
<include file="../bootstrap.xml" />
</project>
The top-level bootstrap.xml (the root), then does the work of getting the jar file and creating the custom tasks, as above:
<project>
<property name="ant.shared.build.version"
value="1.5.3" />
<property name="ant.shared.build.jar.filename"
value="ant-shared-build-${ant.shared.build.version}.jar" />
<property name="ant.shared.build.jar.file"
location="${user.home}/ant/${ant.shared.build.jar.filename}" />
<get src="http://repo.example.com/.../${ant.shared.build.jar.filename}"
dest="${ant.shared.build.jar.file}"
skipexisting="true" />
<taskdef uri="antlib:com.example.ant.sharedbuild"
classpath="${ant.shared.build.jar.file}" />
</project>
Though not directly related to the question, I'm actually reworking the macrodef and scriptdef into a custom ant task, because I want to be able to support a syntax that looks like this:
<project xmlns:build="antlib:com.example.ant.sharedbuild">
<include file="bootstrap.xml" />
<build:build>
<using>
<java />
<bundle>
<manifest>
Import-Package: *,org.joda.time;version="[1.6.0,1.6.0]"
Bundle-Activator: com.example.time.impl.Activator
</manifest>
</bundle>
</using>
</build:build>
</project>
I should point out that just creating a redistributable build doesn't mean it's going to be useful. You still need to put in the time and effort to create a cohesive, modular, consistent implementation in line with a design of similar characteristics. This is more important as you need to share scripts across projects, across teams, across organizational boundaries, etc.
In conclusion, by creating a jar file, with a version number, that can be distributed independent of a specific file location or an SCM tool we can get real shared but reproducible builds.
Dominic Mitchell's comment about the URL reference being a bad idea if you want repeatable builds got me thinking...
Another solution to consider, if you are using SVN for version control, is to create an SVN Externals Definition that points to the common_directive.xml.
Then, just use a relative path for your ANT import file reference.
Sometimes it is useful to construct a
working copy that is made out of a
number of different checkouts. For
example, you may want different
subdirectories to come from different
locations in a repository or perhaps
from different repositories
altogether. You could certainly set up
such a scenario by hand—using svn
checkout to create the sort of nested
working copy structure you are trying
to achieve. But if this layout is
important for everyone who uses your
repository, every other user will need
to perform the same checkout
operations that you did.
Fortunately, Subversion provides
support for externals definitions. An
externals definition is a mapping of a
local directory to the URL—and ideally
a particular revision—of a versioned
directory. In Subversion, you declare
externals definitions in groups using
the svn:externals property. You can
create or modify this property using
svn propset or svn propedit (see the
section called “Manipulating
Properties”). It can be set on any
versioned directory, and its value
describes both the external repository
location and the client-side directory
to which that location should be
checked out.
The convenience of the svn:externals
property is that once it is set on a
versioned directory, everyone who
checks out a working copy with that
directory also gets the benefit of the
externals definition. In other words,
once one person has made the effort to
define the nested working copy
structure, no one else has to
bother—Subversion will, after checking
out the original working copy,
automatically also check out the
external working copies.

What are good Ant target naming conventions?

I'm about to create some complex Ant build files and I wanted find out what people think are best practices for naming ant tasks. It is going to build some Java, C++, compresses JavaScript, generate docs and lots more.
What tasks do you always add to an any script? Things like clean, build?
How to you name targets that make up a single target through dependencies (or don't you do this)? E.g. build.proj1 and build.proj2
Any other naming conventions do you follow?
Another common practice is a kind of 'private' target. Simply put a leading '-' before
the target name, i.e. <target name="-yourprivatetarget" ... />.
Thus it's impossible to call that target via command line, as :
ant -f yourbuild.xml -yourprivatetarget won't work whereas
<target name="yourprivatetarget" ... /> and ant -f yourbuild.xml yourprivatetarget would.
Also a target without a description attribute won't be listed when using
ant -projecthelp (or ant -p).
So you have some kind of private / internal targets, but beware, some tools, i.e. Eclipse
or similar will expose all targets in the Outline view of it's ant editor.
Finally => there's no real private/internal target in ant, but it's helpful sometimes
This link explains the typical targets you should have in your project.
Using standard targets helps with new team members (and any experienced Ant hands) quickly getting to grips with the build process.
From personal experience, I'd say clean, build, deploy/install, test (test for running your junits, findbugs etc)
For the dependent targets, we use a convention like below
<target name="build" depends="clean,compile">
<target name="compile" depends="compile.src, compile.test">

Resources