#!/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 json
import base64
import re
import ast
import xml.etree.cElementTree as ElementTree
from xml.sax.saxutils import escape
from time import sleep
import datetime

from osc import core
from gitbuildsys.errors import ObsError

from common import utils
from common.mapping import git_obs_map, git_virtual_branch_map, get_ref_map
from common.git import Git, clone_gitproject
from common.upload_service import upload_obs_service, UploadError
from common.gerrit import is_ref_deleted
from common.buildservice import BuildService
from common.buildtrigger import trigger_info, trigger_next
from common.backenddb import BackendDB
from common.prerelease import get_prerelease_project_name, prerelease_enabled
from common.iris_rest_client import IrisRestClient
from common.send_mail import prepare_mail
from common.gerrit import Gerrit, get_gerrit_event, GerritError, is_ref_deleted
from gbp.rpm import SpecFile
from gbp.git.repository import GitRepositoryError
from gbp.errors import GbpError

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

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

TITLE_FAILED = '[Submit Request Failed]: tag: %s in %s'

TITLE_SUCCESS = '[Submit Request Success]: tag: %s in %s'

PRERELEASE_EMAIL_BODY = 'A SR (Submit Request) has been triggered to submit ' \
             'the commit to OBS project.\n' \
             'Please check the following details.\n\n' \
             'Git branch : %s\n' \
             'Git commit : %s\n\n' \
             'Git path : %s\n' \
             'Git tag : %s\n' \
             'Submitter : %s\n'

EMAIL_FOOTER = '\n\n--------------------------------------------------------\n'\
               'Automatically generated by backend service.\n'\
               'Please DO NOT Reply!'

def send_mail(title, msg, receiver):
    """ post message back to gerrit and send mail to tag owner """
    print 'msg %s' % msg
    if 'author' in receiver and 'email' in receiver:
        msg = 'Hi, %s,\n\n' % receiver['author'] + msg + EMAIL_FOOTER
        prepare_mail("%s.env" % os.getenv('BUILD_TAG'), title, msg,
                     os.getenv('NOREPLY_EMAIL_SENDER'), receiver['email'])

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 False
        if 'author' not in tagger or 'email' not in tagger:
            recevier = { 'author' : event['event_account_name'],
                          'email'  : event['event_account_email'] }
            send_mail(TITLE_FAILED % (tag, event['project']), msg, recevier)
        else:
            send_mail(TITLE_FAILED % (tag, event['project']), msg, tagger)

        return False

    return True

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 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
        send_mail(TITLE_FAILED % (tag, event['project']), msg, tagger)
        return None
    else:
        print 'specfile %s' % spec
        return spec


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)
        send_mail(TITLE_FAILED % (tag, event['project']), msg, tagger)
        return None

    return spec

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


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)

def create_project(git_url, git_project, git_tag, git_revision, build,
                   obs_target_prj, obs_project, submitter, package, build_flag=True):
    """Create prerelease OBS project and upload sources for the build."""

    # Create review project if it doesn't exist
    print "Creating temporary review OBS project %s" % obs_project
    info = {'projects': [git_project],
            'packages': [package],
            'obs_target_prj': 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': []}

    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(obs_target_prj):
            raise LocalError("Target project %s doesn't exist" % obs_target_prj)
        try:
            build.create_project(obs_project, 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:
        upload_obs_service(git_url, git_project, git_tag,
                           git_revision, obs_project, build, package)
    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

    #build.link_project(obs_project, src=obs_target_prj, linktype="localdep")

    #create the 'link' package that relate the original package
    create_related_packages(build, obs_target_prj, obs_project, package)

    #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=obs_target_prj, linktype="localdep")


def get_branch_name(tag):
    """Get branch name by parsing info
       from submit tag name.
    """
    branch = None
    if tag.startswith('submit/'):
        pos = tag.rfind('/', len('submit/'))
        if pos != -1:
            branch = tag[len('submit/'):pos]
            if branch == 'trunk':
                branch = 'master'
    return branch

def send_mail_sr_message(info, mygerrit):
    """ send mail about buildstatus """

    #make a message
    title = TITLE_SUCCESS % ( info['submitted'].get('tag'), info['submitted'].get('gitpath'))
    email_body = PRERELEASE_EMAIL_BODY % (info['submitted'].get('branch'), \
                                          info['submitted'].get('commit_id'), \
                                          info['submitted'].get('gitpath'), \
                                          info['submitted'].get('tag'), \
                                          info['submitted'].get('submitter')
                                         )
    #add products project
    email_body += 'obs_prj : %s \n' %(info['pre_created'])

    msg = 'Hello \n\n' + email_body + EMAIL_FOOTER
    print title
    print msg
    submitter = info['submitted'].get('submitter')
    if info['submitted'].get('submitter_email'):
        submitter += ' <%s>' % info['submitted'].get('submitter_email')
    if submitter:
#        email_to = []
#        if True:
#            grps = mygerrit.ls_groups(['--project %s' % info['submitted'].get('gitpath')])
#            for dg in [s for s in grps if " - Maintainers" in s]:
#                for line in mygerrit.ls_members(['\'\"%s\"\'' % dg, '--recursive']):
#                    email_to.append(line.split('\t')[3])
#        email_to = [x for x in email_to if x != 'n/a']
#
#        print 'email_to : %s ' % (email_to)
#        for user in email_to:
#            submitter += '%s,' %(user)

        prepare_mail("%s.env" % os.getenv('BUILD_TAG'), title, msg,
                     os.getenv('NOREPLY_EMAIL_SENDER'), submitter)

def main(build_type):
    """
    Script entry point.
    Parameters:
       build_type - type of the build (prerelease, snapshot)

    """

    print '---[JOB STARTED]-------------------------'
    buildmonitor_enabled = os.getenv("BUILDMONITOR_ENABLED", "0") != "0"
    print 'buildmonitor_enabled(%s)\n' % (buildmonitor_enabled)
    if buildmonitor_enabled:
        bm_start_datetime = datetime.datetime.now()

    obs_api = os.getenv("OBS_API_URL")
    obs_user = os.getenv("OBS_API_USERNAME")
    obs_passwd = os.getenv("OBS_API_PASSWD")
    gerrit_project = os.getenv("GERRIT_PROJECT")
    gerrit_refname = os.getenv("GERRIT_REFNAME")
    gerrit_oldrev = os.getenv("GERRIT_OLDREV")
    gerrit_newrev = os.getenv("GERRIT_NEWREV")
    gerrit_account_name = os.getenv("GERRIT_EVENT_ACCOUNT_NAME")
    gerrit_account_email = os.getenv("GERRIT_EVENT_ACCOUNT_EMAIL")

    event = get_gerrit_event()

    # Init backend database
    redis_host = os.getenv("REDIS_HOST")
    redis_port = int(os.getenv("REDIS_PORT"))
    backenddb = BackendDB(redis_host, redis_port)

    # Triggered by Gerrit - use GERRIT_REFNAME to get tag
    git_tag = gerrit_refname.split("refs/tags/")[1]
    git_branch = get_branch_name(git_tag)

    # add submitted log for iris
    pub_enabled = os.getenv("IRIS_PUB_ENABLED", "0") != "0"
    if pub_enabled:
        rest = IrisRestClient(
            os.getenv("IRIS_SERVER"),
            os.getenv("IRIS_USERNAME"),
            base64.b64decode(os.getenv('IRIS_PASSWORDX', '')))
        rest.publish_event("submitted", {
                "branch": git_branch,
                "commit_id": gerrit_newrev,
                "gitpath": gerrit_project,
                "submitter": gerrit_account_name,
                "submitter_email": gerrit_account_email,
                "tag": git_tag,
                })

    # prepare separate temp directory for each build
    git_cache = os.getenv("GIT_CACHE_DIR")
    prjdir = os.path.join(git_cache, event['project'])

    # clone gerrit project to local dir
    if not clone_gitproject(event['project'], prjdir):
        print >> sys.stderr, 'Error cloning %s' % event['project']
        return 1
    mygit = Git(prjdir)

    # check whether tag name is start with 'submit/'
    if not event['refname'].startswith('refs/tags/submit/'):
        print '\nREFNAME "%s" isn\'t start with refs/tags/submit, exit now'\
              % event['refname']
        return 0
    elif is_ref_deleted(event['oldrev'], event['newrev']):
        print '\nREFNAME "%s" is deleted, exit now' % event['refname']
        return 0

    mygerrit = Gerrit(event['hostname'], event['username'], \
            event['sshport'], int(os.getenv('GERRIT_SILENT_MODE')))

    tag = find_submit_tag(event, mygit)
    if not tag:
        print '\nThis commit don\'t contain submit/*/* tag, exit now'
        return 0

    result_str, cd_err, cd_ret = mygit._git_inout('for-each-ref', ['--format=%(tagger)', gerrit_refname])
    lparen = result_str.find('<')
    rparen = result_str.find('>')
    gerrit_account_name = result_str[0:lparen]
    gerrit_account_email = result_str[lparen+1:rparen]

    submitter = ''
    if gerrit_account_name:
        submitter = gerrit_account_name
        if gerrit_account_email:
            submitter += ' <%s>' % gerrit_account_email

    # check whether tag meet format
    if not check_tag_format(mygit, mygerrit, event, tag):
        print 'The check for the tag format is error, exit now\n'
        return 0

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

    # checkout submit tag
    mygit.checkout(tag)

    tagger = mygit.get_tag(tag)

    # get list of target projects from git-obs-mapping
    if git_branch.endswith('_tpk'): # ABS - mappings w/o _tpk postfix(only for profiles).
        obs_target_prjs = git_obs_map(os.getenv("GERRIT_PROJECT"), git_branch.split('_tpk')[0])
    else:
        obs_target_prjs = git_obs_map(os.getenv("GERRIT_PROJECT"), git_branch)

    # get lis of ref projects from git-ref-mapping
    obs_ref_prjs = get_ref_map(os.getenv("GERRIT_PROJECT"), git_branch)

    build = BuildService(obs_api, obs_user, obs_passwd)

    # Get all project lists
    all_obs_prjs = build.get_project_list()

    # prepare submit_info
    submit_info={}
    submit_info['submitted'] = {
                "branch": git_branch,
                "commit_id": gerrit_newrev,
                "gitpath": gerrit_project,
                "submitter": gerrit_account_name,
                "submitter_email": gerrit_account_email,
                "tag": git_tag,
                }
    submit_info['pre_created'] = []
    url = 'ssh://%s:%s' % (os.getenv('GERRIT_HOSTNAME_EXTERNAL'),
                           os.getenv('GERRIT_SSHPORT'))
    for item in obs_target_prjs:
        enable_build = True
        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 'config' in item and item['config'] is not None and item['config'].build == 'no':
            print 'Set disable build for %s' % (obs_target_prj)
            enable_build = False
        if obs_use_specname == 'yes':
            # search specfile under packaging directory
            specfile = find_specfile(prjdir, packagingdir, tag, event, tagger)
            if not specfile:
                return 0
            # parse specfile
            spec = parse_specfile(specfile, tag, event, tagger)
            if not spec:
                return 0
            package = spec.name
            print 'spec name = %s' %(spec.name)
        else:
            # get package name from xml files.
            if obs_pkg:
                package = obs_pkg
            else:
            # get package name from gerrit_project
                package = os.path.basename(gerrit_project)
        print 'package name = %s' %(package)

        if build_type == 'prerelease':
            if obs_stg_prj == 'abs' and git_branch.endswith('_tpk'):
                print 'Create ABS prerelease project...'
            elif obs_stg_prj != 'prerelease':
                print "%s is not 'prerelease' project in git-obs-mapping.xml." \
                      "It has been switched to submitobs workflow." \
                      "Skipping ..." % obs_stg_prj
                continue
            if not prerelease_enabled(backenddb, obs_target_prj):
                print 'Skipping %s as prerelease is not enabled for it' % \
                       obs_target_prj
                continue
            project = get_prerelease_project_name(obs_target_prj, git_tag)

            ref_obs_target_prj = obs_target_prj
            # Set obs_target_prj to ref project if it is enabled
            if os.getenv("REF_CREATE_PRJ_OBS_ENABLE","0") == "1":
                # Check if this is the group submit.
                existing_link_info = build.get_link_project_info(project)
                if existing_link_info is not None and build.exists(existing_link_info):
                    print 'Project already exist. Use previous ref project %s' % existing_link_info
                    ref_obs_target_prj = existing_link_info
                else:
                    if obs_target_prj in [ x['project'] for x in ast.literal_eval(os.getenv('REF_ACTIVE_PRJS')) ]:
                        for ref_info in obs_ref_prjs:
                            if ref_info['OBS_project'] != obs_target_prj:
                                continue
                            ret_ref = re.search(r'(%s):ref:([0-9]{8}.[0-9]+)' % obs_target_prj, \
                                                ref_info['OBS_staging_project'])
                            if not ret_ref or not ret_ref.groups() or len(ret_ref.groups()) != 2:
                                continue
                            print ' ** Set target link project to %s' % ref_info['OBS_staging_project']
                            ref_obs_target_prj = ref_info['OBS_staging_project']
                    # If ref-map does not exists, set the most recent ref project
                    associated_prjs = sorted([ p for p in all_obs_prjs if '%s:ref:' % obs_target_prj in p ])
                    if not associated_prjs or len(associated_prjs) < 1:
                        print 'No ref project for %s' % obs_target_prj
                        ref_obs_target_prj = obs_target_prj
                    elif ref_obs_target_prj not in associated_prjs:
                        print 'No ref map exist. Set it recent ref project %s' % associated_prjs[-1]
                        ref_obs_target_prj = associated_prjs[-1]
            sys.stdout.flush()

            if is_ref_deleted(gerrit_oldrev, gerrit_newrev):
                build.cleanup(project, "Cleaned by job_submit")
            else:
                submitter = ''
                if gerrit_account_name:
                    submitter = gerrit_account_name
                    if gerrit_account_email:
                        submitter += ' <%s>' % gerrit_account_email

                retry_count = 3
                while retry_count > 0:
                    try:
                        create_project(url, gerrit_project, git_tag, gerrit_newrev,
                                build, ref_obs_target_prj, project, submitter, package, build_flag=enable_build)
                        if pub_enabled:
                            rest.publish_event("pre_created", {
                                "project": project,
                                "tag": git_tag,
                                "product": obs_target_prj,
                                "gitpath": gerrit_project,
                                })
                        # prepare submit_info
                        if project:
                            products = submit_info['pre_created'] or []
                            if not obs_target_prj in products:
                                submit_info['pre_created'].append(project)
                            else:
                                submit_info['pre_created'] = products
                        break
                    except Exception, err:
                        print 'obs operation failed, retrying...'
                        print err
                        sleep(5)
                        retry_count -= 1
                if not retry_count:
                    print 'retrying failed'
                    return 1

        elif build_type == 'snapshot':
            if not is_ref_deleted(gerrit_oldrev, gerrit_newrev):
                if build.exists(obs_target_prj):
                    # Upload _service to target project
                    try:
                        upload_obs_service(url, gerrit_project, git_tag, \
                                gerrit_newrev, obs_target_prj, build, package)
                    except UploadError, err:
                        raise LocalError(err)
                else:
                    print "Warning: target project %s doesn't exist, " \
                          "skipping" % obs_target_prj
    # send mail
    if submit_info['pre_created']:
        send_mail_sr_message(submit_info, mygerrit)

    if buildmonitor_enabled:
        bm_end_datetime = datetime.datetime.now()
        commit_date, cd_err, cd_ret = mygit._git_inout('show', ['-s', '--format=%ci'])
        commit_msg, cm_err, cm_ret = mygit._git_inout('show', ['-s', '--format=%s'])
        submit_date, sd_err, sd_ret = mygit._git_inout('for-each-ref', \
                    ['--count=1', '--sort=-taggerdate', '--format=%(taggerdate:iso)'])
        submit_msg, sm_err, sm_ret = mygit._git_inout('for-each-ref', \
                    ['--count=1', '--sort=-taggerdate', '--format=%(subject)'])
        submitter, st_err, st_ret = mygit._git_inout('for-each-ref',\
                    ['--count=1', '--sort=-taggerdate', '--format=%(taggeremail)'])
        #print '[%s] %s%s' % (__file__, commit_date, commit_msg)
        #print '[%s] %s%s%s' % (__file__, submit_date, submit_msg, submitter)

        ### sr_status -> sr_commit -> sr_stage & sr_status_detail
        #buildmonitor.sr_submit_for_sr_status(git_tag)
        #buildmonitor.sr_submit_for_sr_commit(mygit, git_tag, gerrit_project,
        #                                     gerrit_newrev, gerrit_account_name)
        #buildmonitor.package_build_for_sr_detail_sr_stage(git_tag, bm_start_datetime,
        #                                                  bm_end_datetime,
        #                                                  submit_info['pre_created'])
        bm_stage = 'Submit'
        bm_data = {"bm_stage" : bm_stage,
                   "commit_date" : commit_date,
                   "commit_msg" : commit_msg,
                   "submit_date" : submit_date,
                   "submit_msg" : submit_msg,
                   "submitter" : submitter,
                   "git_tag" : git_tag,
                   "gerrit_project" : gerrit_project,
                   "gerrit_newrev" : gerrit_newrev,
                   "gerrit_account_name" : gerrit_account_name,
                   "bm_start_datetime": str(bm_start_datetime),
                   "bm_end_datetime": str(bm_end_datetime),
                   "bm_src_project_lst": submit_info['pre_created']
                    }
        ### sr_status -> sr_commit -> sr_stage & sr_status_detail
        trigger_next("BUILD-MONITOR", bm_data)

if __name__ == '__main__':
    try:
        sys.exit(main(os.path.basename(sys.argv[1])))
    except LocalError, err:
        print err
        sys.exit(1)
