<

Publishing you websites using ANT scripts

Published on
13,419 Points
7,219 Views
2 Endorsements
Last Modified:
Approved
Community Pick
Are you into PHP development and curious how you can make your life easier when publishing your website? Do you sometimes worry you might forget to remove debug lines? Or you spend unnecessary time to double check you haven't accidentally uploaded 'phpinfo.php' or some local development powerscripts that shouldn't be online?

A first step in automating your website publishing is to automate your deployment process. Besides the fact you can stop worrying, you may even include some great optimizations, that might look complex and time consuming when done manually.

1. Introduction to ANT


In the world of software development there are several tools you can use to automate your software development. Tools like ANT, Maven, and Phing help you to compile files, swap in your optimized dependencies, run unit tests, create deployment packages and do all kinds of other cool stuff from a mouseclick.

ANT (http://ant.apache.org/) is an Apache project that allows you to specify routines using simple xml and property files. It is often used in java projects, although Maven has a large market share as well. For the PHP language, Phing could be instead or, depending on your personal taste, you can use Maven or ANT, like I used here.

A simple ANT buildscript consist of 'targets' which you can run one by one or in sequences.

2. A simple ANT script: upload your files


A very basic ANT script could be used to upload your files to your server, but exclude your local uploads, debug and temp files:
[mywebsite.build.xml]
<project name="myWebsite">

  <property name="ftp.host" value="ftp.mywebsite.com" />
  <property name="ftp.username" value="your-ftp-username" />
  <property name="ftp.password" value="your-ftp-password" />
  <property name="ftp.folder" value="httpdocs/myproject/" />

  <target name="uploadWebsite">
   <ftp server="${ftp.host}"
         userid="${ftp.username}"
         password="${ftp.password}"
         remotedir="${ftp.folder}"
   >
      <fileset dir="c:/xampp/www/myproject">
          <exclude name="uploads/**/*.*" />
          <exclude name="debug/**/*.*" />
          <exclude name="temp/**/*.*" />
       </fileset>
    </ftp>
  </target>
</project>

Open in new window


The snippet shows you the basic usage of property tags. You configure one or more at the top of your buildscript, and easily reference them throughout the script.

After downloading and installing ANT you can write a simple .bat or .cmd file or bash script to run the script:
[uploadWebsite.bat]
c:/Apache-ant/bin/ant.exe -f mywebsite.build.xml uploadWebsite

Open in new window


Each time you double click the bat file, or run a similar bash script from command line, you can be sure that only the files you specified are uploaded.

3. Loose coupling: Using property files


In the last section I showed a simple example of using the property tag (e.g. <property name="some-property" value="some-value" />). In ANT you can use separate .properties files (simple INI files) to list your settings:
[myproject.build.properties]
# FTP Settings
ftp.host          = ftp.mywebsite.com
ftp.username = your-ftp-username
ftp.password = your-ftp-password
ftp.folder        = httpdocs/myproject/

Open in new window


The property file can be included in your project using the snippet below:
<project name="myWebsite">
  <property file="myproject.build.properties" />
  
  .. my targets here ..
 </project>

Open in new window


Note that when a property has been set, it cannot be overwritten!

4. Multiple environments: Using target chains


As a professional or semi-professional PHP developer you will probably have a test server you need to deploy to before deploying to production. You might even have a complete OTAP street with four or more servers. Using ANT you can now use the same deployment routines for as many environments as required.
To make the ANT script aware of our multiple environments, we start by upgrading the property file to hold multiple server information sets:
[myproject.build.properties]
# FTP Settings for test
ftp.test.host          = ftp.mywebsite.com
ftp.test.username = your-ftp-username
ftp.test.password = your-ftp-password
ftp.test.folder        = subdomains/test/httpdocs/myproject/

# FTP Settings for production
ftp.production.host          = ftp.mywebsite.com
ftp.production.username = your-ftp-username
ftp.production.password = your-ftp-password
ftp.production.folder        = httpdocs/myproject/

Open in new window


Unless we tell ANT exactly, the script will not know which environment we want to use. Therefore we create additional targets, each for a specific environment. The newly created target's sole task is to start the deployment using the correct environment settings. This is done by calling the uploadWebsite target, and passing the environment settings as target parameters:

<project name="myWebsite">

   <property file="myproject.build.properties" />

  <target name="uploadWebsiteToTest">
     <antcall target="uploadWebsite">
       <param name="ftp.host"     value="${ftp.test.host}" />
       <param name="ftp.username" value="${ftp.test.username}" />
       <param name="ftp.password" value="${ftp.test.password}" />
       <param name="ftp.folder"   value="${ftp.test.folder}" />
     </antcall>
  </target>

  <target name="uploadWebsiteToProduction">
     <antcall target="uploadWebsite">
	     	<param name="ftp.host"     value="${ftp.production.host}" />
     		<param name="ftp.username" value="${ftp.production.username}" />
     		<param name="ftp.password" value="${ftp.production.password}" />
     		<param name="ftp.folder"   value="${ftp.production.folder}" />
     </antcall>
  </target>

  <target name="uploadWebsite">
   <ftp server="${ftp.host}"
         userid="${ftp.username}"
         password="${ftp.password}"
         remotedir="${ftp.folder}">
      <fileset dir="c:/xampp/www/myproject">
          <exclude name="uploads/**/*.*" />
          <exclude name="debug/**/*.*" />
          <exclude name="temp/**/*.*" />
       </fileset>
    </ftp>
  </target>
</project>

Open in new window


To conclude this section, we need to make the new targets run able by adding additional BAT files (or bash scripts). Note that you can easily upgrade the setup to include as many environments as you like, by adding properties, targets and BAT or bash scripts.

[uploadWebsiteToTest.bat]
c:/Apache-ant/bin/ant.exe -f mywebsite.build.xml uploadWebsiteToTest

[uploadWebsiteToProduction.bat]
c:/Apache-ant/bin/ant.exe -f mywebsite.build.xml uploadWebsiteToProduction

Open in new window



5. Including some optimizations


With a basic understanding on how ANT works (we can use it to copy some files, re-use code, use properties), we have just scratched the surface of what automated deployment can do for web development projects. This section will show a basic process which probably benefits all web projects: Javascript and CSS optimization.

There are many different techniques you can use to improve your website's performance. An easy to implement optimization is to minimize your CSS and Javascript automatically as part of the deployment process. Using the ANT script the development files will not be affected, but the scripts on the live website will always be compact and tidy. The key to minifying Javascript and CSS files is a compressor tool. Yahoo provided the web development world with their great YUICompressor (http://developer.yahoo.com/yui/compressor/). Using the YUI compressor we can take any CSS or Javascript file and minify (compress and cleanup) them:
<!-- We need to know where the yuicompressor is located -->
<property name="yui.jar" value="path/to/yuicompressor-2.4.2.jar" />

<!-- @param yui.src  The source file
<!-- @param yui.dest The name of the minimized file -->
<!-- @param yui.type Use "css" or "js" -->
<target name="yuicompress">
		<java jar="${yui.jar}" fork="true">
			<arg value="-v" />
			<arg value="-o" />
			<arg value="${yui.src}" />
			<arg value="--type" />
			<arg value="${yui.type}" />
			<arg value="--line-break" />
			<arg value="60" />
			<arg value="${yui.dest}" />
		</java>
</target>

Open in new window


By having this target in our script we can now start to compress files. To make sure we don't accidentally overwrite our source files, we first copy the tree of source files to a temporary folder (often referred to as the build directory). Inside the build directory the optimizations are performed, leaving the source files unharmed, after which the optimized files are uploaded to the servers.

  <property name="build.dir" value="build" />

  <target name="build" depends="clean">
    <!-- Make sure the build directory exists -->
    <mkdir dir="${build.dir}">
    
    <!-- Copy our files to create a build set -->
    <copy todir="${build.dir}">
      <fileset dir="c:/xampp/www/myproject">
      	<exclude name="uploads/**/*.*" />
      	<exclude name="debug/**/*.*" />
      	<exclude name="temp/**/*.*" />
      	<exclude name="build/**/*.*" />
      </fileset>
    </copy>    
    
    <!-- Start optimizing -->
    <antcall target="yuicompress">
      <param name="yui.src"  value="${build.dir}/scripts/main.js" />
      <param name="yui.dest" value="${build.dir}/scripts/main.js" />
      <param name="yui.type" value="js" />
    </antcall>

    <antcall target="yuicompress">
      <param name="yui.src"  value="${build.dir}/css/styles.css" />
      <param name="yui.dest" value="${build.dir}/css/styles.css" />
      <param name="yui.type" value="css" />
    </antcall>
  </target>

  <!-- An extra target we can use to cleanup before starting a fresh build -->  
  <target name="clean">
    <delete dir="${build.dir}" />
  </target>

Open in new window


6. Putting it all together


We know how to upload and how to do some optimizations by using a temporary build folder. The final step for this tutorial is bringing it all together by showing some additional ANT methods. In our original multi-environment buildscript we used the uploadWebsiteToTest and uploadWebsiteToProduction targets to call the generic uploadWebsite target using the environment specific parameters. Because we want to insert the optimizations from the previous section we copy the build target and change the uploadWebsite to include it:
<target name="uploadWebsite" depends="build">
 <ftp server="${ftp.host}"
       userid="${ftp.username}"
       password="${ftp.password}"
       remotedir="${ftp.folder}">
    <fileset dir="${build.dir}" />
  </ftp>
</target>  

Open in new window


Notice the depends attribute on the target name? This is ANT's way of saying "We need to run the 'build' target every time before we run 'uploadWebsite'".

So by starting our uploadWebsiteToTest/uploadWebsiteToProduction we actually get the following targets run one after another:

1. uploadWebsiteToTest / uploadWebsiteToProduction
2. cleanup
3. build
4. uploadWebsite

You are probably wondering where the 'cleanup' target came from? It was added as a "depends" attribute to "build", just like the "build" target was added before the uploadWebsite target.

By now you can imagine that using just a basic set of ANT calls you have a very powerful deployment, just a mouse-click away.

Think of how powerful your scripts could get if you added:

- Automatically set your website in 'maintenance' mode by uploading a maintenance.txt to your server using an additional <FTP> task and deleting it at the end of your deploy.

- Automatically create a 'mywebsite-{currentdate}.zip' file in your backup folder by using ANT's <tstamp> and <zip> tasks

- Combine all those jQuery libraries into a single (compressed) file using ANT's <concat> with the 'yuicompress' target

- Call a diagnostics or cache cleaning PHP script on your server after FTP-ing, using ANT's <get> task.

- Mail your test team automatically at the end of your test deploy using ANT's <mail> task.

- Strip out debug sections in PHP, CSS and Javascript using ANT's <regexplreplace>:
<?php
  /* <debug> */
  // This code is for development purposes only. Luckely ANT removes it in our build
  set_time_limit(0);
  ini_set('display_errors','1');
  error_reporting(E_ALL);
  /* </debug> */
?>
[code]

[code]
<script type="text/javascript">
  /* <debug> */
  if(typeof console == "undefined") { 
    alert("Please use firebug. It will make your development life easier");
  } 
  /* </debug> */
?>
</script>

Open in new window


The possibilities are numerous and the time invested in setting up a good build and deploy script are probably returning on their investment in as little as four or five runs.
myproject.build.xml.php-ant.txt
2
Comment
Author:Roonaan
0 Comments

Featured Post

Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

Join & Write a Comment

Video by: Mark
This lesson goes over how to construct ordered and unordered lists and how to create hyperlinks.
Learn how to create flexible layouts using relative units in CSS.  New relative units added in CSS3 include vw(viewports width), vh(viewports height), vmin(minimum of viewports height and width), and vmax (maximum of viewports height and width).

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month