Joe Roberts
Joe Roberts

Reputation: 21

Finding the calling (or parent) target in Apache Ant

We use Ant to control our product creation workflow and the number of targets is quite extensive. We make use of numerous build.xml files, targets that call other targets (many of the targets running in parallel).

We have a java class that extends the Ant BuildListener so that we can listen for BuildEvents and write start and stop times for every target to an Oracle database. However, now I need to be able to figure out each target's parent target - this information needs to be logged as well. So if I have this:

<target name="targetA">
    <parallel>
        <antcall target="targetB"/>
        <antcall target="targetC"/>
    </parallel>
    <antcall target="targetD"/>

Sometimes our targets make several antcalls to targets in the same build.xml, and sometimes we make ant calls to other build.xmls in sub-directories specifying a target.

In any regard, I would like to know a way I can figure out that targetA is the parent of targetB. I thought I could have determined this information from the properties in the BuildEvent in my listener. But that does not seem to be available. So when I receive a BuildEvent telling me that targetB started, it appears that the BuildEvent doesn't know about TargetA.

Has anyone else tried something like this with success? I've been trying to use the listener, but would not oppose a post process that can determine the target hierarchy.

Upvotes: 2

Views: 681

Answers (1)

Guillaume Polet
Guillaume Polet

Reputation: 47608

I am not completely sure about this, but I guess that you could something like this (it assumes that when targets are run in parallel, they are run in a different thread than the main thread used by ant and that the other targets are run in the same thread as the one of the build listener):

import java.util.Stack;

import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.Target;


public abstract class MyBuildListener implements BuildListener {

    private Thread mainThread = Thread.currentThread();

    private Stack<Target> callingTargets = new Stack<Target>();

    private ThreadLocal<Stack<Target>> callingTargetsPerThread = new ThreadLocal<Stack<Target>>();

    @Override
    public void targetStarted(BuildEvent event) {
        if(Thread.currentThread()==mainThread) {
            printCallingStack(callingTargets);
            callingTargets.push(event.getTarget());
        } else {
            Stack<Target> callingTargetsForThread = callingTargetsPerThread.get();
            if(callingTargetsForThread==null) {
                callingTargetsPerThread.set(callingTargetsForThread = new Stack<Target>());
            }
            printCallingStack(callingTargetsForThread);
            printCallingStack(callingTargets);
            callingTargetsForThread.add(event.getTarget());
        }
    }

    @Override
    public void targetFinished(BuildEvent event) {
        if(Thread.currentThread()==mainThread) {
            callingTargets.pop();
        } else {
            Stack<Target> callingTargetsForThread = callingTargetsPerThread.get();
            callingTargetsForThread.pop();
            if (callingTargetsForThread.isEmpty()) {
                callingTargetsPerThread.remove();
            }
        }
    }

    private void printCallingStack(Stack<Target> stack) {
        for(int i=stack.size();i>=0;i--) {
            System.out.println(stack.get(i).getName());
        }
    }

}

Upvotes: 1

Related Questions