<?xml version="1.0" encoding="UTF-8"?>
<!-- 
============================================================================ 
Name        : bom.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.bom" xmlns:hlm="http://www.nokia.com/helium">    
    <description>
    Creates a Bill-Of-Materials record based on the Synergy inputs.
    </description>
    
    <!-- Your synergy work area directory (Set as the parent of the helium dir by default).
    @type string
    -->
    <property name="create.bom.workarea.root" value="."/> 
    
    <!--* @property bom.release.regex
    This property (if set) defines the regular expression BOM will use to extract data from 
    a basline release. The regular expression must define 4 fields: TYPE, YEAR, WEEK, REVISION
    Example:
        (?<TYPE>.*)_(?P<YEAR>\d{4})(?P<WEEK>\d{2})_(?<REVISION>.*)
    
    @type string
    @editable allowed
    @scope public
    -->
    
    <!-- The target create-bom creates a Bill-Of-Material based on the SCM project 
    The target can be run in the project's root directory or the directory can be given by
    setting the property create.bom.workarea.root. The IDO builds are expected to set it to their 
    projects work area directory. -->
    <target name="create-bom">
        <runtarget target="get-ccm-password"/>
        <runtarget target="old-bom-log"/>
        <runtarget target="prep-prepare-input" />
        <runtarget target="ccm-prepare-input"/>
        <hlm:startSpecificLogMacro name="${prep.log.dir}/${build.id}_bom.log" regexp="${ccm.user.password}" phase="prep"/>
        <hlm:python>
import os
import build.model
import configuration
import nokia.nokiaccm
import ccm.extra
import ant
import sys
import traceback

session = None
try:
    runccm = ant.get_property(r'${ccm.enabled}')
    database = ant.get_property(r'${ccm.database}')
    username = ant.get_property(r'${ccm.user.login}')
    password = ant.get_property(r'${ccm.user.password}')
    engine = ant.get_property(r'${ccm.engine.host}')
    dbpath = ant.get_property(r'${ccm.database.path}')
    waroot = ant.get_property(r'${create.bom.workarea.root}')
    buildid = ant.get_property(r'${build.id}')
    buildlogdir = ant.get_property(r'${build.log.dir}')
    deliveryfile = ant.get_property(r'${prep.delivery.conf.parsed}')
    oldbom = ant.get_property(r'${old.bom.log}')
    bom = None
    bomfilename = r"%s/%s_bom.xml" % (buildlogdir, buildid)
    if runccm and deliveryfile:
        cache = None
        if ant.get_property(r'${ccm.cache.xml}') is not None:
            cache = str(ant.get_property(r'${ccm.cache.xml}'))
        provider = ccm.extra.CachedSessionProvider(opener=nokia.nokiaccm.open_session, cache=cache)
            
        configBuilder = configuration.NestedConfigurationBuilder(open(deliveryfile, 'r'))
        configSet = configBuilder.getConfiguration()
        for config in configSet.getConfigurations():
            waroot = config['dir']
            print "Found wa for project %s" % waroot
                        
        if database != None:
            session = provider.get(username, password, database=database)
        else:
            session = provider.get(username, password, engine, dbpath)
            
        ccmproject =  ccm.extra.get_toplevel_project(session, waroot)
        
        config_data = {'delivery': deliveryfile, 'prep.xml': ant.get_property(r'${prep.config.file.parsed}'), 'build.id': buildid, 'ccm.database': database, 'symbian_rel_week': ant.get_property(r'${symbian.version.week}'), 'symbian_rel_ver': ant.get_property(r'${symbian.version}'), 'symbian_rel_year': ant.get_property(r'${symbian.version.year}'), 's60_version': ant.get_property(r'${s60.version}'), 's60_release': ant.get_property(r'${s60.release}'), 'currentRelease.xml': ant.get_property(r'${build.drive}') + "/currentRelease.xml", 'release_regexp': ant.get_property(r'${bom.release.regex}') }
        config = configuration.Configuration(config_data)
        
        # let's only support the new spec model!
        bom = build.model.SynergyBOM(config, ccmproject, username=username, password=password, provider=provider)
        
        xml_writer = build.model.BOMXMLWriter(bom)
        xml_writer.write(bomfilename)
    if not bom and os.path.exists(bomfilename):
        config_data = {'prep.xml': ant.get_property(r'${prep.config.file.parsed}'), 'build.id': buildid, 'symbian_rel_week': ant.get_property(r'${symbian.version.week}'), 'symbian_rel_ver': ant.get_property(r'${symbian.version}'), 'symbian_rel_year': ant.get_property(r'${symbian.version.year}'), 's60_version': ant.get_property(r'${s60.version}'), 's60_release': ant.get_property(r'${s60.release}'), 'currentRelease.xml': ant.get_property(r'${build.drive}') + "/currentRelease.xml"}
        config = configuration.Configuration(config_data)
        bom = build.model.SimpleBOM(config, bomfilename)
    if os.path.exists(oldbom):
        xml_delta_writer = build.model.BOMDeltaXMLWriter(bom, oldbom)
        xml_delta_writer.write(buildlogdir + "/" + buildid + "_bom_delta.xml")
        delta_bom_content_validity = xml_delta_writer.validate_delta_bom_contents(buildlogdir + "/" + buildid + "_bom_delta.xml", bomfilename, oldbom)
        if((delta_bom_content_validity == False) and (ant.get_property(r'${hlm.enable.asserts}') is not None)):
            print 'Bom delta contents are not matching'
            raise Exception
        elif((delta_bom_content_validity == True) or (delta_bom_content_validity == None)):
            print 'Bom delta contents are matching.'
        elif(delta_bom_content_validity == False):
            print 'Bom delta contents are not matching.'
    else:
        print 'Old BOM log cannot be found ' + oldbom + ', skipping BOM delta creation.'
    if runccm:
        bom.close()
    if session:
        session.close()
except Exception, ex:
    print 'Caught exception in BOM: ' + str(ex)
    traceback.print_exc()
        </hlm:python>
        <if>
            <available file="${build.log.dir}/${build.id}_bom.xml"/>
            <then>
                <echo>${build.log.dir}</echo>
                <xmltask source="${build.log.dir}/${build.id}_bom.xml" dest="${build.log.dir}/${build.id}_bom.xml" outputter="simple">
                    <replace path="//bom/build/text()" withText="${build.id}"/>
                </xmltask>
                <fmpp sourceRoot="${helium.dir}/tools/preparation/bom"
                      outputRoot="${prep.log.dir}" includes="bom.html.*,bom.txt.*" removeExtensions="ftl">
                    <freemarkerLinks expandProperties="yes">
                        macro: ${helium.dir}/tools/common/templates/macro
                    </freemarkerLinks>
                    <data expandProperties="yes">
                        doc: xml(${build.log.dir}/${build.id}_bom.xml)                
                    </data>
                </fmpp>
                
                <move file="${prep.log.dir}/bom.html" tofile="${build.log.dir}/${build.id}_bom.html"/>
                <move file="${prep.log.dir}/bom.txt" tofile="${prep.log.dir}/${build.id}_bom.txt"/>

                <!-- Transform bom data into the diamonds xml format: 
                     * BOM folders are flattened into tasks.
                     * Schema version is extracted from the appropriate FMPP template. -->
                <mkdir dir="${temp.build.dir}" />
                <fmpp sourcefile="${helium.dir}/tools/common/templates/diamonds/diamonds_header.ftl" 
                      outputfile="${temp.build.dir}/diamonds_header.xml" quiet="true"/>
                <loadfile srcfile="${temp.build.dir}/diamonds_header.xml" property="diamonds.schema.xml">
                    <filterchain>
                        <linecontains>
                            <contains value="schema"/>
                        </linecontains>
                    </filterchain>
                </loadfile>                
                <mkdir dir="${diamonds.build.output.dir}" />
                <xmltask source="${build.log.dir}/${build.id}_bom.xml" dest="${diamonds.build.output.dir}/create-bom.xml">           
                    <insert path="bom/content" xml="${diamonds.schema.xml}" position="before"/>
                    <remove path="bom/content/project/folder/name"/>
                    <remove path="bom/build"/>
                    <rename path="bom" to="diamonds-build"/>
                </xmltask>                
                <delete file="${temp.build.dir}/diamonds_header.xml"/>
                <replace file="${diamonds.build.output.dir}/create-bom.xml" token="&lt;folder&gt;" value="&lt;!-- &lt;folder&gt; --&gt;"/>
                <replace file="${diamonds.build.output.dir}/create-bom.xml" token="&lt;/folder&gt;" value="&lt;!-- &lt;/folder&gt; --&gt;"/>
                <xmltask source="${diamonds.build.output.dir}/create-bom.xml" dest="${diamonds.build.output.dir}/create-bom.xml"
                         outputter="simple">
                    <remove path="//comment()"/>
                </xmltask>
             
                <hlm:assertFileExists file="${diamonds.build.output.dir}/create-bom.xml"/>
                <hlm:assertFileExists file="${build.log.dir}/${build.id}_bom.html"/>
                <hlm:assertFileExists file="${prep.log.dir}/${build.id}_bom.txt"/>
                
                <runtarget target="collect-task-owner-email"/>
            </then>
            <else>
                <echo>WARNING: ${build.log.dir}/${build.id}_bom.xml file not found.</echo>
            </else>
        </if>
        
        <if>
            <available file="${old.bom.log}"/>
            <then>
                <hlm:assertFileExists file="${build.log.dir}/${build.id}_bom_delta.xml"/>
                <fmpp sourceRoot="${helium.dir}/tools/preparation/bom"
                      outputRoot="${prep.log.dir}" includes="bom_delta.*" removeExtensions="ftl">
                    <freemarkerLinks expandProperties="yes">
                        macro: ${helium.dir}/tools/common/templates/macro
                    </freemarkerLinks>
                    <data expandProperties="yes">
                        doc: xml(${build.log.dir}/${build.id}_bom_delta.xml)                
                    </data>
                </fmpp>
                                
                <move file="${prep.log.dir}/bom_delta.html" tofile="${build.log.dir}/${build.id}_bom_delta.html"/>
                <move file="${prep.log.dir}/bom_delta.txt" tofile="${prep.log.dir}/${build.id}_bom_delta.txt"/>
                
                <hlm:assertFileExists file="${build.log.dir}/${build.id}_bom_delta.html"/>
            </then>
        </if>
        <hlm:stopSpecificLogMacro name="${prep.log.dir}/${build.id}_bom.log" phase="prep"/>
    </target>
    
    <!-- The target create-task-owner-email creates a property task.owners.email which will contain
    the list of task owners email IDs seperated by comma, the newly created property can be used thereafter
    to send emails.
    This target is automatically called by create-bom target. @scope private-->
    <target name="collect-task-owner-email">
        <if>
            <available file="${build.log.dir}/${build.id}_bom_delta.xml"/>
            <then>
                <xmltask source="${build.log.dir}/${build.id}_bom_delta.xml" dest="${build.log.dir}/${build.id}_bom_delta.xml"> 
                    <call path="/bomDelta/content/task">
                        <param name="task.delta" path="text()"/>
                        <actions>
                            <var name="task.delta" value="@{task.delta}"/>
                            <propertyregex property="delta.task.id" input="${task.delta}" regexp="^([^:]+):\s*" select="\1"/>
                            <xmltask source="${build.log.dir}/${build.id}_bom.xml" dest="${build.log.dir}/${build.id}_bom.xml"> 
                                <call path="/bom/content/project/folder/task/owner/text()[../../id[.='${delta.task.id}']]" >
                                    <param name="task.owner" path="."/>
                                    <actions>
                                        <var name="task.owner" value="@{task.owner}"/>
                                        <if>
                                            <isset property="task.owners"/>
                                            <then>
                                                <var name="task.owners" value="${task.owners},${task.owner}"/>
                                            </then>
                                            <else>
                                                <var name="task.owners" value="${task.owner}"/>
                                            </else>
                                        </if>
                                    </actions>
                                </call>
                            </xmltask>
                        </actions>
                    </call>
                </xmltask> 
            </then>
            <else>
                <if>
                    <available file="${build.log.dir}/${build.id}_bom.xml"/>
                    <then>
                        <xmltask source="${build.log.dir}/${build.id}_bom.xml" dest="${build.log.dir}/${build.id}_bom.xml"> 
                            <call path="/bom/content/project/folder/task/owner">
                                <param name="task.owner" path="text()"/>
                                <actions>
                                    <var name="task.owner" value="@{task.owner}"/>
                                    <if>
                                        <isset property="task.owners"/>
                                        <then>
                                            <var name="task.owners" value="${task.owners},${task.owner}"/>
                                        </then>
                                        <else>
                                            <var name="task.owners" value="${task.owner}"/>
                                        </else>
                                    </if>
                                </actions>
                            </call>
                        </xmltask> 
                    </then>
                </if>
            </else>
        </if>
        <script language="jython" setbeans="false">
import re
taskOwnersDup = project.getProperty("task.owners")
if taskOwnersDup:
    taskOwnersDup = re.sub(r'\s', '', taskOwnersDup)
    taskOwners = taskOwnersDup.split(',')
    if taskOwners:
        taskOwners = list(set(taskOwners))
        project.setProperty("task.owners.unique", ",".join(taskOwners))
        </script>
        <for list="${task.owners.unique}" delimiter="," param="task.owner" >
            <sequential>
                <var name="task.owner" value="@{task.owner}"/>
                <if>
                    <isset property="email.ldap.server"/>
                    <then>
                        <hlm:ldap url="${email.ldap.server}" rootdn="${email.ldap.rootdn}" filter="uid=${task.owner}" outputproperty="task.owner.email" key="mail"/>
                        <if>
                            <isset property="task.owners.email"/>
                            <then>
                                <var name="task.owners.email" value="${task.owners.email},${task.owner.email}"/>
                            </then>
                            <else>
                                <var name="task.owners.email" value="${task.owner.email}"/>
                            </else>
                        </if>
                    </then>   
                </if>
            </sequential>
        </for>
    </target>

    <!-- Finds the path to the last usable XML BOM log for creating a BOM delta. --> 
    <target name="old-bom-log" unless="old.bom.log">
        <!-- Publish dir location of the old bom log.
        @type string
        -->
        <property name="old.bom.log.publish.dir" value="${publish.dir}" />
        <!-- Location of XML BOM log.
        @type string
        @scope private
        -->
        <property name="bom.log" value="${old.bom.log.publish.dir}/logs/${build.id}_bom.xml"/>
        <script language="jython" setbeans="false">
import re
import ant
import os
from com.nokia.ant.util import Helper

previousbuildnumber = 1
buildnumber = Helper.getProperty(project, "build.number")
bomlog = project.getProperty("bom.log")
while(previousbuildnumber > 0 and previousbuildnumber != ''):
    previousbuildnumber = ant.get_previous_build_number(buildnumber)
    try:
        old_bom_log = re.sub(r'\.(%s)([\/_])' % project.getProperty("build.number"), r'.' + previousbuildnumber + r'\2', bomlog)
        if os.path.exists(old_bom_log):
            break
    except ValueError:
        self.log("Old BOM cannot be found")
    buildnumber = previousbuildnumber
project.setProperty("old.bom.log", old_bom_log)
        </script>
        <echo>Previous BOM log: ${old.bom.log}</echo>
        <available file="${old.bom.log}" property="old.bom.log.present"/>
        <echo>Previous BOM log present: ${old.bom.log.present}</echo>
    </target>
    
</project>
