buildframework/helium/tools/publish/publish.ant.xml
changeset 1 be27ed110b50
child 179 d8ac696cc51f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/buildframework/helium/tools/publish/publish.ant.xml	Wed Oct 28 14:39:48 2009 +0000
@@ -0,0 +1,808 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+============================================================================ 
+Name        : publish.ant.xml 
+Part of     : Helium 
+
+Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+All rights reserved.
+This component and the accompanying materials are made available
+under the terms of the License "Eclipse Public License v1.0"
+which accompanies this distribution, and is available
+at the URL "http://www.eclipse.org/legal/epl-v10.html".
+
+Initial Contributors:
+Nokia Corporation - initial contribution.
+
+Contributors:
+
+Description:
+
+============================================================================
+-->
+<project name="publish" xmlns:hlm="http://www.nokia.com/helium">
+    <description>
+    Zipping, delta zipping and copying targets
+    </description>
+
+    <import file="subcon.ant.xml" />
+    <import file="internal-api/internal-api.ant.xml" />
+    <import file="nwiki.ant.xml" />
+    <import file="synergy.ant.xml" />
+    <import file="test/test2_publishing_to_diamonds.ant.xml" />
+
+    <property name="archive.max.number.of.threads" value="8" />
+    
+    <fileset id="publish.files" dir="${build.output.dir}">
+        <include name="logs/**/*" />
+        <exclude name="logs/**/*_ant_build.log" />
+        <include name="development_flash_images/**/*" />
+        <include name="release_flash_images/**/*" />
+        <include name="sisfiles/**/*" />
+        <include name="build_area/**/*" />
+        <include name="relnotes/**/*" />
+        <include name="test_results/**/*" />
+        <include name="utilities/**/*" />
+        <include name="images/**/*" />
+        <include name="variant_images/**/*" />
+        <include name="BaseForNightlyBuild.txt" />
+    </fileset>
+
+    <!-- above fileset divided into following 4 filesets-->
+    <fileset id="publish.files1" dir="${build.output.dir}">
+        <include name="logs/**/*" />
+        <exclude name="logs/**/*_ant_build.log" />
+    </fileset>
+    <fileset id="publish.files2" dir="${build.output.dir}">
+        <include name="development_flash_images/**/*" />
+    </fileset>
+    <fileset id="publish.files3" dir="${build.output.dir}">
+        <include name="sisfiles/**/*" />
+        <include name="build_area/**/*" />
+        <include name="relnotes/**/*" />
+        <include name="test_results/**/*" />
+        <include name="utilities/**/*" />
+        <include name="variant_images/**/*" />
+        <include name="images/**/*" />
+        <include name="BaseForNightlyBuild.txt" />
+    </fileset>
+    <fileset id="publish.files4" dir="${build.output.dir}">
+        <include name="release_flash_images/**/*" />
+    </fileset>
+
+    <!-- list of filesets -->
+    <property name="publish.fileset.ids" value="publish.files1,publish.files2,publish.files3,publish.files4" />
+
+    <fileset id="helium.files" dir="${helium.dir}">
+        <include name="*.bat" />
+        <include name="**/*.ant.xml" />
+        <include name="tools/common/**/*" />
+        <include name="tools/release/**/*" />
+    </fileset>
+
+    <!-- 
+        If publish property is set, copy the publish.files fileset to the publish.dir directory using 
+        number.of.threads parallel threads
+    -->
+    <macrodef name="publishMacro" uri="http://www.nokia.com/helium">
+        <sequential>
+            <if>
+                <isset property="publish" />
+                <then>
+                    <for list="${publish.fileset.ids}" param="fileset.id" parallel="true" threadCount='${number.of.threads}'>
+                        <sequential>
+                            <copy todir="${publish.dir}" preservelastmodified="true" failonerror="false">
+                                <fileset refid="@{fileset.id}" />
+                            </copy>
+                        </sequential>
+                    </for>
+                </then>
+            </if>
+        </sequential>
+    </macrodef>
+
+
+    <!-- Creates the publish directory. Directory location is defined by property: ${publish.dir} -->
+    <target name="prep-publish" if="publish">
+        <mkdir dir="${publish.dir}" />
+    </target>
+
+
+    <!-- Parses the zip configuration file. Expands all the ant properties. -->
+    <target name="preprocess-zip-config">
+        <property name="zip.config.file.parsed" location="${temp.build.dir}/zip.cfg.xml.parsed" />
+        <copy file="${zip.config.file}" tofile="${zip.config.file.parsed}" overwrite="true">
+            <filterchain>
+                <expandproperties />
+            </filterchain>
+        </copy>
+    </target>
+
+
+    <!-- This macro merges all the generated metadata files together.
+   
+    It uses the archiving configuration to find the output archive directory.
+    The it merges all the <config.name>.metadata.xml files together.
+    e.g:
+    <pre>
+    <hlm:mergeMetadataMacro file="${zip.config.file.parsed}" config="${zips.@{type}.spec.name}"/>
+    </pre>
+    -->
+    <scriptdef name="mergeMetadataMacro" language="jython" uri="http://www.nokia.com/helium">
+        <attribute name="file" />
+        <attribute name="config" />
+        <![CDATA[
+import configuration
+import symrec
+import os
+import traceback
+# Nicer name
+self.setTaskName("merge-metadata")
+
+def merge_filelist(merger, filelist):
+    for filename in filelist:
+        try:
+            self.log(str("Merging %s" % filename))
+            merger.merge(filename)
+            os.unlink(filename)
+        except Exception, exc:
+            self.log("Warning: %s" % exc)
+
+try:
+    builder = configuration.NestedConfigurationBuilder(open(str(attributes.get('file')), 'r'))
+    configSet = builder.getConfiguration()
+    configs = configSet.getConfigurations(str(attributes.get('config')))
+    
+    if len(configs) > 0:
+        filelist = []
+        for config in configs:
+            if config.get_boolean("grace.metadata", False):
+                metadata = os.path.join(config['archives.dir'], config['name']+ ".metadata.xml")
+                if os.path.exists(metadata):
+                    self.log(str("Found %s" % metadata))
+                    filelist.append(metadata)
+        
+        merger = None
+        metadata_main = os.path.join(configs[0]['archives.dir'], "release_metadata.xml")
+        if os.path.exists(metadata_main):
+            merger = symrec.MetadataMerger(metadata_main)
+            merge_filelist(merger, filelist)
+            self.log(str("Writing %s" % metadata_main))
+            merger.save()
+        elif len(filelist) > 0:
+            input = filelist.pop(0)
+            merger = symrec.MetadataMerger(input)
+            merge_filelist(merger, filelist)
+            self.log(str("Writing %s" % metadata_main))
+            merger.save(metadata_main)
+            os.unlink(input)
+except Exception, e:
+    self.log('ERROR: %s' % e)
+    traceback.print_exc()
+    # Let's propagate at the moment
+    raise e
+]]> 
+    </scriptdef>
+
+    <!-- This macro allows you to add or update one archive definition inside the release metadata files.
+    e.g.:
+    <pre>
+        <hlm:updateMetadataMacro file="<path>/release_metadata.xml" archive="<path>/archive.zip" />
+    </pre>
+     -->
+    <scriptdef name="updateMetadataMacro" language="jython" uri="http://www.nokia.com/helium">
+        <attribute name="file" />
+        <attribute name="archive" />
+        <attribute name="filters" />
+        <![CDATA[
+import symrec
+import os
+import traceback
+import fileutils
+self.setTaskName("updateMetadataMacro")
+if attributes.get('file') is None:
+    raise Exception('file attribute is not defined.')
+if attributes.get('archive') is None:
+    raise Exception('archive attribute is not defined.')
+filters = None
+if attributes.get('filters') is not None:
+    filters = str(attributes.get('filters')).split(r',')
+
+try:
+    filename = str(attributes.get('file'))
+    archive = str(attributes.get('archive'))
+    if not os.path.exists(filename):
+        raise Exception("Could not find file: %s" % filename)
+    if not os.path.exists(archive):
+        raise Exception("Could not find file: %s" % archive)
+
+    self.log(str("Opening %s" % filename))
+    md = symrec.ReleaseMetadata(filename)
+    if os.path.basename(archive) not in md.keys():
+        self.log(str("Adding %s to metadata" % os.path.basename(archive)))
+        md.add_package(os.path.basename(archive), md5checksum=fileutils.getmd5(archive), size=os.path.getsize(archive), filters=filters)
+    else:
+        self.log(str("Updating %s to metadata" % os.path.basename(archive)))
+        result = md[os.path.basename(archive)]
+        result['md5checksum'] = unicode(fileutils.getmd5(archive))
+        result['size'] = unicode(os.path.getsize(archive))
+        if filters is not None:
+            result['filters'] = filters
+        md[os.path.basename(archive)] = result
+    md.save()
+except Exception, e:
+    self.log('ERROR: %s' % e)
+    traceback.print_exc()
+    # Let's propagate at the moment
+    raise e
+]]> 
+    </scriptdef>
+    
+    <!-- This macro update the metadata file generated by the config provided by file.
+    e.g:
+    <pre>
+    <hlm:updateMD5Macro file="${zip.config.file.parsed}" config="${zips.@{type}.spec.name}"/>
+    </pre>
+    -->
+    <scriptdef name="updateMD5Macro" language="jython" uri="http://www.nokia.com/helium">
+        <attribute name="file" />
+        <attribute name="config" />
+        <![CDATA[
+import configuration
+import archive
+import os
+import symrec
+import traceback       
+
+self.setTaskName("update-md5")
+          
+# Reading the config from Ant
+try:
+    config_filename = str(attributes.get('file'))
+    spec_name = str(attributes.get('config'))
+    # Loading the config file.                        
+    builder = configuration.NestedConfigurationBuilder(open(config_filename, 'r'))
+    configSet = builder.getConfiguration()
+    configs = configSet.getConfigurations(spec_name)
+
+    if len(configs) > 0:
+        if os.path.exists(os.path.join(configs[0]['archives.dir'], "release_metadata.xml")):
+            md5update = symrec.MD5Updater(os.path.join(configs[0]['archives.dir'], "release_metadata.xml"))
+            md5update.update()
+            md5update.save()
+        else:
+            self.log(str('WARNING: Could not find %s.' % os.path.join(configs[0]['archives.dir'], "release_metadata.xml")))
+    else:
+        self.log('WARNING: No config.')
+except Exception, e:
+    self.log('ERROR: %s' % e)
+    traceback.print_exc()
+    # Let's propagate at the moment
+    raise e
+]]> 
+    </scriptdef>
+
+    <condition property="archive.using.ec">
+        <or>
+            <equals arg1="${build.system}" arg2="ec-helium" />
+            <equals arg1="${build.system}" arg2="sbs-ec" />
+        </or>
+    </condition>
+    
+    <!-- Zips files using a type and zip config file as args -->
+    <macrodef name="zipContentMacro" uri="http://www.nokia.com/helium">
+        <attribute name="type" />
+        <attribute name="file" />
+        <attribute name="ec" default="${archive.using.ec}"/>
+        <sequential>
+            <if>
+                <not>
+                    <isset property="zip.@{type}.log.file" />
+                </not>
+                <then>
+                    <property name="zip.@{type}.log.file" location="${build.log.dir}/${build.id}_@{type}_zip.log" />
+                </then>
+            </if>
+            <trycatch property="exception" reference="exception">
+                <try>
+                    <!-- Don't print 'compressing' on console -->
+                    <hlm:logtoconsole action="stop" />
+                    <!-- Stops writing on ...ant_build.log file-->
+                    <hlm:startSpecificLogMacro name="${zip.@{type}.log.file}" />
+            
+                    <property name="zip.config.file.parsed" location="${temp.build.dir}/zip.cfg.xml.parsed" />
+                    <copy file="@{file}" tofile="${zip.config.file.parsed}" overwrite="true">
+                        <filterchain>
+                            <expandproperties />
+                        </filterchain>
+                    </copy>
+                    <hlm:updateArchiveConfig configtype="${zips.@{type}.spec.name}" configfileparsed="${zip.config.file.parsed}" usingec="@{ec}" />
+                    <if>
+                        <istrue value="@{ec}" />
+                        <then>
+                            <echo>emake.root.to.append=${emake.root.to.append}</echo>
+                            <hlm:emakeMacro name="archive-full-@{type}" makefile="${build.drive}/ZIP_${zips.@{type}.spec.name}.make" target="all" dir="${build.drive}" annodetail="basic,history,file,waiting" root="${emake.root.to.append}" failonerror="false" />
+                        </then>
+                        <else>
+                            <if>
+                                <isgreaterthan arg1="${number.of.threads}" arg2="${archive.max.number.of.threads}"/>
+                                <then>
+                                    <ant antfile="${build.drive}/ZIP_${zips.@{type}.spec.name}.xml">
+                                        <property name="number.of.threads" value="${archive.max.number.of.threads}"/>
+                                    </ant>
+                                </then>
+                                <else>
+                                    <ant antfile="${build.drive}/ZIP_${zips.@{type}.spec.name}.xml" />
+                                </else>
+                            </if>
+                        </else>
+                    </if>
+                    <hlm:python>
+import archive
+import configuration
+
+builder = configuration.NestedConfigurationBuilder(open(r'${zip.config.file.parsed}', 'r'))
+configSet = builder.getConfiguration()
+configs = configSet.getConfigurations(r'${zips.@{type}.spec.name}')
+prebuilder = archive.ArchivePreBuilder(configuration.ConfigurationSet(configs), r'${zips.@{type}.spec.name}')
+prebuilder.cleanupSubstDrives()
+                    </hlm:python>
+                    <hlm:mergeMetadataMacro file="${zip.config.file.parsed}" config="${zips.@{type}.spec.name}" />
+                    <hlm:updateMD5Macro file="${zip.config.file.parsed}" config="${zips.@{type}.spec.name}" />
+                </try>
+                <catch>
+                    <!-- Printing and propagating the error -->
+                    <echo>ERROR: ${exception}</echo>
+                    <throw refid="exception"/>
+                </catch>
+                <finally>
+                    <!-- Todo: metadata: Convert to metadata structure -->
+                    <!-- Stops log back to main log. -->
+                    <hlm:stopSpecificLogMacro name="${zip.@{type}.log.file}" />
+                    <hlm:logtoconsole action="resume" />
+                </finally>
+            </trycatch>
+            <hlm:assertFileExists file="${zip.@{type}.log.file}" />
+            <copy file="${zip.@{type}.log.file}" tofile="${build.log.dir}/${build.id}_@{type}_archive.nopolicy.log" verbose="true">
+                <filterchain>
+                    <linecontainsregexp negate="true">
+                        <regexp pattern="POLICY_(ERROR|WARNING|INFO)" />
+                    </linecontainsregexp>
+                </filterchain>
+            </copy>
+            <hlm:metadatarecord database="${metadata.dbfile}">
+                <hlm:textmetadatainput>
+                    <fileset casesensitive="false" file="${build.log.dir}/${build.id}_@{type}_archive.nopolicy.log" />
+                    <metadatafilterset refid="filterset.archive.nopolicy" />
+                </hlm:textmetadatainput>
+            </hlm:metadatarecord>
+            <hlm:signalMacro logfile="${build.log.dir}/${build.id}_@{type}_archive.nopolicy.log" 
+                signal.input="archiveErrorSignalInput" />
+
+            <!-- Extracting policy errors from archiving. -->
+            <copy file="${zip.@{type}.log.file}" tofile="${build.log.dir}/${build.id}_@{type}_archive.policy.log" verbose="true">
+                <filterchain>
+                    <linecontainsregexp>
+                        <regexp pattern="POLICY_(ERROR|WARNING|INFO)" />
+                    </linecontainsregexp>
+                    <tokenfilter>
+                        <replaceregex pattern=".*(POLICY_(?:ERROR|WARNING|INFO))" replace="\1" flags="gi" />
+                    </tokenfilter>
+                </filterchain>
+            </copy>
+            <hlm:assertFileExists file="${build.log.dir}/${build.id}_@{type}_archive.policy.log" />
+            <hlm:metadatarecord database="${metadata.dbfile}">
+                <hlm:textmetadatainput>
+                    <fileset casesensitive="false" file="${build.log.dir}/${build.id}_@{type}_archive.policy.log" />
+                    <metadatafilterset refid="filterset.archive.policy" />
+                </hlm:textmetadatainput>
+            </hlm:metadatarecord>
+            <hlm:signalMacro logfile="${build.log.dir}/${build.id}_@{type}_archive.policy.log" 
+                signal.input="archivePolicyErrorSignalInput" />
+        </sequential>
+    </macrodef>
+    
+    <!--
+    1. To update the archive configuration file with substituted drives information for UNC paths (if any).
+    2. To create the .make file to zip the sources using EC.    
+    -->
+    <scriptdef name="updateArchiveConfig" language="jython" uri="http://www.nokia.com/helium">
+        <attribute name="configtype" />
+        <attribute name="configfileparsed" />
+        <attribute name="usingec" />
+        <![CDATA[
+import archive
+import configuration
+import logging
+import os
+
+config_parsed_filename = str(attributes.get('configfileparsed'))
+config_type = str(attributes.get('configtype'))
+is_it_ec = str(attributes.get('usingec'))
+                        
+builder = configuration.NestedConfigurationBuilder(open(config_parsed_filename, 'r'))
+configSet = builder.getConfiguration()
+configs = configSet.getConfigurations(config_type)
+
+outputtype = 'ant'
+outputext = '.xml'
+if is_it_ec == "true":
+    outputtype = 'make'
+    outputext = '.make'
+
+if len(configs) > 0:
+    prebuilder = archive.ArchivePreBuilder(configuration.ConfigurationSet(configs), config_type, outputtype)
+    if os.sep == '\\':
+        toAppendEmakeRoot = prebuilder.checkRootDirValue(builder, config_parsed_filename, project.getProperty('build.drive'), config_type)
+        if toAppendEmakeRoot is not None:
+            project.setProperty("emake.root.to.append", str(toAppendEmakeRoot))
+    prebuilder.writeTopLevel(os.path.join(project.getProperty('build.drive') + os.sep, 'ZIP_' + config_type + outputext), project.getProperty('temp.build.dir'), config_parsed_filename)       
+    
+else:
+    raise Exception('There are no archive configs to build. Looked for %s' % config_type)
+]]>
+    </scriptdef>
+    
+
+    <!-- Zips the Engineering English content. -->
+    <target name="zip-ee" unless="skip-zips">
+        <hlm:zipContentMacro type="ee" file="${zip.config.file}" />
+    </target>
+
+    <!-- Zips the subcon content. -->
+    <target name="zip-subcon" unless="skip-zips">
+        <hlm:zipContentMacro type="subcon" file="${zip.config.file}" />
+    </target>
+
+
+    <!-- Zips the subcon rom content. -->
+    <target name="zip-subcon-roms" unless="skip-zips">
+        <hlm:zipContentMacro type="subcon_roms" file="${zip.config.file}" />
+    </target>
+
+
+    <!-- Zips the localised content. -->
+    <target name="zip-localised" unless="skip-zips">
+        <hlm:zipContentMacro type="localised" file="${zip.config.file}" />
+    </target>
+
+
+    <!-- Zips the trace rom content -->
+    <target name="zip-trace-roms" unless="skip-zips">
+        <hlm:zipContentMacro type="trace_roms" file="${zip.config.file}" />
+    </target>
+
+
+    <!-- Zips the trace rom content -->
+    <target name="zip-uda-roms" unless="skip-zips">
+        <hlm:zipContentMacro type="uda_roms" file="${zip.config.file}" />
+    </target>
+
+
+    <!-- Zips .loc files into individual packages. -->
+    <target name="zip-loc-files">
+        <mkdir dir="${temp.loc.dir}" />
+        <exec executable="perl" dir="${build.drive}/" failonerror="${failonerror}">
+            <arg file="${helium.dir}/tools/publish/get_loc_files.pl" />
+            <arg value="${build.drive}" />
+        </exec>
+        <zip destfile="${loc.output.dir}/${loc.output.filename}" basedir="${temp.loc.dir}" />
+    </target>
+
+
+    <!-- Publishes the content defined by the filesets at the top of this project.
+    
+    The files are split into 4 filesets to parallelize the publish operation:
+    
+    * publish.files1
+    * publish.files2
+    * publish.files3
+    * publish.files4
+    
+    All content is copied to the location defined by publish.dir. Also verify the source and target content after publish.
+    -->
+    <target name="publish" depends="prep-publish" if="publish">
+        <hlm:publishMacro />
+        <resourcecount property="total.changes.in.fileset">
+            <fileset id="publish.files.location" dir="${build.output.dir}">
+                <exclude name="logs/**/*_ant_build.log" />
+                <exclude name="*" />
+                <exclude name="build/**/*" />
+                <exclude name="ec/**/*" />
+                <exclude name="temp_build_files/**/*" />
+                <exclude name="uda/**/*" />
+                <different targetdir="${publish.dir}" ignoreFileTimes="true" ignoreContents="yes" />
+            </fileset>
+        </resourcecount>
+        <if>
+            <not>
+                <equals arg1="${total.changes.in.fileset}" arg2="0" />
+            </not>
+            <then>
+                <echo message="ERROR: There are ${total.changes.in.fileset} changes in the publish directory. Uploading the changes again..." />
+                <hlm:publishMacro />
+            </then>
+        </if>
+    </target>
+
+
+    <!-- Basic publish target that publishes all important content. -->
+    <target name="publish-generic" depends="prep-publish,publish-tools" if="publish">
+        <hlm:publishMacro />
+    </target>
+
+
+    <!-- Publishes tools needed to run commands from a published build area. -->
+    <target name="publish-tools" depends="prep-publish" if="publish">
+        <echoproperties destfile="${publish.dir}/build_properties.txt">
+            <propertyset>
+                <propertyref name="publish.dir" />
+                <propertyref name="publish.release.dir" />
+            </propertyset>
+        </echoproperties>
+        <copy todir="${publish.dir}" preservelastmodified="true" failonerror="false">
+            <fileset refid="helium.files" />
+        </copy>
+        <copy todir="${publish.dir}" preservelastmodified="true" failonerror="false">
+            <fileset dir="${helium.dir}/tools/publish/publish_dir_files" includes="*" />
+        </copy>
+    </target>
+
+
+    <!-- The same as a basic publish. -->
+    <target name="publish-variants" depends="prep-publish" if="publish">
+        <hlm:publishMacro />
+    </target>
+
+
+    <!-- Notifies the lxr indexing engine that the build area is ready to be indexed. -->
+    <target name="lxr">
+        <copy todir="${lxr.publish.dir}" preservelastmodified="true" failonerror="false" flatten="true">
+            <fileset refid="publish.files" />
+        </copy>
+        <echo file="${lxr.publish.dir}\${build.id}_ready.txt" />
+    </target>
+
+
+    <!-- Mails the Diamonds XML data to the Diamonds server account. -->
+    <target name="mail-log-to-diamonds">
+        <runtarget target="lookup-email" />
+        <echo message="Sending XML log through email." />
+        <!--Ant mail task can not include xml as msg body. so do it in python-->
+        <!-- TODO - would this work by using a <message> subelement? -->
+        <hlm:python>
+import sys, smtplib, string
+            
+fromaddr = r'${email.from}'
+toaddrs  = r'${diamonds.mail}'
+smtpserver  = r'${email.smtp.server}'
+subject  = "[DIAMONDS_DATA] ${build.id}>>>${diamonds.host}>>>${diamonds.path}"
+file = open(r'${diamonds.log.file}', 'r')
+msg = file.read()
+body = string.join(("From: %s" %fromaddr, "To: %s" %toaddrs, "Subject: %s" %subject, "", msg), "\r\n")
+try:
+    server = smtplib.SMTP(smtpserver)
+    server.sendmail(fromaddr, toaddrs, body)
+    server.quit()
+    print "Mail sent to " , toaddrs
+except Exception:
+    print "SMTP server " + smtpserver + " unavailable!! Unable to send log to " , toaddrs
+    
+        </hlm:python>
+    </target>
+
+
+    <!-- Reports on the status of the build, through other targets. -->
+    <target name="report" depends="binary-sizes-log" unless="env.HLM_SUBCON">
+        <antcall target="rndsdk-create-api-descr-xml" />
+    </target>
+
+
+    <!-- Delta zips -->
+
+    <property name="delta.zip.location" value="${build.output.dir}/build_area/delta_zip" />
+    <property name="delta.zip.temp.location" value="${temp.build.dir}/delta_zip" />
+    <property name="delta.zip.file" value="${delta.zip.location}/${build.id}_delta_zip.zip" />
+    <property name="delta.zip.file.size" value="11000000" />
+    <!--default value of approx 11GB-->
+
+    <property name="delta.zip.delete.file" value="${delta.zip.location}/specialInstructions.xml" />
+    <property name="delta.ant.file" value="${delta.zip.temp.location}/delta_zip.ant.xml" />
+    <property name="md5.signature.file" value="${delta.zip.location}/${build.id}.md5" />
+    <property name="md5.split" value="100" />
+    <!-- old.md5.file needs to be specified by the user -->
+
+
+    <!-- Private: Patch evalid tool -->
+    <target name="patch-evalid">
+        <patch patchfile="${helium.dir}/tools/publish/evalidmd5.patch" originalfile="${build.drive}/epoc32/tools/evalidmd5.pm" />
+    </target>
+
+
+    <!-- Private: Revert evalid patch -->
+    <target name="unpatch-evalid">
+        <patch reverse="true" patchfile="${helium.dir}/tools/publish/evalidmd5.patch" originalfile="${build.drive}/epoc32/tools/evalidmd5.pm" />
+    </target>
+
+
+    <!-- Private: Copy extra tool for evalid -->
+    <target name="pre-build-md5" depends="patch-evalid">
+        <copy todir="${build.drive}\epoc32\tools" file="${helium.dir}/tools/publish/evalid_multiple.pl" />
+    </target>
+
+
+    <!-- Private: Revert patches -->
+    <target name="post-build-md5" depends="unpatch-evalid" />
+
+
+    <!-- Private: Generate a list of checksums for all files in the build area using EBS system -->
+    <target name="build-md5-ebs" depends="pre-build-md5">
+        <mkdir dir="${delta.zip.location}" />
+        <hlm:python failonerror="true">
+import os
+import delta_zip
+builder = delta_zip.MD5SignatureBuilderEBS("${build.drive}", r"${md5.split}", r"${delta.zip.temp.location}", r"${delta.exclude.commasep}", r"${delta.zip.temp.location}\list_files.txt")
+builder.build(r"${md5.signature.file}")       
+        </hlm:python>
+
+        <antcall target="post-build-md5" />
+    </target>
+
+    <!-- Private: Generate a list of checksums for all files in the build area using EC system -->
+    <target name="build-md5-ec" depends="pre-build-md5">
+        <mkdir dir="${delta.zip.location}" />
+        <echo>delta.zip.temp.location: ${delta.zip.temp.location}</echo>
+        <hlm:python failonerror="true">
+import os
+import delta_zip
+builder = delta_zip.MD5SignatureBuilderEC("${build.drive}", r"${md5.split}", r"${delta.zip.temp.location}", r"${delta.exclude.commasep}", "${ec.cluster.manager}", "${ec.build.class}", r"${delta.zip.temp.location}\list_files.txt")
+builder.build("${md5.signature.file}")       
+        </hlm:python>
+
+        <antcall target="post-build-md5" />
+    </target>
+
+
+    <!-- Generate a list of checksums for all files in the build area -->
+    <target name="build-md5">
+        <property name="delta.exclude.commasep" value="epoc32_save.zip,output/**/*,delta_zips/**/*,temp/**/*,epoc32/**/*.sym,epoc32/BUILD/**/*" />
+        <echo>build MD5 started</echo>
+        <if>
+            <isset property="build.system.ec-helium" />
+            <then>
+                <echo>build EC MD5</echo>
+                <antcall target="build-md5-ec" />
+            </then>
+            <else>
+                <echo>build EBS MD5</echo>
+                <antcall target="build-md5-ebs" />
+            </else>
+        </if>
+    </target>
+
+
+    <!-- Compare builds using md5 files and generate zips -->
+    <target name="generate-delta" if="old.md5.file.present">
+        <hlm:python>
+import delta_zip
+
+delta = delta_zip.DeltaZipBuilder(r'${build.drive}', r'${delta.zip.temp.location}', r'${old.md5.file}', r'${md5.signature.file}')
+delta.create_delta_zip(r'${delta.zip.file}', r'${delta.zip.delete.file}', r'${number.of.threads}', r'${delta.ant.file}')
+        </hlm:python>
+
+        <ant antfile="${delta.ant.file}" />
+
+        <hlm:python outputproperty="old.release.label">
+import ant
+import os
+md5file = os.path.basename(ant.get_property(r'${old.md5.file}'))
+print md5file.replace('.md5', '')
+        </hlm:python>
+
+        <move file="${delta.zip.delete.file}" todir="${delta.zip.temp.location}" />
+        <move file="${md5.signature.file}" todir="${delta.zip.temp.location}" />
+
+        <exec executable="C:\APPS\symrec\symrec" failonerror="${failonerror}">
+            <arg value="create" />
+            <arg value="-ser" />
+            <arg value="${release.grace.service}" />
+            <arg value="-pro" />
+            <arg value="${release.grace.product}" />
+            <arg value="-rel" />
+            <arg value="${release.label}" />
+            <arg value="-relroot" />
+            <arg value="${delta.zip.location}" />
+            <arg value="-dep" />
+            <arg value="${release.grace.service}/${release.grace.product}/${old.release.label}" />
+        </exec>
+
+        <move file="${delta.zip.temp.location}/specialInstructions.xml" tofile="${delta.zip.delete.file}" />
+        <move file="${delta.zip.temp.location}/${build.id}.md5" tofile="${md5.signature.file}" />
+
+    </target>
+
+
+    <!-- Set prop old.md5.file to md5 file from last build in publish dir -->
+    <target name="delta-use-last-build">
+        <property name="md5.current.build" value="${publish.dir}/build_area/delta_zip/${build.id}.md5" />
+        <hlm:python outputproperty="old.md5.file">
+import re
+import ant
+import os
+
+previousbuildnumber = 1
+buildnum = r"${build.number}"
+
+while(previousbuildnumber > 0 and previousbuildnumber != ''):
+    previousbuildnumber = ant.get_previous_build_number(buildnum)
+    
+    try:
+        md5lastbuild = re.sub(r'\.(${build.number})([\/_.])', r'.' + previousbuildnumber + r'\2', r'${md5.current.build}')
+        if os.path.exists(md5lastbuild):
+            print md5lastbuild
+            break
+    except ValueError:
+        print "Old MD5 cannot be found"
+    
+    buildnum = previousbuildnumber
+if not os.path.exists(md5lastbuild):
+    print "Old MD5 cannot be found"
+        </hlm:python>
+        <echo>old.md5.file: ${old.md5.file}</echo>
+        <available file="${old.md5.file}" property="old.md5.file.present" />
+        <echo>${old.md5.file.present}</echo>
+    </target>
+
+
+    <!-- Creates a delta from the prevous build to the current one -->
+    <target name="delta-zip" depends="delta-use-last-build,build-md5,generate-delta" description="Generate a delta between two build areas" />
+
+
+    <!-- Upload the delta and config into Grace -->
+    <target name="delta-zip-grace-upload">
+        <fileset id="grace.delta.zips.id" dir="${delta.zip.location}">
+            <include name="**/*.zip" />
+            <include name="**/*.xml" />
+        </fileset>
+
+        <antcall target="grace-upload">
+            <reference refid="grace.delta.zips.id" torefid="gracezips" />
+        </antcall>
+    </target>
+
+    <!-- Publishes the Ant build log.
+        
+    First the logging should be stopped, before the file is copied. Hence this target should be called
+    by the "final" target last.
+    -->
+    <target name="publish-build-log" depends="prep-publish" if="publish">
+        <record name="${build.log}" action="stop" append="true" />
+        <copy todir="${publish.dir}/logs" preservelastmodified="true" failonerror="false">
+            <fileset dir="${build.log.dir}" includes="${build.id}*_ant_build.log" />
+        </copy>
+    </target>
+
+
+    <!-- Does any wrap-up at the end of the build. This should be the last target for every top-level target. -->
+    <target name="final" depends="publish-build-log">
+    </target>
+    
+    <!-- This target will zip the WA depending on the ado mapping file -->
+    <target name="zip-wa" depends="ido-create-ado-mapping" if="zip.wa">
+        <tempfile property="zipwa.dynamic.config" suffix=".xml" deleteonexit="false" destdir="${temp.build.dir}"/>
+        <fmpp sourceFile="${helium.dir}/tools/common/templates/ido/zip-ant-wa-copy.xml.ftl" outputFile="${zipwa.dynamic.config}">
+            <data expandProperties="yes">
+                inputfile: antProperty(ado.mapping.file)
+                ant: antProperties()
+                data: eval('
+                    java.io.FileInputStream pin = new java.io.FileInputStream(filename);
+                    java.util.Properties props = new java.util.Properties();
+                    props.load(pin);
+                    return props;
+                    ', {filename:get(inputfile)})
+                </data>
+        </fmpp>
+        <ant antfile="${zipwa.dynamic.config}"/>
+    </target>
+
+</project>