#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4
#
# Copyright (C) 2010, 2011, 2012, 2013, 2014 Intel, Inc.
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of the GNU General Public License
#    as published by the Free Software Foundation; version 2
#    of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
"""
This job is triggered by Gerrit RefUpdate event.
"""

import os
import sys
import re
import ast
import xml.etree.cElementTree as ElementTree
from time import sleep

from gitbuildsys.errors import ObsError
from common.upload_service import UploadError
from common.buildservice import BuildService
from common.buildtrigger import trigger_info, trigger_next

class LocalError(Exception):
    """Local error exception."""
    pass

def main():

    ref_project = trigger_info(os.getenv('TRIGGER_INFO'))['target']
    profile = trigger_info(os.getenv('TRIGGER_INFO'))['project']
    target_project = 'home:devel:Build:%s' % ref_project.replace(':ref:',':check:')
    package_to_build = os.getenv('REF_BUILDCHECK_PKG_PROFILE')
    if ':Base:ref:' in ref_project:
        package_to_build = os.getenv('REF_BUILDCHECK_PKG_BASE')

    build = BuildService(os.getenv('OBS_API_URL'), \
                         os.getenv('OBS_API_USERNAME'), \
                         os.getenv('OBS_API_PASSWD'))

    if True:
        if build.exists(target_project):
            build.delete_project(target_project)
            sleep(5)

        build.create_project(target_project, src=ref_project.split(':ref:')[0]) # from base
        for flag in ("build", "publish"):
            build.disable_build_flag(target_project, repo = None, flag=flag, status="disable")

        build.create_copy_pac(ref_project, package_to_build, target_project, package_to_build)
        print 'Copypac %s from %s to %s.' % (package_to_build, ref_project, target_project)

        # aggregate package
        si = build.get_sourceinfo_list(ref_project)
        for package in si:
            if re.search('_aggregate', package):
                build.create_copy_pac(ref_project, package, target_project, package)
                aggregate_file_name="_aggregate"
                build.get_source_file(ref_project, package, aggregate_file_name)
                content = ""
                with open(aggregate_file_name, 'r') as f:
                    content = f.read()
                content_xml_root = ElementTree.fromstringlist(content)
                for element in content_xml_root.findall('aggregate'):
                    if element.get('project') == ref_project:
                        element.set('project', target_project)
                content = ElementTree.tostring(content_xml_root)
                with open(aggregate_file_name, 'w') as f:
                    f.write(content)
                commit_msg="uploaded to copy pac %s/%s from %s" % (target_project, package, ref_project)
                try:
                    build.commit_files(target_project, package,
                           [(aggregate_file_name, True)], commit_msg)
                except ObsError, error:
                    raise UploadError("Unable to upload _aggregate to %s: %s" % \
                        (target_project, error))

        # Sync project meta
        meta = build.get_meta(target_project)
        xml_meta = ElementTree.fromstringlist(meta)
        for repo_elem in xml_meta.findall('repository'):
            for path_elem in repo_elem.findall('path'):
                path_elem.set('project', ref_project)
        build.set_meta(ElementTree.tostring(xml_meta), target_project)
        build.default_build_flag(target_project, repo = None, flag="build")
        build.link_project(target_project, src=ref_project, linktype="localdep")

        # Check build result
        result_map = {'Fail': -1, 'Pass': 0, 'Building': 1}
        def precheck_result():
            sys.stdout.flush()
            et = ElementTree.fromstring(''.join(build.get_build_results(target_project)))
            for result in et.findall('result'):
                for summary in result.findall('summary'):
                    for status in summary.findall('statuscount'):
                        if status.get('code') in ('unresolvable', 'failed', 'broken'):
                            print 'Build fail. %s %s %s' % (result.get('repository'), \
                                                            result.get('arch'), \
                                                            status.get('code'))
                            return result_map['Fail']
            for result in et.findall('result'):
                for summary in result.findall('summary'):
                    for status in summary.findall('statuscount'):
                        if status.get('code') in ('building'):
                            return result_map['Building']
            return result_map['Pass']

        while True:
            sleep(30)
            build_result = precheck_result()
            if build_result not in (result_map['Pass'], result_map['Fail']):
                continue
            break

        # Trigger next
        if os.getenv('TRIGGER_CLEAN_PROJECTS'):
            enabled_projects = ast.literal_eval(os.getenv('TRIGGER_CLEAN_PROJECTS'))
            count = 0
            if enabled_projects.get(profile):
                for project in enabled_projects.get(profile):
                    trigger_next("TRIGGER_CLEAN_PROJECT_%s" %(count), {"data":"dummy"}, \
                                 extra_params={"ID": "-1", \
                                               "DECISION": "clean", \
                                               "PROJECT": project.get('target'), \
                                               "PACKAGE": "All"})
                    count += 1

        if build_result == result_map['Pass']:
            build.delete_project(target_project)
        return build_result

if __name__ == '__main__':
    try:
        sys.exit(main())
    except LocalError, err:
        print err
        sys.exit(1)

