生成Ant构建文件

我有以下项目结构:

root/ comp/ env/ version/ build.xml build.xml build.xml 

root / comp / env / version / build.xml是:

   Comp Env Version tasks  Comp Env Version run task   

root / comp / env / build.xml是:

   Comp Env tasks  Comp Env run task   

root / comp / build.xml是:

  Comp tasks  

每个构建文件都会导入父构建文件,每个子项都会inheritance覆盖父任务/属性。

我需要的是获得生成的构建XML而不运行任何东西

例如,如果我在root / comp / env / version /上运行“ant”(或类似的东西),我想得到以下输出:

  Comp tasks Comp Env tasks Comp Env Version tasks  Comp Env Version run task   

有没有一个Ant插件可以做到这一点? 有了Maven? 如果不是,我有什么选择?

编辑: 我需要像Ant的“mvn help:effective-pom”这样的东西。

根据导入任务的描述,它非常像实体包含两个附加function:

  • 目标压倒一切
  • 特殊属性

为了查看“有效构建”,我不认为需要特殊属性处理(尽管可以通过迭代插入的目标来添加它)。 所以实现这一目标的处理就变成了。

  1. 将build.xml解析为DOM
    • 对于找到的每个顶级包含标记(仅允许顶级),找到引用的源文件。
    • 解析引用的build.xml
    • 从引用的build.xml中插入任何不与当前文件中的内容冲突的内容。
    • 对引用的build.xml文件重复步骤2,直到找不到为止
    • 输出结果DOM

您可以定义自定义Ant任务,以便可以在要在构建中运行的任务中定义此处理。 有关详细信息,请参阅本教程 。

这是一个基本实现,通过导入进行递归并从引用的文件中插入DOM元素。 当我把它扔在一起时,几乎肯定会有一些错误,但它应该在很大程度上完成你所追求的:

 /** * Reads the build.xml and outputs the resolved build to stdout */ public static void main(String[] args) { try { Element root = new EffectiveBuild().parse(new File(args[0])); XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat()); outputter.output(root, System.out); } catch (Exception e) { // TODO handle errors e.printStackTrace(); } } /** * Get the DOM for the passed file and iterate all imports, replacing with * non-duplicate referenced content */ private Element parse(File buildFile) throws JDOMException, IOException { Element root = getRootElement(buildFile); List imports = root.getChildren("import"); for (int i = 0; i < imports.size(); i++) { Element element = imports.get(i); List importContent = parseImport(element, root, buildFile); int replaceIndex = root.indexOf(element); root.addContent(replaceIndex, importContent); root.removeContent(element); } root.removeChildren("import"); return root; } /** * Get the imported file and merge it into the parent. */ private List parseImport(Element element, Element currentRoot, File buildFile) throws JDOMException, IOException { String importFileName = element.getAttributeValue("file"); File importFile = new File(buildFile.getParentFile(), importFileName) .getAbsoluteFile(); if (importFileName != null) { Element importRoot = getRootElement(importFile); return getImportContent(element, currentRoot, importRoot, importFile); } return Collections.emptyList(); } /** * Replace the passed element with the content of the importRoot * (not the project tag) */ private List getImportContent(Element element, Element currentRoot, Element importRoot, File buildFile) throws JDOMException, IOException { if (currentRoot != null) { // copy all the reference import elements to the parent if needed List childNodes = importRoot.cloneContent(); List importContent = new ArrayList(); for (Content content : childNodes) { if (content instanceof Element && ((Element) content).getName().equals("import")) { importContent.addAll(parseImport((Element) content, currentRoot, buildFile)); } if (!existsInParent(currentRoot, content)) { importContent.add(content); } else { // TODO note the element was skipped } } return importContent; } return Collections.emptyList(); } /** * Return true if the content already defined in the parent */ private boolean existsInParent(Element parent, Content content) { if (content instanceof Text) { if (((Text) content).getText().trim().length() == 0) { // let the pretty printer deal with the whitespace return false; } return true; } if (content instanceof Element) { String id = ((Element) content).getAttributeValue("name"); String name = ((Element) content).getName(); List parentContent = parent.getChildren(); if (id != null) { for (Content content2 : parentContent) { if (content2 instanceof Element && ((Element) content2).getName().equals(name)) { String parentId = ((Element) content2) .getAttributeValue("name"); if (parentId != null && parentId.equals(id)) { return true; } } } } } return false; } /** * Parse the passed file. */ private Element getRootElement(File buildFile) throws JDOMException, IOException { SAXBuilder builder = new SAXBuilder(); builder.setValidation(false); builder.setIgnoringElementContentWhitespace(true); Document doc = builder.build(buildFile); Element root = doc.getRootElement(); return root; } 

Eclipse了解Ant文件。 您可以看到内部build.xml中可见的任务。 它不是您要求的格式,但它可能满足您的需求。

我已经编写了7到8年的Ant构建脚本,但我真的不明白你想要在这里实现什么。 也许是我,但我担心即使你让你的构建工作(我相信你可以),几乎没有其他人会理解/维护它。

为什么不保持简单和兄弟项目?

 root build.xml comp build.xml env build.xml version build.xml 

单个build.xml文件可以在其他地方导入任务定义(使用Macrodef),你的顶级build.xml会按顺序调用各个?

一旦你的基本版本运行,你可以玩Ivy或Maven来获得更多有趣的东西。

但是如果你真的想要生成构建文件,你可以尝试使用Groovy及其模板引擎。

我建议构建你的构建文件,以便它们使用依赖树,这是ant真正擅长的。 如果您按照@ Vladimir的建议并构建类似的构建文件,那么您可以在“root”中拥有一个构建文件,并以递归方式执行构建。 例如:

                

听起来像gradle可以帮助你。 Gradle能够导入您的ant build.xml文件 。 然后你可以开始一个干运行来获得要执行的目标列表。

你可以用Java,Groovy,Ruby或者你最熟悉的任何东西编写一个脚本/应用程序……脚本将解析构建文件的xml,并通过实际交换相应的DOM节点来替换“over-ridden”目标及其覆盖。 您最终得到的是您的复合build.xml作为DOM,然后可以序列化。

您可以在源代码管理中保留脚本,以便可以根据需要进行重新生成。

这可能听起来有点极端,但听起来大多数其他解决方案都超出了您的需求范围。

注意:您可以从Ant运行一些脚本lang,因此您仍然可以使用And作为您的启动器。

祝你好运。