Using if:set, unless:set etc. with macrodefs in Ant

In a previous post I outlined how to use if:set and unless:set to execute tasks conditionally in Ant 1.9.1.

Unfortunately, this does not work with macrodefs. When I try to execute a macrodef conditionally like this:

<project
    xmlns:if="ant:if"
    xmlns:unless="ant:unless"
    default="build"
>

    <macrodef name="mymacro">
        <sequential>
            <echo message="inside mymacro"/>
        </sequential>
    </macrodef>

    <target name="build">
        <mymacro if:set="doit"/>
    </target>

</project>

When I set the “doit” property and run like this, it fails:

$ ant -Ddoit=true
Buildfile: build.xml

build:

BUILD FAILED
build.xml:14: Unknown attribute [ant:if:if:set]

Total time: 0 seconds

It looks to me like this is a bug: the if:set attribute is getting passed into the macro, which is complaining that it doesn’t expect an attribute with that name. (If you try to create an attribute with that name, you’ll find that “if:set” is an illegal name…)

However, there is a workaround. You can wrap the call to your macrodef in a <sequential> tag:

<project
    xmlns:if="ant:if"
    xmlns:unless="ant:unless"
    default="build"
>

    <macrodef name="mymacro">
        <sequential>
            <echo message="inside mymacro"/>
        </sequential>
    </macrodef>

    <target name="build">
        <sequential if:set="doit">
            <mymacro/>
        </sequential>
    </target>

</project>

And now it works!

$ ant -Ddoit=true
Buildfile: build.xml

build:
     [echo] inside mymacro

BUILD SUCCESSFUL
Total time: 0 seconds
$ ant
Buildfile: build.xml

build:

BUILD SUCCESSFUL
Total time: 0 seconds

Conditional execution even when calling a macrodef. Enjoy.

Using if:set, unless:set etc. to execute a task conditionally in Ant

I’m not sure anyone except me is still struggling on with using Ant, but just in case, here is a nice thing.

In Ant 1.9.1 they added a useful feature: instead of needing to use the <if> tag and similar from ant-contrib, you can conditionally execute “any” task.

(In fact, this appears to mean “any task except a macrodef” – see my post Using if:set, unless:set etc. with macrodefs in Ant.)

You need to add these namespaces at the top of your project:

<project
     xmlns:if="ant:if"
     xmlns:unless="ant:unless"
>

and then make any task conditional by adding one of these attributes:

if:set
if:true
if:blank
unless:set
unless:true
unless:blank

if:set and unless:set take a property name and run the task if it is set at all (or unless it is set at all).

<mytask if:set="property.name" other_attrs="" .../>

Where mytask is the name of any ordinary Ant task like echo, jar etc.

(Note there is no ${} around the property name for if:set.)

if:true and unless:true take a value and run the task if it is true (or unless it is true), so they need to be used like this:

<mytask if:true="${property}" other_attrs="" .../>

(Note the ${} here, but not above.)

Similarly, if:blank and unless:blank take a value and run the task if it is blank (or unless it is blank), e.g.:

<mytask if:blank="${property}" other_attrs="" .../>

NOTE: The example in the documentation is wrong (at this time, 2013-09-13) – it uses the property name, but this does not work – you must surround it with ${} to get its value.

The properties can be specified in your build file as normal, or supplied on the command line to ant with -Dproperty.name=value.

Here’s an example of using set:

build.xml:

<project
    xmlns:if="ant:if"
    xmlns:unless="ant:unless"
    default="build"
>

    <property name="setinxml" value="true"/>

    <target name="build">
        <echo if:set="setinxml"     message="if:set=setinxml"/>
        <echo unless:set="setinxml" message="unless:set=setinxml"/>
        <echo if:set="notset"       message="if:set=notset"/>
        <echo unless:set="notset"   message="unless:set=notset"/>
        <echo if:set="setincmd"     message="if:set=setincmd"/>
        <echo unless:set="setincmd" message="unless:set=setincmd"/>
    </target>

</project>

And here’s the output:

$ ant -version
Apache Ant(TM) version 1.9.2 compiled on July 8 2013
$ ant -Dsetincmd=true
Buildfile: build.xml

build:
     [echo] if:set=setinxml
     [echo] unless:set=notset
     [echo] if:set=setincmd

BUILD SUCCESSFUL
Total time: 0 seconds

The documentation for this, such as it is, is here: If And Unless.

Working with others in git

Series: Why git?, Basics, Branches, Merging, Remotes

Now I’ve covered almost everything you need to understand the basics of how git works. In this video I discuss how to clone, pull from and fork remote git repositories, and how to send patches and make pull requests to a project maintainer.

Slides: Working with others in git.

Merging in git

Series: Why git?, Basics, Branches, Merging, Remotes

The last video covered how to make branches and simple merges.

This time we look at what to do when you want just one change from another branch (cherry-picking) and how to merge two branches when there are conflicts between them. We also look at rebasing, which is a different way to combine the work done on two branches, which hides complexity from other people at the expense of changing history.

Slides: Merging in git.