|
2.1. Using Properties to Control TasksAnt provides extensive support for controlling the build process; though Ant is not a programming language, it has a number of control structures, and those control structures rely on properties. As if and TRy/catch allow you to handle several logic paths in Java, Ant's control tasks allow you the same flexibility within the context of a build process. 2.1.1. Setting ConditionsThe foundation to any type of control processing is some form of the if statement. This typically involves two steps:
In Java, this all happens in a single line of code; in Ant, the condition must be set in one step, and the evaluation of that condition occurs in another step. First, you need to set a condition based on some criteria; not surprisingly, condition is the name of the task Ant provides. condition allows you to specify one or more true/false tests (sometimes called criteria). If all the criteria evaluate to true, a property, supplied to the condition task, is set to TRue; if one or more of the criteria evaluate to false, the property is assigned a false value. You can check that property's value later in the build file. In this example, the build file checks to see if two files exist using the available task (covered later in the chapter) and sets the property all.set (to true) if the files are found: <condition property="all.set"> <and> <available file="file1.java"/> <available file="file2.java"/> </and> </condition> Here's another example where the build file checks to see if it's running on Mac OS but not Mac OS X, which Ant treats as part of the Unix family: <condition property="MacOs.Not.MacOsX"> <and> <os family="mac"/> <not> <os family="unix"/> </not> </and> </condition> Here's how you can set a property; in this case, called do.abort--if the do.delete property value equals "yes": <condition property="do.abort"> <equals arg1="yes" arg2="${do.delete}"/> </condition> You can see the attributes of the condition task in Table 2-1.
This task depends on nested elements for evaluation; you can see the possibilities in Table 2-2.
Here's an example that sets the property omit.debug.info to true if the property build.type contains either of the words "release" or "gold" and if the property explicitly.include.debug.info is false: <condition property="omit.debug.info"> <and> <or> <contains string="${build.type}" substring="release"/> <contains string="${build.type}" substring="gold"/> </or> <isfalse value="${explicitly.include.debug.info}"/> </and> </condition> Here's another example, which sets the property use.property.file true if the files build.properties and version.properties are available, or if the file core.jar is not current: <condition property="use.property.file"> <or> <and> <available file="build.properties"/> <available file="version.properties"/> </and> <not> <uptodate srcfile="core.java" targetfile="core.jar"/> </not> </or> </condition> 2.1.2. Performing Conditional ActionsActions can be conditionally executed based on two factors: if a certain condition has been met (using the if attribute) and if a certain condition has not been met (using the unless attribute). You can determine if a task runs using if and unless to check the values of properties. Three elements support if and unless attributes: target, patternset (which can group file-matching patterns like "*.java", "*.class", and so on. See "Working with Patterns" in this chapter); fail target is the simplest, as shown here: <target name="buildModule" if="code.complied.OK"/> . . . </target> The buildModule target is executed only if the code.complied.OK property is true. Example 2-1 demonstrates the unless attribute. In this case, the build file won't compile the source files if the file enduser.agreement exists, which sets a property named final.version. Example 2-1. Using the unless attribute (ch02/if/build.xml)<?xml version="1.0" ?> <project default="main"> <property name="message" value="Building the .jar file." /> <property name="src" location="source" /> <property name="output" location="bin" /> <available file="${output}/enduser.agreement" property="final.version"/> <target name="main" depends="init, compile, compress"> <echo> ${message} </echo> </target> <target name="init"> <mkdir dir="${output}" /> </target> <target name="compile" unless="final.version"> <javac srcdir="${src}" destdir="${output}" /> </target> <target name="compress"> <jar destfile="${output}/Project.jar" basedir="${output}" includes="*.class" /> </target> </project> 2.1.3. Stopping BuildsYou can make a build fail at runtime using property values and the fail task.
For example, this build will fail with a message unless the specified classes are found in the classpath: <target name= <condition property="classes.available"> <and> <available classname="org.steven.SAXparser" /> <available classname="org.steven.DOMparser" /> </and> </condition> <fail message="Could not find all classes." unless="classes.available" /> . . . </target> You can see the available attributes of fail in Table 2-3.
2.1.4. Property-Setting TasksA few tasks allow you to indirectly set properties; that is, you specify a task (like available) and assign the result of that task's processing to a property. These function are like the condition task, though the syntax is different. 2.1.4.1 Availability of resourcesThe available task sets a property to true if a resource is available at runtime. The resource can be a file, a directory, a class in the classpath, or a JVM system resource. If the resource is available, the property value is set to true; otherwise, the property is not set. For example, the following build fragment will set the property Math.present to true if org.steve.Math is in Ant's classpath: <available classname="org.steve.Math" property="Math.present"/> Here's another example, which sets file.present to true if the file build.properties exists in the current directory: <available file="build.properties" property="file.present"/> You can see the attributes of this task in Table 2-4. You can set the property value to something other than the default by using the value attribute.
2.1.4.2 Checking file modification datesThe uptodate task sets a property to true under certain conditions. In this case, the property is set to true if a target file, or set of target files, is more current than a source file or set of source files. You can specify the file you want to check with the targetfile attribute and the source file that is used to create it with the srcfile attribute. If you want to check a set of source files, use nested srcfiles elements. If the target (or targets) is current, based on the source file or files, the property whose name you specify will be set to true. In this example, the property Do.Not.Build will be set to true if the target file, classes.jar, is current when compared to its source .java files: <uptodate property="Do.Not.Build" targetfile="classes.jar" > <srcfiles dir= "${src}" includes="*.java"/> </uptodate> You can use the ** wildcard to stand for the current directory and any subdirectory of that directory, which makes it easy to work with a directory hierarchy in depth. For example, if you want to check the ${src} directory for .java files, as in the previous example, and any subdirectory of ${src}, you could set includes to **/*.java. Doing so would match the .java files in the ${src} directory and in any subdirectories of ${src}. Here's how that might look: <uptodate property="Do.Not.Build" targetfile="classes.jar" > <srcfiles dir= "${src}" includes="**/*.java"/> </uptodate> Here's an example checking against a single source file, using the srcfile attribute: <uptodate property="Do.Not.Build" targetfile="classes.jar" > <srcfile includes="/usr/local/bin/classes.java"/> </uptodate> You can see attributes for the uptodate task in Table 2-5.
|
|