Извлечение определенных задач программным путем из файла сборки ant - PullRequest
6 голосов
/ 31 марта 2012

У меня есть build.xml, который импортирует другие файлы ant xml.Я хотел бы получить от него все задачи javac, чтобы видеть, какой classpath установлен для этих задач (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 Ответ

5 голосов
/ 11 апреля 2012

Хорошо, чтобы прояснить вашу проблему, я переформулирую вопрос.

Как собрать все пути классов для всех задач в файле build.xml, даже если некоторые из них могут быть вложены в определения ?

Простой ответ заключается в том, что общий ответ для каждого случая невозможен. Причины этого глубоко связаны с теорией информатики, охватывающей вопросы вычислимости и ограничения машины Тьюринга. В вашем случае мы знаем, что входные данные могут быть бесконечными (поскольку язык ANT может ссылаться на временные метки), и что выходные данные могут быть отражением входных данных, поэтому мы знаем , что потребуется бесконечное количество времени для сбора каждого возможного пути к классам.

Тем не менее, шансы превосходны, что вы можете легко вывести некоторые пути к классам и даже, возможно, вывести все пути к классам за разумное (т. Е. Бесконечное) количество времени. Ключевым моментом является то, что ANT выполняет множество предварительных настроек, но в конечном итоге необходимо выполнить некоторые настройки на лету. 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());
                }
            }

Но вложенному в тег javac macrodef потребуется симуляция прогона. Фактическая конфигурация не будет храниться непосредственно внутри задачи, она будет храниться в оболочке RuntimeConfigurable вокруг класса. Узлы Task будут создаваться при выполнении проекта, что означает, что их конфигурация будет вычислена на лету.

Я перечислю немного кода о том, как перейти к дочерним элементам macrodef Wrapper:

            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 не существует в предопределении макроса, невозможно по-настоящему «знать» ее путь к классу во всех случаях до выполнения. Да, вы можете сделать какой-нибудь модный код для имитации прогона, отслеживая переходные свойства ANT, но вы никогда не сможете «доказать», что такой код совпадает с прогоном, если вы не имеете дело с подмножеством свойств (а именно с теми, которые гарантированы всегда имеют одинаковое значение между все прогонов).

Надеюсь, я не пропустил оценку, ответив на ваш вопрос, и, если я так и сделал, надеюсь, что что-то из этого будет полезным для вашего решения вашей проблемы. Будьте уверены, что существует нет решения для распечатки пути к классам для каждого возможного файла build.xml, где задачи javac встроены в вызовы macrodef.

--- оригинальный пост следует --- Чтобы действительно захватить содержимое макроопределения, вам нужно захватить задачу, которая ссылается на макроопределение, а затем захватить макроопределение, а затем посмотреть на элементы внутри макроопределения (помня, что они тоже могут быть макросами).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...