<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Basil Vandegriend: Professional Software Development &#187; ANT</title>
	<atom:link href="http://www.basilv.com/psd/blog/tag/ant/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.basilv.com/psd</link>
	<description></description>
	<lastBuildDate>Wed, 25 Jan 2012 13:23:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Using Ivy to Manage Build Dependencies</title>
		<link>http://www.basilv.com/psd/blog/2009/using-ivy-to-manage-build-dependencies</link>
		<comments>http://www.basilv.com/psd/blog/2009/using-ivy-to-manage-build-dependencies#comments</comments>
		<pubDate>Mon, 01 Jun 2009 15:00:25 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[ANT]]></category>
		<category><![CDATA[automated build]]></category>
		<category><![CDATA[Ivy]]></category>
		<category><![CDATA[software development]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=406</guid>
		<description><![CDATA[Ivy is a tool for managing build dependencies within the Ant build tool. In this article I share my experiences using Ivy and provide recommendations on what to do and not do. This article is not a tutorial on using Ivy: for that see the Ivy documentation. Before getting into the specifics of Ivy, the [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://ant.apache.org/ivy/">Ivy</a> is a tool for managing build dependencies within the <a href="http://ant.apache.org/">Ant build tool</a>. In this article I share my experiences using Ivy and provide recommendations on what to do and not do. This article is not a tutorial on using Ivy: for that see the Ivy documentation.</p>
<p>Before getting into the specifics of Ivy, the first question to answer is why use Ivy at all? Why is managing build dependencies important? All the significant Java software I have worked on makes use of third-party libraries such as Hibernate for persisting objects to a relational database or JUnit for unit testing. Both the IDE projects and automated builds for these pieces of software have the common need to deal with these dependencies, most frequently by including them on the classpath for either compilation or at runtime. </p>
<p>These dependencies can be handled manually in an ad-hoc manner. This is what I have done in the past and what I have frequently observed to be done by other teams. But there are significant advantages to using a tool such as Ivy to manage these dependencies:</p>
<ul>
<li><em>Explicit tracking of the versions of the third-party software being used.</em> Too often I have come across projects with a library directory holding a collection of third-party jar files without any information as to the versions being used. Ivy supports defining dependencies explicitly by version number. If dependencies are defined more loosely, such as via a version range (e.g. version 1.0+), then Ivy can generate a report listing the specific versions used. Knowing the version of dependencies is important when trying to resolve issues or make use of the latest features.</li>
<li><em>Management of transitive dependencies.</em> If your software depends on third party software that itself has dependencies on other software, Ivy can automatically pull in these transitive dependencies. When multiple dependencies themselves depend on different versions of the same third-party software, Ivy can automatically resolve the conflict. An example will help illustrate this. Let us say that your software depends on two other libraries B and C. B in turn depends on D version 1.0 while C depends on D version 1.1. Ivy will pull in B, C, and D v1.1 and leave out D v1.0.</li>
<li><em>Standardized approach to storing dependencies.</em> Ivy uses one or more repositories of software as the source for obtaining dependencies. Each piece of software in these repositories is characterized by a standard set of metadata: the key attributes are organization, module, and revision. Using a public repository that the third-party software you require is updated within makes it trivial to upgrade to a new version: just change the version you depend on, and Ivy can then automatically download the new version. You can also use an enterprise repository to publish your own software into in order to facilitate reuse by others.</li>
</ul>
<p>There are a number of decisions to be made when using Ivy. In the remainder of this article I provide my experience and recommendations regarding these decisions.</p>
<h3>Building Classpaths</h3>
<p>There are two main options for building classpaths within your Ant build. The first is to use the <a href="http://ant.apache.org/ivy/history/2.1.0-rc1/use/cachepath.html">Ivy CachePath Ant task</a> to build an Ant path for your project's dependencies that references your local Ivy cache of dependencies. This nicely avoids any duplication of dependency information within your Ant build file. Unfortunately, the same cannot be done for your IDE classpath. Maven's solution is to generate the necessary IDE project files (e.g. Eclipse's .classpath file). The tooling support for Ivy to generate IDE files appears weak (I did not try it myself). Another limitation of this approach is that you will not have the libraries required for your project checked into version control. (You could, however, check an organizational repository into version control separately.)</p>
<p>The second option is to use the <a href="http://ant.apache.org/ivy/history/2.1.0-rc1/use/retrieve.html">Ivy Retrieve Ant task</a> to copy dependencies into your project workspace. You can specify the directory structure and file naming convention to use. I recommend copying the jars into a single lib directory (or one directory per Ivy configuration) and do not include revision information in the file names. This allows the classpath to be easily built in Ant using a simple fileset – e.g. <code>&lt;fileset dir="lib" includes="*.jar"/&gt;</code>. The IDE classpath must be manually maintained but at least keeping files revision-agnostic avoids needing to update the IDE when a dependency is upgraded. Because this lib directory is located within the project you can manage it in version control along with the rest of your project. One drawback of doing so, however, is that this lib directory full of jars now resembles a manual solution to maintaining dependencies so there is a risk that developers unfamiliar with the build or Ivy will directly add libraries to this lib path. I recommend using the retrieve task's option <code>sync="true"</code> to remove anything not specified as a current dependency.</p>
<p>I prefer the second option, partly because I am a fan of putting all project-related artifacts including third-party jars into version control, and partly because it makes it easier to manually manage the classpath within the IDE.</p>
<h3>Using Repositories</h3>
<p>Ivy requires at least one repository to be defined to obtain dependencies from and provides a number of options for doing so. One option is to use one or more public repositories: third-party repositories available over the Internet. Ivy provides built-in support for two: the public <a href="http://repo1.maven.org/maven2/">Maven repository</a>, which is probably the largest and best known repository, and <a href="http://www.jayasoft.fr/org/ivyrep/">IvyRep</a>, which only provides Ivy metadata for dependencies defined elsewhere (typically in the Maven repository). I recommend against using IvyRep: it appears it is no longer updated and I encountered errors resolving dependencies from it. The Maven repository seems like the best place to obtain third-party open source dependencies. You can use the site <a href="http://mvnrepository.com/">mvnrepository.com</a> to search for the metadata for the dependencies you are looking for.</p>
<p>The Maven repository does have its share of problems. Dependency metadata does not always match the directory structure or is plain wrong. For large projects like Hibernate or Spring with many dependencies, I was unable to resolve the complete set of their dependencies out of the Maven repository. I have also heard about and observed stability issues: sometimes downloads of dependencies fail. </p>
<p>Since I believe that builds must be reliable and repeatable I feel that relying solely on a public repository is a bad idea. The alternative is an organizational repository, which could be defined for the team or project or spanning the entire enterprise. In either case, Ivy supports a number of options for defining home-built repositories with my favorites being the local file system (typically on a shared network drive) or SFTP/SSH to access a remote file system. Ivy also supports defining a chain of repositories, so you could define an organizational repository first and then a public repository second. </p>
<p>The approach I prefer, however, is to only use an organizational repository for builds and use public repositories solely to install dependencies into the organizational repository. The <a href="http://ant.apache.org/ivy/history/2.1.0-rc1/use/install.html">Ivy Install Ant task</a> can be used to do this. It supports automatically installing transitive dependencies, which is very convenient but comes at a price. By default the install task fails if the dependency you are trying to install already exists in the target repository. This seems like reasonable behavior: you do not want to modify dependencies once they are installed. When combined with transitive dependencies, however, this is no longer useful: it is very likely that modules will have one or more common transitive dependencies, so when trying to install the second module, it will fail because it tries to transitively install a dependency that has already been installed. The workaround is to use the <code>overwrite="true"</code> option. I would prefer instead to have an option on the install task to ignore dependencies that are already installed.</p>
<p>When specifying a repository you must define the pattern used for the directory structure and file naming convention. My preferred pattern is: <code>${ivy-repository.dir}/[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision].[ext]</code>. Making the revision into a sub-directory allows Ivy to use atomic publishing. Specifying the optional classifier was required for certain dependencies that define, for example, source code and javadoc artifacts as well as the compiled code – without the classifier specified, all three artifacts resolve incorrectly to the same file (which Ivy fortunately identifies as an error).</p>
<h3>Defining Dependencies</h3>
<p>When defining dependencies for a module I believe that the general goal should be to use the minimum set of dependencies that are required. To do this effectively requires that you use configurations, which are basically defined sets of dependencies for a given module. Typical configurations include compile, runtime, and test. If you do not define the configuration(s) you want from a third-party module then Ivy defaults to pulling in all dependencies. For a third-party library like Spring which defines a large number of optional dependencies (in a configuration appropriately called "optional") this will result in pulling in a large number of jars that you simply do not require to compile or even run your code.</p>
<p>Should you explicitly define all your dependencies or automatically pull in transitive dependencies? One of the whole points of using a dependency management system like Ivy is to handle transitive dependencies, so I am a fan of using them. If you want to be aware of all the dependencies that are pulled in, you can produce a report using the <a href="http://ant.apache.org/ivy/history/2.1.0-rc1/use/report.html">Ivy Report Ant task</a> that lists all the resolved dependencies for a module. </p>
<h3>Conclusion</h3>
<p>If you use Ant for your builds then I highly recommend using Ivy to manage dependencies. For an example Ant+Ivy build check out the <em>Java Examples</em> project available for download from the <a href="http://www.basilv.com/psd/software">Software</a> page.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2009/using-ivy-to-manage-build-dependencies/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Add Logging to Ant Builds</title>
		<link>http://www.basilv.com/psd/blog/2007/how-to-add-logging-to-ant-builds</link>
		<comments>http://www.basilv.com/psd/blog/2007/how-to-add-logging-to-ant-builds#comments</comments>
		<pubDate>Sat, 15 Dec 2007 20:58:26 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[ANT]]></category>
		<category><![CDATA[automated build]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/blog/2007/how-to-add-logging-to-ant-builds</guid>
		<description><![CDATA[The Apache Ant build tool is a great aid in automating builds and deployments. When the build fails, however, diagnosing the problem can be painful - especially if it only occurs intermittently. Logging details of the Ant build can therefore be useful. By default Ant writes informational messages to the console. While this is usually [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://ant.apache.org/">Apache Ant build tool</a> is a great aid in automating builds and <a href="http://www.basilv.com/psd/blog/2007/automated-deploys-using-ssh-and-ant">deployments</a>. When the build fails, however, diagnosing the problem can be painful - especially if it only occurs intermittently. Logging details of the Ant build can therefore be useful.</p>
<p>By default Ant writes informational messages to the console. While this is usually sufficient for a successful build, more detail is often useful in the case of failed builds.  Relying on the console output for information about the build has limitations – there might be too much output to fix in the console's buffer, or you might clear or close the console. The solution is to write Ant's output to a log file. This can be done using the <code>&lt;record&gt;</code> task, which allows you to specify a log level of "verbose" or "debug" to provide more details than the standard "info" log level. This task should be the first one performed by the build for any target to ensure that a log is always produced. To accomplish this, I put the <code>&lt;record&gt;</code> task at the start of a target named "init" which I ensure is the first dependency of every other target. An example is given below:</p>
<pre class="prettyprint">
&lt;target name="init"&gt;
  &lt;record name="build.log" loglevel="verbose" append="false"/&gt;
&lt;/target&gt;
</pre>
<p>Normally I prefer to use the "verbose" level for the log file, as the "debug" level provides so much additional detail that it is only really useful for debugging bad behavior within Ant code. Notice that I specified the option <code>append="false"</code> which ensures that at the start of the build any existing log file is deleted and a new one created. This makes it easier to see what happens for an individual execution of the build and avoids having the log become too large. This can be a problem, however, if you need to refer back to the log from a prior build to resolve problems or for auditing purposes. I have had situations where after a build fails I look at the build log for the problem, run some other ant target (such as clean) before I have finished resolving the problem, then realize that I have wiped the record of the problem. </p>
<p>One solution to this issue is to create a separate log file for each execution of the build. This can be done by using a build timestamp as part of the log file name, as shown in the below example:</p>
<pre class="prettyprint">
&lt;target name="init"&gt;
  &lt;tstamp&gt;
    &lt;format property="timestamp" pattern="yyyy-MM-dd_HH-mm-ss"/&gt;
  &lt;/tstamp&gt;
  &lt;property name="build.log.dir" location="${basedir}/buildlogs"/&gt;
  &lt;mkdir dir="${build.log.dir}"/&gt;
  &lt;property name="build.log.filename" value="build_${timestamp}.log"/&gt;
  &lt;record name="${build.log.dir}/${build.log.filename}"
    loglevel="verbose" append="false"/&gt;
  &lt;echo message="Build logged to ${build.log.filename}"/&gt;
&lt;/target&gt;
</pre>
<p>The log files are written to a <code>buildlogs</code> subdirectory to avoid cluttering the main directory. For some reason the <code>&lt;record&gt;</code> task requires an absolute path when specifying a directory, so the <code>build.log.dir</code> property is prefixed with <code>${basedir}</code>. After setting up the logging, a message is written to the console displaying the log filename used to make it easier to look up the log file if a problem occurs. This approach will cause log files to accumulate within the log directory. If this becomes a problem, you could add some Ant logic to delete log files older than a certain date. I will leave the implementation of this as an exercise to the reader. Hint: use a <code>&lt;delete&gt;</code> task with a <code>&lt;fileset&gt;</code> that contains a <code>&lt;date&gt;</code> selector.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2007/how-to-add-logging-to-ant-builds/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Automated Deploys using SSH and Ant</title>
		<link>http://www.basilv.com/psd/blog/2007/automated-deploys-using-ssh-and-ant</link>
		<comments>http://www.basilv.com/psd/blog/2007/automated-deploys-using-ssh-and-ant#comments</comments>
		<pubDate>Thu, 01 Nov 2007 14:39:23 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[ANT]]></category>
		<category><![CDATA[automated build]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[SSH]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/blog/2007/automated-deploys-using-ssh-and-ant</guid>
		<description><![CDATA[I am a big proponent of automating the building and deployment of application code: this minimizes the chance of human error and ensures a consistent process is followed. Last year I wrote an article about automatically deploying code via FTP using the Java-based Apache Ant build tool. Since then I have needed to deploy to [...]]]></description>
			<content:encoded><![CDATA[<p>I am a big proponent of automating the building and deployment of application code: this minimizes the chance of human error and ensures a consistent process is followed. Last year I wrote an article about <a href="http://www.basilv.com/psd/blog/2006/automating-ftp-with-ant">automatically deploying code via FTP</a> using the Java-based <a href="http://ant.apache.org/">Apache Ant build tool</a>. Since then I have needed to deploy to servers which do not have FTP enabled for security reasons. The alternative is to use <a href="http://en.wikipedia.org/wiki/Secure_Shell">SSH</a>, a secure network protocol which supports the transfer of files via SFTP or SCP. This article describes how to automate deployments using SSH and Ant.</p>
<p>Ant ships with two relevant tasks: <code>&lt;scp&gt;</code> and <code>&lt;sshexec&gt;</code>. Both of these tasks require the third-party library <a href="http://www.jcraft.com/jsch/">Java Secure Channel (Jsch)</a> to provide a Java implementation of the SSH protocol. The <code>jsch.jar</code> file should be placed in the <code>/lib</code> directory of your Ant installation. While these tasks support both the SSH 1 and SSH 2 protocols, SSH 2 is preferred because it is much more secure. Use of SSH 2, however, requires Ant version 1.7.0 or greater. </p>
<p>Using the <code>&lt;scp&gt;</code> task appears at first glance to be quite similar to the <code>&lt;ftp&gt;</code> task. Here is an example:</p>
<pre class="prettyprint">
&lt;scp remoteTodir="${user}@${server}:${target.dir}"
  password="${password}"
  trust="yes"
  sftp="true"&gt;
    &lt;fileset dir="${source.dir}"&gt;
      &lt;include name="**/*"/&gt;
    &lt;/fileset&gt;
&lt;/scp&gt;
</pre>
<p>This transfers files from <code>${source.dir}</code> on your machine running the Ant build to the directory <code>${target.dir}</code> on the machine <code>${server}</code>. Despite the similarity to the <code>&lt;ftp&gt;</code> task, there are several significant differences:</p>
<ul>
<li>SCP transfers files as binary copies only and has no support for the ASCII transfer mode of FTP. This means that transferring text files between operating systems (Windows, Unix, Mac) can cause problems as the line ending characters vary across the three operating systems. The solution is to use the <code>&lt;fixcrlf&gt;</code> task to convert the line endings of text files before or after they are transferred.</li>
<li>SCP transfers all the files in the fileset every time, whereas the FTP task supports transferring only newer files.</li>
<li>SCP provides no mechanism for setting the file access permissions of newly created or existing files. On UNIX operating systems, SCP grants read &#038; write access to the file owner and no permissions for the group or the world (other). These restrictive permissions are seldom appropriate – executable files should have the execute flag set and often the group needs read &#038; execute permission. The solution I use to fix the permissions is to run a script on the target server using the <code>&lt;sshexec&gt;</code> task after the <code>&lt;scp&gt;</code> task to fix the permissions on the files &#038; directories. This script is maintained as part of the code base and transferred to the target server via SCP along with the rest of the code. Below is an example of using <code>&lt;sshexec&gt;</code> to do this.</li>
</ul>
<pre class="prettyprint">
&lt;sshexec host="${server}"
  username="${user}"
  password="${password}"
  trust="yes"
  command="perl -W ${target.dir}/bin/post_deploy_configuration.pl"
/&gt;
</pre>
<p>One capability that the <code>&lt;scp&gt;</code> and <code>&lt;sshexec&gt;</code> tasks have that the <code>&lt;ftp&gt;</code> task lacks is the ability to use <a href="http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter8.html#pubkey">public key authentication</a> instead of passwords. One significant advantages of using keys instead of passwords for an automated build is that keys do not expire, whereas passwords are often required to expire regularly. Keys are also much more secure in situations when the server or the network between the build machine and the server is at risk of being compromised. </p>
<p>The downside to using public key authentication is that some up-front work is required to set up and install the keys. The necessary steps are:</p>
<ul>
<li>Create a new key pair, either using the SSH software on your server or using an utility such as <a href=" http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html">PuTTYgen</a>. You should end up with a file holding the public key, a file holding the private key, and a passphrase for accessing the private key.</li>
<li>Ensure the private key is stored in the openssh format, which is what the Jsch library used by the <code>&lt;scp&gt;</code> and <code>&lt;sshexec&gt;</code> tasks requires. PuTTYgen, for example, by default stores private keys in PuTTY's format but can convert a key to openssh format.</li>
<li>Install the public key on the target server under the user id being used by the build. This involves copying the public key file into a specially-named subdirectory of the user's home directory and adding an entry listing the public key file to a special file within this subdirectory. The name of the subdirectory and special file depends on the specific operating system and specific version of SSH being used.</li>
<li>Make the private key available to the build machine.</li>
<li>Change your build.xml to include the following attributes for the <code>&lt;scp&gt;</code> and <code>&lt;sshexec&gt;</code> tasks instead of the <code>password</code> attribute: <code>keyfile="${key.file}"</code> <code>passphrase="${passphrase}"</code>. Just like with passwords, do not embed the passphrase directly within build.xml. I store it in a property file which along with the private key is stored in a secured non-public location available to the build machine.</li>
</ul>
<p>The <code>&lt;sshexec&gt;</code> task is limited to executing a single command on the server. The <a href="http://sourceforge.net/projects/sshtools">SSHTools project</a> provides a more powerful <code>&lt;ssh&gt;</code> Ant task that supports automating an interactive remote session. Below is an example:</p>
<pre class="prettyprint">
&lt;ssh host="${server}"
  username="${user}"
  password="${password}"
  verifyhost="false"
&gt;
  &lt;shell term="vt100"&gt;
    &lt;write&gt;whoami&lt;/write&gt;
    &lt;read timeout="50000"&gt;${user}&lt;/read&gt;
    &lt;write&gt;chmod -R u+rwx,g+rx ${target.dir}&lt;/write&gt;
    &lt;write&gt;echo Done&lt;/write&gt;
    &lt;read timeout="50000"&gt;Done&lt;/read&gt;
  &lt;/shell term="vt100"&gt;
&lt;/ssh&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2007/automated-deploys-using-ssh-and-ant/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>EnvGen &#8211; the Environment-Specific File Generator</title>
		<link>http://www.basilv.com/psd/blog/2007/envgen-the-environment-specific-file-generator</link>
		<comments>http://www.basilv.com/psd/blog/2007/envgen-the-environment-specific-file-generator#comments</comments>
		<pubDate>Sun, 18 Feb 2007 22:24:24 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[ANT]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[EnvGen]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/blog/2007/new-software-envgen-%e2%80%93-the-environment-specific-file-generator</guid>
		<description><![CDATA[I have added a new software utility called EnvGen to my Software page. EnvGen is an Ant task for generating different versions of the same file parameterized for different environments (i.e. development, test, and production). File generation is done using FreeMarker, a template engine with a full-featured templating language. You specify environment-specific properties in a [...]]]></description>
			<content:encoded><![CDATA[<p>I have added a new software utility called <strong>EnvGen</strong> to my <a href="http://www.basilv.com/psd/software">Software</a> page. EnvGen is an <a href="http://ant.apache.org/">Ant</a> task for generating different versions of the same file parameterized for different environments (i.e. development, test, and production). File generation is done using <a href="http://freemarker.sourceforge.net/">FreeMarker</a>, a template engine with a full-featured templating language. You specify environment-specific properties in a CSV file (comma separated value spreadsheet). EnvGen functions similar to Ant's Copy task: you run EnvGen against one or more source filesets into a target directory. Rather than simply copying each file over, EnvGen generates a version of the target file for each environment specified in the properties CSV file. Usually the target directory or filename is parameterized by environment so that EnvGen writes each version to a different physical file.</p>
<p>In my previous article on <a href="http://www.basilv.com/psd/blog/2007/designing-for-deployability">Designing for Deployability</a>, I wrote about generating files per environment as one approach to handling environmental differences. EnvGen is designed to allow you to easily use this approach. </p>
<p>You can read more about EnvGen in the <a href="http://www.basilv.com/psd/software-files/EnvGen/index.html">EnvGen Release Documentation</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2007/envgen-the-environment-specific-file-generator/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automating FTP with ANT</title>
		<link>http://www.basilv.com/psd/blog/2006/automating-ftp-with-ant</link>
		<comments>http://www.basilv.com/psd/blog/2006/automating-ftp-with-ant#comments</comments>
		<pubDate>Thu, 14 Dec 2006 15:00:48 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[ANT]]></category>
		<category><![CDATA[automated build]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[FTP]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/blog/2006/automating-ftp-with-ant</guid>
		<description><![CDATA[This article describes how to automate the transfer of files between servers via FTP using the Java-based ANT build tool. I have been using ANT to do automated FTP for a number of years now, and will share some of the lessons and limitations I have discovered. ANT provides a FTP task. It requires the [...]]]></description>
			<content:encoded><![CDATA[<p>This article describes how to automate the transfer of files between servers via FTP using the Java-based <a href="http://ant.apache.org/">ANT build tool</a>. I have been using ANT to do automated FTP for a number of years now, and will share some of the lessons and limitations I have discovered. </p>
<p>ANT provides a FTP task. It requires the installation of two external libraries into ANT's <code>\lib</code> directory: <a href="http://jakarta.apache.org/oro/">Jakarta ORO</a> and <a href="http://jakarta.apache.org/commons/net/">Jakarta Commons Net</a>. The FTP task connects to a remote server via the FTP protocol and provides all the basic FTP operations: send files, get files, delete files, create directories, delete directories, and change permissions. For the full details on how to use the FTP task, see the ANT manual's <a href="http://ant.apache.org/manual/OptionalTasks/ftp.html">entry on the FTP task</a>. </p>
<p>For my website, I use the FTP task to transfer my server logs to my local workstation for analysis. Here is an example (using ANT version 1.6.5):</p>
<pre class="prettyprint">
&lt;ftp action="recv"
  server="ftp.server"
  remotedir="/logs"
  userid="my-userid"
  password="my-password"
  verbose="yes"
&gt;
  &lt;fileset dir="${log.dir}"&gt;
      &lt;include name="*.log"/&gt;
  &lt;/fileset&gt;
&lt;/ftp&gt;
</pre>
<p>This task transfers the files named <code>*.log</code> from the directory <code>/logs</code> of the server <code>ftp.server</code> to the <code>${log.dir}</code> directory on your local machine.</p>
<p>At work, I usually use the FTP task for <a href="http://www.basilv.com/psd/blog/2006/deploying-application-changes">deploying application changes</a> - sending a set of files built on my local workstation or development server to the test or production server. Here is an example:</p>
<pre class="prettyprint">
&lt;ftp action="send"
  server="ftp.server"
  userid="my-userid"
  password="my-password"
  remotedir="/incoming"
  depends="yes"
  binary="no"
  chmod="755"
&gt;
  &lt;fileset dir="${ftp.source.dir}"&gt;
      &lt;include name="**/*"/&gt;
  &lt;/fileset&gt;
&lt;/ftp&gt;
</pre>
<p>This task transfers all the files within the local directory <code>${ftp.source.dir}</code> to the directory <code>/incoming</code> of the server <code>ftp.server</code>. Files in sub-directories are also transferred into corresponding sub-directories on the remote server, and the sub-directories are created if they do not already exist. Only new or changed files are actually transferred (<code>depends="yes"</code>). The files are transferred in ASCII mode (<code>binary="no"</code>). Assuming the remote server runs UNIX, the permissions of the files are set to 755 (<code>chmod="755"</code>). </p>
<p>Using the FTP task to deploy a set of files has a number of limitations, especially if these files are organized into a hierarchy of directories. While the FTP task will automatically create sub-directories as required, I have not found a way to ensure that the required directory permissions are assigned for new directories (this assumes the remote server runs UNIX). In particular, the <code>chmod</code> attribute is only assigned to new files, not new directories. The only workaround I have found is to execute a script on the server that assigns the necessary directory permissions. Another limitation is that the FTP task will not create empty directories. If you want to create a particular directory structure on the remote server, then each directory you want created must have at least a single file in it. The workaround is to create a dummy file to ensure the directory is created.</p>
<p>Deleting obsolete files and directories on the remote server is also difficult for a couple of reasons. The FTP task does provide all the basic FTP operations, including deleting files and directories. But each is handled as a separate action which requires a separate invocation of the FTP task, instead of performing all the operations within a single FTP session. This is a minor inconvenience. The more significant limitation is in determining how to delete obsolete files and directories. The development build usually assembles a set of files to transfer to the server without caring about the individual files or directories - it just assembles a directory structure. Therefore, if certain files or directories are deleted or renamed, this just results in a new set of files without the build process knowing which are to be deleted. Therefore, automating the deletion of these obsolete files by listing each one is quite difficult. An easier approach would be to simply delete all the files and directories deployed to the server and then re-deploy the new set. This solution also has its problems. First, this requires recreating all the sub-directories, which as I explained above leads to the problem of ensuring their permissions are properly configured. Second, the directory structure into which files are deployed may include files created by server processes which cannot or should not be deleted, such as server logs or application data files. The workaround I use to deal with obsolete files and directories is to simple leave them in place - they typically have no impact on the operation of the system. But I am on the lookout for a better solution to this problem - if you know of any, please let me know via a comment. </p>
<p>Despite the limitations, I have been pleased with my experiences using ANT to automate FTP tasks. I encourage you to give it a try.</p>
<p><strong>Update June, 2009</strong>: I have had questions about what version of the ORO and Commons Net libraries to use, as not all versions are compatible. I have had success with Ant 1.7, Commons Net 1.4.0, and Jakarta ORO 2.0.8.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2006/automating-ftp-with-ant/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

