簡體   English   中英

生成Ant構建文件

[英]Generate Ant build file

我有以下項目結構:

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

root / comp / env / version / 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>

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>

root / comp / build.xml是:

<project name="comp" basedir=".">
    <echo>Comp tasks</echo>
</project>

每個構建文件都會導入父構建文件,每個子項都會繼承覆蓋父任務/屬性。

我需要的是獲得生成的構建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>

有沒有一個Ant插件來做到這一點? 有了Maven? 如果沒有,我有什么選擇?

編輯: 我需要像Ant的“mvn help:effective-pom”之類的東西。

根據導入任務的描述,它非常像實體包含兩個附加功能:

  • 目標覆蓋
  • 特殊屬性

為了查看“有效構建”,我不認為需要特殊屬性處理(盡管可以通過迭代插入的目標來添加它)。 所以實現這一目標的過程就變成了。

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

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及其模板引擎。

我建議構建你的構建文件,以便它們使用依賴樹,這是螞蟻真正擅長的。 如果您遵循@ Vladimir的建議並構建類似的構建文件,那么您可以在“root”中擁有一個構建文件,並以遞歸方式執行構建。 例如:

<!-- iterate finds all build files, excluding this one
     and invokes the named target 
-->
<macrodef name="iterate">
    <attribute name="target"/>
    <sequential>
        <subant target="@{target}">
            <fileset dir="." 
                     includes="**/build.xml"
                     excludes="build.xml"/>
        </subant>
    </sequential>
</macrodef>


<target name="build"  description="Build all sub projects">
    <iterate target="build"/>
</target>

<target name="clean"  description="Clean all sub projects">
    <iterate target="clean"/>
</target>

聽起來像gradle可以幫助你。 Gradle能夠導入您的ant build.xml文件 然后你可以開始一個干運行來獲得要執行的目標列表。

您可以用Java,Groovy,Ruby或者您最熟悉的任何內容編寫腳本/應用程序...腳本將解析構建文件的xml,並通過實際交換相應的DOM節點來替換“over-ridden”目標及其覆蓋。 你最終得到的是你的復合build.xml作為一個DOM,然后可以序列化。

您可以在源代碼管理中保留腳本,以便您可以根據需要進行重新生成。

這可能聽起來有點極端,但聽起來大多數其他解決方案都超出了您的需求范圍。

注意:您可以從Ant運行一些腳本lang,因此您仍然可以使用And作為啟動器。

祝好運。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM