Wednesday, January 29, 2014

Making Ant Scripts Smarter Using Macrodef

General:


Have you struggled using Ant? Have you experienced the frustration of getting scripts to work exactly the way you want?  I have been dealing with the Ant-isms that seem to make the process of creating a build difficult to accomplish for some time now.  I have added the Apache.org ant-contrib jar file to add some intelligence but it can fall short.  Sometimes it even causes the build to run longer because of a need to create objects to handle some of the tasks that I need done.   Not wanting to create my own "addon" classes to address my issues due to current time constraints I reached the point where I felt my only solution was to write copious lines of redundant targets to address multiple tasks.  Then I found the macrodef task and my Ant scripts have now picked up considerably in the smart department.

As fair warning this blog topic is not to replace the Ant documents already in place which document the macrodef task.  My intention is only to give some basics to people needing some intelligent Ant scripts.  By introducing them to the macrodef task through a few simple examples, they may have confidence to tackle the official documentation to get more details on all the sub tasks, properties and nuances of this very useful Ant task.   To this end, only required properties and sub-tasks will be listed where a task is described.

The Basics:


A macrodef should be a child of the project task in the ant script. If enclosed inside a target task, it can only be used within that target task.

Here is the most basic example so we can start discussing some of the elements:
<macrodef name="mymacro">
    <sequence>
    </sequence>
</macrodef>
The main XML element for this is <macrodef>.  This task has only one required property: "name".   This will be the name by which you will call the macro in future targets.  We will see this more in a bit.

The macro, "mymacro" does nothing.  So, lets improve on it a bit.  Consider the following:
<macrodef name="sayhello">
    <sequential>
        <echo>Hello World! I am "sayhello" macrodef!</echo>
    </sequential>
</macrodef>
Now, to run the macro, you only need to put the following as a child of project task or in a target.:
<sayhello />
which produces:
    [echo] Hello World! I am "sayhello" macrodef!
If entered as a child of the project task, it will run every time the ant XML file is run whereas if it is in a target, it will only run when that target is run.

The macrodef task requires a nested sequential task. Any ant task can be put inside the sequential task. This is the unit of work the macrodef task will perform.

At this point, the macro still is not very useful. It would seem a waste to write all the macrodef when you could have just enclosed the echo task directly inside a target task.

So, we introduce the attribute task.  Attribute tasks are the parameters passed to the macro from the calling function with no nested tasks.  The name of each attribute is the name of the corresponding property you pass in the call.  An example will explain better:
<macrodef name="sayhello">
    <attribute name="addressee" />
    <sequential>
        <echo>Hello World! I am "sayhello" macrodef!</echo>
    </sequential>
</macrodef>
So the call to implement the macro would look like:
<sayhello addressee="Bob"/>
This has now passed the parameter addressee with a value of "Bob" to the macro.  We still have a problem because the macro does not do anything with the parameter.  Again, lets go back to the macrodef task and connect the attribute.
<macrodef name="sayhello">
    <attribute name="addressee" default="World"/>
    <sequential>
        <echo>Hello @{addressee}! I am "sayhello" macrodef!</echo>
    </sequential>
</macrodef>
As you can see there are two changes.  First, I added an optional parameter "default" to the attribute task and set the value to "World".  This is because we do not want the line to print to the console as:
    [echo] Hello @{addressee}! I am "sayhello" macrodef!
If not defined, the attribute, as does an undefined property, will not expand in the Ant processor.

Secondly, note the use of the "@{someattribute}".  It is used to expand an attribute just as ${someproperty} is used to expand a property in Ant.

Now, lets finally run the call again.  First using:
<sayhello />
We see the output still is the same as the original macro:
    [echo] Hello World! I am "sayhello" macrodef!
If we call it with the parameter "addressee", we see the glory of parameters because this:
<sayhello addressee="Bob"/>
will now display this:
    [echo] Hello Bob! I am "sayhello" macrodef!

No comments :

Post a Comment

All comments are moderated. NO ADS. NO SPAM.