Posted tagged ‘Ant’

Ant Article online

24. März 2010

After a long time of not-writing I have finished my (German) article about Ant 1.8.0. It is now published on JaxCenter: Der ANTwickler – Das neue Majorrelease

Advertisements

Ant: Use optional dependencies in JavaDoc

19. November 2009

If you create your Javadocs you sometimes get unresolved reference warnings: package xy does not exist or cannot find symbol

If you define the path with these dependencies outside of the target you could reference that path using the classpathref attribute.

But if the path definition is done in an other target and you don’t want to have a dependency on that (e.g. many dependencies are downloaded there, e.g. using Ivy), using the classpathref would throw a BuildException because the path is not defined: Reference my-path.reference not found.

You could do a little hack: use a classpath attribute and use a special PropertyEvaluator for using that path: classpathref=“${toString:my-path.reference}“. If your defining target is executed before, the toString: resolves that into a usable path-string. If the target is not executed before, the resulting string toString:my-path.reference is just ignored by the javadoc task.

Let Ant tasks choose the attribute values by themself

30. Oktober 2009

For a long time an idea travelled in my head. But now it arrived.

In my several Ant build files I have constructs like

<javac source=”${javac.source}” debug=”${javac.debug}” target=”${javac.target}” …

and the according properties defined in an external file. Now have a compile run for the source code and the test code and you have doubled this amount of configuration. And I thought that just writing a <javac> and starting with an -autoconf option would be easier.

The idea is: apply the properties directly before the task execution.

So I could implement a method call in oata.Task.perform() direclty before calling the execute() method.
Hhm …. I don’t want to change the Ant core that deeply because so many external tasks exist and I don’t want to (maybe) break their build.

Another idea is using an AOP framework like AspectJ for jumping in: before <? extends Task>.execute() : applyAttributeValues()
(I am not familiar with AspectJ but you get the idea.)
But then I would depend on the AOP library. That’s nothing for the Core. And Ant options should not depend on any further libraries.
I could implement it as a task:

  <project><autoconf/><javac/></project>    

Better. But I have to learn AspectJ … so not for now…

On the Hudson dev-mailinglist I heard from the Hudson Clover Plugin. It gatheres code coverage from Ant jobs WITHOUT configuring the job itself.-It adds a BuildListener which stores the srcdir and destdir values from <javac> tasks.
Nice idea …. use the Listeners taskStarted(event) and taskFinished(event) methods for doing AOP-stuff.

This results in the <autoconf> task, currently in the sandbox and feedback is welcome.

The goal:

  • apply attribute values from properties
  • do not overwrite user specified values
  • switch on/off the behaviour
  • support name prefix for using different values for different targets

While the last two points are easily to implement (add/remove the listener, use a prefix for property search) the first two are difficult.

apply attribute values from properties / which attributes are supported by a given task?

Why is this difficult? Just ask mytask.getClass() for declared setters ….

The problem is that you don’t get the task object. Due lazy instantiation/configuration the only thing you get from the BuildEvent is an UnknownElement. And therefore you cannot just ask getClass() for the class object you need.

I saw three different strategies according to that value:

  • if it is a <macrodef> I could ask it directly for its <attribute>s
  • if it is a normal task I ask the class object
  • if it is a <presetdef> I ask the class object from preset.getTypeClass()

do not overwrite user specified values

I could ask an object for its values, but which are set by the user and which are just implementation defaults? From the Java perspective you cannot distinguish between them…

My strategy is using a “clean” object (I called it template object) and compare its values with the values from the given object.

I found an overview article …

28. Dezember 2008

On JavaWorld John Ferguson Smart wrote a nice article about some of the most interesting Java evolutions in 2008. He discovers tools for Build automatisation (Hudson, Bamboo, Maven, Ant, Grant, Gradle, Subversion), Testing tools (JBehave, easyb, Selenium, WebTest) and IDEs (Eclipse, NetBeans). Conclusion: a very nice read.

Ant + JavaFront: start Ant tasks from the command line (2)

11. November 2008

In my last blog I wrote about a new AntLib in Ants sandbox: javafront with which you have the ability to start tasks directly from the command line – without any buildfile. With that I was able to do the pom2ivy conversion Torsten Curdt asked for:

task.bat -lib path-to-ivy.jar -xmlns:jar antlib:org.apache.ivy.ant ivy:convertpom pomFile my.pom ivyFile ivy.xml

Ant + JavaFront: start Ant tasks from the command line

7. November 2008

Reading the blog Converting maven pom to ivy I asked myself, why it should not be possible to start Ant tasks from the command line.

Stefan on the other side was bored always to here that Ant relies on XML and he presented a way for writing Buildfiles in plain (annotated) Java using JavaFront, a library in Ants sandbox.

Ant provides a way to override the class to start by providing an implementation of AntStart and specifying that class by -main option. So I wrote a new start class which parses the command line parameters and executes that task. The first parameter is the taskname and following parameters are attributes with their values. (There is no support for nested elements yet.)

public class TaskExec implements AntMain {

public void startAnt(String[] args, Properties additionalUserProperties, ClassLoader coreLoader) {
Map attributes = new Hashtable();

// Analyzing the command line arguments
String taskname = args[0];
for(int i=1; iant -lib build\classes -main org.apache.ant.javafront.TaskExec echo message „Hello World“

Other examples are in the launcher script.

Ant: catching all marked lines in text files for creating a changes document

17. Oktober 2008

MartianSoftware has released (a long time ago) two Ant task: <snip> and <rundoc>. While I am not sure about the benefits of <rundoc> (as I dont know docbook really well) <snip> seems to be a nice task. Extracting parts of a file with Ant on board utilities is not that easy.

Using the snip task extracting is a few-liner. Just think we have a class

/**
 * This is normal JavaDoc comment.
 * @@snip:changes@@
 * This is a comment which should be in the changes.txt!
 * @@endSnip@@
 * @author Jan Materne
 */
public class MyProgram {
}

Ant I want to generate the document containing this line
This is a comment which should be in the changes.txt!

<project>
<property name="build.dir" value="build"/>

    <target name="clean">
        <delete dir="${build.dir}"/>
    </target>

    <target name="snip">
        <!-- Getting snip task -->
        <mkdir dir="${build.dir}"/>
        <get src="http://www.martiansoftware.com/lab/snip/snip-0.11.jar" dest="${build.dir}/snip.jar"/>
        <taskdef name="snip" classname="com.martiansoftware.snip.Snip" classpath="${build.dir}/snip.jar"/>
        <!-- Collecting the information -->
        <snip>
            <fileset dir="src" includes="**/*.java" />
        </snip>
        <!-- Use these informaion -->
        <echo file="${build.dir}/changes.txt">
        Changes
        -----------------------------------------------------------------
        ${snip.changes}
        </echo>
        <!-- For easier test: output the file -->
        <concat><fileset file="${build.dir}/changes.txt"/></concat>
    </target>

</project>

I can see, that the information is gathered:

..>ant snip
Buildfile: build.xml
snip:
      [get] Getting: http://www.martiansoftware.com/lab/snip/snip-0.11.jar
      [get] To: ...\build\snip.jar
   [concat]
   [concat]         Changes
   [concat]         -----------------------------------------------------------------
   [concat]
   [concat]  * This is a comment which should be in the changes.txt!
   [concat]

BUILD SUCCESSFUL

Fine, let’s try having more information with a second class:

/**
 * This is normal JavaDoc comment.
 * @@snip:changes@@
 * This is another comment which should be in the changes.txt!
 * @@endSnip@@
 *
 * @author Jan Materne
 *
 * @@snip:changes@@
 * Maybe another line in the comments.
 * @@endSnip@@
 */
public class Class2 {
}

And I want to get:

...>ant snip
Buildfile: build.xml

snip:
[get] Getting: http://www.martiansoftware.com/lab/snip/snip-0.11.jar
[get] To: ...\build\snip.jar
[concat]
[concat]         Changes
[concat]         -----------------------------------------------------------------
[concat]
[concat]  * This is a comment which should be in the changes.txt!
[concat]  * This is another comment which should be in the changes.txt!
[concat]  * Maybe another line in the comments.
[concat]

BUILD SUCCESSFUL

But the result doesnt change. Thats because <snip> sets properties directly when getting the @@endSnip@@ mark. And – as Ant properties are immutable – once set a property cant be extended.

It would be better to extend <snip> for first collecting all values and then storing the values into Ant properties.

I thought I could start collecting these lines with Ant built-in facilities could be done like

    <target name="ant" depends="clean">
        <mkdir dir="${build.dir}"/>
        <!-- Collecting and using the information -->
        <concat destfile="${build.dir}/changes.txt">
            <header>
                Changes
                -----------------------------------------------------------------
            </header>
            <fileset dir="src" includes="**/*.java" />
            <filterchain>
                <!-- Something special here -->
            </filterchain>
        </concat>
        <!-- For easier test: output the file -->
        <concat><fileset file="${build.dir}/changes.txt"/></concat>
    </target>

But I couldnt get one file after the next in that filterchain. By default I get one line after the next and then I have troubles for storing the current state (in @@snip-@@endSnip section or out). When using a <tokenfilter><filetokenizer/> I’ll get not only one whole file – I’ll get one token containing ALL catched files including the specified headers. And I dont want to run THAT on a larger codebase …

Ok, it is difficult to gather all content BETWEEN two special markers. But it is very easy to catch all lines with a PREPENDING marker:

    <target name="ant">
        <mkdir dir="${build.dir}"/>
        <!-- Collecting and using the information -->
        <echo file="${build.dir}/changes.txt">
        Changes
        -----------------------------------------------------------------
        </echo>
        <concat destfile="${build.dir}/changes.txt" append="true">
            <fileset dir="src" includes="**/*.java" />
            <filterchain>
	<linecontainsregexp>
                    <regexp pattern="^&#91; \*&#93;*CHANGES:"/>
                </linecontainsregexp>
                <replaceregex pattern="^&#91; \*&#93;*CHANGES: *" replace=""/>
            </filterchain>
        </concat>
        <!-- For easier test: output the file -->
        <concat><fileset file="${build.dir}/changes.txt"/></concat>
    </target>
/**
 * This is normal JavaDoc comment.
 * CHANGES: This is a comment which should be in the changes.txt!
 * @author Jan Materne
 */
public class MyProgram {
}