Phing Guide - Project Components

# Project Components

This goal of this chapter is to make you familiar with the basic components of a buildfile. After reading this chapter, you should be able to read and understand the basic structure of any buildfile even if you don't know exactly what the individual pieces do.

For supplemental reference information, you should see Appendix B, Appendix D and Appendix D.

## Projects

In the structure of a Phing buildfile, there must be exactly one Project defined; the <project> tag is the root element of the buildfile, meaning that everything else in the buildfile is contained within the <project > element.

    <?xml version="1.0"?>

    <project name="test" description="Simple test build file" default="main" >
      <!-- Everything else here -->
    <project>

The listing above shows a sample <project> tag that has all attributes available for Projects. The name and description attributes are fairly self-explanatory; the default attribute specifies the default Target to execute if no target is specified (Targets are described below). For a complete reference, see Appendix D.

## Version

Since Phing 2.4.2 it is possible to include a phingVersion attribute in the <project> tag. This attribute allows you to define the minimum Phing version required to execute a build file, in order to prevent compatibility issues.

    <?xml version="1.0"?>

    <project name="test" phingVersion="2.4.2" >
      <!-- Everything else here -->
    <project>

## Project Components in General

Project Components are all the elements found inside a project, i.e. targets, tasks, types, etc. Project components may have attributes and nested tags. Attributes only contain simple values, i.e. strings, integers etc. Nested elements may be complex Phing types (like FileSets) or simple wrapper classes for values with custom keys (see FileSet for example).

Any nested elements must be supported by the class that implements the project component, and because the nested tags are handled by the project component class the same nested tag may have different meanings (and different attributes) depending on the context. So, for example, the nested tag <param.../> within the <phingcall> tag is handled very differently from the<param.../> tag within the <xsltfilter> tag -- in the first case setting project properties, in the second case setting XSLT parameters.

## Targets

Targets are collections of project components (but not other targets) that are assigned a unique name within their project. A target generally performs a specific task -- or calls other targets that perform specific tasks -- and therefore a target is a bit like a function (but a target has no return value).

Targets may depend on other targets. For example, if target A depends on a target B, then when target A is called to be executed, target B will be executed first. Phing automatically resolves these dependencies. You cannot have circular references like: "target A depends on target B that depends on target A".

The following code snippet shows an example of the use of targets.

    <target name="othertask" depends="buildpage" description="Whatever">
      <!-- Task calls here -->
    <target>

    <target name="buildpage" description="Some description">
      <!-- Task calls here -->
    <target>

When Phing is asked to execute the othertask target, it will see the dependency and execute buildpage first. Notice that the the dependency task can be defined after the dependent task.

## Tasks

Tasks are responsible for doing the work in Phing. Basically, tasks are the individual actions that your buildfile can perform. For example, tasks exist to copy a file, create a directory, TAR files in a directory. Tasks may also be more complex such as XsltTask which copies a file and transforms the file using XSLT, SmartyTask which does something similar using Smarty templates, or CreoleTask which executes SQL statements against a specified DB. See Appendix B for descriptions of Phing tasks.

Tasks support parameters in the form of:

- Simple parameters (i.e. strings) passed as XML attributes, or
- More complex parameters that are passed by nested tags

Simple parameters are basically strings. For example, if you pass a value "A simple string." as a parameter, it is evaluated as a string and accessible as one. You can also reference properties as described in Getting Started.

Note: There are special values that are not mapped to strings, but to boolean values instead. The values true, false, yes, no, on and off are translated to true/false boolean values.

    <property name="myprop" value="value" override="true"/>

However, some tasks support more complex data types as parameters. These are passed to the task with nested tags. Consider the following example:

    <copy>
      <fileset dir=".">
        <include name="**" />
      </fileset>
    </copy>

Here, CopyTask is passed a complex parameter, a Fileset. Tasks may support multiple complex types in addition to simple parameters. Note that the names of the nested tags used to create the complex types depend on the task implementation. Tasks may support default Phing types (see below) or may introduce other types, for example to wrap key/value pairs.

Refer to Appendix B for a list of system tasks and their parameters.

## Types

### Basics

Besides the simple types (strings, integer, booleans) you can use in the parameters of tasks, there are more complex Phing Types. As mentioned above, they are passed to a task by using nesting tags:

    <task>
      <type />
    </task>

    <!-- or: -->

    <task>
      <type1>
        <subtype1>
          <!-- etc. -->
        </subtype1>
      </type1>
    </task>

Note that types may consist of multiple nested tags -- and multiple levels of nested tags, as you can see in the second task call above.

### Referencing Types

An additional fact about types you should notice is the possibility of referencing type instances, i.e. you define your type somewhere in your build file and assign an id to it. Later, you can refer to that type by the id you assigned. Example:

    <project>
      <fileset id="foo">
        <include name="*.php" />
      </fileset>

      <!-- Target that uses the type -->
      <target name="foo" >
        <copy todir="/tmp">
          <fileset refid="foo" />
        </copy>
      </target>
    </project>

As you can see, the type instance is assigned an id with the id attribute and later on called by passing a plain fileset tag to CopyTask that only contains the refid attribute.

## Basic Types

The following section gives you a quick introduction into the basic Phing types. For a complete reference see Appendix D.

### FileSet

FileSets are groups of files. You can include or exclude specific files and patterns to/from a FileSet. The use of patterns is explained below. For a start, look at the following example:

    <fileset dir="/tmp" id="fileset1">
      <include name="sometemp/file.txt" />
      <include name="othertemp/**" />
      <exclude name="othertemp/file.txt" />
    </fileset>

    <fileset dir="/home" id="fileset2">
      <include name="foo/**" />
      <include name="bar/**/*.php" />
      <exclude name="foo/tmp/**" />
    </fileset>

The use of patterns is quite straightforward: If you simply want to match a part of a filename or dirname, you use *. If you want to include multiple directories and/or files, you use **. This way, filesets provide an easy but powerful way to include files.

### FileList

FileLists, like FileSets, are collections of files; however, a FileList is an explicitly defined list of files -- and the files don't necessarily have to exist on the filesystem.

Besides being able to refer to nonexistent files, another thing that FileLists allow you to do is specify files in a certain order. Files in FileSets are ordered based on the OS-level directory listing functions, in some cases you may want to specify a list of files to be processed in a certain order -- e.g. when concatenating files using the <append> task.

    <filelist dir="base/" files="file1.txt,file2.txt,file3.txt"/>

    <!-- OR: -->
    <filelist dir="basedir/" listfile="files_to_process.txt"/>

#### FilterChains and Filters

FilterChains can be compared to Unix pipes. Unix pipes add a great deal of flexibility to command line operations; for example, if you wanted to copy just those lines that contained the string blee from the first 10 lines of a file called foo to a file called bar, you could do:

    cat foo | head -n10 | grep blee > bar

Something like this is not possible with the tasks and types that we have learned about thus far, and this is where the incredible usefulness of FilterChains becomes apparent. They emulate Unix pipes and provide a powerful dimension of file/stream manipulation for the tasks that support them.

FilterChain usage is quite straightforward: you pass the complex Phing type filterchain to a task that supports FilterChains and add individual filters to the FilterChain. In the course of executing the task, the filters are applied (in the order in which they appear in the XML) to the contents of the files that are being manipulated by your task.

    <filterchain>
      <replacetokens>
        <token key="BC_PATH" value="${top.builddir}/"/>
        <token key="BC_PATH_USER" value="${top.builddir}/testsite/user/${lang}/"/>
      </replacetokens>

      <filterreader classname="phing.filters.TailFilter">
        <param name="lines" value="10"/>
      </filterreader>
    </filterchain>

The code listing above shows you some example of how to use filter chains. For a complete reference see Appendix D. This filter chain would replace all occurences of BC_PATH and BC_PATH_USER with the values assigned to them in lines 4 and 5. Additionally, it will only return the last 10 lines of the files.

Notice above that FilterChain filters have a "shorthand" notation and a long, generic notation. Most filters can be described using both of these forms:

    <replacetokens>
      <token key="BC_PATH" value="${top.builddir}/"/>
      <token key="BC_PATH_USER" value="${top.builddir}/testsite/user/${lang}/"/>
    </replacetokens>

    <!-- OR: -->

    <filterreader classname="phing.filters.ReplaceTokens">
      <param type="token" name="BC_PATH" value="${top.builddir}/"/>
      <param type="token" name="BC_PATH" value="${top.builddir}/testsite/user/${lang}/"/>
    </filterreader>

As the pipe concept in Unix, the filter concept is quite complex but powerful. To get a better understanding of different filters and how they can be used, take a look at any of the many uses of FilterChains in the build files for the binarycloud [bc] project.

#### File Mappers

With FilterChains and filters provide a powerful tool for changing contents of files, Mappers provide a powerful tool for changing the names of files.

To use a Mapper, you must specify a pattern to match on and a replacement pattern that describes how the matched pattern should be transformed. The simplest form is basically no different from the DOS copy command:

    copy *.bat *.txt

In Phing this is the glob Mapper:

    <mapper type="glob" from="*.bat" to="*.txt"/>

Phing also provides support for more complex mapping using regular expressions:

    <mapper type="regexp" from="^(.*)\.conf\.xml$$" to="\1.php"/>

Consider the example below to see how Mappers can be used in a build file. This example includes some of the other concepts introduced in this chapter, such as FilterChains and FileSets. If you don't understand everything, don't worry. The important point is that Mappers are types too, which can be used in tasks that support them.

    <copy>
      <fileset dir=".">
        <include name="*.ent.xml" />
      </fileset>

      <mapper type="regexp" from="^(.*)\.ent\.xml$" to="\1.php"/>

      <filterchain>
        <filterreader classname="phing.filters.XsltFilter">
          <param name="style" value="ent2php.xsl" />
        </filterreader>
      </filterchain>
    </copy>

For a complete reference, see Appendix D.

## Conditions

Conditions are nested elements of the condition and if tasks.

#### not

The `<not>` element expects exactly one other condition to be nested into this element, negating the result of the condition. It doesn't have any attributes and accepts all nested elements of the condition task as nested elements as well.

#### and

The `<and>` element doesn't have any attributes and accepts an arbitrary number of conditions as nested elements. This condition is true if all of its contained conditions are, conditions will be evaluated in the order they have been specified in the build file.

The `<and>` condition has the same shortcut semantics as the && operator in some programming languages, as soon as one of the nested conditions is false, no other condition will be evaluated.

#### or

The `<or>` element doesn't have any attributes and accepts an arbitrary number of conditions as nested elements. This condition is true if at least one of its contained conditions is, conditions will be evaluated in the order they have been specified in the build file.

The `<or>` condition has the same shortcut semantics as the || operator in some programming languages, as soon as one of the nested conditions is true, no other condition will be evaluated.

#### os

Test whether the current operating system is of a given type.

Attribute | Description | Required
family | The name of the operating system family to expect. | Yes

Supported values for the family attribute are:

- windows (for all versions of Microsoft Windows)
- mac (for all Apple Macintosh systems)
- unix (for all Unix and Unix-like operating systems)

#### equals

Tests whether the two given Strings are identical

Attribute | Description | Required
arg1 | First string to test. | Yes
arg2 | Second string to test. | Yes
casesensitive | Perform a case sensitive comparision. Default is true. | No
trim | Trim whitespace from arguments before comparing them. Default is false. | No

#### isset

Test whether a given property has been set in this project.

Attribute | Description | Required
property | The name of the property to test. | Yes

#### contains

Tests whether a string contains another one.

Attribute | Description | Required
string | The string to search in. | Yes
substring | The string to search for. | Yes
casesensitive | Perform a case sensitive comparision. Default is true. | No

#### istrue

Tests whether a string evals to true.

Attribute | Description | Required
value | value to test | Yes

        <istrue value="${someproperty}"/>
        <istrue value="false"/>

#### isfalse

Tests whether a string evals to not true, the negation of <istrue>

Attribute | Description | Required
value | value to test | Yes

        <isfalse value="${someproperty}"/>
        <isfalse value="false"/>

#### referenceexists

Tests whether a specified reference exists.

Attribute | Description | Required
ref | reference to test for | Yes

        <referenceexists ref="${someid}"/>

#### available

This condition is identical to the Available task, all attributes and nested elements of that task are supported, the property and value attributes are redundant and will be ignored.