Thursday, November 10, 2011

ANT- 'upToDate' to rescue build time overhead

I kind of performing a refactor on ANT Build.,

Goals in mind -

* Do not run ANT targets unnecessarly.
* Make build to get pass ant-clean test. (If there are no code changes and when you run ANT build nothing should happen.)

Observed -

* ANT was running unnecessarly for TARGETS that doesn't have code changes.
   Say the build contains
   3 targets -
    
          1. CodeGen - Do's, Sql's, Ejb's, Annotations
          2. Compile - Javac
          3. Package - Jar
     
      1. Target CodeGen It contains child targets GenDo's , GenSql's, GenEjb's, GenAnnotation's - ANT doesn't know when to run and not.
      2. Compile - Javac determines code changes and run on those files alone, thus reduces the build time.
      3. Package - Jar, Ant runs Jar target only If compiled set of files are modified, thus skips the unnecessary runs.
     
      A build with out refactor will try to run all the Code gen targets irrespect of Code changes, thus increases build time.
     
      So we need a way to tell ANT Skip Targets If there are no Code Changes made.
     
      ANT provides a mechanism called UP-TO-DATE
     
      It Sets a property if a target file or set of target files is more up-to-date than a source file or set of source files.
      A single source file is specified using the srcfile attribute.
      A set of source files is specified using the nested <srcfiles> elements. These are FileSets, whereas multiple target files are specified using a nested <mapper> element.

      By default, the value of the property is set to true if the timestamp of the target file(s) is more recent than the timestamp of the corresponding source file(s). You can set the value to something other than the default by specifying the value attribute.

      If a <srcfiles> element is used, without also specifying a <mapper> element, the default behavior is to use a merge mapper, with the to attribute set to the value of the targetfile attribute.

      Normally, this task is used to set properties that are useful to avoid target execution depending on the relative age of the specified files.
     
      For Example -
     
      If you need to do an xml build only If any changes made to DTD files, you can do this by., checking the timestamp of the final output.
     
          This can be written as:

          <uptodate property="xmlBuild.notRequired">
            <srcfiles dir= "${src}/xml" includes="**/*.dtd"/>
            <mapper type="merge" to="${deploy}\xmlClasses.jar"/>
          </uptodate>
     
        sets the property xmlBuild.notRequired to true if the ${deploy}/xmlClasses.jar file is more up-to-date than any of the DTD files in the ${src}/xml directory.
     
        The xmlBuild.notRequired property can then be used in a <target> tag's unless attribute to conditionally run that target. For example, running the following target:

        <target name="xmlBuild" depends="chkXmlBuild" unless="xmlBuild.notRequired">
          ...
        </target>

        will first run the chkXmlBuild target, which contains the <uptodate> task that determines whether xmlBuild.notRequired gets set. The property named in the unless attribute is then checked for being set/not set. If it did get set (ie., the jar file is up-to-date), then the xmlBuild target won't be run.
       
        Courtesy - http://www.jajakarta.org/ant/ant-1.6.1/docs/en/manual/CoreTasks/uptodate.html
       
        Thus you can Skip unnecessary Targets, and reduces build time a lot.