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

ldx*_*ldx 6 java xml ant parsing 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) {}                                                                                                                                                                             
    }                                                                                                                                                                                                            
 }
Run Code Online (Sandbox Code Playgroud)

但是,有些任务MacroDef可能嵌套了其他任务.该TaskContainer接口只指定了addTask(task),我看不出有什么方法来检索嵌套任务.

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

Edw*_*uck 5

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

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

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

也就是说,你很容易推断出一些类路径,甚至可能在合理的(即非无限的)时间内推断出所有的类路径.关键是ANT预先做了很多配置,但最终必须在运行中进行一些配置.目标中的<javac>类路径是预先配置的; 因为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());
                }
            }
Run Code Online (Sandbox Code Playgroud)

但嵌套在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());
              }
            }
Run Code Online (Sandbox Code Playgroud)

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

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

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