#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4
#
# Copyright (c) 2014, 2015, 2016 Samsung Electronics.Co.Ltd.
#
# 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.
#
import os
import re
import sys
import json
import requests
import urlparse
from time import sleep
from datetime import datetime

import urllib2

from osc import conf, core
from common.buildservice import BuildService
from common.buildtrigger import trigger_info, trigger_next, trigger_jenkins_build
from gitbuildsys.errors import ObsError
import xml.etree.ElementTree as ET
import xml.etree.cElementTree as ElementTree
from common.mapping import git_obs_map, get_ref_map, git_obs_map_full_list
from common.gerrit import GerritEnv
from common.upload_service import UploadError

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

def get_manifest_filelists_snapshot(profile, request_url, timeout=5, group=None):
        p = re.compile(r'alt=\"\[(TXT|DIR|   )]*\]\".*<a href=\"(.*)\">')

        if not request_url:
            return []
        print request_url
        # get data from url
        for loop in range(10):
            try:
                f = requests.get(request_url,
                                 auth=(profile['snapshot_username'],
                                       profile['snapshot_password']),
                                 timeout=timeout)
                if f.status_code == 200:
                    break
            except requests.exceptions.Timeout as e:
                print(e)
                continue
            except requests.exceptions.ConnectionError as e:
                print(e)
                continue
            except Exception as e:
                print(e)
                raise Exception('exception from get manifest filelists')
        else:
            raise Exception('can\'t get manifest filelists')

        # returns
        results = {}
        exclude_pkgs = []
        found_links = p.findall(f.text)
        for link in found_links:
            manifest_url = os.path.join(request_url, link[1])
            if link[0] == 'TXT':
                f = requests.get(manifest_url,
                                 auth=(profile['snapshot_username'],
                                       profile['snapshot_password']),
                                 timeout=timeout)
                try:
                    tree = ElementTree.fromstring(f.text)
                except ElementTree.ParseError:
                    raise ElementTree.ParseError
                for result in tree.findall('project'):
                    if '_preloadapp.xml' in link[1]:
                        exclude_pkgs.append(''.join(result.get('path')))
                    else:
                        results[''.join(result.get('path'))] = result.get('revision')

        if group == 'abs':
            preloadapp_pkgs = {}
            for app in exclude_pkgs:
                preloadapp_pkgs[app] = results[app]
            return preloadapp_pkgs

        #print results
        return results

class trigger_for_sync_obs(object):

    profiles = [
                {'name': 'base',
                 'project': 'Tizen:Base',
                 'baseproject': '',
                 'dest_dir': 'public_mirror/tizen/base',
                 'snapshot_url': '',
                 'snapshot_username': '', 
                 'snapshot_password': ''
                },
                {'name': '3.0-base',
                 'project': 'Tizen:3.0:Base',
                 'baseproject': '',
                 'dest_dir': 'public_mirror/tizen/3.0-base',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': 'mobile',
                 'project': 'Tizen:Mobile',
                 'baseproject': 'Tizen:Base',
                 'dest_dir': 'public_mirror/tizen/mobile',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': '3.0-mobile',
                 'project': 'Tizen:3.0:Mobile',
                 'baseproject': 'Tizen:3.0:Base',
                 'dest_dir': 'public_mirror/tizen/3.0-mobile',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': 'common',
                 'project': 'Tizen:Common',
                 'baseproject': 'Tizen:Base',
                 'dest_dir': 'public_mirror/tizen/common',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': '3.0-common',
                 'project': 'Tizen:3.0:Common',
                 'baseproject': 'Tizen:3.0:Base',
                 'dest_dir': 'public_mirror/tizen/3.0-common',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': 'wearable',
                 'project': 'Tizen:Wearable',
                 'baseproject': 'Tizen:Base',
                 'dest_dir': 'public_mirror/tizen/wearable',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': '3.0-wearable',
                 'project': 'Tizen:3.0:Wearable',
                 'baseproject': 'Tizen:3.0:Base',
                 'dest_dir': 'public_mirror/tizen/3.0-wearable',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': 'tv',
                 'project': 'Tizen:TV',
                 'baseproject': 'Tizen:Base',
                 'dest_dir': 'public_mirror/tizen/tv',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': '3.0-tv',
                 'project': 'Tizen:3.0:TV',
                 'baseproject': 'Tizen:3.0:Base',
                 'dest_dir': 'public_mirror/tizen/3.0-tv',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': 'ivi',
                 'project': 'Tizen:IVI',
                 'baseproject': 'Tizen:Base',
                 'dest_dir': 'public_mirror/tizen/ivi',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': '3.0-ivi',
                 'project': 'Tizen:3.0:IVI',
                 'baseproject': 'Tizen:3.0:Base',
                 'dest_dir': 'public_mirror/tizen/3.0-ivi',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                {'name': 'unified',
                 'project': 'Tizen:Unified',
                 'baseproject': 'Tizen:Base',
                 'dest_dir': 'public_mirror/tizen/unified',
                 'snapshot_url': '',
                 'snapshot_username': '',
                 'snapshot_password': ''
                },
                ]

    profile = None
    pattern = r'tizen[0-9a-zA-Z_\-\.]*[0-9]{8}.[0-9]{1,2}'

    def setup_profile(self, project):
        # set up profile
        for l in self.profiles:
            if project == l['project']:
                self.profile = l
                snap = os.path.join(os.getenv("URL_PUBLIC_REPO_BASE"), self.profile['dest_dir'])
                self.profile['snapshot_url'] = snap
                print 'project = %s' % (project)
                return self.profile
        return False

    def remove_duplicates(self, t, s):
        """docstring for make_unique:"""
        result=[]
        result=list(set(t) - set(s))
        return result

    def get_snapshot_version(self, profile, timeout=5):
        p = re.compile(self.pattern)
        
        if not profile['snapshot_url']:
            return []

        # get data from url
        for loop in range(10):
            try:
                f = requests.get(profile['snapshot_url'],
                                 auth=(profile['snapshot_username'],
                                       profile['snapshot_password']),
                                 timeout=timeout)
                if f.status_code == 200:
                    break
            except requests.exceptions.Timeout as e:
                print(e)
                continue
            except requests.exceptions.ConnectionError as e:
                print(e)
                continue
            except Exception as e:
                print(e)
                raise Exception('exception from get_latest_snapshot_version')
        else:
            raise Exception('can\'t get latest snapshot version')

        # return snapshot version
        results = [str(s) for s in p.findall(f.text)]
        #print results
        if len(results) > 2:
            return [results[-1], results[-3]]
        else:
            return [results[-1]]

    def create_project(self, build, target, info, meta, config, baserefproject=None):
        """
        create project
        """

        try:
            if not build.exists(target):
                try:
                    build.create_project(target, None, description=json.dumps(info))
                except ObsError, error:
                    raise LocalError("Unable to create project %s: %s" % (target, error))

                # set meta
                xml_meta = ElementTree.fromstringlist(meta)
                #change the target project name
                xml_meta.set('name',target)
                #delete remote person
                for person_element in xml_meta.findall('person'):
                    xml_meta.remove(person_element)

                # replace
                if baserefproject:
                    for repo_element in xml_meta.findall('repository'):
                        for element in repo_element.findall('path'):
                            element.set('project',baserefproject)

                #print ElementTree.tostring(xml_meta)
                #add target person
                element = ElementTree.Element('person', {"userid": "%s" % ('Admin'),"role": "maintainer"})
                xml_meta.append(element)
                print ElementTree.tostring(xml_meta)
                build.set_meta(ElementTree.tostring(xml_meta), target)
                # set project config
                #print config
                build.set_project_config(target, config)

                #disable publish flag
                build.disable_build_flag(target, repo = None, flag="publish", status="disable")
                #disable build flag
                build.disable_build_flag(target, repo = None, flag="build", status="disable")
                print "\nTarget project %s created" %(target)
                return True
            else:
                print "\nTarget project %s exist" %(target)
                return False
        except ObsError, error:
            raise LocalError("Unable to create project %s: %s" % (target, error))

    def create_copy_pac(self, remote_build, build, profile, target, pkgname):
        """                         """
        if not build.exists(target, pkgname):
            try:
                build.create_package(target, pkgname)
            except ObsError, error:
                raise UploadError("Unable to create package %s/%s :%s" % \
                        (target, pkgname, error))

        service_file_name = "_service"
        remote_build.get_source_file(profile, pkgname, service_file_name)
        content = ""
        with open(service_file_name, 'r') as f:
            content = f.read()
        content = content.replace("%s:%s" % (os.getenv("GERRIT_FETCH_URL"),os.getenv("GERRIT_SSHPORT")),
                        "file://%s" %(os.getenv("TRBS_GIT_CACHE_DIR")))
        print content
        with open(service_file_name, 'w') as f:
            f.write(content)
        commit_msg="uploaded to copy pac %s/%s from %s" % (target, pkgname, profile)
        try:
            build.commit_files(target, pkgname,
                   [(service_file_name, True)], commit_msg)
        except ObsError, error:
            raise UploadError("Unable to upload _service to %s: %s" % \
                (target, error))
        print "Copypac done."

    def list_packages_from_remote(self, remote_build, build, profile, target, packages=None, existing=False):
        """                         
            "<services><service name='gbs'>" \
            "<param name='revision'>%s</param>" \
            "<param name='url'>%s</param>" \
            "<param name='git-meta'>_git-meta</param>" \
            "<param name='error-pkg'>2</param>" \
            "</service></services>"
        """
        ret_dict = {}

        sourceinfo = remote_build.get_sourceinfo_list(profile)
        upload_packages=""
        if packages:
            upload_packages = packages
        else:
            upload_packages = [ package for package in sourceinfo if not re.search("_aggregate", package) ]

        for package in upload_packages:
            if sourceinfo[package]:
                print "    [sourceinfo(%s)] %s" % (package, sourceinfo[package])
                link_prj, link_pkg = sourceinfo[package][-1].split('/')
                if link_prj and link_pkg :
                    continue
            elif re.search("_aggregate", package):
                print "    [_aggregate] %s/%s" % (profile, package)
                aggregate_file_name="_aggregate"
                remote_build.get_source_file(profile, package, aggregate_file_name)
                content = ""
                with open(aggregate_file_name, 'r') as f:
                    content = f.read()

                if not re.search("qemu_aggregate", package):
                    content_xml_root = ElementTree.fromstringlist(content)
                    for element in content_xml_root.findall('aggregate'):
                        element.set('project',target)
                    content = ElementTree.tostring(content_xml_root)

                print "      [_aggregate] O %s" % (package)

                meta = remote_build.get_meta(profile, package)
                xml_meta = ElementTree.fromstringlist(meta)
                xml_meta.set('project',target)
                meta = ElementTree.tostring(xml_meta)
                print "      [_aggregate] META %s: %s" % (package, meta)

                ret_dict[package] = {'type': aggregate_file_name, \
                                     'content': content, \
                                     'meta': meta}
            else:
                service_file_name = "_service"
                remote_build.get_source_file(profile, package, service_file_name)
                content = ""
                with open(service_file_name, 'r') as f:
                    content = f.read()

                if content:
                    #### replace ssh://review.tizen.org:29418
                    content = content.replace("%s:%s" % (os.getenv("GERRIT_FETCH_URL"),os.getenv("GERRIT_SSHPORT")),
                                              "file://%s" %(os.getenv("TRBS_GIT_CACHE_DIR")))
                    #### replace ssh://review.tizen.org
                    content = content.replace("%s" % (os.getenv("GERRIT_FETCH_URL")),
                                              "file://%s" %(os.getenv("TRBS_GIT_CACHE_DIR")))

                    _git = ''
                    _rev = ''
                    _root = ElementTree.fromstringlist(content)
                    for elem in _root.findall('service'):
                        for param in elem.findall('param'):
                            if param.get('name') == 'url':
                                _url = param.text
                                if len(_url.split(os.getenv('TRBS_GIT_CACHE_DIR')+'/')) == 2:
                                    _git = _url.split(os.getenv('TRBS_GIT_CACHE_DIR')+'/')[1]
                                elif len(_url.split(os.getenv('GERRIT_FETCH_URL')+'/')) == 2:
                                    _git = _url.split(os.getenv('TRBS_GIT_CACHE_DIR')+'/')[1]
                            if param.get('name') == 'revision':
                                _rev = param.text

                    print "      [_service] O %s (%s,%s)" % (package, _git, _rev)

                    ret_dict[package] = {'type': service_file_name, \
                                         'content': content, \
                                         'meta': None, \
                                         'git': _git, \
                                         'rev': _rev, \
                                         'exist': existing}
                else:
                    print "      [_service] X %s" % (package)

        return ret_dict

    def _update_packages(self, remote_build, build, profile, target, upload_packages):
        dbg_idx = 0
        for package in upload_packages:
            dbg_idx += 1
            _update_type = upload_packages[package]['type']
            raw = upload_packages[package]['content']
            with open(_update_type, 'w') as f:
                f.write(raw)
            #if not build.exists(target, package):
            if True:
                try:
                    build.create_package(target, package)
                except ObsError, error:
                    #raise UploadError('[%s] Unable to create package %s/%s :%s' \
                    print '[%s] Unable to create package %s/%s :%s' \
                                      % (_update_type, target, package, error)
            commit_msg="uploaded to package %s/%s from %s" % (target, package, profile)
            try:
                build.commit_files(target, package,
                       [(_update_type, True)], commit_msg)
            except ObsError, error:
                raise UploadError("Unable to upload %s to %s: %s" % \
                    (_update_type, target, error))

            dbg_prn = '%s %s\n        ' % (_update_type, package)
            if _update_type == '_aggregate':
                build.set_meta(upload_packages[package]['meta'], target, package)
                dbg_prn = '%s%s' % (dbg_prn, raw)
            elif _update_type == '_service':
                dbg_prn = '%s%s (%s)' % (dbg_prn, raw.split("\'revision\'>")[1].split('<')[0], \
                                         raw.split("file://")[1].split('<')[0])

            print '    [_update %d/%d] %s' % (dbg_idx, len(upload_packages), dbg_prn)

    def update_packages(self, remote_build, build, profile, target, upload_packages):
        print '  Total packages to check... %d' % len(upload_packages)
        plain_packages = upload_packages.copy()

        # Move time-consuming packages to front
        power_packages = {}
        for x in ['chromium-efl', 'linux-exynos', 'gdb', 'elementary', 'efl', 'emulator-kernel']:
            if x in upload_packages:
                power_packages[x] = upload_packages[x]
                del plain_packages[x]
        if power_packages:
            self._update_packages(remote_build, build, profile, target, power_packages)
        if upload_packages:
            self._update_packages(remote_build, build, profile, target, plain_packages)

    def create_related_packages(self, remote_build, build, profile, target):
        """create the 'link' package that relate the original package
           profile is the base project
           target  is the target project
        """
        sourceinfo = remote_build.get_sourceinfo_list(profile)
        for package in sourceinfo:
            if sourceinfo[package]:
                link_prj, link_pkg = sourceinfo[package][-1].split('/')
                if link_prj and link_pkg:
                    if build.exists(target, package):
                        build.delete_package(target, package)
                    build.create_link_pac(target, link_pkg, \
                                           target, package)
                    print '  [_link] %s/%s -> %s/%s' % (target, link_pkg, target, package)

    def compare_with_manifest(self, todo_dict, manifest_packages):
        #TODO: If we have changed git path???
        #TODO: If manifest items are not proceeded???
        for item in todo_dict:
            if 'git' in todo_dict[item] and todo_dict[item]['git'] \
                and todo_dict[item]['git'] in manifest_packages:
                rev_my = todo_dict[item]['rev']
                rev_snapshot = manifest_packages[todo_dict[item]['git']]
                if rev_my != rev_snapshot:
                    print '  >> DIFFER (%s) -> (%s) %s' % (rev_my, rev_snapshot, item)
                    todo_dict[item]['rev'] = rev_snapshot
                    todo_dict[item]['content'] = todo_dict[item]['content'].replace(rev_my, rev_snapshot)
                    todo_dict[item]['exist'] = False

        # Remove packages that are already exists which do not need to update
        for k, v in todo_dict.items():
            if 'exist' in v and v['exist'] == True:
                del todo_dict[k]
        return todo_dict

    def run_profile_update(self, profile, target):

        obs_api = os.getenv("OBS_API_URL")
        obs_user = os.getenv("OBS_API_USERNAME")
        obs_passwd = os.getenv("OBS_API_PASSWD")

        build = BuildService(obs_api, obs_user, obs_passwd)

        this_project = profile

        if build.exists(this_project):
            try:
                build.unlink_project(this_project)
            except Exception, err:
                print 'Your project %s is broken: %s. Re-create it!' % (this_project, err)
                build.cleanup(this_project, "Create new.")
                sleep(10) # Wait 30 seconds...
                build.create_project(this_project, target)
        else:
            build.create_project(this_project, target)

        build.disable_build_flag(this_project, repo = None, flag='build', status='disable')
        build.disable_build_flag(this_project, repo = None, flag='publish', status='disable')
        #build.link_project(this_project, src=target, linktype=None)

        target_meta = build.get_meta(target)
        print 'OK we got target_meta...\n%s' % target_meta
        target_xml_meta = ElementTree.fromstringlist(target_meta)
        target_xml_meta.attrib['name'] = this_project
        target_xml_meta.find('title').text = 'Reference from %s' % target
        for repo_element in target_xml_meta.findall('repository'):
            for element in repo_element.findall('path'):
                repo_element.remove(element)
            #element.set('project', target)
            #element.set('repository', repo_element.get('name'))
            repo_element.insert(-1, ElementTree.Element('path', project=target, repository=repo_element.get('name')))

        print 'set meta started...\n%s' % ElementTree.tostring(target_xml_meta)
        build.set_meta(ElementTree.tostring(target_xml_meta), this_project)

        build.link_project(this_project, src=target, linktype=None)

        print 'Profile %s updated to %s' % (profile, target)

    def run_sync_obs(self):

        force_trigger = False

        print '---[JOB STARTED]-------------------------'

        obs_api = os.getenv("OBS_API_URL")
        obs_user = os.getenv("OBS_API_USERNAME")
        obs_passwd = os.getenv("OBS_API_PASSWD")

        remote_obs_api = os.getenv("PUBLIC_OBS_API_URL")
        remote_obs_user = os.getenv("PUBLIC_OBS_API_USERNAME")
        remote_obs_passwd = os.getenv("PUBLIC_OBS_API_PASSWD")

        remote_meta = ''
        config = ''
        remote_package_list = ''

        todo_dict = {}

        # precheck profile
        fields = ''
        fields = trigger_info(os.getenv('TRIGGER_INFO'))

        # Check if we've got required field in TRIGGER_INFO
        for field in ('snapshotdir', 'build_id', 'project'):
            if field not in fields:
                print 'Error: TRIGGER_INFO doesn\'t contain %s' % field
                return -1

        self.profile = self.setup_profile(fields['project'])
        if not self.profile:
            print 'Skip Sync OBS project %s' % fields['project']
            return 0

        print '\nJOB Started at %s' % (str(datetime.now()))

        src = profile = self.profile['project']
        baseproject = self.profile['baseproject']
        build_id = fields['build_id']
        buildid = fields['build_id'].split('_')[1]
        snapshotdir = fields['snapshotdir']
        #print "buildid %s" %(buildid)

        refname = "%s:ref:" % (profile)
        target = "%s%s" %(refname,buildid)
        if os.getenv('TRIGGER_MISC') == 'importrpmdone':
            return self.run_profile_update(self.profile['project'], target)

        #### remote buildservice ####
        remote_build = BuildService(remote_obs_api, remote_obs_user, remote_obs_passwd)
        #### target buildservice ####
        build = BuildService(obs_api, obs_user, obs_passwd, \
                             remote_obs_api, remote_obs_user, remote_obs_passwd)
        #get project list
        projectlist = [ prj for prj in build.get_package_list("") if prj.split(':')[0] == "Tizen" ]
        #print "\n********\n  Project List=%s" % projectlist

        refprojectlist = [ obj for obj in projectlist if refname in obj ]
        #exclude target project in refprojectlist
        if target in refprojectlist:
            refprojectlist.remove(target)
        print "\n  Ref Project List=%s" % refprojectlist

        # get base ref project
        # get list of ref projects from git-ref-mapping
        gerrit_env = GerritEnv("PUBLIC_")
        obs_ref_prjs = get_ref_map(baseproject, None, \
                                   gitcache=gerrit_env.gitcache, \
                                   gerrit_hostname=gerrit_env.hostname, \
                                   gerrit_username=gerrit_env.username, \
                                   gerrit_sshport=gerrit_env.sshport
                                   )
        #TODO:HYOKEUN
        print 'baseproject:%s' % baseproject
        print 'obs_ref_prjs:%s' % obs_ref_prjs
        base_mapping_list = [ x['OBS_package'] for x in obs_ref_prjs if x['OBS_project'] == baseproject ]
        #TODO:HYOKEUN
        print 'base_mapping_list:%s' % base_mapping_list
        baserefproject = ''
        if base_mapping_list:
            baserefproject = base_mapping_list[0]
            print "\n  Ref Base Project from mapping=[%s]" % baserefproject
        else:
            if baseproject:
                basereflists = []
                [ basereflists.append(obj) for obj in projectlist \
                  if "%s:ref:" % (baseproject) in obj ]
                if basereflists:
                    baserefproject = list(basereflists)[-1]
                    print "\n  Ref Base Project from latest=[%s]" % baserefproject
        print "\n********"

        if not refprojectlist: # CopyLocalProject = False
            src = profile
            build_src = remote_build
        else:                  # CopyLocalProject = True
            src = list(refprojectlist)[-1]
            build_src = build
        print "src = %s , target = %s" %(src, target)

        print "  0) Get meta, config, package list from remote [ %s ]" % (profile)
        remote_meta = remote_build.get_meta(profile)
        config = remote_build.get_project_config(profile)
        remote_package_list = remote_build.get_package_list(profile)
        print '\nGet Package List from Remote Done at %s' % (str(datetime.now()))

        print "\n    0-1) copy package list (%d):\n %s" %(len(remote_package_list), remote_package_list)
        if not build.exists(target):
            print "\n    0-2) create project: %s" %(target)
            self.create_project(build, target, None, remote_meta, config, baserefproject)
            todo_dict = self.list_packages_from_remote(build_src, build, src, target)
        else:
            print "\n    0-2) project already exists: %s" %(target)
            todo_dict = self.list_packages_from_remote(build_src, build, target, target, existing=True)

        print '\nListing from Remote Done at %s' % (str(datetime.now()))
        print 'todo_dict(%d):' % (len(todo_dict))

        if True:
            package_list = [ x for x in todo_dict ]
            print "\n********"
            print "  1) package list of target project \n %s" %(package_list)

            packages = self.remove_duplicates(package_list, remote_package_list)
            print "\n********"
            print "  2) remove package %s" %(packages)
            for pkgname in packages:
                del todo_dict[pkgname]
                #build.delete_package(target, pkgname)

            packages = self.remove_duplicates(remote_package_list, package_list)
            print "\n********"
            print "  3) add packages %s" %(packages)
            if packages:
                ret_dict_add = self.list_packages_from_remote(\
                                        remote_build, build, profile, target, packages=packages)
                if ret_dict_add:
                    todo_dict.update(ret_dict_add)
            print '\nAdd Remove Done at %s' % (str(datetime.now()))

            print "\n********"
            print "  4) compare package project "
            manifest_packages = get_manifest_filelists_snapshot(self.profile, \
                                                 os.path.join(os.getenv("URL_PUBLIC_REPO_BASE"), \
                                                 snapshotdir,\
                                                 "builddata/manifest"))
            todo_dict = self.compare_with_manifest(todo_dict, manifest_packages)
            print '\nCompare With Manifest Done at %s' % (str(datetime.now()))

            print '\n  4-1) Final packages to be updated %d' % len(todo_dict)
            sys.stdout.flush()
            self.update_packages(remote_build, build, profile, target, todo_dict)
            print '\nUpdate Packages Done at %s' % (str(datetime.now()))

        print "\n********"
        print "  5) Precheck all error package list from project"

        need_runservice = []
        for _wait in range(0,15):
            sys.stdout.flush()
            sleep(10) # Wait 10 seconds...
            viewinfofile = build.get_source_viewinfo(target, nofilename=0)
            root = ElementTree.parse(viewinfofile).getroot()
            errpackages = ''
            errpackages = [ s.get('package') for s in root.iter('sourceinfo') if s.findall('error') ]
            for x in root.iter('sourceinfo'):
                for y in x.findall('filename'):
                    if '_service:gbs:service-error.spec' in y.text:
                        errpackages.append(x.get('package'))
                        break
                for y in x.findall('error'):
                    if 'bad build configuration, no build type' in y.text:
                        errpackages.remove(x.get('package'))
            if errpackages:
                print '    5-1) Under packages are still... (%d)\n    %s' % (len(errpackages), errpackages)
                # Retrigger git sync
                for item in errpackages:
                    pkgview = ElementTree.fromstring(build.get_source_info(target, item))
                    for sv in pkgview.findall('serviceinfo'):
                        if sv.get('code') != 'failed': continue
                        for er in sv.findall('error'):
                            print '        %s %s with cause: (%s)' % (item, sv.get('code'), er.text)
                            need_runservice.append(item)
                            if item not in todo_dict or 'git' not in todo_dict[item]: continue
                            queue_id = trigger_jenkins_build('TRBS_OBS_UPDATE_GIT', \
                                                             {'GERRIT_PROJECT': todo_dict[item]['git']}, \
                                                             cred={'url': os.getenv('REMOTE_TRBS_JENKINS_URL'), \
                                                                   'username': os.getenv('REMOTE_TRBS_JENKINS_USER'), \
                                                                   'password': os.getenv('REMOTE_TRBS_JENKINS_PW')}, \
                                                             block=False)
                            print '        QUEUED.. %s' % queue_id
                sys.stdout.flush()
                sleep(30) # Wait 30 seconds...
                for item in need_runservice:
                    print '        runservice for %s' % item
                    build.runservice(target, item)
                need_runservice = []
            else:
                print '    5-2) All packages imported.'
                break

        print "\n********"
        print "  6) create related packages \n"
        self.create_related_packages(remote_build, build, profile, target)

        print "\n********"
        print "  7) Sync Done..."

        # importrpm trigger next
        fields['profile'] = profile
        fields['target'] = target
        trigger_next("importrpm_obs", fields)

        if errpackages:
            return 1
        return 0

    def main(self):

        print('-----[JOB STARTED: trigger_for_sync_repo ]-----')
        for loop in range(1):
            try:
                return self.run_sync_obs()
            except Exception, err:
                print 'run_sync_obs operation failed, retrying...'
                print err
                raise LocalError("FAIL %s" % (err))
            sleep(5)

        return True

if __name__ == '__main__':

    try:
        trigger = trigger_for_sync_obs()
        sys.exit(trigger.main())
    except Exception as e:
        print(e)
        sys.exit(1)

