<?xml version="1.0" encoding="UTF-8"?>
<!-- 
============================================================================ 
Name        : preparation.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:

============================================================================
-->
<!--* @package preparation -->
<project name="preparation" xmlns:hlm="http://www.nokia.com/helium">
    <description>Preparation of a build area and other build initialization.</description>
    
    <!--* @property prep.config.file
    Defines configuration file used in prep-copy target. The file defines how files are copied and extracted into build area.
    @type string
    @editable required
    @scope public
    -->
    
    <!-- includes all necessary stuff -->
    <!-- To check which ccmgetinput helium will be use
    @type string
    -->
    <property name="ccmgetinput" value="ccmgetinput" />
    
    <!--* Set to false to skip diamonds.
    @type boolean
    @editable required
    @scope public
    @since 11.0
    -->
    <property name="diamonds.enabled" value="true"/>

    
    <!--* @property internal.diamonds.enabled
    Run the diamonds related targets if diamonds.enabled is set to true.
    @type boolean
    @scope private
    -->
    
    <!--* @property skip.diamonds 
    Set to true to skip diamonds. - deprecated: Start using diamonds.enabled property.
    @type boolean
    @editable required
    @scope public
    @deprecated since 11.0
    -->       
    
    <!--* @property ccm.enabled
    Defines that property if you want the ccm-get-input step to be run during the build area preparation.
    @type boolean
    @editable required
    @scope public
    -->
        
    <!--* @property internal.ccm.enabled
    Set to run synergy targets if ccm.enabled set to true.
    @type boolean
    @scope private
    -->
    
    <!--* @property remote.builds.enabled
    Set to true to run the builds on remote machines.
    @type boolean
    @scope public
    @editable required
    @since 11.0
    -->
    
    <!--* @property internal.remote.builds.enabled
    Set to run remote build targets if remote.builds.enabled set to true.
    @type boolean
    @scope private
    -->
    
    <!-- Check, is diamonds feature enabled -->
    <condition property="internal.diamonds.enabled">
        <and>
            <not>
                <isfalse value="${diamonds.enabled}" />
            </not>
            <not>
                <isset property="skip.diamonds"/>
            </not>
        </and>
    </condition>
    
    <!-- Check, is synergy enabled -->
    <condition property="internal.ccm.enabled">
        <istrue value="${ccm.enabled}"/>
    </condition>
    
    <!-- Check, is synergy enabled -->
    <condition property="internal.remote.builds.enabled">
        <istrue value="${remote.builds.enabled}"/>
    </condition>
    

    <typedef file="${ant.file.preparation}/../preparation.antlib.xml" uri="http://www.nokia.com/helium"/>
    <import file="bom/bom.ant.xml" />
    <import file="password.ant.xml" />
    <import file="ido-prep.ant.xml" />
    <import file="synergy/ccmgetinput.ant.xml" />
    <import file="synergy/buildmanagement.ant.xml" />
    <import file="ivy/dependencies.ant.xml"/>


    <!-- Gets a release from network drive. -->
    <target name="preparation-getenv" if="base_release.path" depends="init-build-area">
        <!-- Making sure we have nothing to pass -->
        <property name="base_release.path" value=""/>
        <property name="base_release.getenv_options" value=""/>
        <!-- Using the cleaned version of getenv.pl -->
        <!-- Defines the location of the getenv.pl script.
        @type string
        @scope private
        -->
        <property name="getenv.tool.location" location="${helium.dir}/tools/preparation/getenv.pl"/>
        <hlm:tempRecordStartMacro name="${build.id}_getenv.log"/>        
        <trycatch>
            <try>
                <if>
                    <not>
                        <equals arg1="${base_release.getenv_options}" arg2="" />
                    </not>
                    <then>
                        <exec executable="perl" dir="${build.drive}/" failonerror="true">
                            <arg value="${getenv.tool.location}"/>
                            <arg value="-start"/>
                            <arg value="-path"/>
                            <arg value="${base_release.path}"/>
                            <arg line="${base_release.getenv_options}"/>
                        </exec>
                    </then>
                    <else>
                        <exec executable="perl" dir="${build.drive}/" failonerror="true">
                            <arg value="${getenv.tool.location}"/>
                            <arg value="-start"/>
                            <arg value="-nosoap"/>            
                            <arg value="-path"/>
                            <arg value="${base_release.path}"/>
                        </exec>
                    </else>
                </if>
            </try>
            <catch>
                <echo message="Error: getenv failed"/>
            </catch>
        </trycatch>
        <hlm:tempRecordStopMacro name="${build.id}_getenv.log" filterref="filterset.getenv" phase="prep"/>
    </target>

        
    <!-- Removes an older build area from a machine, based on a count of 
    how many build areas to maintain at a time.
    -->
    <target name="delete-old-build-area" if="build.area.limit">
        <dirset id="build.area.dirs" dir="${prep.root.dir}" includes="${build.name}*"/>
        <resourcecount property="build.area.count">
            <dirset refid="build.area.dirs"/>
        </resourcecount>
        <if>
            <scriptcondition language="jython">
                <![CDATA[
if project.getProperty("build.area.count") > project.getProperty("build.area.limit"):
    self.value = True
                ]]>
            </scriptcondition>
            <then>
                <math result="num.to.delete" operand1="${build.area.count}" operation="-" operand2="${build.area.limit}" datatype="int"/>
                <pathconvert property="build.area">
                    <first count="${num.to.delete}">
                        <sort xmlns:rcmp="antlib:org.apache.tools.ant.types.resources.comparators">
                            <rcmp:date/>
                            <dirset refid="build.area.dirs"/>
                        </sort>
                    </first>
                </pathconvert>
                <echo>${build.area}</echo>
                <shellscript shell="cmd.exe" tmpsuffix=".bat" dir="${prep.root.dir}">
                    <arg value="/c"/>
                    <arg value="call"/>
                    rmdir /s/q ${build.area}
                </shellscript>
            </then>
        </if>
    </target>


    <!-- Defines the start of a build from logging point of view. -->
    <target name="log-build-start">
        <tstamp>
            <format property="log.build.start_time" pattern="yyyy-MM-dd'T'HH:mm:ss" />
        </tstamp>
        <!-- Used in ROM configuration files for version date. -->
        <tstamp>
            <format property="today" pattern="dd-MM-yyyy" />
        </tstamp>
    </target>


 
     <!-- Prepares the Synergy configuration input for processing.
     
     This inserts Ant properties to the config file. --> 
    <target name="ccm-prepare-input" if="prep.delivery.file">        
        <property name="prep.delivery.conf.parsed" location="${build.cache.dir}/delivery.xml.parsed" />
        <copy file="${prep.delivery.file}" tofile="${prep.delivery.conf.parsed}" overwrite="true">
            <filterchain>
                <expandproperties />
            </filterchain>
        </copy>
    </target>
    

    <!-- Checks the build drive is available. -->
    <target name="check-env-build-drive">
        <available file="${build.drive}/" property="build.drive.available" />
        <fail unless="build.drive.available" />
    </target>

    <!-- Macro to check enough disk space available or not. Notify build manager
    in case of insufficient disk space. -->
    <macrodef name="diskspaceMacro" uri="http://www.nokia.com/helium">
        <attribute name="drive"/>
        <attribute name="space"/>
        <sequential>
            <trycatch>
                <try>
                    <exec executable="python" failonerror="true">
                        <arg value="-m" />
                        <arg value="freedisk" />
                        <arg value="--drive" />
                        <arg value="@{drive}" />
                        <arg value="--space" />
                        <arg value="@{space}" />
                    </exec>
                </try>
                <catch>
                    <hlm:notifyMacro message="${env.COMPUTERNAME} has insufficient disk space on drive @{drive} for ${build.id}. Build will continue..."/>
                </catch>
            </trycatch>
        </sequential>
    </macrodef>
    
    
    <!-- Checks there is sufficient disk space on the local machine and on the network. -->
    <target name="check-free-space">
        <if>
            <isset property="local.free.space"/>
            <then>
                <echo message="drive: ${build.drive}"/>
                <echo message="Required Space: ${local.free.space}MB"/>
                <if>
                    <not>
                        <hasfreespace partition="${build.drive}" needed="${local.free.space}M"/>
                    </not>
                    <then>
                        <hlm:notifyMacro message="${env.COMPUTERNAME} has insufficient disk space on drive ${build.drive} for ${build.id}. Build will continue..."/>
                    </then>
                </if>
            </then>
        </if>
        <if>
            <isset property="network.free.space"/>
            <then>
                <hlm:diskspaceMacro drive="${network.drive}" space="${network.free.space}"/>
            </then>
        </if>
    </target>


    <!-- Checks that filedisk is on the machine.
    
    TODO: do we still need this if filedisk is in /external? Also should handle
    tools dependencies in more structured way. 
    -->
    <target name="check-env-filedisk" depends="check-env-build-drive">
        <available file="${env.SystemRoot}/system32/filedisk.exe" property="filedisk.available" />
        <fail unless="filedisk.available" />
    </target>


    <!-- Gets the ARM compiler license text. -->
    <target name="get-arm-license">
        <exec executable="armcc" outputproperty="arm.compiler.version.text" failonerror="${failonerror}">
            <arg value="--vsn" />
        </exec>
        <echo message="ARM compiler version text: ${arm.compiler.version.text}" />
    </target>


    <!-- Checks if there was any error getting the ARM license information. -->
    <target name="check-env-arm-license" depends="get-arm-license">
        <!-- Fail if the compiler version string contains error text. -->
        <fail message="Error with ARM compiler configuration.">
            <condition>
                <contains string="${arm.compiler.version.text}" substring="Error" />
            </condition>
        </fail>
    </target>


    <!-- Sets the ARM compiler version to a property so it can be set in the environment
    during compilation. -->
    <target name="set-arm-version" depends="check-env-arm-license" unless="not.using.rvct">
        <loadresource property="arm.compiler.version">
            <propertyresource name="arm.compiler.version.text"/>
            <filterchain>
                <linecontainsregexp>
                    <regexp pattern="ARM.* C/C\+\+ Compiler" />
                </linecontainsregexp>
            </filterchain>
        </loadresource>
        <echo message="ARM compiler version: ${arm.compiler.version}" />
    </target>


    <!-- Prepares the preparation configuration by inserting Ant properties. -->
    <target name="prep-prepare-input" if="prep.config.file">
        <property name="prep.config.file.parsed" location="${build.output.dir}/prep.xml.parsed" />
        <copy file="${prep.config.file}" tofile="${prep.config.file.parsed}" overwrite="true">
            <filterchain>
                <expandproperties />
            </filterchain>
        </copy>
    </target>


    <!-- Obsolete. Left as placeholder. 
         Earlier: Checks that all the build area inputs are available.  -->
    <target name="check-env-prep" depends="prep-prepare-input">
    </target>


    <!-- Generates a starting XML file for the build summary. -->
    <target name="build-info" depends="start-ant-log,log-build-start">
        <dirname file="${build.summary.file}" property="build.summary.file.dir"/>
        <mkdir dir="${build.summary.file.dir}"/>
        <mkdir dir="${prep.log.dir}"/>
        <xmltask dest="${build.log.dir}/${build.id}_info.log.xml">
            <insert path="/">
                <![CDATA[
            <info>
                <id>${build.id}</id>
                <number>${build.number}</number>
                <startTime>${log.build.start_time}</startTime>
                <machine>${env.COMPUTERNAME}</machine>
                <publish>
                    <status>${is.published}</status>
                    <location>${publish.dir}</location>
                </publish>
            </info>
                ]]>
            </insert>
        </xmltask>
    </target>
    
    <propertyset id="password.list.ref">
        <propertyref name="ccm.password.rc" />
        <propertyref name="ccm.user.password" />
        <propertyref name="release.grace.password" />
        <propertyref name="unix.password" />
        <propertyref name="release.notes.password" />
        <propertyref name="nwiki.password" />
        <propertyref name="noe.password" />
        <propertyref name="ats.password" />
        <propertyref name="hydra.password" />
        <propertyref name="coverity.password" />
    </propertyset>
    
    <!-- Logs the Ant property build environment. -->
    <target name="log-build-env">
        <echoproperties destfile="${build.log.dir}/${build.id}_ant_env.log">
            <!-- Do not log passwords... -->
            <propertyset negate="true">
                <propertyset refid="password.list.ref"/>
            </propertyset>
        </echoproperties>
    </target>
    
    
    <!-- Create a free substed drive for running the build on.
        
    Helium can now subst/unsubst build drive automatically. If you don't define the property "build.drive" then helium will search the next available build drive and assign it to in "build.drive" property.
    To unsubst the build drive after the build use property "unsubst.after.build=yes", the value "no" will let the drive still in subst.
        
    This target will: 
    * Rename the prep directory if it exists and we don't have prep.build.dir.keep defined. 
    * Create a new directory for prepping the build area.
    * Subst that directory to the build drive.
    -->
    <target name="prep-drive">
      
      <!-- Just un-subst the drive if build.drive is predefined. -->
        <propertyregex property="prep.build.dir.drive" input="${prep.build.dir}" regexp="^([^:]*:\\).*" select="\1" />
        <fail message="${prep.build.dir.drive} could not be located">
            <condition>
                <and>
                    <os family='windows'/>
                    <not>
                        <available file="${prep.build.dir.drive}"/>
                    </not>
                </and>
            </condition>
        </fail>
        <if>
            <and>
                <not>
                    <isset property="env.HLM_SUBCON"/>
                </not>
                <or>
                    <istrue value="${dragonfly.enabled}"/>
                    <isset property="use.dragonfly"/>
                </or>
            </and>
            <then>
                <antcall target="dragonfly-prep-drive"/>
            </then>
            <else> 
                <tstamp>
                    <format property="old.prep.dir.timestamp" pattern="yyyyMMdd'_'HHmmss" />
                </tstamp>
                <if>
                    <not>
                        <isset property="prep.build.dir.keep"/>
                    </not>
                    <then>
                        <script language="jython" setbeans="false">
from java.io import *
import time
prep_build_dir_str = project.getProperty('prep.build.dir')
prep_build_dir = File(prep_build_dir_str)
print prep_build_dir
if prep_build_dir.exists(): 
    timestamp = time.strftime("%Y%m%d_%H%M%S", time.localtime(time.time()))
    renamed_prep_build_dir = File('%s.%s' % (prep_build_dir_str, timestamp))
    print renamed_prep_build_dir
    result = prep_build_dir.renameTo(renamed_prep_build_dir)
    if result:
        print 'Dir rename successful.'
    else:
        print 'Dir rename failed!'

        raise Exception('Could not rename prep dir')
                        </script>
                    </then>
                </if>
                <!-- Create a new directory for the build and subst it to a drive. 
                fail build if prep.root.dir property is not set.-->
                <fail unless="prep.root.dir" message="prep.root.dir value should be specified." />
                <mkdir dir="${prep.build.dir}" />
                <hlm:unsubst drive="${build.drive}" failonerror="false"/>
                <exec osfamily="windows" executable="subst" failonerror="false">
                    <arg value="${build.drive}" />
                    <arg value="${prep.build.dir}" />
                </exec>
                <antcall target="backup-subst-drives"/>
            </else>
        </if>
    </target>

    <!-- To initialization prep-drive-->
    <target name="init-drive" depends="prep-drive"/>

    <!-- To initialization substituted drive-->
    <target name="restore-subst-drives">
        <if>
            <available file="${cache.dir}/hlmsubsteddrives.bat" type="file"/>
            <then>
                <exec dir="${cache.dir}" executable="${cache.dir}/hlmsubsteddrives.bat" osfamily="windows" failonerror="false"/>
            </then>
        </if>
    </target>
    
     
    <!-- Creates several initial directories in a new build area. -->
    <target name="init-build-area" depends="check-env-build-drive">
        <mkdir dir="${build.output.dir}" />
        <mkdir dir="${build.log.dir}" />
        <mkdir dir="${prep.log.dir}" />
        <mkdir dir="${temp.build.dir}" />  
        <mkdir dir="${diamonds.build.output.dir}" />
    </target>
    
    
    <!-- Basic initialization for a build, including starting the main ant_build log.
        It also copies the additional logs from the temp directory into the build area. -->
    <target name="init" depends="get-ccm-password">
        <runtarget target="build-number"/>
        <runtarget target="init-build-area"/>
        <runtarget target="build-info"/>
        
        <echo>Copying temp logs from ${build.cache.log.dir} into the build area.</echo>
        <copy todir="${prep.log.dir}" verbose="true" failonerror="false">
            <fileset dir="${build.cache.log.dir}">
                <include name="*.log"/>
                <include name="*.xml"/>
            </fileset>
        </copy>
        
    </target>

    <!-- Loading some properties from the cache. Mainly diamonds related properties are
         stored in there. 
     -->
    <target name="load-property-from-cache-file">
        <if>
            <available file="${build.property.cache.file}" />
            <then>
                <property file="${build.property.cache.file}" />
            </then>
        </if>
    </target>

    <!-- This target exists as a trigger for initiating the Diamonds logger. If 
          it is not included in the build sequence, the build will not be logged to 
          Diamonds. Also  build.property.cache.file will be there contains all the diamonds related properties 
    --> 
    <target name="diamonds" if="internal.diamonds.enabled" depends="load-property-from-cache-file">
        <mkdir dir="${diamonds.build.output.dir}" />
        <var name="diamonds.build.url"  value="http://${diamonds.host}:${diamonds.port}${diamonds.build.id}"/>
        <echoproperties destfile="${build.property.cache.file}">
            <propertyset>
                <propertyref prefix="diamonds.build.url"/>
                <propertyref prefix="diamonds.host"/>
                <propertyref prefix="diamonds.port"/>
                <propertyref prefix="diamonds.build.id"/>
            </propertyset>
        </echoproperties>
    </target>    
   
    <!-- Used to prep the build area, now only a placeholder target for the customer -->
    <target name="prep-copy" />

    <!-- Wrapper target to call prep-work-area during the build.
         log will get recorded under the log directory.
         Property ccm.enabled has to be set to 'true' to enable that step!
         prep-work-area-check-errors is also run so it emits a signal in case of errors.
      -->
    <target name="do-prep-work-area" depends="find-files-pre">
        <runtarget target="prep-work-area"/>
        <runtarget target="find-files-post"/>
    </target>
    
    
    <!-- Wrapper target to call start-remote-builds during the build.
         log will get recorded under the log directory.
         Property remote.builds.enabled has to be defined to enable that step!
      -->
    <target name="do-start-remote-builds" if="internal.remote.builds.enabled">
        <runtarget target="start-remote-builds"/>
    </target>
    
    
    <!-- check-env-prep has to be called after getting the delivery else it doesn't works for the first build. -->
    <target name="do-prep" depends="check-free-space,do-prep-work-area,
                                    do-start-remote-builds,check-env-prep,diamonds,create-bom,log-build-env,prep-copy,
                                    set-arm-version" />
    
    
    <!-- Macro to notify user by email/sms -->
    <macrodef name="notifyMacro" uri="http://www.nokia.com/helium">
        <attribute name="message"/>
        <sequential>
            <runtarget target="lookup-email" />
            <tstamp>
                <format property="time.failure" pattern="yyyy-MM-dd_HH.mm.ss" />
            </tstamp>
            <preset.mail tolist="${email.from}" subject="${env.COMPUTERNAME} prep stage problem!" message="@{message}" />
            <!-- Get the first part of email address to use with SMS gateway -->
            <propertyregex property="email.from.name" input="${email.from}" regexp="(.*?)@" select="\1" />
            <preset.mail tolist="${email.from.name}@${sms.server}" subject="" message="@{message}" />
        </sequential>
    </macrodef>
    
    
    <!-- Fails the build if prep did not succeed. -->
    <target name="prep-fail">
        <if>
            <available file="${build.log}"/>
            <then>
                <record name="${build.log}" action="stop" append="true"/>
            </then>
        </if>
        <hlm:metadatarecord database="${metadata.dbfile}">
            <hlm:antmetadatainput>
                <fileset casesensitive="false" file="${build.log.dir}/${build.id}_main.ant.log" />
                <metadatafilterset refid="filterset.ant.output" />
            </hlm:antmetadatainput>
        </hlm:metadatarecord>
        <hlm:generateBuildStatus file="${build.log.dir}/${build.id}_main.ant.log" />
        <!-- Todo: metadata: insert assertions for metadata parsing here -->
    </target>
    
    <!-- Set properties for track full build event. -->
    <target name="set-fullbuild-properties">
        <!-- Enables logging of the start and end of individual targets.
        @type string
        -->
        <property name="log.target" value="yes"/>
        <!-- Ensures the cleanup-all target is called when the build finishes.
        @type string
        -->
        <property name="call.cleanup" value="no"/>
    </target>
    
    <!-- Top-level target for preparing the build area. -->
    <target name="prep" depends="set-fullbuild-properties,init-drive,init">
        <trycatch property="build.exception">
            <try>
                <runtarget target="do-prep" />
            </try>
            <catch>
                <echo message="Build has failed during prep: ${build.exception}" />
                <runtarget target="prep-fail" />
                <fail />
            </catch>
        </trycatch>
    </target>

    
    <!-- Can be used to unsubst the drive . -->
    <target name="remove-drive">
        <hlm:unsubst drive="${build.drive}"/>
    </target>
    
    <!--
      Simple target to create a set of directory based on a path reference.
     -->
    <target name="create-directory-structure">
        <if>
            <isreference refid="directory.structure.config" />
            <then>
                <for param="dir">
                    <path refid="directory.structure.config" />
                    <sequential>
                        <mkdir dir="@{dir}" />
                    </sequential>
                </for>
            </then>
            <else>
                <echo>'directory.structure.config' reference not found, so not any directory structure will be created.</echo>
            </else>
        </if>
    </target>
    
</project>
