Showing posts with label ant. Show all posts
Showing posts with label ant. Show all posts

Monday, July 13, 2015

Ant Properties

If you are a Java programmer, you should be familiar with properties which are used to maintain the list of key-value pairs. Ant properties too store key-value pairs.

Ant properties play an important role during the build as the placeholder for key/value pairs. To successfully run Ant build, some of the useful properties must be set first and then read it during appropriate targets. So you set it once and can use it multiple times during the build.  You might need build number, app name etc during multiple targets (during generating jar, war or ear). Let's explore it:

Create Properties

Ant provides property task to create properties. Depending on the scope we can create them at the top of the build.xml file or in the specific target.

<!-- simple key value pairs -->
<property name="build.debug" value="true"/>
<property name="blog.name" value="geekrai"/>

<!-- location attribute converts relative path to an absolute path-->
<property name="release.dir" location="../release" />

In the second case, release.dir property stores platform agnostic path of the release directory.  So, depending on underlying OS (Window/Unix/Mac) it will appropriately store the release directory path.

Reading Properties

Property value can be read by surrounding it with ${}.


<echo message="user.name = ${user.name}"/>
<echo>release.dir = ${release.dir}</echo>



So, quite logically the property needs to be defined first before reading its value. Here, Ant does an incredible job of providing some pre-populated in-build properties. So you can just use them without bothering for declaration.

Common inbuilt-properties
ant.file: Absolute path of build file
ant.home: Absolute path of Ant installation directory
ant.java.version: Ant detected JVM version
basedir: Absolute path of projects home directory
user.name: Username

This list is quite big, if you want to see the full list provided by Ant, use below target ($ant printAll).

<target name="printAll">
    <echoproperties />
</target>

Loading from a Properties file

Properties by default are put in the build file, but you can organize them into a separate properties file as well. This helps in easy management of properties, especially if your build file is quite huge. So to achieve this, we can create build.properties in the root directory of the project.

#sample property from build.property file
app.name=AntDemo
build.debug=true
#end of file

It can be loaded using Ant property task as shown below:
<property file="build.properties">

But, do keep in mind that properties are loaded as simple string values so if you set relative file path, it stays as it (unlike location). Also, Ant uses java.util.Properites class to load properties so you should do proper escaping for backslash (\ into \\).


Setting from Command Line

Until now, we discussed about setting properties in build file or separate file. Ant also allows to dynamically set the value of a property. If the value is already getting assigned in build file, then it will get overridden with this approach. Remember, the first assignment rules!

$ant -D<<propertyName=value>> <<target>>
$ant -Dapp.name=dummy build

So in above example, app.name value will become dummy. This always takes precedence. The reason for this is that, properties are immutable so once set it will not change during the course of that build process. 


---
keep coding !!!

Sunday, July 12, 2015

Ant Data Types

As users of Ant build systems, we deal mostly with targets ($ant target). Targets, use multiple tasks(or actions) to achieve the goal. Echoing something to console, making directory, compiling source file are some of the commonly occurring tasks in Ant build. Task requires some inputs like a list of files, list of jars, known as datatypes in Ant world. 

Ant datatype store piece of information during the build, for example, list of files, to be created, compiled, deleted etc.  The datatypes can be declared inside a task or can be declared outside and then passed to task as a parameter. The second approach allows you to share the datatype in multiple tasks with the reference.  To stress on the concepts, I have abstracted some of the datatypes into simple targets:

File Set

Fileset datatype can abstract list of files to be compiled, copied, detected, tested etc. This datatype basically refers to set of files contained in a given directory (including files in subdirectories). Let's take a simple example of copying files from one directory to another directory:

//build.xml

<?xml version="1.0"?>
<project name="AntDemo">
 <fileset id="source.fileset" dir="src"/>

 <target name="copy1">
  <copy todir="backup1">
    <fileset refid="source.fileset"/>
  </copy>
 </target>
 
 <target name="copy2">
  <copy todir="backup2">
    <fileset dir="src"/>
  </copy>
 </target>
 
</project>

So, there are two approaches to copy files. In the first approach (copy1), we have declared a reference to the list of all Java files inside src directory. This is helpful if you want to do this activity multiple times. The second approach (copy2) is more traditional and provides all details inside the same element. For the first approach to work make sure that fileset was defined earlier.

$ant copy1
$ant copy2

Both targets perform the same operation. i.e. copy all files from src directory and copy them over to the backup directory.

Pattern Set

In above example, both targets will copy all files from the src directory. Now, what if you want to copy, say, only java files. Pattern set filters files from the given directory.

//build.xml

<?xml version="1.0"?>
<project name="AntDemo">
 <target name="copyJava">
  <delete dir="backup"/>
  <copy todir="backup">
    <fileset dir="src" includes="**/*.java"/>
  </copy>
 </target>
 
 <target name="copyJava2">
  <delete dir="backup"/>
  <copy todir="backup">
    <fileset dir="src">
     <include name="**/*.java"/>
    </fileset>
  </copy>
 </target>
 
 <patternset id="java.files.only">
     <include name="**/*.java"/>
     <exclude name="**/*.js"/>
 </patternset>
 
 <target name="copyJavaOnly">
  <delete dir="backup"/>
  <copy todir="backup">
    <fileset dir="src">
      <patternset refid="java.files.only"/>
    </fileset>
  </copy>
 </target> 
</project>

Above build.xml shows multiple ways you can apply filter to fileset.

**/*.java - matches all the java files in directory and sub-directories.
*.java - matches only java files in the given directory

File List

This data type is similar to fileset and it's useful when you need to order set of files. Also filelist can be applied on non-existent files.  Shown below a task which creates files.

 <touch>
  <filelist dir="." files="1.txt,2.txt">
   <file name="web.xml" />
   <file name="*.txt" />
  </filelist>
 </touch>

*.txt will just create a single file with name, *.txt.


Filter Set

During the build process, we might need to dynamically fill in values of the file with today's date or build number. Ant has a specific data type of handle this scenerio, filterset.

Below task copies, version.txt from build directory to dist directory and replaces the token @DATE with today's date.

 <copy file="${build.dir}/version.txt" toFile="${dist.dir}/version.txt">
  <filterset>
   <filter token="DATE" value="${TODAY}" />
  </filterset>
 </copy>

More examples, here.


Path

Path data type in Ant is used to represent Java CLASSPATH or the PATH environment variable of Unix/Windows systems. It's an ordered list of elements where each element can be either a file or directory.  We can separate individual elements with either color or semicolon (: or ;). Also for directories, we can choose either Unix style (forward slash, /) or Windows style (backward slash, \). Ant handles it properly depending on the type of system.

If path structure consists of a single path or location or with multiple files:
<path location="lib/junit.jar" />

<path>
 <pathelement path="build/classes;lib/junit.jar" />
</path>



Can be used below approach if path consists of set of files:
<path>
  <fileset dir="lib">
    <include name="*.jar"/>
  </fileset>
</path>


---
keep coding !!!


Saturday, July 4, 2015

Invoking Java class through Ant

Ant is a powerful tool which can run Java programs as well as part of your build process. This might be helpful in running a utility class during the build. It can also be handy to do smoke testing by running some of the test classes during the build. Literary you can perform any operation during the build if you are able to call a Java class.

This post, I will discuss creating a dedicated target to run a Java class.

Create Java Project

Let's create a sample Java project with a single class file with the main method so that it can be invoked from an external tool (i.e. Ant).




/**
 * Sample Java class
 * @author Siddheshwar
 *
 */
public class RunMe{
 public static void main(String[] args){
     System.out.println("Inside main method of RunMe");
            if(args.length !=0 ){
              System.out.println("you passed argument="+args[0]);
            }  
       }
} 

build.xml

<?xml version="1.0"?>
<project name="AntSample" default="compile">
 <!--Declare common properties  -->
 <property name="src.dir"     value="src"/>
 <property name="build.dir"   value="build"/>
 <property name="RunMe-class"  value="RunMe"/>
 <property name="classes.dir" value="${build.dir}/classes"/>

 <!-- init target to clean up existing build directory -->
 <target name="clean">
  <delete dir="${build.dir}"/>
 </target>

 <!--Before running a Java class; that class should be compiled   -->
 <target name="compile" depends="clean">
  <echo>compilation started -</echo>
  <mkdir dir="${classes.dir}"/>
  <javac srcdir="src" destdir="build/classes" />
  <echo>compilation complete!</echo>
 </target>

 <!--Execute the java class   -->
 <target name="execute" depends="compile">
  <java classname="RunMe" classpath="build/classes">
   <arg value="hello" />
   <arg file="." />
  </java>
 </target>

 <!-- abstracts clean and execute target -->
 <target name="main" depends="clean,execute"/>
</project>


Executing Java class

In build.xml file execute target is declared to run the Java class. Before running the class it should have been compiled and that's the reason for adding dependency on compile target. This way when we run execute target, it will run compile first. Target, execute provides all information required for running a program. It provides name of the class (i.e. className) as well as path of class through classpath. It also passes an argument to the main method having value hello. 
The last argument file, tells Ant to resolve that attribute to an absolute file location. 

That's it; you are done!

Now let's run the class: 
I have given below multiple options for running the Java program (Ant Cheat Sheet), you can call any of them:

$ant execute
or
$ant main
or
$ant compile execute
or
$ant clean compile execute

Response

$ant main
Buildfile: /Users/siddheshwar/Documents/gitRepo/AntSample/build.xml

clean:
   [delete] Deleting directory /Users/siddheshwar/Documents/gitRepo/AntSample/build

compile:
     [echo] compilation started -
    [mkdir] Created dir: /Users/siddheshwar/Documents/gitRepo/AntSample/build/classes
    [javac] /Users/siddheshwar/Documents/gitRepo/AntSample/build.xml:18: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 1 source file to /Users/siddheshwar/Documents/gitRepo/AntSample/build/classes
     [echo] compilation complete!

execute:
     [java] Inside main method of RunMe
     [java] you passed argument=hello

main:

BUILD SUCCESSFUL
Total time: 0 seconds

--

Keep coding!

Saturday, April 25, 2015

Ant Cheat Sheet

This post list some of the commonly used ant commands and shortcuts.

Test if ant is installed
$ant -version
Ant is a command-line tool so it must be on the path to be used. If Ant is installed, above command will return version details otherwise it will say that ant command is not found (i.e. Ant is not installed).

It gives below response when I run it on my Mac:
Apache Ant(TM) version 1.9.2 compiled on July 8 2013

Running ant target(s)
$ant                                     //runs default target
$ant compile                       //runs compile target
$ant <target1> <target2>    //runs multiple targets

Generate verbose log during build
$ant -verbose        //runs default target in verbose mode
$ant <target> -verbose
$ant <target> -v   // v is shortcut for verbose
Ant produces verbose log when invoked with -verbose (or -v) parameter. This is useful to figure out what's going out during build and specially when build fails.

Generate debug log during build
$ant -debug                 //runs default target in debug mode
Debug prints more log information than verbose. This option prints lot more low-level details along with verbose details.
$ant -quiet                  //to see nothing but errors and final build status message
$ant -keep-going        //tells ant to try to recover from failure

List all targets
$ant -projecthelp        //or -p
$ant -p -verbose         // list sub-targets as well
Lists all the targets provided by build file. Ant list only public targets with optional description attribute. To see optional targets also along with main targets run above command with -verbose.

Pass a property dynamically

$ant execute -Dproperty=value
Passes a key value (property) pair to the ant build. This will override if the property already exist in the build or config file.

Get build sequence
Target dependency is transitive. So if the build file is quite huge then knowing the dependency becomes quite difficult. To get it, I often run the build in verbose mode and then grep for the given String.

$ant -v main | grep "Complete build sequence is"
Complete build sequence is [clean, compile, execute, main, ]

Help
$ant -help     //or -h
If you don't remember this cheat sheet, just ask ant to help. It will give all the options which ant supports. I have covered some of them here, but some other useful options like providing your own build file other than build.xml etc are not covered here.