生成Ant构建文件

ina*_*abt 4 java xml ant build

我有以下项目结构:

root/
    comp/
        env/
           version/
                  build.xml
           build.xml
        build.xml
Run Code Online (Sandbox Code Playgroud)

根/ comp/env的/版本/ build.xml文件是:

<project name="comp-env-version" basedir=".">
    <import file="../build.xml" optional="true" />
    <echo>Comp Env Version tasks</echo>
    <target name="run">
        <echo>Comp Env Version run task</echo>
    </target>
</project>
Run Code Online (Sandbox Code Playgroud)

root/comp/env/build.xml是:

<project name="comp-env" basedir=".">
    <import file="../build.xml" optional="true" />
    <echo>Comp Env tasks</echo>
    <target name="run">
        <echo>Comp Env run task</echo>
    </target>
</project>
Run Code Online (Sandbox Code Playgroud)

root/comp/build.xml是:

<project name="comp" basedir=".">
    <echo>Comp tasks</echo>
</project>
Run Code Online (Sandbox Code Playgroud)

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

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

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

<project name="comp-env-version" basedir=".">
    <echo>Comp tasks</echo>
    <echo>Comp Env tasks</echo>
    <echo>Comp Env Version tasks</echo>
    <target name="run">
        <echo>Comp Env Version run task</echo>
    </target>
</project>
Run Code Online (Sandbox Code Playgroud)

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

编辑: 我需要像Ant的"mvn help:effective-pom"之类的东西.

Ric*_*ler 5

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

  • 目标覆盖
  • 特殊属性

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

  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<Element> imports = root.getChildren("import");

    for (int i = 0; i < imports.size(); i++) {
        Element element = imports.get(i);

        List<Content> 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<Content> 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<Content> 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<Content> childNodes = importRoot.cloneContent();
        List<Content> importContent = new ArrayList<Content>();

        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<Content> 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;
}
Run Code Online (Sandbox Code Playgroud)