Extract specific tasks programmatically from an ant build file

I have a build.xml file that imports other ant xml files. I would like to get all javac tasks from him, so that I can see for which classes these tasks are set (javac is used for several purposes). I came up with the following code (simplified bit):

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) {} } } 

However, there are tasks such as MacroDef that may have other tasks. The TaskContainer interface indicates only addTask(task) , I see no way to get nested tasks.

How to get all javac tasks? It is good to have a solution in which the ant library is not used, but XML parsing seems cumbersome because ant uses properties, links, buildfiles can import other files, etc.

+6
source share
1 answer

Well, therefore, to clarify your problem, I will repeat the question.

How can I collect all class paths for all <javac> tasks in the build.xml file, even if some of them can be nested in the <macrodef> definitions?

The simple answer is that a common answer is not possible for each case. The reasons why they are deeply connected in computer science theory cover computability issues and the limitations of the Turing machine. In your case, we know that the input can be infinite (since the ANT language can refer to timestamps), and that the output can be a reflection of the input, so we know that it takes an infinite amount of time to collect all possible paths to the classes.

However, there are excellent chances that you can easily infer some classpaths and even possibly infer all class paths in a reasonable (i.e. infinite) amount of time. The key is that ANT does most of the configuration, but ultimately needs to do some tuning on the fly. A <javac> classpath in the target configuration is set up; because ANT decision to make all variables immutable. This means that for a “typical” javac tag, you only need code that looks like this:

  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()); } } 

But the macrodeff nested in the javaac tag needs a run simulation. The actual configuration will not be held directly inside the task, it will be stored in the RuntimeConfigurable shell around the class. Task nodes will then be created as the project progresses, which means that their configuration will be computed on the fly.

I have listed some code on how to go to the "children" of the Wrapper macroblock:

  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()); } } 

Since the actual javac task being called does not exist at the preliminary runtime of the macrodef, in all cases before execution it is not possible to "know" its path to the classes. Yes, you can make some fancy code to simulate a run by tracking the transition properties of ANT, but you can never “prove” that such a code matches a run if you are not dealing with a subset of properties (namely those that always will have the same value between all runs).

I hope I didn’t miss the mark answering your question, and if I did, I hope that something in this will be useful to solve your problem. Be sure, however, that there is no solution to print the class path for every possible build.xml file, where javac tasks are embedded in macrodef calls.

--- The original message follows --- To really capture the contents of the macrodef, you need to capture the macrodef task, then grab the macrodef and then look at the elements inside the macrodef (bearing in mind that they can also be macros).

+5
source

Source: https://habr.com/ru/post/912107/


All Articles