![](/img/trans.png)
[英]Is it possible to generate the file 'build.xml' from the command line in 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”之類的東西。
根據導入任務的描述,它非常像實體包含兩個附加功能:
為了查看“有效構建”,我不認為需要特殊屬性處理(盡管可以通過迭代插入的目標來添加它)。 所以實現這一目標的過程就變成了。
您可以定義自定義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.