Deploying Applications

As you'd expect, Ant excels at deploying applications, and there are a number of tasks to choose from. You've saw the javac task's destdir attribute for deployment back in Chapter 1. In this section, you'll see copy, move, ftp, telnet, and sshexec.

The copy and move tasks are useful for local and network deployments, and tasks like ftp are great for remote deployments. Additionally, Chapter 8 will cover deployment to web servers with tasks like get, which you can use to send administrative commands to servers like Tomcat (I'll cover Tomcat's built-in custom Ant tasks), and serverdeploy.

Tip

Want to get a file's name without the path attached? Pass the filename to the basename task. Want to get just the path? Use dirname. The pathconvert task converts a nested path or reference to a Path, FileSet, DirSet, or FileList into a path (automatically adjusted for the target platform) and stores the result in a given property.

Deploying by Copying

This task copies a file, or a fileset, to a new file or a new directory. This is Ant's most basic deployment task for local and network deployment. Here are a few examples, starting with copying just one file:

<copy file="file.txt" tofile="backup.txt"/>

This example copies a file to a new location:

<copy file="file.txt" todir="../backup"/>

This example copies an entire directory to a new location:

<copy todir="../backup">
    <fileset dir="${src}"/>
</copy>

This copies a set of files to a new directory:

<copy todir="../backup">
    <fileset dir="src">
        <include name="**/*.java"/>
    </fileset>
</copy>

Want to copy files and change their names? Use a mapper element like this:

<copy todir="../backup">
    <fileset dir="src"/>
    <mapper type="glob" from="*" to="*.old"/>
</copy>

Here's how to copy a set of files to a directory, replacing @TODO@ with "DONE" in all copied files:

<copy todir="../backup">
    <fileset dir="src"/>
    <filter set>
        <filter token="TODO" value="DONE"/>
    </filter set>
</copy>

Warning

In Unix, file permissions are not retained when files are copied; files end up with the default UMASK permissions instead. If you need a permission-preserving copy function, use the system copy utilities—see the exec task in Chapter 7 (you'd use <exec executable="cp" ... > here). Or use the chmod task, coming up in this chapter, after the copy.

Example 4-3 uses copy to copy a documentation file to make sure it's included in the final JAR for a project and then deploys the JAR file to a directory named user.

Example 4-3. Using the copy task (ch04/copy/build.xml)

<?xml version="1.0" ?>
<project default="main">

    <property name="message" value="Deploying the .jar file." />
    <property name="src" location="source" />
    <property name="output" location="bin" />
    <property name="dist" location="user" />

    <target name="main" depends="init, compile, compress, deploy">
        <echo>
            ${message}
        </echo>
    </target>
  
    <target name="init">
        <mkdir dir="${output}" />
        <mkdir dir="${dist}" />
    </target>
  
    <target name="compile">
        <javac srcdir="${src}" destdir="${output}" />
    </target>
  
    <target name="compress">
        <copy todir="${output}" file="${src}/readme.txt"/>
        <jar destfile="${output}/Project.jar" basedir="${output}">
            <include name="*.class"/>
            <include name="*.txt"/>
        </jar>
    </target>

    <target name="deploy">
        <copy todir="${dist}">
            <fileset dir="${output}">
                <exclude name="*.java"/>
                <exclude name="*.class"/>
                <exclude name="*.txt"/>
            </fileset>
        </copy>
    </target>

</project>

You can see the attributes of this task in Table 4-11.

Table 4-11. The copy task's attributes

Attribute

Description

Required

Default

enablemultiplemappings

Specifies that you want to use multiple mapper elements. Available since Ant 1.6.

No

false

encoding

Specifies the encoding to use. For use when copying files using filters.

No

Defaults to default JVM encoding.

failonerror

Specifies whether you want the task to fail if there is an error.

No

true

file

Specifies the file you want to copy.

Yes, unless a nested fileset element is used.

 

filtering

Specifies whether you want to use filtering. Nested filterset elements will always be used; you don't have to set this attribute to true for that.

No

false

flatten

Specifies you want to ignore the directory structure of source files, copying all files into the directory given by the todir attribute.

No

false

includeEmptyDirs

Specifies you want to copy any empty directories as well.

No

true

outputencoding

Specifies the encoding you want to use when writing files. Available since Ant 1.6.

No

Defaults to the value of the encoding attribute if given, or the default JVM encoding otherwise.

overwrite

Specifies whether you want to overwrite existing files.

No

false

preservelastmodified

Specifies you want copied files to have the same modified time as the source files.

No

false

todir

Specifies the directory the files should be copied to.

If you use the file attribute, tofile or todir can be used. If you use nested fileset elements and if the number of files is more than 1 or if only the dir attribute is specified in the fileset, then only todir is allowed.

 
tofile

Specifies the file you want to copy to.

If you use the file attribute, tofile or todir can be used. If you use nested fileset elements and if the number of files is more than 1 or if only the dir attribute is specified in the fileset, then only todir is allowed.

 
verbose

Specifies you want to see filenames displayed as the files are being copied.

No

false

Tip

By default, files are only copied if the source file is newer than the destination file or when the destination file does not exist. However, you can explicitly overwrite files with the overwrite attribute.

You can use fileset elements inside copy elements to create a fileset to copy. If you want to use a fileset, the todir attribute must be set. You can use nested mapper elements, and filter set elements and the copy task supports nested FilterChains.

Warning

If you use filters in your copy operation, limit the operation to text files. Binary files will be corrupted by that kind of copy operation. This is true whether the filters are implicitly defined by the filter task or explicitly provided to the copy operation as filter sets.

Moving Files

The move task moves a file (copies and then deletes the original) to a new file or a new directory or it moves sets of files to a new directory. The attributes and nested elements are the same as for copy (see Table 4-11 and related sections).

Tip

By default, the destination file is overwritten if it already exists. When overwrite is turned off, files are only moved if the source file is newer than the destination file, or when the destination file does not exist.

Here's an example that moves a single file (the net result is that the file is renamed):

<move file="file.txt" tofile="file.backup"/>

Here's how to move a directory to a new directory:

<move todir="source">
    <fileset dir="backup"/>
</move>

Example 4-4 uses move to deploy the files it creates.

Example 4-4. Moving a file (ch04/move/build.xml)

<?xml version="1.0" ?>
<project default="main">

    <property name="message" value="Deploying the .jar file." />
    <property name="src" location="source" />
    <property name="output" location="bin" />
    <property name="dist" location="user" />

    <target name="main" depends="init, compile, compress, deploy">
        <echo>
            ${message}
        </echo>
    </target>
  
    <target name="init">
        <mkdir dir="${output}" />
        <mkdir dir="${dist}" />
    </target>
  
    <target name="compile">
        <javac srcdir="${src}" destdir="${output}" />
    </target>
  
  <target name="compress">
        <jar destfile="${output}/Project.jar" basedir="${output}" 
            includes="*.class" />
  </target>

  <target name="deploy">
    <move todir="${dist}">
      <fileset dir="${output}">
          <exclude name="*.java"/>
          <exclude name="*.class"/>
      </fileset>
    </move>
  </target>

</project>

Tip

For more examples, look at the section "Deploying By Copying".

Deploying Remotely Using FTP

The ftp task is handy for remote deployment. This task can send, receive, list, delete files, and create directories. This is one of Ant's optional tasks, so you'll need two JAR files, which you place in the Ant lib directory: jakarta-oro.jar (available from http://jakarta.apache.org/oro/) and commons-net.jar (available from http://jakarta.apache.org/commons/net/index.html).

Warning

If you want to use this task with MS FTP servers, you need a version of commons-net.jar and jakarta-oro.jar released after 02/01/2004, or a release of commons-net.jar after 1.1.0 and jakarta-oro.jar after 2.0.8.

Here's an example that deploys the results of a build to the directory /cgi-bin on a remote server. Since it's a bad idea to hardcode the username and password in build files, I'll set those as properties on the command line (you can use the input task here) using the properties name and password:

%ant -Dname=Steve -Dpassword=let_me_in

The build file is shown in Example 4-5. Before running the file, supply the IP address of the server by changing the value of the server attribute from "000.000.000.000" to the IP address of your server or use the name of the server, like "ftp.apache.org." Though you usually supply an action attribute telling ftp what to do, the default action is to send files (action="send"), so you can omit action here.

Example 4-5. Using ftp (ch04/ftp/build.xml)

<?xml version="1.0" ?>
<project default="main">

    <property name="message" value="Deploying the .jar file." />
    <property name="src" location="source" />
    <property name="output" location="bin" />

    <target name="main" depends="init, compile, compress, deploy">
        <echo>
            ${message}
        </echo>
    </target>
  
    <target name="init">
        <mkdir dir="${output}" />
    </target>
  
    <target name="compile">
        <javac srcdir="${src}" destdir="${output}" />
    </target>
  
    <target name="compress">
        <jar destfile="${output}/Project.jar" basedir="${output}">
            <include name="*.class"/>
            <include name="*.txt"/>
        </jar>
    </target>

    <target name="deploy">
        <ftp server="000.000.000.000" binary="true" verbose="true"
            userid="${name}" password="${password}" remotedir="/cgi-bin">
            <fileset dir="${output}">
                <exclude name="*.java"/>
                <exclude name="*.class"/>
                <exclude name="*.txt"/>
            </fileset>
        </ftp>
    </target>

</project>

Here's what running this build file looks like in Windows when uploading the results of a build to a remote server:

C:\ant\ch04\ftp>ant -Dname=steven -Dpassword=let_me_in
Buildfile: build.xml

init:
    [mkdir] Created dir: C:\ant\ch04\ftp\bin

compile:
    [javac] Compiling 1 source file to C:\ant\ch04\ftp\bin

compress:
      [jar] Building jar: C:\ant\ch04\ftp\bin\Project.jar

deploy:
      [ftp] sending files
      [ftp] transferring C:\ant\ch04\ftp\bin\Project.jar
      [ftp] 1 files sent

main:
     [echo]
     [echo]             Deploying the .jar file.
     [echo]

BUILD SUCCESSFUL
Total time: 10 seconds

That's it; you've deployed the results of the build remotely. Very cool!

Tip

If you want to build in delay times to take into account delays in getting responses from a server, use the Ant waitfor task. You can use the sleep task for this purpose.

To retrieve files from the server using ftp, you set action to get, the remotedir attribute to the remote directory, and the dir attribute to the directory you want the retrieved files stored in locally:

<ftp action="get"
    server="000.000.000.000"
    remotedir="/cgi-bin"
    userid="${name}"
    password="${password}">
    <fileset dir="docs">
        <include name="**/*.html"/>
    </fileset>
</ftp>

To delete files, set action to "del":

<ftp action="del"
    server="000.000.000.000"
    remotedir="/cgi-bin"
    userid="${name}"
    password="${password}">
    <fileset>
        <include name="**/*.html"/>
    </fileset>
</ftp>

To list files, set action to "list;" here's how to store the listing of files in the remote /cgi-bin directory in a file named file.list:

<ftp action="list"
    server="000.000.000.000"
    remotedir="/cgi-bin"
    userid="${name}"
    password="${password}"
    listing="ftp.list">
    <fileset>
        <include name="**"/>
    </fileset>
</ftp>

Here's how to create a directory, /cgi-bin, by setting action to "mkdir:"

<ftp action="mkdir"
    server="000.000.000.000"
    remotedir="/cgi-bin"
    userid="${name}"
    password="${password}"/>

Tip

You can remove directories; set action to rmdir.

You can see the attributes of this task in Table 4-12.

Table 4-12. The ftp task's attributes

Attribute

Description

Required

Default

action

Specifies the ftp action you want to perform. Possible values: put, get, del, list, chmod, mkdir and rmdir.

No

send

binary

Specifies the transfer mode. Possible values: binary-mode (yes) or text-mode (no).

No

yes

chmod

Specifies the file permissions for new or existing files (Unix only).

No

 

depends

Specifies you want to transfer only new or changed files. Set to yes/no.

No

no

ignoreNoncriticalErrors

Specifies you want to allow the task to continue despite some non-fatal error codes.

No

false

listing

Specifies a file to write output from the "list" action.

Required for the "list" action, but ignored otherwise.

 

newer

The same as the depends attribute.

No

 

passive

Specifies you want to use passive transfers.

No

no

password

Specifies the login password for the FTP server.

Yes

 

port

Specifies the port of the FTP server.

No

21

preservelastmodified

Specifies whether you want to give downloaded files the same modified time as the original files.

No

false

remotedir

Specifies a directory on the FTP server you want to use.

No

 

separator

Specifies the directory separator used on the target FTP server.

No

/

server

Specifies the address of the FTP server.

Yes

 

skipFailedTransfers

Specifies unsuccessful transfers should be skipped (with a warning).

No

false

timediffauto

Specifies if to make this task calculate the time difference between you and server. Available in Ant 1.6 or later.

No

 

timediffmillis

Specifies the number of milliseconds between times on the target machine compared to the local machine. Available since Ant 1.6.

No

 

umask

Specifies the default file permission (unix only).

No

 

userid

Specifies the login you want to use on the FTP server.

Yes

 

verbose

Specifies whether you want to see information on each file as it's transferred. Set to yes/no.

No

no

Tip

The condition task lets you probe if remote systems are available before attempting an FTP operationYou can use two nested elements in condition: http (which can test can probe for remote servers) and socket (which can send messages to remote servers).

The ftp task supports any number of nested fileset elements, which is how you specify the files to be retrieved, deleted, or listed, or whose mode you want to change.

Deploying Remotely Using Telnet

Ant includes a telnet task that you can use when deploying remotely. For security reasons, Telnet is losing popularity (in favor of SSH), but I'll take a look at telnet, followed by the sshexec task. This is one of Ant's optional tasks, so you'll need commons-net.jar (available from http://jakarta.apache.org/commons/net/index.html) in the Ant lib directory.

This task uses nested read elements to indicate strings to wait for and write elements to specify text to send. Here's an example that connects to a server, and asks for a listing of the directory /home/steven:

<telnet userid="steven" password="let_me_in" server="000.000.000.000">
     <read>/home/steven</read>
     <write>ls</write>
</telnet>

You can see the attributes of this task in Table 4-13.

Table 4-13. The telnet task's attributes

Attribute

Values

Required

Default

initialCR

Specifies that you want to send a carriage return after connecting to the server.

No

no

password

Specifies the login password you want to use on the Telnet server.

Yes, if userid is specified.

 

port

Specifies the port on the Telnet server to use.

No

23

server

Specifies the address of the remote Telnet server you want to use.

Yes

 

timeout

Specifies a default timeout for Telnet actions (in seconds).

No

No timeout

userid

Specifies the username to use to log into the Telnet server.

Yes, if password is specified.

 

Deploying Remotely Using SSH

The more secure SSH protocol is replacing Telnet in general use, and Ant 1.6 added the sshexec task to execute SSH commands on a remote system. This is an optional task, so you'll need jsch.jar (which you can get at http://www.jcraft.com/jsch/index.html) in the Ant lib directory. Here's an example that runs a command, touch, on a remote machine, using sshexec:

<sshexec host="000.000.000.000"
    username="${name}"
    password="${password}"
    command="touch index.html"/>

You can find the attributes of this task in Table 4-14.

Tip

See the scp task for copying files for deployment to web servers using SSH in Chapter 8.

Table 4-14. The sshexec task's attributes

Attribute

Description

Required

Default

append

Specifies if you want the output file to be appended to or overwritten.

No

false

command

Specifies the command to run remotely.

Yes

 

failonerror

Specifies whether you want to stop the build if there are errors.

No

true

host

Specifies the host you want to work with.

Yes

 

keyfile

Specifies the name of a file holding a private key.

Yes, if you are using key-based authentication.

 

knownhosts

Specifies the known hosts file. Used to check the identity of remote hosts. Must be an SSH2 format file.

No

${user.home}/.ssh/known_hostswn_hostts

output

Specifies the name of a file in which you want output written.

No

 

outputproperty

Specifies the name of a property in which you want output written.

No

 

passphrase

Specifies a passphrase you want to use for your private key.

No

""

password

Specifies the password to use for SSH.

No

 

port

Specifies the port to connect to.

No

22

timeout

Specifies whether you want the operation stopped if it timed out (in milliseconds).

No

0 (wait forever)

trust

Specifies if to trust all unknown hosts if set to "yes."

No

no

username

Specifies the username you want to use.

Yes

 

Deploying Remotely Through Email

You can deploy using email with the mail task, attaching files you want to deploy (attachments can be sent using the files attribute or nested fileset elements). You'll need access to an SMTP server, which you specify in the mailhost attribute and need two JAR files in the Ant lib directory: mail.jar (which you can get from http://java.sun.com/products/javamail/) and activation.jar (which you can get from http://java.sun.com/products/javabeans/glasgow/jaf.html).

Here's an example, where the results of a build are deployed as an attachment to an email message. This email has the subject "New Build", the message body "Here is the new build.", and has the build's newly created .tar.gz files attached:

<target name="deploy">
    <mail mailhost="smtp.isp.com" mailport="1025" subject="New Build">
        <from address="developer@isp.com"/>
        <replyto address="developer@isp.com"/>
        <to address="list@xyz.com"/>
        <message>Here is the new build.</message>
        <fileset dir="dist">
            <includes name="**/*.tar.gz"/>
        </fileset>
    </mail>
</target>

Now you're deploying via email using Ant. You can see the attributes of the mail task in Table 4-15.

Table 4-15. The mailTask's attributes

Attribute

Description

Required

Default

bcclist

List of addresses to send a blind copy of the email to. A comma-separated list.

At least one of tolist, cclist, bcclist, or the equivalent elements (to, cc, or bcc).

 

cclist

List of addresses to send a copy of the email to. A comma-separated list.

At least one of tolist, cclist, bcclist, or the equivalent elements (to, cc, or bcc).

 

charset

Specifies the character set you want to use in the email.

No

 

encoding

Specifies the encoding to use. Possible values are mime, uu, plain, or auto.

No

auto

failonerror

Specifies whether you want to stop the build if there are errors.

No

true

files

Specifies files you want to send as attachments. Use a comma-separated list. You can use nested fileset elements.

No

 

from

Specifies the email address of the sender.

Either a from attribute or a from element.

 

includefilenames

Specifies whether you want to include filename(s) before file contents.

No

false

mailhost

Specifies the hostname of the SMTP server.

No

localhost

mailport

Specifies the TCP port of the SMTP server to use.

No

25

message

Specifies the email's body.

One of message, messagefile, or a message element.

 

messagefile

Specifies a file to send as the email's body.

One of message, messagefile, or a message element.

 

messagemimetype

Specifies the type of the message's content.

No

text/plain

password

Specifies the password for SMTP authorization.

Yes, if SMTP authorization is required on your SMTP server.

 

replyto

Specifies the reply-to address.

No

 

ssl

Specifies if you want to use TLS/SSL.

No

 

subject

Specifies the email's subject.

No

 

tolist

Specifies a list of recipients. A comma-separated list.

At least one of tolist, cclist, bcclist, or the equivalent elements (to, cc, or bcc).

 

user

Specifies the username used to log into the SMTP server.

Yes, if SMTP authorization is required on your SMTP server.

 

The mail task can take nested to, cc, bcc, from, and replyto elements, which hold email addresses. Here are the attributes of these elements (these attributes are common across all these elements):

address

Specifies the email address

name

Specifies the display name for the email address

In addition, the nested message element sets the message to include in the email body. Here are the attributes of this element (all are optional):

charset

Specifies the character set used in the message

mimetype

Specifies the content type of the message

src

Specifies the file to use as the message

You can use email to send the results of a build with the mail logger, which is useful if you've set up unattended nightly builds with utilities like at in Windows or crontab in Unix (see Chapter 7 for coverage of both of these). Here's how you use this logger:

%ant -logger org.apache.tools.ant.listener.MailLogger

You set these properties in the build file to set up the email you want sent:

MailLogger.mailhost

Specifies the mail server to use (default: localhost)

MailLogger.port

Specifies the default port for SMTP (default: 25)

MailLogger.from

Specifies the mail "from" address (required)

MailLogger.failure.notify

Specifies if to send on failure (default: true)

MailLogger.success.notify

Specifies if to send on success (default: true)

MailLogger.failure.to

Specifies the address to send failure messages to (required if failure mail to be sent)

MailLogger.success.toSpecifies

The address to send success messages to (required if success mail to be sent)

MailLogger.failure.subject

Specifies the subject of failed build (default: "Build Failure")

MailLogger.success.subject

Specifies the subject of successful build (default: "Build Success")

Setting File Protections with chmod

The chmod task changes the permissions of a file or files, and it's useful in deployment after you've got your files deployed in case you need to set file permissions. You set the permissions in Unix style (just as the arguments for the Unix chmod command).

Here's an example that makes run.sh readable, writable and executable for the owner on a Unix system, and readable and executable for others:

<chmod file="${dist}/run.sh" perm="755"/>

This makes all .sh files in and below ${dist} readable and executable for anyone on a Unix system:

<chmod dir="${dist}" perm="ugo+rx" 
    includes="**/*.sh"/>

You can see the attributes for this task in Table 4-16.

Warning

At present, the chmod task only works in Unix and the NonStop Kernel (Tandem).

Table 4-16. The chmod task's attributes

Attribute

Description

Required

Default

defaultexcludes

Specifies if you want to use default excludes. Set to yes/no.

No

Default excludes are used.

dir

Specifies the directory holding the files to work on.

One of file, dir, or nested fileset/list elements.

 

excludes

Specifies the patterns matching files to exclude, as a comma- or space-separated list.

No

 

file

Specifies the file or single directory where you want permissions to be changed.

One of file, dir, or nested fileset/list elements.

 

includes

Specifies the patterns matching files to include, as a comma- or space-separated list.

No

 

maxparallel

Specifies limits on how many files to pass at once. Set this attribute to 0 or negative values for unlimited parallelism. Available in Ant 1.6 or later.

No

unlimited

parallel

Specifies the task should process multiple files using a single chmod command.

No

true

perm

Specifies the new permissions you want.

Yes

 

type

Specifies the target type. Possible values: file, dir, or both.

No

file

verbose

Specifies whether the task should display what it's doing as it does it. Available in Ant 1.6 or later.

No

false

This task holds an implicit FileSet and supports all of FileSet's attributes and nested elements directly. Since Ant 1.6, you can specify nested fileset or dirset elements, and you can use nested filelists.

Get Ant: The Definitive Guide, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.