#!/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 re
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 gbp.rpm import SpecFile
from gbp.git.repository import GitRepositoryError
from gbp.errors import GbpError

sys.path.insert(1, os.path.join(sys.path[0], '..'))

from common import utils
from common.mapping import git_obs_map, get_ref_map, git_virtual_branch_map
from common.git import Git, clone_gitproject
from common.upload_service import upload_obs_service, UploadError
from common.buildservice import BuildService
from common.buildtrigger import trigger_info, trigger_next, get_jenkins_instance
from common.send_mail import prepare_mail
from common.gerrit import Gerrit, get_gerrit_event, GerritError, is_ref_deleted, GerritEnv
from common.trbs import get_trbs_project_name, trbs_enabled, is_trbs_project, get_ref_prj_from_trbs_name

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:
        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

        return False

    return True

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

    msg = ''

    if pkg_name:
        spec = '%s/%s/%s.spec' % (prj_dir, packaging_dir, pkg_name)
        if not os.path.isfile(spec):
            msg = "The tag %s pushed, but backend service can not find %s \n"\
                    "under packaging directory, which is caused by mistake \n"\
                    "OBS_PACKAGE parameter in scm/git-obs-mapping project. \n"\
                    "Please correct it or contact system administrator for \n"\
                    "more details." % (tag, os.path.basename(spec))
    else:
        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]
        else:
            # multiple specs exist under packaging, use default name
            spec = '%s/%s/%s.spec' % (prj_dir, packaging_dir, \
                    os.path.basename(event['project']))
            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:
        print msg
        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)
        print msg
        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)
        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()
            content_xml_root = ElementTree.fromstringlist(content)
            for element in content_xml_root.findall('aggregate'):
                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')
    raise LocalError("Cannot determine base project for %s" % _project)

def create_project(build, obs_project, args):
    """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

    git_url = args[0]['url']
    git_project = [ t['gerrit_project'] for t in (u for u in args) ]
    git_tag = args[0]['git_tag']
    git_revision = [ t['gerrit_newrev'] for t in (u for u in args) ]
    obs_target_prj = args[0]['obs_target_prj']
    submitter = ','.join(list(set([ t['submitter'] for t in (u for u in args) ])))
    package = [ t['package'] for t in (u for u in args) ]
    print '\nCREATING....%s\n%s\n%s\n%s\n%s\n' % (obs_project, git_project, git_revision, submitter, package)

    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'), \
                                    'project/show?project=%s' % obs_project),
            'chksnap' : '0',
            'images': [],
            'base': get_base_project(build, obs_target_prj)}

    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:
            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:
        for idx, val in enumerate(git_project):
            upload_obs_service(git_url, git_project[idx], git_tag,
                               git_revision[idx], obs_project, build, package[idx])
    except UploadError, err:
        raise LocalError(err)

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

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

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

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

    #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

queued_requests = {} # key would be project name (home:trbs:...)
def enqueue_request(url, gerrit_project, git_tag, gerrit_newrev,
                    build, obs_target_prj, project, submitter, package):
    #TODO: Check group submits...
    enqueue_item = {'url': url, \
                    'gerrit_project': gerrit_project, \
                    'git_tag': git_tag, \
                    'gerrit_newrev': gerrit_newrev, \
                    'obs_target_prj': obs_target_prj, \
                    'project': project, \
                    'submitter': submitter, \
                    'package': package}
    if project in queued_requests:
        queued_requests[project].append(enqueue_item)
    else:
        queued_requests[project] = [enqueue_item]
    print 'QUEUED... %s\n' % enqueue_item

def process_requests(build):
    fail_count = 0

    for x in queued_requests:
        print '\n[%s]:\n  %s' % (x, queued_requests[x])

    for x in queued_requests:
        args = queued_requests[x]
        retry_count = 3
        while retry_count > 0:
            try:
                create_project(build, x, args)
                break
            except Exception, err:
                print '******* obs operation failed %s, retrying...' % err
                sleep(10)
        if not retry_count:
            print 'retrying failed'
            fail_count += 1

    return fail_count


def entry(action):

    if len(action) > 1 and action[1] == 'bypass':
        print '\n** Forward %s to group routine' % os.getenv('GERRIT_REFNAME')
        with open('TRBS-SUBMIT-GROUP_%d.env' % int(os.getenv('BUILD_NUMBER')), 'w') as info_f:
            for x in ['EVENT_TYPE', 'EVENT_HASH', 'REFNAME', 'PROJECT', 'OLDREV', 'NEWREV', \
                      'EVENT_ACCOUNT', 'EVENT_ACCOUNT_NAME', 'EVENT_ACCOUNT_EMAIL']:
                info_f.write('%s=%s\n' % ('GERRIT_' + x, os.getenv('GERRIT_' + x)))
                print '    %s=%s' % (x, os.getenv('GERRIT_' + x))
        return

    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)

    # First store current build and all the rest queued builds
    build_queue = []
    job = os.getenv('JOB_NAME')
    cred = {'url': os.getenv('REMOTE_TRBS_JENKINS_URL'), \
            'username': os.getenv('REMOTE_TRBS_JENKINS_USER'), \
            'password': os.getenv('REMOTE_TRBS_JENKINS_PW')}
    jenkinsinst = get_jenkins_instance(job, cred)
    curr_build = jenkinsinst.get_job(job).get_build(int(os.getenv('BUILD_NUMBER')))
    up_id = curr_build.get_upstream_build_number()
    if up_id is None: up_id = 0
    curr_data = {}
    for k in curr_build.get_actions()['parameters']:
        curr_data[k['name']] = k['value']
    build_queue.append({'%d-%d' % (up_id, curr_build._data['queueId']): curr_data})
    #TODO: Keep original process
    if up_id != 0:
        jq = jenkinsinst.get_queue()
        for pending_build in jq.get_queue_items_for_job(os.getenv('JOB_NAME')):
            for action in pending_build._data.get('actions', []):
                if type(action) is dict and 'causes' in action:
                    up_id = [x.get('upstreamBuild', None) for x in action['causes']][0]
                    if up_id is None: up_id = 0
                    break
            build_queue.append({'%d-%d' % (up_id, pending_build.queue_id): pending_build.get_parameters()})
            print '\n    %s DELETED: %s' % (pending_build.queue_id, pending_build.get_parameters())
            jq.delete_item_by_id(pending_build.queue_id)

    build_queue = sorted(build_queue)
    print '\nBelow will be proceeded: "%s"' % [int(k.keys()[0].split('-')[0]) for k in build_queue]
    for k in build_queue:
        item = k[k.keys()[0]]
        print '%s : %s(%s)' % (k.keys()[0], \
                               item['GERRIT_PROJECT'], \
                               item['GERRIT_NEWREV'])

    event = get_gerrit_event("PUBLIC_")
    sr_count = 1
    for k in build_queue:
        item = k[k.keys()[0]]
        #TODO: Just forward it to main routine. (Merging group submits need target project name)
        print item['GERRIT_PROJECT'], item['GERRIT_NEWREV']
        event.update({'project': item['GERRIT_PROJECT'], \
                      'refname': item['GERRIT_REFNAME'], \
                      'oldrev': item['GERRIT_OLDREV'], \
                      'newrev': item['GERRIT_NEWREV'], \
                      'event_account': item['GERRIT_EVENT_ACCOUNT'], \
                      'event_account_name': item['GERRIT_EVENT_ACCOUNT_NAME'], \
                      'event_account_email' : item['GERRIT_EVENT_ACCOUNT_EMAIL'], \
                      'event_type': item['GERRIT_EVENT_TYPE'], \
                      'event_hash': item['GERRIT_EVENT_HASH']})
        main(build, event, sr_count)
        sr_count += 1

    return process_requests(build)

def main(build, event, sr_count):
    """
    Script entry point.
    """
    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()
 
    # Triggered by Gerrit - use GERRIT_REFNAME to get tag
    git_tag = event['refname'].split("refs/tags/")[1]
    git_branch = get_branch_name(git_tag)

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

    # clone gerrit project to local dir
    if not clone_gitproject(event['project'], prjdir, \
                            gerrit_hostname=gerrit_env.hostname, \
                            gerrit_username=gerrit_env.username, \
                            gerrit_sshport=gerrit_env.sshport
                            ):
        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(gerrit_env.hostname, gerrit_env.username, \
               gerrit_env.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

    submitter = ''
    if event['event_account_name']:
        submitter = event['event_account_name']
        if event['event_account_email']:
            submitter += ' <%s>' % event['event_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)

    # precheck tpk branch (ABS)
    if '_tpk' in git_branch:
        git_branch = git_branch.replace('_tpk','')

    # get list of target projects from git-obs-mapping
    obs_target_prjs = git_obs_map(event['project'], git_branch, \
                                  gitcache=gerrit_env.gitcache, \
                                  gerrit_hostname=gerrit_env.hostname, \
                                  gerrit_username=gerrit_env.username, \
                                  gerrit_sshport=gerrit_env.sshport
                                  )

    # get list of ref projects from git-ref-mapping
    obs_ref_prjs = get_ref_map(event['project'], git_branch, \
                               gitcache=gerrit_env.gitcache, \
                               gerrit_hostname=gerrit_env.hostname, \
                               gerrit_username=gerrit_env.username, \
                               gerrit_sshport=gerrit_env.sshport
                               )

    # prepare submit_info
    submit_info={}
    submit_info['submitted'] = {
                "branch": git_branch,
                "commit_id": event['newrev'],
                "gitpath": event['project'],
                "submitter": event['event_account_name'],
                "submitter_email": event['event_account_email'],
                "tag": git_tag,
                }
    submit_info['pre_created'] = []

    #get project list
    project_list = build.get_package_list("")
    #print 'project list = %s' %(project_list)

    for target in obs_target_prjs:
        enable_build = True
        obs_target_prj = target['OBS_project']
        obs_stg_prj = target['OBS_staging_project']
        obs_pkg = target['OBS_package']
        if 'config' in target and target['config'] is not None and target['config'].build == 'no':
            print 'Set disable build for %s' % (obs_target_prj)
            enable_build = False
        if enable_build == True: # Opposite from public
            print 'Skip TRBS build(%s)! Will be handled in public infra.' % enable_build
            continue

        url = 'ssh://%s:%s' % (gerrit_env.hostname,
                               gerrit_env.sshport)
        # get package name from xml files.
        if obs_pkg:
            package = obs_pkg
        else:
            # get package name from gerrit_project
            package = os.path.basename(event['project'])

        if True:
            if obs_stg_prj != 'prerelease' and obs_stg_prj != 'abs':
                print "%s is not 'prerelease' project in git-obs-mapping.xml." \
                      "It has been switched to submitobs workflow." \
                      "Skipping ..." % obs_stg_prj
                continue

            # Skip ABS project if selected branch is not _tpk.
            if obs_stg_prj == 'abs' and not get_branch_name(git_tag).endswith('_tpk'):
                print "(%s) is an ABS project but the branch(%s) is not _tpk." \
                      % (package, get_branch_name(git_tag))
                continue

            if not trbs_enabled(obs_target_prj):
                print 'Skipping %s as trbs is not enabled for it' % \
                       obs_target_prj
                continue

            # Check for Group submit
            group_prj = [ obj for obj in project_list if is_trbs_project(obj) \
                          and not obj.find(obs_target_prj) == -1 \
                          and not obj.find(git_tag.replace('/',':')) == -1 ]

            if not group_prj:
                # ref project
                # obs_target_prj is src and obs_ref_prjs is ref project
                ref_prj_enable = False
                for reftarget in obs_ref_prjs:
                    target_prj = reftarget['OBS_project']
                    ref_prj = reftarget['OBS_staging_project']
                    pkg = reftarget['OBS_package']
                    if obs_target_prj == target_prj:
                        obs_target_prj = ref_prj
                        ref_prj_enable = True
                        break

                if not ref_prj_enable:
                    print 'Skipping %s as trbs(git-ref-mapping.xml) is not enabled for it' % \
                           obs_target_prj
                    continue
                project = get_trbs_project_name(obs_target_prj, git_tag)
            else:
                # is group submission
                project = group_prj[0]
                # Make build id from latest snapshot + project suffix
                ref_project = get_ref_prj_from_trbs_name(project, git_tag)
                obs_target_prj = ref_project
                print 'is group submission : %s target : %s ' %(project, obs_target_prj)

            if is_ref_deleted(event['oldrev'], event['newrev']):
                build.cleanup(project, "Cleaned by job_submit")
            else:
                submitter = ''
                if event['event_account_name']:
                    submitter = event['event_account_name']
                    if event['event_account_email']:
                        submitter += ' <%s>' % event['event_account_email']

                enqueue_request(url, event['project'], git_tag, event['newrev'],
                                build, obs_target_prj, project, submitter, package)
                if True:
                        # 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

            # Disable triggerring make_dep_graph.
            # Code remained to enable it in the future
            #data={}
            #data['obs_project'] = project
            #data['obs_linked_project'] = obs_target_prj
            #data['action'] = "prerelease_build_progress"
            #trigger_next('make_dep_graph', data)

    if buildmonitor_enabled and submit_info['pre_created']:
        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" : event['project'],
                   "gerrit_newrev" : event['newrev'],
                   "gerrit_account_name" : event['event_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_%d" % sr_count, bm_data)
    else:
        print '[%s] submit_info data is NULL(%s)\n' \
              % (__file__, submit_info['pre_created'])

if __name__ == '__main__':
    try:
        sys.exit(entry(sys.argv))
    except Exception as err:
        print err
        sys.exit(1)

