我们使用Ant来控制我们的产品创建工作流程,目标数量非常广泛。我们使用了许多build.xml文件,这些目标调用其他目标(许多目标并行运行)。
我们有一个扩展Ant BuildListener的java类,以便我们可以监听BuildEvents并将每个目标的开始和停止时间写入Oracle数据库。但是,现在我需要能够找出每个目标的父目标 - 这些信息也需要记录下来。如果我有这个:
<target name="targetA">
<parallel>
<antcall target="targetB"/>
<antcall target="targetC"/>
</parallel>
<antcall target="targetD"/>
有时我们的目标会在同一个build.xml中向目标发出几个antcall,有时我们会在指定目标的子目录中对其他build.xmls进行ant调用。
在任何方面,我想知道一种方法,我可以弄清楚targetA是targetB的父亲。我以为我可以从我的监听器中的BuildEvent属性中确定这些信息。但这似乎不可用。因此,当我收到一个BuildEvent告诉我targetB启动时,看起来BuildEvent并不了解TargetA。
有没有其他人尝试过这样的事情并取得成功?我一直试图使用监听器,但不会反对可以确定目标层次结构的后期处理。
答案 0 :(得分:1)
我对此并不完全确定,但我想你可以这样(它假设当目标并行运行时,它们运行在与ant使用的主线程不同的线程中,而其他目标运行在与构建侦听器之一的线程中运行:
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());
}
}
}