Please remember that the following examples are greatly simplified from our very complex assembly structure.
Suppose I have an assembly that fully utilizes the capabilities of Ant 1.8 extension points, so I have a common set of goals, defined as:
<?xml version="1.0" encoding="utf-8"?> <project name="common-targets"> <extension-point name="compile" /> <extension-point name="test" depends="compile" /> <extension-point name="package" depends="test" /> <extension-point name="deploy" depends="package" /> </project>
Each of the subsequent phases depends on an earlier phase, creating a chain of clearly defined steps that can contribute to other parts of the assembly; for example, a compilation step can be defined as:
<?xml version="1.0" encoding="utf-8"?> <project name="compile"> <import file="common-targets.xml" /> <target name="compile:compile" extensionOf="compile"> <echo message="Compiling..." /> </target> </project>
while the test may be:
<?xml version="1.0" encoding="utf-8"?> <project name="test"> <import file="common-targets.xml" /> <target name="test:test" extensionOf="test"> <echo message="Testing..." /> </target> </project>
etc. I can combine them in different ways, and for discussion let them say that they are in the same assembly file called default-lifecycle.xml:
<?xml version="1.0" encoding="utf-8"?> <project name="default-lifecycle"> <import file="compile.xml" /> <import file="test.xml" /> <import file="package.xml" /> <import file="deploy.xml" /> </project>
A project called child1 can use this as:
<?xml version="1.0" encoding="utf-8"?> <project name="child1"> <import file="../scripts/default-lifecycle.xml" /> </project>
while the peer name child1 (smartly) called child2 will be the same:
<?xml version="1.0" encoding="utf-8"?> <project name="child2"> <import file="../scripts/default-lifecycle.xml" /> </project>
So, I have achieved the laudable goal of creating reusable collections that can be divided into several projects. Even better, each build can be customized by adding targets that add to well-defined extension points, which makes things very flexible when we need to.
However, I was having trouble finding the best way to create a hierarchical parent / child assembly, so I have a directory structure, for example:
.-+ | +-build.xml +-child1 | +-build.xml +-child2 | +-build.xml +-scripts
so that I can call, say, the installation goal in the top-level assembly and set the installation goal for each of these children.
IMHO, ideally, I would do this by setting a parent fee to import common goals and bind the target to each of the common goals, for example:
<?xml version="1.0" encoding="utf-8"?> <project name="parent"> <import file="common-targets.xml" /> <target name="parent:compile" depends="parent:init-build-path" extensionOf="compile"> <subant target="compile" buildpathref="parent..build-path" /> </target> <target name="parent:test" depends="parent:init-build-path" extensionOf="test"> <subant target="test" buildpathref="parent..build-path" /> </target> <target name="parent:package" depends="parent:init-build-path" extensionOf="package"> <subant target="package" buildpathref="parent..build-path" /> </target> <target name="parent:deploy" depends="parent:init-build-path" extensionOf="deploy"> <subant target="deploy" buildpathref="parent..build-path" /> </target> <target name="parent:init-build-path"> <path id="parent..build-path"> <fileset dir="." includes="**/build.xml" excludes="build.xml" /> </path> <echo message="Build order is ${toString:parent..build-path}" /> </target> </project>
However, this does not work for me, because first we start first down the hierarchy, not the depth: if we deploy at the top level of the hierarchy, we first collect in each project, then we test, then we make a package, then we deploy. I need to do all the steps for deployment in child1, then all the steps in child2, etc.
That will work, forgetting to use extension points in the parent assembly and simply define each target directly, for example:
<?xml version="1.0" encoding="utf-8"?> <project name="parent"> <target name="compile" depends="parent:init-build-path"> <subant target="compile" buildpathref="parent..build-path" /> </target> <target name="test" depends="parent:init-build-path"> <subant target="test" buildpathref="parent..build-path" /> </target> <target name="package" depends="parent:init-build-path"> <subant target="package" buildpathref="parent..build-path" /> </target> <target name="deploy" depends="parent:init-build-path"> <subant target="deploy" buildpathref="parent..build-path" /> </target> <target name="parent:init-build-path"> <path id="parent..build-path"> <fileset dir="." includes="**/build.xml" excludes="build.xml" /> </path> <echo message="Build order is ${toString:parent..build-path}" /> </target> </project>
However, now my parent assemblies do not have an extension mechanism in which they can be easily expanded without overriding goals.
Am I over thinking things? Is the Ant community reporting an idiom, template, usage guide, instructions or anything else to help me resolve this dilemma?