JWare Logo  “Strategies in (*)ability” [iDareMedia] [JWare] [PET] [CI-Dashboard]
<JWare/AntXtras Simple Artifact Management (SAM)>

 [home]    [overview] [download[learning] [problems] [ourplans]    [contacts] [legalese

[how-to]

home » learning » how-to 

How do I declare an <artifactdef> so that property evaluation is delayed?

To force SAM to re-evaluate an <artifactdef>’s simple parameters every time it is used, substitute the macrodef attribute reference syntax for the normal property reference syntax. In other words, use the “@{…}” wrapper instead of the “${…}” wrapper like the following example demonstrates:

    <artifactdef name="readmes">
        <defaults>
            <method use="mkreadmes"/>
            <version use="latest">
            <parameter name="for" value="@{package}-readmes-pkg"/>
            <parameter name="uploads" value="@{docs.dir}/readmes"/>
            <parameter name="clean" value="yes"/>
            <parameter name="license" value="MIT"/>
            <parameter name="saladbar" value="@{saladbar.dir}"/>
            <announcement>
               <include parameter="for"/>
            </announcement>
        </defaults>
        <version name="latest">
            <parameter name="downloads" value="${pristine.dir}"/>
        </version>
        …
    </artifactdef>
Example 1: Using SAM’s delayed property evaluation syntax.

In this example, the parameter values for uploads, for, and saladbar will be re-determined for each use of the definition from ${docs.dir}/readmes, ${package}-readmes-pkg, ${saladbar.dir} respectively. Alternatively, the value for ${pristine.dir} will be evaluated once, when the definition is first parsed and added to its catalog (caveat: if pristine.dir is not defined at the time of parsing, the property reference is kept and will be reevaluated for each use of the definition; this might be good or it might be bad; it’s definitely unpredictable). The next example shows a build script that relies on the fact that the paramaeter values are recalculated for each use. The script can generate multiple independent sets of readme packages by using a single readmes artifact definition and changing the surrounding fixture for each call to genarate the artifact.

    <property name="saladbar.dir" value="…"/>
    <property name="pristine.dir" value="…"/>
    <property name="sources.dir" value="…">

    [load artifactdefs into project somehow...]

    <macrodef name="local-readmes">
        <attribute name="for"/>
        <sequential>
            <macrolocals>
                <property name="package" value="@{for}"/>
                <property name="docs.dir" value="${sources.dir}/@{for}/docs">
            <macrolocals>
            <macroisolate>
                <mkdir dir="${docs.dir}"/>
                <readmes-latest/>
            <macroisolate>
        </sequential>
    </macrodef>

    <target name="local-readmes" depends="…">
        <local-readmes for="antx-core"/>
        <local-readmes for="antx-flowcontrol"/>
        …
    </target>
Example 2: Using recalculation of artifactdef properties to reuse single definition.

You might wonder why the second and subsequent uses of <readmes-latest> do not pick up the announced first package? When an artifact is announced, context information (like ARM parameters) can be included as part of the identity of the artifact. In our case, we explicitly include the for attribute as part of the identity; see the <announcement> item. And because we are essentially altering the artifact’s identity in each call, none of the previously generated packages match the new request.

Reference Parameters

SAM lets you define complex data objects inside your artifact definitions directly with the <refparameter> element. This feature is most useful for defining data sets like file sets, class paths, and filter sets right where they’re used. However, if you use a <refparameter>, you must also use regular property reference syntax for the nested element’s attribute values; standard Ant types do not understand the alternate “@{…}” syntax outside of macrodefs. The following snippet is broken:
    <artifactdef name="mainclasses">
        <default>
            <parameter name="outputs" value="@{java-classes.dir}"/>
            <refparameter name="sources.set">
                <fileset dir="@{java-sources.dir}"> [<fileset> won’t interpret right]
                    <include name="**/*.java"/>
                    <exclude name="**/tests*/**"/>
                    <exclude name="**/doc-files/**"/>
                </fileset>
            </refparameter>
        </default>
        ...
    </artifactdef>
Example 3: Broken use of SAM’s delayed property syntax with <refparameter>.

Why Would I Do This?

Aside from the dynamically changing artifact definition cited early, two more common reasons for explicitly using this alternate syntax are value URIs evaluations and references to location properties generated by other artifact definitions. Because value URIs usually evaluate to something they are rarely undefined (as the caveat above describes), so having their values evaluated at definition load time or evaluated only once is usually incorrect. Take the following definition for instance:

    <artifactdef name="statusfile">
        <version name="programmertests">
            <parameter name="filenames" value="programmertests"/>
            <parameter name="status"
                value="@{$isset:tests.unclean|$truefalse:?FAIL,,PASS}"/>
        </version>
        ...
    </artifactdef>
Example 4: Using SAM’s delayed property syntax with AntX value URIs in artifactdefs.

If we used the regular property syntax for the value of the status parameter, it would evaluate once at load time to “PASS” and would never reflect the value of the subsequently set tests.unclean property from a failing <junit> run as the following snippet intends:

    <target name="testresults" depends="build">
        <programmertests-baselines/>
        <programmertests-main/>       [sets 'tests.unclean' if any problems]
        <statusfile-programmertests/> [will never record FAIL in main tests]
    </target>
Example 5: A typical expectation of delayed property evaluation in an Ant script.
SourceForge.net Logo
Copyright © 2004-2006 iDare Media, Inc. All rights reserved.
 
JWare/AntXtras uses software developed by and on behalf of the Apache Software Foundation, http://www.apache.org/.
All other product names mentioned on this website are trademarks of their respective owners; refer to full legalese statement.