以编程方式从ant构建文件中检索某些任务

时间:2012-03-31 09:20:13

标签: java xml parsing ant build

我有一个build.xml,用于导入其他ant xml文件。我想从中获取所有javac任务,以便我可以看到为这些任务设置了什么类路径(javac用于多个目标)。我想出了以下代码(简化了一下):

public static void main(String[] args) throws Exception {                                                                                                                                                        
    Project project = new Project();                                                                                                                                                                             
    project.init();                                                                                                                                                                                              
    String build = "build.xml";                                                                                                                                                                                  
    File buildFile = new File(build);                                                                                                                                                                            
    ProjectHelper.configureProject(project, buildFile);                                                                                                                                                          

    Hashtable<String,Object>ht = project.getTargets();                                                                                                                                                           
    for (String key : ht.keySet()) {                                                                                                                                                                             
        try {                                                                                                                                                                                                    
            Target target = (Target)ht.get(key);                                                                                                                                                                 
            Task[] tasks = target.getTasks();                                                                                                                                                                    
            for (Task task : tasks) {                                                                                                                                                                            
                if (task instanceof UnknownElement) {                                                                                                                                                            
                    ((UnknownElement)task).maybeConfigure();                                                                                                                                                     
                    task = ((UnknownElement)task).getTask();                                                                                                                                                     
                    if (task == null) {                                                                                                                                                                          
                        return;                                                                                                                                                                                  
                    }                                                                                                                                                                                            
                }                                                                                                                                                                                                
                if (task instanceof Javac) {                                                                                                                                                                     
                    // here we go                                                                                                                                                                                
                }                                                                                                                                                                                                
            }                                                                                                                                                                                                    
        } catch(Exception ignore) {}                                                                                                                                                                             
    }                                                                                                                                                                                                            
 }

但是,像MacroDef这样的任务可能嵌套了其他任务。 TaskContainer接口仅指定addTask(task),我认为无法检索嵌套任务。

如何检索所有javac任务?没有使用ant库的解决方案是可以的,但是XML解析似乎很麻烦,因为ant使用属性,引用,构建文件可以导入其他文件等。

1 个答案:

答案 0 :(得分:5)

好的,为了澄清你的问题,我将重申这个问题。

如何收集所有&lt; javac&gt;的所有类路径? build.xml文件中的任务,即使其中一些可能嵌套在&lt; macrodef&gt;中定义

简单的答案是每个案例的一般答案是不可能的。其原因与计算机科学理论密切相关,涵盖了可计算性问题以及图灵机的局限性。在您的情况下,我们知道输入可以是无限的(因为ANT语言可以引用时间戳),并且输出可以是输入的反映,因此我们知道它将需要无限收集每个可能的类路径的时间。

尽管如此,你很容易推断某些类路径,甚至可能在合理(即非无限)的时间内推断出所有类路径。关键是ANT预先做了很多配置,但最终必须在运行中进行一些配置。 A&lt; javac&gt;目标中的classpath是预先配置的;因为ANT决定让所有变量都不可变。这意味着对于“典型”javac标记,您只需要一些看起来像这样的代码:

            if (task instanceof Javac) {
                Javac javac = (Javac)task;
                Path path = javac.getClasspath();
                if (path == null) {
                  System.out.println("javac: Path is null");
                } else {
                  System.out.println("javac: Path is " + path.toString());
                }
            }

但嵌套在macrodef javac标签中需要模拟运行。实际配置不会直接保存在任务中,它将保存在类的RuntimeConfigurable包装内。然后将在项目执行时创建Task个节点,这意味着它们的配置将在运行中进行计算。

我将列出一些关于如何导航到macrodef Wrapper“child”元素的代码:

            if (task instanceof MacroDef) {
              MacroDef macroDef = (MacroDef)task;
              // a Sequence element, but not really, as `unkSeq.getRealThing()` will return null
              UnknownElement unkSeq = macroDef.getNestedTask();
              // Make sure we are dealing with the wrapper, or we won't get very far
              RuntimeConfigurable wrapper = unkSeq.getWrapper();
              // Wrappers can be configured too.
              wrapper.maybeConfigure(project, true);
              Enumeration enumeration = wrapper.getChildren();
              while (enumeration.hasMoreElements()) {
                // children of the wrapper
                RuntimeConfigurable child = (RuntimeConfigurable) enumeration.nextElement();
                UnknownElement unkchild = (UnknownElement)child.getProxy();
                // you can use this to print the name
                System.out.println("child(wrapper): " + unkchild.getTaskName());
                // this will be null, as the macro hasn't "executed"
                System.out.println("child(real): " + unkchild.getRealThing());
              }
            }

由于实际调用的javac任务在macrodef pre-runtime中不存在,因此在执行之前的所有情况下都不可能真正“知道”它的类路径。是的,你可以做一些花哨的代码来模拟运行,跟踪瞬态ANT属性,但你永远不能“证明”这样的代码与运行相同,除非你正在处理属性的子集(即那些保证的属性) 总是所有运行之间具有相同的值。

我希望我在回答你的问题时没有错过标记,如果我这样做,希望这方面的内容对你解决问题有用。但请放心,有 no 解决方案可以打印每个可能的 build.xml文件的类路径,其中javac任务嵌入在macrodef调用中。

---原帖如下--- 要真正捕获macrodef的内容,您需要捕获引用macrodef的任务,然后捕获macrodef,然后查看macrodef中的元素(请记住它们也可能是宏)。