#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4
#
# Copyright (C) 2017 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.
#
#    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.
#
"""
Common part of the CI process
"""

import os
import sys
import json
import re
import requests
import ast
import xml.etree.cElementTree as ElementTree
from xml.sax.saxutils import escape
from time import sleep

from gitbuildsys.errors import ObsError

from common import utils
from common.mapping import git_obs_map, git_virtual_branch_map
from common.upload_service import upload_obs_service, upload_obs_service_gbp, UploadError
from common.prerelease import get_info_from_prerelease_name, is_devbase_project
from common.git import Git, clone_gitproject
from common.gerrit import GerritEnv, GerritError
from common import runner
from common.send_mail import prepare_mail

from gbp.rpm import SpecFile
from gbp.git.repository import GitRepositoryError
from gbp.errors import GbpError

from common import buildmonitor_db

# set default char-set endcoding to utf-8
reload(sys)
sys.setdefaultencoding('utf-8') # pylint: disable-msg=E1101

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

HIGHLIGHT = '+'
GREYEDOUT = '-'
EMPTY_REV = '0'
MODE_NORMAL = 'NORMAL'
MODE_SRSYNC = 'SR-SYNC'

WRONG_DATE_MSG = '- The date %s in tag does NOT follow correct format.\n You can'\
                 ' use shell command "date --utc +%%Y%%m%%d.%%H%%M%%S" to '\
                 'generate it, like 20120801.083113.'

UNDER_REVIEW_MSG = '- Submission %s has been rejected because tagged commit %s'\
                   ' is still under review in gerrit.\n Please re-trigger '\
                   'submission after your change is accepted.'

WRONG_COMMIT_MSG = '- The commit %s tag attached does NOT exist in git tree or'\
                   ' gerrit open change.\n Please make sure the commit has been '\
                   'pushed to gerrit and correct magical ref refs/for/branch, '\
                   'then re-submit tag.'

UNKNOWN_FORMAT_MSG = '- Unknown tag format,\n please follow the format '\
                     'submit/{version}/{date.time}.'

WRONG_FORMAT_MSG = '- Wrong tag format,\n please follow the format '\
                   'submit/{branch}/{date.time}. \n'\
                   'Git branch : %s. Tag branch: %s'

NOT_ANNOTATED_MSG = '- Tag should be annotated tag.'

SUGGESTION = 'Suggest to use "gbs submit" to trigger submission\n'\

SR_PROCESS_FINISHED_MSG = '- Submit blocked due to group SR(%s) already been %s.\n'\
                          '  Please refer to %s.\n'\
                          '  Or re-submit with another tag if needed.'

class MailSender(object):
    email_title = ''
    email_head  = ''
    email_body = ''
    email_footer = '\n\n--------------------------------------------------------\n'\
                   'Automatically generated by backend service.\n'\
                   'Please DO NOT Reply!'
    email_to = []

    def __init__(self, receiver=None, title=None, body=None):
        if receiver is not None: self.email_to = receiver
        if title is not None: self.email_title = title
        if body is not None: self.email_body = body

    def add_receiver(self, add_new):
        """ add receiver """
        if type(add_new) == list:
            self.email_to.extend(x for x in add_new)
        elif type(add_new) == str:
            self.email_to.append(add_new)
        else:
            print 'TYPE(%s) == %s' % (add_new, type(add_new))
        self.email_to = list(set(self.email_to))

    def add_title(self, add_new):
        """ add title """
        self.email_title = self.email_title + ' ' + add_new

    def add_message(self, add_new, top=None):
        """ add message """
        if top is not None:
            self.email_body = add_new + '\n' + self.email_body
        else:
            self.email_body = self.email_body + '\n' + add_new

    def add_maintainers(self, mygerrit, group_name=None, project=None):
        """ add maintainers """
        if not mygerrit:
            print 'mygerrit is Null...'
            return

        if not project and group_name:
            mbrs = mygerrit.ls_members(['\'\"%s\"\'' % group_name, '--recursive'])
            for line in mbrs:
                self.add_receiver(line.split('\t')[3])
            return

        if project:
            grps = mygerrit.ls_groups(['--project %s' % project])
            dest_grp = [s for s in grps if " - Maintainers" in s]
            for dg in dest_grp:
                mbrs = mygerrit.ls_members(['\'\"%s\"\'' % dg, '--recursive'])
                for line in mbrs:
                    self.add_receiver(line.split('\t')[3])
            return

    def send_mail(self):
        """ send mail """
        self.email_body = self.email_head + self.email_body + self.email_footer

        self.email_to = [x for x in self.email_to if x != 'n/a']
        print '\n\n'
        print self.email_title
        #m_body = ''
        #for m in self.email_body.splitlines():
        #    m_body += '\n'.join(m[i:i+128] for i in xrange(0, len(m), 128)) + '\n'
        #self.email_body = m_body
        print self.email_body
        print self.email_to

        prepare_mail("%s.env" % os.getenv('BUILD_TAG'), \
                     self.email_title, \
                     self.email_body, \
                     os.getenv('NOREPLY_EMAIL_SENDER'), \
                     self.email_to)

def parse_submit_tag(tag):
    """parse info from submit tag name"""

    branch = None
    date = None

    if tag.startswith('submit/'):
        pos = tag.rfind('/', len('submit/'))
        if pos != -1:
            branch = tag[len('submit/'):pos]
            if branch == 'trunk':
                branch = 'master'
            date = tag[pos+1:]

    return branch, date

def find_submit_tag(event, mygit):
    """find the corresponding submit tag for this event"""

    if event['event_type'] == 'ref-updated':
        tag = event['refname'][len('refs/tags/'):]
        event['branch'] = parse_submit_tag(tag)[0]
        # Since patchset_revision is used in gerrit feedback, real tag check
        # is needed; and the key point is parse_submit_tag can not ensure the
        # tag exsisting too.
        try:
            event['patchset_revision'] = mygit.rev_parse('%s^{commit}' % tag)
        except GitRepositoryError:
            tag = None
    elif event['event_type'] == 'change-merged':
        # for chanage-merged, search submit tag on this commit
        branch = event['branch']
        if event['branch'] == 'master':
            branch = 'trunk'
        try:
            tag = mygit.describe(event['patchset_revision'],
                                 pattern='submit/%s/*' % branch,
                                 exact_match=True)
        except GitRepositoryError:
            # don'n find submit tag on this commit, return None
            tag = None

    return tag

def check_tag_format(git, mygerrit, event, tag):
    """check whether tag follow proper format"""

    branch, date = parse_submit_tag(tag)
    message = []
    psr = event['patchset_revision']

    # check tag name format
    if branch and date:
        # check date format
        pattern = re.compile(r'^[0-9]{8}\.[0-9]{6}$')
        if not pattern.match(date):
            message.append(WRONG_DATE_MSG % date)

        if not git.branch_contains(tag):
            # Check if change is still under review
            cmd = '--current-patch-set status: open project: %s commit: %s' % \
                      (event['project'], psr)
            gerritinfo = mygerrit.query(cmd)
            if len(gerritinfo) == 1 and 'number' in gerritinfo[0] \
                    and 'currentPatchSet' in gerritinfo[0]:
                if gerritinfo[0]['branch'] == branch:
                    # the tagged commit still open, abort submit this time
                    message.append(UNDER_REVIEW_MSG % (tag, psr))
            else:
                # cannot find tagged commit in git tree or gerrit open change
                message.append(WRONG_COMMIT_MSG % psr)
        else:
            # check for contains branch
            contain = False
            cbrch = git.branch_contains(tag)
            if branch in cbrch:
                print '%s branch is contains in %s branch' %(branch, cbrch)
                contain = True
            else:
                vbrch = git_virtual_branch_map()
                for items in vbrch:
                    if '%s' %(branch) in items and \
                        items['%s' %(branch)] is not None \
                        and items['%s' %(branch)] in cbrch:
                        print '%s branch is virtual %s branch' %(branch, items['%s' %(branch)])
                        contain = True
            if not contain:
                # wrong tag format
                print '%s branch is not contains in %s branch' %(branch, cbrch)
                message.append(WRONG_FORMAT_MSG % (cbrch, branch))
    else:
        # wrong tag format
        message.append(UNKNOWN_FORMAT_MSG)

    # check whether tag is an annotated tag
    tagger = git.get_tag(tag)
    if 'author' not in tagger or 'email' not in tagger:
        message.append(NOT_ANNOTATED_MSG)

    # post comment to gerrit and send email if check failed
    if message:
        print message

        msg = 'The tag %s was pushed, but it was not completed because of '\
                'the following reason(s):\n\n' % tag + '\n'.join(message)

        if len(message) != 1 or (message[0] != UNDER_REVIEW_MSG % (tag, psr) \
           and message[0] != WRONG_COMMIT_MSG % psr):
            msg += '\n\n' + SUGGESTION

        try:
            mygerrit.review(commit=psr, message=msg)
        except GerritError, err:
            print >> sys.stderr, 'Error posting review comment '\
                                 'back to Gerrit: %s' % str(err)
            # return 1 if this exception is not caused by invalid commit
            if 'no such patch set' not in str(err):
                return None

        return {'message': msg, 'tagger': tagger}

    return None

def find_specfile(prj_dir, packaging_dir, tag, event, tagger, pkg_name=None, debug_prj_name=None):
    """search specfile under packaging directory"""

    msg = ''

    if True:
        specs = utils.find_spec('%s/%s' % (prj_dir, packaging_dir))
        if not specs:
            # no spec exist under packaging, use default name
            msg = "The tag %s pushed, but packaging directory doesn't \n"\
                    "contain any spec file. Please create one and \n"\
                    "re-submit it." % tag
        elif len(specs) == 1:
            # only one spec exist under packaging
            spec = specs[0]
            print 'Single spec. Use %s' % os.path.basename(spec)
        else:
            # multiple specs exist under packaging, use default name
            spec = None
            if pkg_name:
                spec = '%s/%s/%s.spec' % (prj_dir, packaging_dir, pkg_name)
                print 'Multiple specs. Try %s' % os.path.basename(spec)
            if spec is None or not os.path.isfile(spec):
                spec = '%s/%s/%s.spec' % (prj_dir, packaging_dir, \
                        os.path.basename(event['project']))
                print 'Multiple specs with no pkg_name.spec. Try %s' % os.path.basename(spec)
            if spec is None or not os.path.isfile(spec) or os.path.basename(event['project']).find('.') != -1:
                print os.path.basename(event['project'])
                spec = '%s/%s/%s.spec' % (prj_dir, packaging_dir, os.path.basename(event['project']).split('.')[-1])
                print 'Multiple specs with no pkg_name.spec. Try %s' % os.path.basename(event['project']).split('.')[-1]
            if not os.path.isfile(spec):
                spec = sorted(specs)[0]
                print 'Multiple sorted(specs)[0] %s' % os.path.basename(spec)
            if not os.path.isfile(spec):
                msg = "The tag %s pushed, but packaging directory contains \n"\
                        "multiply spec files, backend service can not decide \n"\
                        "which spec file to use. Please use OBS_PACKAGE \n"\
                        "parameter in scm/git-obs-mapping project to specify \n"\
                        "the target spec file or contact system \n"\
                        "administrator for more details." % tag

    if msg:
        if debug_prj_name is not None:
            msg = "TARGET_PROJECT: %s\n%s" % (debug_prj_name, msg)
        print msg
        return {'message': msg, 'spec': None}
    else:
        print 'specfile %s' % spec
        return {'message': None, 'spec': spec}

def parse_specfile2(specfile, tag, event, tagger):
    """parse specfile"""

    spec = None

    try:
        # use gbp to parse specfile
        spec = SpecFile(specfile)
    except GbpError, err:
        print 'gbp parse spec failed. %s' % err
        msg = 'The tag %s pushed, but backend service failed to parse %s. \n'\
                'Please try "gbs export" on this tag and make sure it can '\
                'work.\n\n'\
                'Error message:\n'\
                '%s' % (tag, os.path.basename(specfile), err)
        del spec
        return {'message': msg, 'spec': None}

    specname = spec.name
    del spec
    return {'message': None, 'spec': specname}

def parse_specfile(specfile, tag, event, tagger):
    """parse specfile"""

    spec = None

    try:
        # use gbp to parse specfile
        spec = SpecFile(specfile)
    except GbpError, err:
        print 'gbp parse spec failed. %s' % err
        msg = 'The tag %s pushed, but backend service failed to parse %s. \n'\
                'Please try "gbs export" on this tag and make sure it can '\
                'work.\n\n'\
                'Error message:\n'\
                '%s' % (tag, os.path.basename(specfile), err)
        return {'message': msg, 'spec': None}

    return {'message': None, 'spec': spec}

def change_release_name(build, project, git_tag):
    """
    Change release name from project config in OBS
    Add the datetime into release name.
    Eg: 'Release: <CI_CNT>.<B_CNT>' ----> 'Release: 20141010.<CI_CNT>.<B_CNT>'
    """
    # get project config
    config = build.get_project_config(project)
    release_name = 'Release: %s' % (git_tag.split('/')[-1])
    res = re.findall(r'^Release: ?\S+$', config, flags=re.MULTILINE)
    if res:
        if git_tag.split('/')[-1] not in res[0]:
            note = '#Insert time from submission into release name\n'
            release_name = '%s.%s' % (release_name,
                                      res[0].split('Release:')[1].strip())
            config = config.replace(res[0], '%s%s' % (note, release_name), 1)
    else:
        note = '#Add release name into prjconf\n'
        config = note + '%s\n' % release_name + config

    #Add rpmbuild stage option
    if os.getenv('PRERELEASE_RPMBUILD_STAGE'):
        # Check if we've got required fields in TRIGGER_INFO
        if not os.getenv('PRERELEASE_RPMBUILD_STAGE') in ('ba', 'bb'):
            print 'Error: PRERELEASE_RPMBUILD_STAGE %s' % (os.getenv('PRERELEASE_RPMBUILD_STAGE'))
        else:
            rpmbuildstage = 'Rpmbuildstage: -%s' % (os.getenv('PRERELEASE_RPMBUILD_STAGE'))
            res = re.findall(r'^Rpmbuildstage: ?\S+$', config, flags=re.MULTILINE)
            if res:
                config = config.replace(res[0], '%s' % (rpmbuildstage), 1)
            else:
                config = config + '#Add RpmbuildStage option into prjconf\n' + '%s\n' % (rpmbuildstage)

    # Add "CopyLinkedPackages: yes" for prerelease projects.
    if not re.search("CopyLinkedPackages:", config):
      config = config + "\nCopyLinkedPackages: yes\n"

    # set project config
    build.set_project_config(project, config)

def copy_person_project_meta(build, obs_target_prj, obs_project):
    """copy the maintainer list from obs_target_prj meta to corresponding
       prerelease project
    """
    src_meta_xml = build.get_meta(obs_target_prj)
    src_xml_root = ElementTree.fromstringlist(src_meta_xml)
    # get peron list from obs_target_prj meta
    person_dict = {}
    for person in src_xml_root.findall('person'):
        if person.get('userid') in person_dict:
            person_dict[person.get('userid')].append(person.get('role'))
        else:
            person_dict[person.get('userid')] = [person.get('role')]
    # add person to prerelease project
    if person_dict:
        build.addPerson(obs_project, person_dict)

def create_related_packages(build, obs_target_prj, obs_pre_prj, pre_package):
    """create the 'link' package that relate the original package
       obs_target_prj is the base project
       obs_pre_prj is the prelease project
       pre_package is the original package
    """
    sourceinfo = build.get_sourceinfo_list(obs_target_prj)
    for package in sourceinfo:
        if sourceinfo[package]:
            link_prj, link_pkg = sourceinfo[package][-1].split('/')
            if link_prj == obs_target_prj and link_pkg == pre_package:
                build.create_link_pac(obs_pre_prj, pre_package, \
                                       obs_pre_prj, package)
        if re.search("_aggregate", package):
            print "Copypac aggregate package: %s/%s" %(obs_pre_prj, package)
            build.create_copy_pac(obs_target_prj, package, obs_pre_prj,\
                package)
            aggregate_file_name="_aggregate"
            build.get_source_file(obs_target_prj, package, aggregate_file_name)
            content = ""
            with open(aggregate_file_name, 'r') as f:
                content = f.read()

            if not re.search("qemu_aggregate", package) and \
               not re.search("java-1_6_0-sun_aggregate", package) and \
               not re.search("jpackage-utils_aggregate", package):
                content_xml_root = ElementTree.fromstringlist(content)
                for element in content_xml_root.findall('aggregate'):
                    #TODO: Set aggregate project only for matched project
                    if element.get('project') == obs_target_prj:
                        element.set('project',obs_pre_prj)
                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" % (obs_pre_prj, package, obs_target_prj)
                try:
                    build.commit_files(obs_pre_prj, package,
                           [(aggregate_file_name, True)], commit_msg)
                except ObsError, error:
                    raise UploadError("Unable to upload _aggregate to %s: %s" % \
                        (obs_pre_prj, error))
            print "Copypac done."

def get_base_project(build, _project):
    _meta = build.get_meta(_project)
    xml_meta = ElementTree.fromstringlist(_meta)
    _base_prj = ''
    for repos in xml_meta.findall('repository'):
        for path in repos.findall('path'):
            if 'base' not in path.get('project').lower(): continue
            print 'Found base project %s for %s' % (path.get('project'), \
                                                    _project)
            return path.get('project')
    return None

def create_project(build, obs_project, submit_list, mode=MODE_NORMAL):
    """
    Create prerelease OBS project and upload sources for the build.
    Parameters:
      @ build (buildservice.BuildService): Instance of BuildService
      @ obs_project (str): Project name to be created
      @ submit_list (list):
         [
            {
              'project'(O)           : Prerelease project name
              'package'(M)           : OBS package name
              'gerrit_project'(M)    : Git path
              'git_tag'(M)           : Git tag name
              'gerrit_newrev'(O)     : Revision of the tag
              'submitter'(M)         : Author of the tag
              'build_flag'(O)        : Enable/Disable OBS build after create
              'obs_target_prj'(O)    : Target OBS project
              'ref_obs_target_prj'(O): Reference target OBS project to be linked
              'url'(O)               : Hostname of the gerrit server for _service file
            },
         ]
    """

    # Create review project if it doesn't exist
    print "Creating temporary review OBS project %s" % obs_project

    print '\nsubmit_list:\n'
    for s in submit_list:
        print '++++'
        for u in s:
            print '[%s]: %s' % (u, s[u])

    _git_url = 'ssh://%s:%s' % (os.getenv('GERRIT_HOSTNAME_EXTERNAL'),
                               os.getenv('GERRIT_SSHPORT'))
    git_revision = []
    _dest_obs_prj, tstamp = get_info_from_prerelease_name(obs_project)

    git_url = submit_list[0].get('url', _git_url)
    git_project = [ t['gerrit_project'] for t in (u for u in submit_list) ]
    if mode == MODE_SRSYNC:
        git_project = [ t['gerrit_project'][1:] for t in (u for u in submit_list) ]
    git_tag = submit_list[0].get('git_tag')
    # Group submit should have the same tag name
    for gt in submit_list:
        if mode == MODE_NORMAL:
            assert gt['git_tag'] == git_tag
    for u in submit_list:
        gerrit_path = u.get('gerrit_project')
        if 'gerrit_newrev' in u:
            git_revision.append(u.get('gerrit_newrev'))
        else:
            _rev = EMPTY_REV
            # Find revision of the tag
            if mode == MODE_NORMAL:
                _path = os.path.join(os.getenv('GIT_CACHE_DIR'), gerrit_path)+'.git'
                _rev = Git(_path).get_tag(u.get('git_tag'))['tagrevision']
            elif mode == MODE_SRSYNC:
                if gerrit_path.startswith(HIGHLIGHT):
                    _path = os.path.join(os.getenv('PUBLIC_GIT_CACHE_DIR'), gerrit_path[1:])
                    _rev = Git(_path).get_tag(u.get('git_tag'))['tagrevision']
            git_revision.append(_rev)

    # Return if all the packages are forked git
    if mode == MODE_SRSYNC:
        if git_revision[0] == EMPTY_REV and \
            git_revision.count(git_revision[0]) == len(git_revision):
            print 'ALL HAVE THE EMPTY_REV. SKIP!'
            return

    obs_target_prj = submit_list[0].get('obs_target_prj', _dest_obs_prj)
    ref_obs_target_prj = submit_list[0].get('ref_obs_target_prj', obs_target_prj)
    if mode == MODE_SRSYNC:
        obs_target_prj = ref_obs_target_prj = _dest_obs_prj
    submitter = ','.join(list(set([ t['submitter'] for t in (u for u in submit_list) if 'submitter' in t ])))
    package = [ t['package'] for t in (u for u in submit_list) ]
    build_flag = submit_list[0].get('build_flag', True)
    print '\nCREATING....%s\n%s\n%s\n%s\n%s\n' % (obs_project, git_project, git_revision, submitter, package)
    sys.stdout.flush()

    info = {'projects': git_project,
            'packages': package,
            'obs_target_prj': obs_target_prj,
            'ref_obs_target_prj': ref_obs_target_prj,
            'git_tag': git_tag,
            'git_commit': git_revision,
            'obs_url': os.path.join(os.getenv('OBS_URL_EXTERNAL'), \
                                    'project/show?project=%s' % obs_project),
            'images': [],
            'base': get_base_project(build, ref_obs_target_prj)
           }

    # Enable Github Connection
    github_item = {}
    for u in submit_list:
        if u.get('github_type'):
            github_item[u.get('gerrit_project')] = u.get('github_fetch_url')

    if github_item:
        info['github'] = {}
        info['github'].update(github_item)

    if mode == MODE_SRSYNC:
        submissions = []
        for x in submit_list:
            # Lets add submit tag name only w/o git path
            submissions.append({x['git_tag']: []})
            #TODO: Adding project git path and its package name delimited by =
            #bFound = False
            #for idx, t in enumerate(submissions):
            #    if t.keys()[0] == x['git_tag']:
            #        bFound = True
            #        submissions[idx][submissions[idx].keys()[0]].append(x['gerrit_project'] + '=' + x['package'])
            #        break
            #if bFound == False:
            #    submissions.append({x['git_tag']: [x['gerrit_project'] + '=' + x['package']]})
        info['projects'] = []
        info['packages'] = []
        info['git_tag'] = obs_project.split(':'+obs_target_prj+':')[-1].replace(':','/')
        info['git_commit'] = []
        info['submissions'] = submissions

    if build.exists(obs_project):
        if submitter:
            info['submitter'] = submitter

        # update project info
        build.update_info(info, obs_project)
        # unlink the project to upload packages
        try:
            if build_flag == True:
                build.unlink_project(obs_project)
        except ObsError, error:
            print 'Modify the meta conf to unlink failed: %s' % error
    else:
        if submitter:
            info['submitter'] = escape(submitter)

        if not build.exists(ref_obs_target_prj):
            raise LocalError("Target project %s doesn't exist" % ref_obs_target_prj)
        try:
            build.create_project(obs_project, ref_obs_target_prj,
                                 description=json.dumps(info))
        except ObsError, error:
            LocalError("Unable to create project %s: %s" % (obs_project, error))

    # change release name of project config in OBS
    change_release_name(build, obs_project, git_tag)

    #disable publish flag
    build.disable_build_flag(obs_project, repo = None, flag="publish", status="disable")
    #disable build flag
    build.disable_build_flag(obs_project, repo = None, flag="build", status="disable")

    try:
        for idx, val in enumerate(git_project):
            if mode == MODE_SRSYNC and \
                (not git_project[idx] or not git_tag  or \
                 not package[idx] or git_revision[idx] == EMPTY_REV):
                print '**** SKIP FORKED PACKAGE: %s,%s,%s,%s' \
                    % (git_project[idx], package[idx], git_tag, git_revision[idx])
                continue
            print '<< %s >>' % package[idx]
            sys.stdout.flush()
            # if obs_project is devbase project then use the gbp to export.
            if is_devbase_project(obs_project):
                upload_obs_service_gbp(git_url, git_project[idx], git_tag,
                                       git_revision[idx], obs_project, build, package[idx])
            else:
                upload_obs_service(git_url, git_project[idx], git_tag,
                                   git_revision[idx], obs_project, build, package[idx])
    except UploadError, err:
        raise LocalError(err)

    # copy the maintainer list from obs_target_prj meta to corresponding
    # prerelease project
    copy_person_project_meta(build, obs_target_prj, obs_project)

    if build_flag != True:
        return

    #create the 'link' package that relate the original package
    for idx, val in enumerate(package):
        if val and package[idx]:
            create_related_packages(build, obs_target_prj, obs_project, package[idx])

    #Wait 10 seconds to upload the package to the OBS
    sleep(10)

    #default build flag
    build.default_build_flag(obs_project, repo = None, flag="build")
    #default publish flag
    build.default_build_flag(obs_project, repo = None, flag="publish")

    # Enabled link project
    sleep(1)
    build.link_project(obs_project, src=ref_obs_target_prj, linktype="localdep")

def get_info_from_tag(git, branch, target_project, tag, gerrit_env=None):

    ret_data = {}
    ret_data['commit_id'] = None
    ret_data['spec_name'] = None

    if not gerrit_env:
        gerrit_env = GerritEnv()
    git_cache = gerrit_env.gitcache

    prjdir = os.path.join(git_cache, git)
    if not clone_gitproject(git, prjdir, \
                            gerrit_hostname=gerrit_env.hostname, \
                            gerrit_username=gerrit_env.username, \
                            gerrit_sshport=gerrit_env.sshport, \
                            git_cache_dir=git_cache):
        print >> sys.stderr, 'Error cloning %s' % git
        return ret_data

    mygit = Git(prjdir)
    mygit.checkout(tag)

    #TODO: Find commit id
    ret_data['commit_id'] = mygit.rev_parse('HEAD')
    print 'commit_id: %s' % ret_data['commit_id']

    packagingdir = utils.parse_link('%s/%s' % (prjdir, 'packaging'))

    obs_target_prjs = git_obs_map(git, \
                           gerrit_branch=branch, \
                           gitcache=git_cache
                          )
    for item in obs_target_prjs:
        obs_target_prj = item['OBS_project']
        obs_stg_prj = item['OBS_staging_project']
        obs_pkg = item['OBS_package']
        obs_use_specname = item['OBS_use_specname']

        if obs_target_prj != target_project:
            continue
        if obs_stg_prj not in ['prerelease', 'abs']:
            continue

        if obs_use_specname == 'yes':
            resp = find_specfile(prjdir, packagingdir, tag, {'project': git}, None)
            if not resp['spec']:
                return ret_data
#            resp = parse_specfile2(resp['spec'], tag, git, None)
#            if not resp['spec']:
#                return ret_data
            external_program = os.path.join(os.getenv('JENKINS_HOME'), 'jenkins-scripts/common/get_name_from_specfile.py')
            cmdln = '%s search -f %s -t %s' % (external_program, resp['spec'], tag)
            ret, outs = runner.show(cmdln)
            if ret == 0:
                ext_data = outs[outs.find('-----BEGIN RC OUTPUT-----')+26:outs.find('-----END RC OUTPUT-----')-1]
                resp = ast.literal_eval(ext_data)
            else:
                print ret
                raise Exception
            sys.stdout.flush()
            print 'spec name = %s' %(resp['spec'])
            ret_data['spec_name'] = resp['spec']
        else:
            if obs_pkg:
                print 'package name from mapping = %s' % (obs_pkg)
                ret_data['spec_name'] = obs_pkg
            else:
                print 'package name from basename = %s' % (os.path.basename(git))
                ret_data['spec_name'] = os.path.basename(git)

    del mygit
    return ret_data

def get_manifest_filelists_snapshot(profile, request_url, timeout=5, group=None):
        """ get manifest filelists from snapshot"""
        #p = re.compile(r'alt=\"\[(TXT|DIR|   )]*\]\".*<a href=\"(.*)\">')
        #p = re.compile(r'.*<a href=\"(.*)\">')
        #FIXME: Ubuntu Apache 2.4.18
        p = re.compile(r'.*<a href=\"(.*)\">.*</a>.*')

        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')

        results = {}
        exclude_pkgs = []
        found_links = p.findall(f.text)
        for link in found_links:
            if link == '../':
                continue
            if not link.endswith('.xml'):
                continue
            manifest_url = os.path.join(request_url, link)
            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:
                    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

        return results

def get_sr_process_status(sr):

    if os.getenv("BUILDMONITOR_ENABLED", "0") != "1":
        return None

    buildmonitor_db.connect_db()
    query = "SELECT ssd.obs_request_status, sc.git_repository, sc.sr_submitter " \
            "FROM sr_status s, sr_status_detail ssd, sr_commit sc " \
            "WHERE s.sr=%s " \
            "AND s.id = ssd.sr_status_id " \
            "AND s.id = sc.sr_status_id"
    ret_data = buildmonitor_db.get_multi_values_from_query_data(query, (sr,))
    buildmonitor_db.disconnect_db()

    message = None
    repos = []
    submitters = []
    sr_decision = None
    for row in ret_data:
        if type(row) != tuple or len(row) <= 1: continue
        if row[0] == "A": #pylint: disable=unsubscriptable-object
            sr_decision = "Accepted"
        elif row[0] == "R": #pylint: disable=unsubscriptable-object
            sr_decision = "Rejected"
        else:
            continue
        repos.append("%s" % row[1]) #pylint: disable=unsubscriptable-object
        submitters.append("%s" % row[2].strip()) #pylint: disable=unsubscriptable-object

    if sr_decision is not None:
        message = SR_PROCESS_FINISHED_MSG % (sr, sr_decision, repos) + '\n\n'

    return message

if __name__ == '__main__':
    print 'Non-executable module'
    sys.exit(0)

