【问题标题】:Finding the calling (or parent) target in Apache Ant在 Apache Ant 中查找调用(或父)目标
【发布时间】:2015-01-29 15:51:54
【问题描述】:

我们使用 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.xml 进行 ant 调用。

无论如何,我想知道一种方法可以找出 targetA 是 targetB 的父级。我以为我可以从侦听器的 BuildEvent 中的属性中确定此信息。但这似乎不可用。因此,当我收到一个 BuildEvent 告诉我 targetB 已启动时,BuildEvent 似乎不知道 TargetA。

有没有其他人成功地尝试过这样的事情?我一直在尝试使用监听器,但不会反对可以确定目标层次结构的后期处理。

【问题讨论】:

  • 您是在构建东西,还是在使用 Ant 作为编程语言?
  • 我们使用 ant 来构建我们的软件,同时也使用工作流来构建一些东西(我们的产品)——这是一个 ETL 过程。但是软件中的一些 java 类扩展了 ant 类,例如 BuildListener。

标签: java ant


【解决方案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());
        }
    }

}

【讨论】:

  • 谢谢!我不确定你的假设,但我会试一试。
  • @JoeRoberts 据我所知 Ant 代码,我的假设是可以接受的。如果您在运行 Ant 的同一线程中实例化 BuildListener,我相信我的假设是正确的。在调试模式下运行它应该很快告诉你这是否正确。您还可以在构造函数和事件通知方法中打印出当前线程的名称。
  • 谢谢!我认为这是正确的轨道。但它一直有效,直到你遇到嵌套并行性——我有。鉴于这种情况: dirB/fileB: ... targetB、targetX 和 targetY 在三个单独的线程中调用:每个 targetStarted 我都得到一个新堆栈。我无法确定 targetB 是两者的父级。
  • @JoeRoberts 请编辑原始问题或发布另一个问题,因为我无法阅读或理解您的最后评论。
  • 抱歉,评论没有像我希望的那样格式化。我说过这个解决方案一直有效,直到你遇到嵌套并行性——我有。我试图布局一个 XML 场景,其中 targetA 并行调用 targetB 和 targetC。然后 TargetB 还会并行调用 targetX 和 targetY。发生这种情况时,targetB、targetX 和 targetY 在三个单独的线程中被调用:我得到一个带有每个 targetStarted BuildEvent 的新堆栈。我无法确定 targetB 是 targetX 还是 targetY 的父级。
猜你喜欢
  • 1970-01-01
  • 2013-06-17
  • 1970-01-01
  • 2012-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-15
相关资源
最近更新 更多