#!/usr/bin/env python
#
# Copyright (c) 2014, 2015, 2016 Samsung Electronics.Co.Ltd.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; version 2 of the License
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
"""This job is triggered by gerrit submit ref update event for preloaded app.
   It will generate tizen app package(.tpk) and requests prerelease routine.
"""

import os
import sys
import shutil
import re
import glob
import zipfile
import ast
import base64
import json
from urllib import quote_plus

from datetime import datetime
from random import randint
from time import sleep
import xml.etree.cElementTree as ElementTree

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

from common.utils import parse_link
from common.mapping import git_obs_map
from common.git import Git, clone_gitproject
from common.gerrit import Gerrit, is_ref_deleted, GerritEnv
from common.buildservice import BuildService
from common.prerelease import get_prerelease_project_name
from common.buildtrigger import trigger_info, trigger_next, remote_jenkins_build_job
from common.send_mail import prepare_mail
from common.workflow import find_specfile, parse_specfile
from common.tizen_studio import TizenStudio


# 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

class MailSender(object):

    email_title = '[ABS]'
    email_head  = 'App Build System(ABS) inform you the SDK build result.\n' \
                 '(ABS will trigger build if you issues an SR on preloaded app branch)\n\n'
    email_body = ''
    email_footer = '\n\n--------\n'\
                   'Automatically generated by backend service.\n'

    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 set_gerrit_infra(self, infra):
        if infra.startswith('LOCAL'):
            self.dashboard_url = os.getenv("DASHBOARD_URL")
        else:
            self.dashboard_url = os.getenv("PUBLIC_DASHBOARD_URL")

    def add_receiver(self, add_new):
        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))

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

    def add_message(self, add_new, top=None):
        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, project):
        mygerrit = Gerrit(GerritEnv().hostname, GerritEnv().username,\
                          port=int(GerritEnv().sshport))
        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])

    def send_mail(self):

        if 'SUCCESS' not in self.email_title:
            self.add_title('FAILURE')

        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():
            for i in xrange(0, len(m), 128):
                m_body += '\n'.join(m[i:i+128]) + '\n'
        self.email_body = m_body

        # Dashboard links
        self.email_body = self.email_body \
            + '\n\nFor detailed info, please visit %s/abs_rbs.code\n\n' % (self.dashboard_url)

        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)

        if 'SUCCESS' not in self.email_title:
            return 4

def get_gerrit_infra(switch):
    """ Retrieve matching gerrit configuration """

    merged_env = {}

    if switch == 'PUBLIC':
        gerrit_env = GerritEnv('PUBLIC_')
        merged_env['username'] = os.getenv('ABS_GERRIT_USERNAME_PUBLIC')
        merged_env['obs_api_url'] = os.getenv('PUBLIC_OBS_API_URL')
        merged_env['obs_api_username'] = os.getenv('PUBLIC_OBS_API_USERNAME')
        merged_env['obs_api_password'] = os.getenv('PUBLIC_OBS_API_PASSWD')
    elif switch == 'LOCAL':
        gerrit_env = GerritEnv('')
        merged_env['username'] = os.getenv('ABS_GERRIT_USERNAME_LOCAL')
        merged_env['obs_api_url'] = os.getenv('OBS_API_URL')
        merged_env['obs_api_username'] = os.getenv('OBS_API_USERNAME')
        merged_env['obs_api_password'] = os.getenv('OBS_API_PASSWD')

    merged_env['hostname'] =  gerrit_env.hostname
    merged_env['gitcache'] = gerrit_env.gitcache
    merged_env['sshport'] = int(gerrit_env.sshport)

    return merged_env

def set_gerrit_event(fields):
    """ Merge all the required input arguments """

    event = fields.get('event')
    source = fields.get('source', None)

    # FROM GERRIT EVENT
    _data = {'obs_project': fields.get('obs_project'), \
             'obs_package': fields.get('obs_package'), \
             'project': event.get('GERRIT_PROJECT'), \
             'package': os.path.basename(event.get('GERRIT_PROJECT')), \
             'email': event.get('GERRIT_EVENT_ACCOUNT_EMAIL'), \
             'name': event.get('GERRIT_EVENT_ACCOUNT_NAME'), \
             'newrev': event.get('GERRIT_NEWREV', None), \
             'refname': event.get('GERRIT_REFNAME', None), \
             'changenumber': event.get('GERRIT_CHANGE_NUMBER', None), \
             'refspec': event.get('GERRIT_REFSPEC', None), \
             'patchset': event.get('GERRIT_PATCHSET_REVISION', None), \
             'type': fields.get('type'), \
             'tag': fields.get('tag'), \
             'branch': fields.get('branch'), \
             'revision': fields.get('revision'), \
             'buildcheck': fields.get('full_build', None)}

    #TODO: Profile will be fetched from tizen-manifest.xml
    #_data['profile'] = _data.get('obs_project').split(':')[-1].lower()
    ## Set new branch and tag
    #if _data.get('branch').endswith('_' + _data.get('profile')):
    #    _data['new_branch'] = _data.get('branch') + '_tpk'
    #else:
    #    _data['new_branch'] = _data.get('branch') + '_' + _data.get('profile') + '_tpk'
    #_data['new_tag'] = _data.get('tag').replace(_data.get('branch'), _data.get('new_branch'))

    print 'TOUCHED_DATA:'
    for f in _data:
        print '  [%s]: %s' % (f, _data[f])
    return _data

def retrieve_last_accepted_tag(working_git, project, profile=None, obs_project=None):
    """ Find most recent accepted tag in case of build check mode"""

    # full build will use the most recent accepted tag.
    #if obs_project == 'Tizen:Unified':
    #    check_branch = 'tizen'
    #else:
    if True:
        check_branch = ('/'.join(obs_project.split(':')).lower())
    t_outs, t_err, t_code = working_git._git_inout('for-each-ref', \
                                 ['--sort=-taggerdate', '--format=%(refname)%0a%(*subject)%0a%(*body)', \
                                  'refs/tags/accepted/%s/' % check_branch, '--count=1'])
    #if len(t_outs) == 0 or '/%s/' % profile not in t_outs.split('\n')[0]:
    if len(t_outs) == 0:
        print 'Sorry. Most recent accepted tag %s is not desired one.' % t_outs.split('\n')[0]
        return None
    accepted_tag = t_outs.split('\n')[0].replace('refs/tags/','').rstrip()
    orig_tag = t_outs[t_outs.rfind('Reference: ')+11:].split('\n')[0].split(' ')[0].strip().rstrip()
    if orig_tag.startswith('submit/tizen'):
        print 'FULL BUILD! Accepted tag from _tpk branch %s -> %s' % (accepted_tag, orig_tag)
        return orig_tag

    t_outs, t_err, t_code = working_git._git_inout('show', \
                                 [accepted_tag])
    if len(t_outs) == 0 or '- Git project: %s' % project not in t_outs:
        print 'Sorry(1). Fail to retrieve original tag from %s' % accepted_tag
        return None
    orig_tag = t_outs[t_outs.rfind('- Tag:')+6:].split('\n')[0].strip().rstrip()
    if orig_tag.startswith('submit/tizen'):
        print 'FULL BUILD! Accepted tag from source branch %s -> %s' % (accepted_tag, orig_tag)
        return orig_tag

    print 'Sorry(2). Fail to retrieve original tag from %s' % accepted_tag
    return None

def retrieve_project_property(src_git, tag):
    """ Search APP properties """

    ret_prop = {}

    def get_git_repo_size(quiet=True):
        if quiet == False:
            src_git._git_inout('gc', ['--quiet'])
        pack_size, t_err, t_code = src_git._git_inout('count-objects', ['-v'])
        pack_size = pack_size[pack_size.find('size-pack:')+11:].split('\n')[0]
        print '"UNPACK-SIZE": \"%d\"' % int(pack_size)
    try:
        get_git_repo_size()
    except Exception as err:
        print repr(err)

    def retrieve_license(src_root):
        sdk_license = None
        for f in os.listdir(src_root):
            if os.path.isfile(os.path.join(src_root, f)) and f.startswith('LICENSE'):
                with open(os.path.join(src_root, f), 'r') as r_file:
                    for x in r_file.readlines():
                        matchline = re.search(r'.*Licensed under the (.*) License, Version (.*) \(the \"License\"\).*;', x)
                        if matchline:
                            sdk_license = '%s-%s' % (matchline.groups()[0], matchline.groups()[1])
                            print 'LICENSE %s from %s' % (sdk_license, f)
        #FIXME:
        if sdk_license is None:
            sdk_license = 'Samsung'
        return sdk_license

    def retrieve_properties_from_project_def(src_root):

        sdk_package = ''
        sdk_version = ''
        sdk_profile = ''
        sdk_web_name = ''
        ret_error = ''
        app_type = None

        # As guided, the last is the main app from multi project listup.
        def_file_list = []
        # Multi project
        multiproject_list_f = os.path.join(src_root, 'WORKSPACE')
        if os.path.isfile(multiproject_list_f):
            with open(multiproject_list_f, 'r') as r_file:
                for x in r_file.readlines():
                    if os.path.isdir(os.path.join(src_root, x.rstrip())):
                        if os.path.isfile(os.path.join(src_root, x.rstrip(), 'tizen-manifest.xml')):
                            def_file_list.append(os.path.join(src_root, x.rstrip(), 'tizen-manifest.xml'))
                        elif os.path.isfile(os.path.join(src_root, x.rstrip(), 'config.xml')):
                            def_file_list.append(os.path.join(src_root, x.rstrip(), 'config.xml'))
        else:
            # Single project
            if os.path.isfile(os.path.join(src_root, 'tizen-manifest.xml')):
                def_file_list.append(os.path.join(src_root, 'tizen-manifest.xml'))
            if os.path.isfile(os.path.join(src_root, 'config.xml')):
                def_file_list.append(os.path.join(src_root, 'config.xml'))

        #for def_file in def_file_list:
        #TODO: Should be the last item
        def_file = def_file_list[-1]
        if os.path.isfile(def_file):
            print 'Property file: %s' % def_file
            try:
                with open(def_file, 'r') as df:
                    manifest_dump = df.read()
                if os.path.basename(def_file) == 'tizen-manifest.xml':
                    xmlstring = re.sub('\\sxmlns="[^"]+"', '', manifest_dump, count=1)
                    _root = ElementTree.fromstring(xmlstring)
                    for child in _root:
                        if child.tag == 'profile':
                            sdk_profile = child.attrib.get('name', sdk_profile)
                            print 'Set SDK_PROFILE:[%s]' % sdk_profile
                    sdk_package = _root.attrib.get('package', sdk_package)
                    sdk_version = _root.attrib.get('version', sdk_version)
                    app_type = 'tpk'
                elif os.path.basename(def_file) == 'config.xml':
                    xmlstring = re.sub('\\sxmlns:tizen="[^"]+"', '', manifest_dump, count=1)
                    xmlstring = re.sub('\\sxmlns="[^"]+"', '', manifest_dump, count=1)
                    xmlstring = xmlstring.replace('tizen:', '')
                    _root = ElementTree.fromstring(xmlstring)
                    for child in _root:
                        if child.tag == 'profile':
                            sdk_profile = child.attrib.get('name', sdk_profile)
                            print 'Set SDK_PROFILE:[%s]' % sdk_profile
                        elif child.tag == 'application':
                            sdk_package = child.attrib.get('package', sdk_package)
                            print 'Set SDK_PACKAGE:[%s]' % sdk_package
                            sdk_web_name = child.attrib.get('id', sdk_package)
                            if "%s." % sdk_package in sdk_web_name:
                                sdk_web_name = sdk_web_name.replace("%s." % sdk_package, "")
                            print 'Set SDK_WEB_NAME:[%s]' % sdk_web_name
                        #elif child.tag == 'name' and child.attrib == {}:
                        #    sdk_web_name = child.text
                        #    print 'Set SDK_WEB_NAME:[%s]' % sdk_web_name
                    sdk_version = _root.attrib.get('version', sdk_version)
                    app_type = 'wgt'
            except Exception as err:
                ret_error = err
        if not sdk_profile:
            sdk_profile = ''
        #    ret_error += 'ERROR: No "profile" tag in property file(tizen-manifest.xml)'
        print 'TIZEN-MANIFEST.XML (%s) (%s)' % (sdk_package, sdk_version)
        return {'sdk_package': sdk_package, 'sdk_version': sdk_version, 'sdk_profile': sdk_profile, \
                'ret_error': ret_error, 'app_type': app_type, 'sdk_web_name': sdk_web_name}

    def retrieve_commit_id(src_git):
        commit_id = src_git.rev_parse('HEAD')
        print 'commit from (HEAD) = %s' % (commit_id)
        return commit_id

    def retrieve_revision_number(src_git, tag):
        _ret = {}
        try:
            _ret['revision_number'] = src_git.rev_parse(tag)
        except Exception as err:
            print repr(err)
        print 'revision from (%s) = %s' % (tag, _ret)
        return _ret

    def retrieve_commit_message(src_git):
        t_outs, t_err, t_code = src_git._git_inout('log', ['--format=%B', '-n 1'])
        commit_message = t_outs[:t_outs.rfind("\nChange-Id: ")].rstrip() + '\n'
        print "author comment : %s" % commit_message
        return commit_message

    def retrieve_sr_message(src_git, tag):
        t_outs, t_err, t_code = src_git._git_inout('show', [tag, '--format=##chkstr:%b'])
        sr_message = '\n'.join(t_outs[:t_outs.rfind("##chkstr:")].split('\n')[3:])
        print "sr comment from(%s) : [%s]" % (tag, sr_message.rstrip())
        return sr_message

    def retrieve_committer(src_git):
        t_outs, t_err, t_code = src_git._git_inout('log', ['--format=%cE', '-n 1'])
        committer = t_outs.strip().rstrip().replace('<','').replace('>','')
        print "committer : %s" % committer 
        return committer

    def retrieve_submitter(src_git, tag):
        t_outs, st_err, st_ret = src_git._git_inout('for-each-ref', \
                    ['--count=1', '--sort=-taggerdate', '--format=%(taggeremail)', 'refs/tags/%s' % tag])
        submitter = t_outs.strip().rstrip().replace('<','').replace('>','')
        print "submitter : %s" % submitter
        return submitter

    def retrieve_submitter_name(src_git, tag):
        t_outs, st_err, st_ret = src_git._git_inout('for-each-ref', \
                    ['--count=1', '--sort=-taggerdate', '--format=%(taggername)', 'refs/tags/%s' % tag])
        submitter_name = t_outs.strip().rstrip()
        print "submitter name : %s" % submitter_name
        return submitter_name

    def retrieve_commit_date(src_git):
        t_outs, t_err, t_code = src_git._git_inout('log', ['--format=%ci', '-n 1'])
        commit_date = t_outs
        print "commit_date : %s" % commit_date
        return commit_date

    def retrieve_submit_date(src_git, tag):
        submit_date, sd_err, sd_ret = src_git._git_inout('for-each-ref', \
                    ['--count=1', '--sort=-taggerdate', '--format=%(taggerdate:iso)', 'refs/tags/%s' % tag])
        print "submit_date : %s" % submit_date
        return submit_date

    ret_prop.update(retrieve_properties_from_project_def(src_git.path))
    ret_prop['commit_id'] = retrieve_commit_id(src_git)
    ret_prop['revision_number'] = retrieve_revision_number(src_git, tag).get('revision_number', \
                                  ret_prop.get('commit_id'))
    ret_prop['commit_message'] = retrieve_commit_message(src_git)
    ret_prop['sr_message'] = retrieve_sr_message(src_git, tag)
    ret_prop['sdk_license'] = retrieve_license(src_git.path)

    ret_prop['committer'] = retrieve_committer(src_git)
    ret_prop['submitter'] = retrieve_submitter(src_git, tag)
    ret_prop['submitter_name'] = retrieve_submitter_name(src_git, tag)
    ret_prop['commit_date'] = retrieve_commit_date(src_git)
    ret_prop['submit_date'] = retrieve_submit_date(src_git, tag)

    for r in ret_prop:
        if ret_prop[r]:
            print '  [%s]: %s' % (r, ret_prop[r].rstrip())
        else:
            print '  [%s]: %s' % (r, ret_prop[r])
    return ret_prop

def fetch_source(gerrit_env, src_root, project, branch=None, tag=None, patchset=False, \
                 build_check=None, profile=None, obs_project=None, clone_type=None):
    """ Cloning APP source code """

    print 'Cloning into bare repo %s' % os.path.join(gerrit_env.get('gitcache'), project)
    clone_gitproject(project, \
                     '%s.git' % os.path.join(gerrit_env.get('gitcache'), project), \
                     gerrit_hostname=gerrit_env.get('hostname'), \
                     gerrit_username=gerrit_env.get('username'), \
                     gerrit_sshport=gerrit_env.get('sshport'), \
                     bare=True)
    print 'Cloning source code %s' % src_root
    if clone_type is not None:
        if not clone_gitproject(project, \
                                src_root, \
                                gerrit_hostname=gerrit_env.get('hostname'), \
                                gerrit_username=gerrit_env.get('username'), \
                                gerrit_sshport=gerrit_env.get('sshport')):
            raise LocalError('Error cloning project %s' % project)
    else:
        if not clone_gitproject(project, \
                                src_root, \
                                gerrit_hostname=gerrit_env.get('hostname'), \
                                gerrit_username=gerrit_env.get('username'), \
                                gerrit_sshport=gerrit_env.get('sshport'), \
                                git_cache_dir='nonexist'):
            raise LocalError('Error cloning project %s' % project)

    working_git = Git(src_root)

    if patchset:
        if tag and tag.startswith('refs/changes/'):
            working_git._git_inout('fetch', ['origin', '%s' % tag])
            working_git._git_inout('reset', ['--hard', 'FETCH_HEAD'])
            return working_git, tag
        else:
            raise LocalError('Patchset but no tag')

    if build_check is not None:
        tag = retrieve_last_accepted_tag(working_git, project, profile=profile, obs_project=obs_project)
        if tag is None:
            return None, 'no-tag-to-check'
        print 'Force to checkout build check for [%s]' % tag

    if tag is None:
        working_git.checkout(branch)
    else:
        working_git.checkout(tag)

    assert tag and tag.startswith('submit/tizen')
    return working_git, tag

def zipping_workspace(src_root):
    """ Create tarball to share source code easily between VM machine """

    def ZipDir(inputDir, outputZip):
        '''Zip up a directory and preserve symlinks and empty directories'''
        zipOut = zipfile.ZipFile(outputZip, 'w', compression=zipfile.ZIP_DEFLATED)

        rootLen = len(os.path.dirname(inputDir))
        def _ArchiveDirectory(parentDirectory):
            contents = os.listdir(parentDirectory)
            #store empty directories
            if not contents:
                archiveRoot = parentDirectory[rootLen:].replace('\\', '/').lstrip('/')
                zipInfo = zipfile.ZipInfo(archiveRoot+'/')
                zipOut.writestr(zipInfo, '')
            for item in contents:
                fullPath = os.path.join(parentDirectory, item)
                if fullPath.endswith('/.git'): continue
                if os.path.isdir(fullPath) and not os.path.islink(fullPath):
                    _ArchiveDirectory(fullPath)
                else:
                    archiveRoot = fullPath[rootLen:].replace('\\', '/').lstrip('/')
                    if os.path.islink(fullPath):
                        zipInfo = zipfile.ZipInfo(archiveRoot)
                        zipInfo.create_system = 3
                        # long type of hex val of '0xA1ED0000L',
                        # say, symlink attr magic...
                        zipInfo.external_attr = 2716663808
                        zipOut.writestr(zipInfo, os.readlink(fullPath))
                    else:
                        zipOut.write(fullPath, archiveRoot, zipfile.ZIP_DEFLATED)
        _ArchiveDirectory(inputDir)
        zipOut.close()

    current_dir = os.getcwd()
    os.chdir(os.path.dirname(src_root))
    src_d = os.path.basename(src_root)
    out_f = src_d + '.zip'
    ZipDir(src_d, out_f)
    os.chdir(current_dir)

def generate_spec_file(tizen_studio, src_git, prop, data, app_type):
    """ Use spec file template """

    found_archs = []
    archs_lookup = [['i386', 'i486', 'i586', 'i686', 'x86'], \
                    ['arm', 'armv7l'], \
                    ['x86_64'], \
                    ['aarch64']]
    arch_postfix_list_in_file = []

    internal_package_name = prop.get('sdk_package')
    if app_type == 'wgt':
        internal_package_name = '%s' % data.get('obs_package')

    for fn in os.listdir(tizen_studio.builddir):
        if app_type == 'tpk':
            mtch = re.search(r'(.*)-([0-9.]+)-(.*)(?<!-debug).tpk', fn)
            if mtch and mtch.groups() and len(mtch.groups()) == 3:
                for l in archs_lookup:
                    if mtch.groups()[2] in l:
                        arch_postfix_list_in_file.append(mtch.groups()[2])
                        found_archs.extend(l)
                        break
        elif app_type == 'wgt':
            if True:
                mtch = re.search(r'(.*).wgt', fn)
                if mtch:
                    _app_version = prop.get('sdk_version')
                    os.rename(os.path.join(tizen_studio.builddir, fn), \
                              os.path.join(tizen_studio.builddir, "%s-%s.wgt" % (internal_package_name, _app_version)))
            else:
                full_arch = []
                for l in archs_lookup:
                    full_arch.extend(l)
                mtch = re.search(r'(.*)-(%s)(?<!-debug).wgt' % '|'.join(full_arch), fn)
                if mtch and mtch.groups() and len(mtch.groups()) == 2:
                    for l in archs_lookup:
                        _a = mtch.groups()[1]
                        if _a in l:
                            found_archs.extend(l)
                            _app_name = prop.get('sdk_web_name')
                            _app_arch = _a
                            _app_version = prop.get('sdk_version')
                            #Append version info in filename
                            os.rename(os.path.join(tizen_studio.builddir, fn), \
                                      os.path.join(tizen_studio.builddir, "%s-%s-%s.wgt" % (_app_name, _app_version, _app_arch)))
                                      #fn.replace(_a, '%s-%s' % (prop.get('sdk_version'), _a))))
                            break

    found_archs = list(set(found_archs))
    print 'found_archs=%s' % found_archs

    # SPEC configuration
    group = ''
    sdk_license = prop.get('sdk_license')
    summary = ''
    license = ''
    if os.path.isdir(os.path.join(src_git.path, 'packaging')):
        for filename in os.listdir(os.path.join(src_git.path, 'packaging')):
            if re.match('.*\.spec', filename):
                with open(os.path.join(src_git.path, 'packaging', filename)) as f_spec:
                    for x in f_spec.readlines():
                        if group == '' and re.match('Group:.*', x):
                            group = x.split(':')[1].strip().rstrip()
                        if license == '' and re.match('License:.*', x):
                            license = x.split(':')[1].strip().rstrip()
                        if summary == '' and re.match('Summary:.*', x):
                            summary = x.split(':')[1].strip().rstrip()

    if group == '' or group is None: group = 'N/A'
    if license == '' or license is None: license = 'N/A'
    if summary == '' or summary is None: summary = data.get('obs_package')

    if sdk_license is not None and sdk_license != '':
        license = sdk_license

    vcs = '#VCS_FROM:   %s' % (data.get('project') + "#" + prop.get('commit_id'))
    vcs_desc = vcs.split(' ')[-1]

    if os.getenv('EXCLUDE_ARCH'):
        exclude_arch = 'ExcludeArch: '
        for exa in os.getenv('EXCLUDE_ARCH').split(','):
            exclude_arch = exclude_arch + ' ' + exa
    else:
        exclude_arch = ''

    if found_archs is not None:
        exclusive_arch = 'ExclusiveArch: '
        for exa in found_archs:
            exclusive_arch = exclusive_arch + ' ' + exa
    else:
        exclusive_arch = ''

    rpm_build_mode = '%{nil}'

    if app_type == 'wgt':
        spec_template = tizen_studio.get_template('spec-wgt')
    else:
        spec_template = tizen_studio.get_template('spec')
    spec_template = spec_template.replace( \
                        '__OBS_PACKAGE_NAME__', data.get('obs_package')).replace( \
                        '__VCS__', vcs).replace( \
                        '__ROOTSTRAP_VERSION__', tizen_studio.built_version).replace( \
                        '__SUMMARY__', summary).replace( \
                        '__VERSION__', prop.get('sdk_version')).replace( \
                        '__GROUP__', group).replace( \
                        '__LICENSE__', license).replace( \
                        '__EXCLUSIVE_ARCH__', exclusive_arch).replace( \
                        '__EXCLUDE_ARCH__', exclude_arch).replace( \
                        '__TIZEN_STUDIO_PACKAGE_NAME__', internal_package_name).replace( \
                        '__BUILD_MODE__', rpm_build_mode).replace( \
                        '__VCS_DESCRIPTION__', vcs_desc).replace( \
                        '__APP_TYPE__', app_type)
    if 'i586' in arch_postfix_list_in_file and 'x86' not in arch_postfix_list_in_file:
        spec_template = spec_template.replace('%define target x86\n', '%define target i586\n')

    return spec_template

def post_processing(tizen_studio, src_git, prop, data, builddir, mailer, build):
    """ Create SR of the generated tpks thru git tagging """

    print 'TizenStudio: builddir: %s' % tizen_studio.builddir

    #TODO: Check app type (tpk|wgt)
    app_type = None
    for filename in os.listdir(builddir):
        if re.match('.*\.(tpk|wgt)', filename):
            if filename.endswith('.tpk'):
                app_type = 'tpk'
            elif filename.endswith('.wgt'):
                app_type = 'wgt'

    spec = generate_spec_file(tizen_studio, src_git, prop, data, app_type)
    print 'SPEC:\n%s' % spec

    gerrit_env = get_gerrit_infra(data.get('gerrit_infra', 'LOCAL'))
    remote = 'ssh://%s@%s:%d/%s' % (gerrit_env.get('username'), \
                                    gerrit_env.get('hostname'), \
                                    gerrit_env.get('sshport'), \
                                    data.get('project'))

    #TODO: Checkout _tpk branch and push the tpks and tag it
    new_branch = data.get('new_branch')
    new_tag = data.get('new_tag')
    # Register local git user
    with open(os.path.join(src_git.path, '.git', 'config'), 'a') as gitconfig:
        gitconfig.write('[user]\n\tname = %s\n\temail = %s\n' \
                        % (prop.get('submitter_name'), prop.get('submitter')))
    #                    % (data.get('name'), data.get('email')))
    # Checkout tpk branch
    if src_git.has_branch('origin' + new_branch, remote = True):
        print 'Branch (%s) already exist' % new_branch
        src_git.checkout(new_branch)
    else:
        src_git._git_inout('checkout', ['--orphan', '%s' % new_branch])
        src_git._git_inout('rm', ['-rf', '.'])
    print src_git._git_inout('fetch', ['origin'])[0]
    print src_git._git_inout('reset', ['origin/' + new_branch, '--hard'])[0]
    try:
        chk_tag = src_git.rev_parse(new_tag)
        print 'Checking tag [%s]' % chk_tag
        if chk_tag:
            print 'Tag(%s) already exist.' % new_tag
            #TODO: Force remove previous tag...
            if True:
                src_git.delete_tag(new_tag)
                src_git.remove_tag_from_remote(remote, new_tag)
            else:
                mailer.add_title('The same tag exist')
                mailer.add_message('Result: FAIL')
                mailer.add_message('\n\nTag %s already exist.' % new_tag)
                return
    except Exception as err:
        print repr(err)
        pass
    try:
        src_git.remove_files('*')
    except:
        pass
    try:
        src_git.remove_files('packaging/*')
    except:
        pass
    if not os.path.exists(os.path.join(src_git.path, 'packaging')):
        os.makedirs(os.path.join(src_git.path, 'packaging'))
    for filename in os.listdir(builddir):
        if re.match('.*\.(tpk|wgt)', filename):
            print 'Found [%s].' % filename
            shutil.copy(os.path.join(builddir, filename), os.path.join(src_git.path, filename))
    try:
        src_git.add_files('*.tpk', True)
    except:
        pass
    try:
        src_git.add_files('*.wgt', True)
    except:
        pass
    with open(os.path.join(src_git.path, 'packaging', data.get('obs_package') + '.spec'), 'w') as sf:
        sf.write('%s' % spec)
    src_git.add_files('packaging/*.spec', True)

    commit_message = "[ABS] %s\nReference: %s\nCommit id: %s\nRequested by: %s\nSDK rootstrap version: %s" \
                     % (prop.get('commit_message'), data.get('tag'), prop.get('commit_id'), \
                        data.get('email'), tizen_studio.built_version)
    print commit_message
    src_git.commit_staged(commit_message)
    commit_id_new = src_git.rev_parse('HEAD')
    print 'commit from new HEAD: %s' % commit_id_new

    push_err_msg = ''
    push_retry = 5
    while push_retry > 0:
        try:
            src_git.push(repo = 'origin', src = '%s' % new_branch, force=True)
            break
        except Exception as err:
            print 'git push exception: %s' % repr(err)
            push_err_msg = push_err_msg + '\n' + str(err)
            push_retry -= 1
            sleep(5)
    if not push_retry:
        mailer.add_title('Git push tpk branch failed')
        mailer.add_message('Result: FAIL')
        mailer.add_message('\n\nGit push branch %s failed %s' % (new_branch, push_err_msg))
        return

    message = '%s\n' \
        '[ABS] Ready.\n' \
        '- Original Tag: %s (%s)\n' \
        '- Original Commit: %s\n' \
        '- Requested By: %s\n' \
        % (prop.get('sr_message'), data.get('tag'), \
           prop.get('revision_number'), prop.get('commit_id'), data.get('email'))

    try:
        src_git.create_tag(name=new_tag, msg=message, commit=commit_id_new)
    except Exception as err:
        mailer.add_title('Creating tag failed')
        mailer.add_message('Result: FAIL')
        mailer.add_message('\n\nCreating tag %s failed: %s' % (new_tag, str(err)))
        return

    try:
        revision_number_new = src_git.self.rev_parse(new_tag)
    except:
        revision_number_new = prop.get('commit_id')

    push_err_msg = ''
    push_retry = 5
    while push_retry >0:
        try:
            src_git.push_tag(remote, new_tag)
            break
        except Exception as err:
            print 'Cannot push tag %s (%s)' % (new_tag, str(err))
            push_err_msg = push_err_msg + '\n' + str(err)
            push_retry -= 1
            sleep(5)
    if not push_retry:
        mailer.add_title('Git push tag failed')
        mailer.add_message('Result: FAIL')
        mailer.add_message('\n\nGit push tag %s failed: %s' % (new_tag, str(err)))
        return

    mailer.add_title('SUCCESS')
    mailer.add_message('To view, visit %s/project/show/%s' \
               % (build.apiurl, \
                  get_prerelease_project_name(data.get('obs_project'), data.get('new_tag'))))

def start_build(fields):
    """ Running build using Tizen Studio """

    # Adjust arguments
    data = set_gerrit_event(fields)

    print '\n"Title": "%s/%s"\n' % (os.path.basename(data.get('project')), data.get('tag'))

    data['gerrit_infra'] = fields.get('gerrit_infra', 'LOCAL')
    gerrit_env = get_gerrit_infra(data.get('gerrit_infra'))
    build = BuildService(gerrit_env.get('obs_api_url'), \
                         gerrit_env.get('obs_api_username'), \
                         gerrit_env.get('obs_api_password'))

    mailer = MailSender()
    mailer.set_gerrit_infra(data.get('gerrit_infra'))
    mailer.add_receiver(data.get('email'))
    mailer.add_message('Package: %s' % data.get('project'))
    mailing_list = os.getenv('ABS_MAILINGLIST').split(',')
    try:
        mailing_list.extend(ast.literal_eval(os.getenv('ABS_MAILINGLIST_2')).get(data.get('obs_project')).split(','))
    except Exception as err:
        pass
    mailer.add_receiver(filter(None, mailing_list))

    non_exist_prjs = [ prj for prj in set([data.get('obs_project')]) if not build.exists(prj) ]
    if non_exist_prjs:
        raise LocalError('Target OBS project %s does not exist' % non_exist_prjs)

    # Working directory
    basedir = os.path.join(os.getenv('WORKSPACE'), os.getenv('JOB_NAME'))
    if os.path.exists(basedir):
        shutil.rmtree(basedir)
    builddir = os.path.join(basedir, 'build')
    os.makedirs(builddir)

    # Fetch Source Code
    src_root = os.path.join(builddir, os.path.basename(data.get('project')))
    src_git, int_tag = fetch_source(gerrit_env, \
                                    src_root, \
                                    data.get('project'), branch=data.get('branch'), \
                                    tag=data.get('tag'), \
                                    patchset=data.get('type')=='REVIEW', \
                                    build_check=data.get('buildcheck'), \
                                    profile=data.get('profile'), \
                                    obs_project=data.get('obs_project'),
                                    clone_type=data.get('buildcheck'))
    if src_git is None and int_tag == 'no-tag-to-check':
        print 'Do not report back to checker'
        return 0
    if src_git is None or int_tag is None:
        return 1
    print 'Got tag: [%s]' % int_tag

    # Find package name from spec file
    if fields.get('use_specname', None):
        # search specfile under packaging directory
        resp = find_specfile(src_root, \
                             parse_link('%s/%s' % (src_root, 'packaging')), \
                             data.get('tag'), {'project': data.get('project')}, None)
        if resp['spec']:
            # parse specfile
            resp = parse_specfile(resp['spec'], data.get('project'), None, None)
            if resp['spec']:
                print 'spec name = %s' %(resp['spec'].name)
                data['obs_package'] = resp['spec'].name

    project_properties = retrieve_project_property(src_git, int_tag)
    #TODO:
    if data['obs_package'] is None:
        data['obs_package'] = project_properties['sdk_package']
        print 'Set obs_package to sdk [%s]' % data['obs_package']

    #FIXME: 
    if project_properties.get('sdk_profile') == "" or project_properties.get('sdk_profile') is None \
        or project_properties.get('app_type') == 'wgt':
        profile_search = re.search(r'profile/(.*)/apps/native|web/.*', data.get('project'))
        if profile_search and profile_search.groups():
            project_properties['sdk_profile'] = profile_search.groups()[0]
        else:
            project_properties['sdk_profile'] = "mobile"
    print project_properties.get('sdk_profile')
    data['profile'] = project_properties.get('sdk_profile')
    # Set new branch and tag
    branch_postfix = project_properties.get('app_type', 'tpk')
    if data.get('branch').endswith('_' + data.get('profile')):
        data['new_branch'] = data.get('branch') + '_' + branch_postfix
    else:
        data['new_branch'] = data.get('branch') + '_' + data.get('profile') + '_' + branch_postfix
    #TODO: SPIN will use only _tpk postfix. Do not use profile name.
    if data.get('gerrit_infra') == 'LOCAL':
        data['new_branch'] = data.get('branch') + '_' + branch_postfix

    #TODO: If app source postfix, link to original branch
    if data.get('branch').endswith(os.getenv('ABS_SOURCE_BRANCH_PREFIX')):
        data['new_branch'] = data.get('new_branch').replace(os.getenv('ABS_SOURCE_BRANCH_PREFIX'),'')
    data['new_tag'] = data.get('tag').replace(data.get('branch'), data.get('new_branch'))

    mailer.add_title(data.get('obs_package'))
    mailer.add_title('(' + data.get('branch') + ')')
    if data.get('buildcheck', None):
        mailer.add_message('Build cause: New Rootstrap %s' % data.get('buildcheck'))
    mailer.add_message('Tag/Branch: %s' % data.get('tag'))
    mailer.add_message('Target OBS project: %s' % data.get('obs_project'))
    mailer.add_message('SR subject: %s' % project_properties.get('sr_message'), top=True)

    #TODO:
    if project_properties.get('ret_error') != '':
        print 'You got property error:\n%s' % project_properties.get('ret_error')
        if data.get('buildcheck', None) == None:
            mailer.add_title('Property file parsing error')
            mailer.add_message('Result: FAIL')
            mailer.add_message('\n\n%s' % project_properties.get('ret_error'))
        mailer.send_mail()
        #TODO: DASHBOARD
        update_dashboard(int_tag, data, project_properties, \
             status='failed', status_reason='%s' % project_properties.get('ret_error'), \
             rootstrap_version=data.get('buildcheck').split('_')[-1].replace('.','_') if data.get('buildcheck') else None)
        return 1
    if 'sdk_license' not in project_properties or project_properties.get('sdk_license') is None:
        print 'No LICENSE provided.'
        if data.get('buildcheck', None) == None:
            mailer.add_title('No LICENSE file')
            mailer.add_message('Result: FAIL')
            mailer.add_message('\n\n%s' % 'No LICENSE provided.')
            mailer.send_mail()
            #TODO: DASHBOARD
            update_dashboard(int_tag, data, project_properties, \
                 status='failed', status_reason='No LICENSE.', \
                 rootstrap_version=data.get('buildcheck').split('_')[-1].replace('.','_') if data.get('buildcheck') else None)
            return 1

    # Make tarball to share source codes easily with vm machine
    zipping_workspace(src_root)

    parallel_jobs = '"-j 1"'
    #if data.get('buildcheck'):
    #    parallel_jobs = '"-j 4"'
    #### Running QEMU to launch Tizen Studio ####
    print '[ TizenStudio START ] %s' % (str(datetime.now()))
    sys.stdout.flush()
    vm_map = ast.literal_eval(os.getenv('ABS_PROJECT_VM_MAP')).get(data.get('obs_project')).split(',')
    vm_image = vm_map[0]
    vm_rootstrap_profiles = vm_map[1]
    # Adjust rootstrap search profile keyword
    rs_search_profile = data.get('profile')
    if vm_rootstrap_profiles and len(vm_rootstrap_profiles.split('|')) == 1 \
        and data.get('profile') not in vm_rootstrap_profiles.split('|'):
        rs_search_profile = vm_rootstrap_profiles
    print 'Set rootstrap search profile: %s' % rs_search_profile
    print 'vm_image:%s' % vm_image

    meta_script_map = ast.literal_eval(os.getenv('ABS_CLI_SCRIPT_GIT_MAP'))
    meta_script = meta_script_map.get('default')
    if meta_script_map.get(data.get('obs_project'), None) is not None:
        meta_script = meta_script_map.get(data.get('obs_project'))
    print 'meta_script:%s' % meta_script

    my_tizen_studio = TizenStudio(vm_image, meta_script)
    for x in data:
        print '[%s] %s' % (x, data[x])
    sys.stdout.flush()

    for retry_count in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10):
        ret = my_tizen_studio.build_app_source(package=data.get('package'), \
                                               profile=rs_search_profile, \
                                               gitpath=data.get('project'), \
                                               build_mode=os.getenv('BUILD_MODE'), \
                                               parallel_jobs=parallel_jobs, \
                                               build_type=data.get('type', 'default'), \
                                               app_type=branch_postfix)
        print '[ TizenStudio END ] %s' % (str(datetime.now()))
        print ret

        _br = my_tizen_studio.gather_build_result()
        rs_ver = _br.get('built_version')
        fail_title = _br.get('title')
        fail_log = _br.get('buildlog')
        ts_version = _br.get('tizen_studio_version')
        ts_distribution = _br.get('tizen_studio_distribution')
        print 'VM returned [%s] [%s] [%s] [%s]\n' % (rs_ver, fail_title, ts_version, ts_distribution)

        if fail_log is not None and 'Exception signing error for ' in fail_log:
            print 'Retry due to keystore fail...'
            continue
        else:
            break

    if rs_ver is None and data.get('buildcheck', None) is not None:
        rs_ver = data.get('buildcheck').split('_')[-1]
        print 'Force to set RS version: %s' % rs_ver
    mailer.add_message('SDK Rootstrap Version: %s' % rs_ver)

    if my_tizen_studio.build_result != 0 and fail_title != None:
        print 'App Build Fail'
        mailer.add_title(fail_title)
        mailer.add_message('Result: FAIL')
        mailer.add_message('\n\n%s' % fail_log)

    if data.get('buildcheck', None) == None and data.get('type', None) == 'SUBMIT':
        # Send mail only for failed build
        if 'FAIL' in mailer.email_title:
            mailer.send_mail()
            #TODO: DASHBOARD
            update_dashboard(int_tag, data, project_properties, \
                 status='failed', status_reason=fail_log, \
                 rootstrap_version=rs_ver.strip(), \
                 tizen_studio_version=ts_version, \
                 tizen_studio_distribution=ts_distribution)
            return 2
        post_processing(my_tizen_studio, src_git, project_properties, data, builddir, mailer, build)
        # Send mail only for failed build
        if 'FAIL' in mailer.email_title:
            mailer.send_mail()
            #TODO: DASHBOARD
            update_dashboard(int_tag, data, project_properties, \
                 status='failed', status_reason=mailer.email_body, \
                 rootstrap_version=rs_ver.strip(), \
                 tizen_studio_version=ts_version, \
                 tizen_studio_distribution=ts_distribution)
            return 3

    if 'FAIL' in mailer.email_title:
        #TODO: DASHBOARD
        update_dashboard(int_tag, data, project_properties, \
             status='failed', status_reason=fail_log, \
             rootstrap_version=rs_ver.strip(), \
             tizen_studio_version=ts_version, \
             tizen_studio_distribution=ts_distribution)
        return 1
    #TODO: DASHBOARD
    update_dashboard(int_tag, data, project_properties, \
         status='succeeded', status_reason='ok', \
         rootstrap_version=rs_ver.strip(), \
         tizen_studio_version=ts_version, \
         tizen_studio_distribution=ts_distribution)

#TODO: DASHBOARD
def update_dashboard(git_tag, data, props, \
                     status, status_reason, \
                     rootstrap_version=None, \
                     tizen_studio_version=None, tizen_studio_distribution=None):
    try:
        event_type = "START_ABS"
        data = {"event_type": "START_ABS", \
                "type": 'CHECK' if data.get('buildcheck') is not None else 'GIT', \
                "project": data.get('obs_project'), \
                "git_path": data.get('project'), \
                "commit_id": props.get('commit_id'), \
                "committer": props.get('committer'), \
                "commit_date": props.get('commit_date'), \
                "commit_message": props.get('commit_message'), \
                "tag_name": git_tag, \
                "tag_revision": props.get('revision_number'), \
                "tagger": props.get('submitter'), \
                "tag_date": props.get('submit_date'), \
                "tag_message": props.get('sr_message'), \
                "tpk_git_tag": data['new_tag'], \
                "status": status, \
                "status_reason": status_reason, \
                "tizen_studio_version": tizen_studio_version, \
                "tizen_studio_distribution": tizen_studio_distribution, \
                "rootstrap_version": rootstrap_version, \
                "infra": data.get('gerrit_infra', 'LOCAL')}
        print 'update_dashboard'
        print data
        encoded_data = base64.b64encode(json.dumps(data))
        trigger_next('UPDATE_ABS_STATUS', data)
    except Exception as err:
        print repr(err)
        print 'Updating Dashboard Failed'

def main(argv):
    """
    Script entry point.
    """

    print '---[SCRIPT START at %s]---' % str(datetime.now())

    args = os.getenv('TRIGGER_INFO', None)

    # Manual trigger (Actual build step)
    if args:
        trigger_data = trigger_info(args)
        return start_build(trigger_data)

    # Regular gerrit event (Dispatcher)
    elif os.getenv('GERRIT_PROJECT', None):

        if os.getenv('GERRIT_NAME').startswith('public_gerrit'):
            gerrit_infra = 'PUBLIC'
        else:
            gerrit_infra = 'LOCAL'
        gerrit_env = get_gerrit_infra(gerrit_infra)

        project = os.getenv('GERRIT_PROJECT')

        # Distingush event type
        if os.getenv('GERRIT_CHANGE_NUMBER', None):
            derived_data = {'type': 'REVIEW', \
                            'tag': os.getenv('GERRIT_REFSPEC'), \
                            'branch': os.getenv('GERRIT_BRANCH'), \
                            'revision': os.getenv('GERRIT_PATCHSET')}
        elif os.getenv('GERRIT_REFNAME', None) and os.getenv('GERRIT_REFNAME').startswith('refs/tags/submit/'):
            tag = os.getenv('GERRIT_REFNAME').split('refs/tags/')[1]
            derived_data = {'type': 'SUBMIT', \
                            'tag': tag, \
                            'branch': tag[len('submit/'):tag.rfind('/', len('submit/'))], \
                            'revision': os.getenv('GERRIT_NEWREV')}
        else:
            derived_data = {'type': 'COMMIT', \
                            'tag': os.getenv('GERRIT_NEWREV'), \
                            'branch': os.getenv('GERRIT_REFNAME'), \
                            'revision': os.getenv('GERRIT_NEWREV')}
        print derived_data

        obs_target_prjs = git_obs_map(project, derived_data.get('branch'), \
                                      gitcache=gerrit_env.get('gitcache'), \
                                      gerrit_hostname=gerrit_env.get('hostname'), \
                                      gerrit_username=gerrit_env.get('username'), \
                                      gerrit_sshport=gerrit_env.get('sshport'))

        index = 0
        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_stg_prj != 'abs':
                continue
            print 'Trying to call builder for: Branch(%s), Package(%s), OBS(%s), Staging(%s)' \
                   % (derived_data.get('branch'), obs_pkg, obs_target_prj, obs_stg_prj)

            if is_ref_deleted(os.getenv('GERRIT_OLDREV'), os.getenv('GERRIT_NEWREV')):
                print 'REF DELETED(%s)!' % os.getenv('GERRIT_OLDREV')
                continue

            if obs_pkg is not None:
                obs_package = obs_pkg
            else:
                obs_package = None

            derived_data['obs_project'] = obs_target_prj
            derived_data['obs_package'] = obs_package
            derived_data['use_specname'] = obs_use_specname == 'yes'

            trigger_data = {'source': {'package': derived_data.get('obs_package'), \
                                       'branch': derived_data.get('branch'), \
                                       'tag': derived_data.get('tag'), \
                                      }, \
                            'event': {'GERRIT_PROJECT': project, \
                                      'GERRIT_EVENT_ACCOUNT_EMAIL': os.getenv('GERRIT_EVENT_ACCOUNT_EMAIL'), \
                                      'GERRIT_EVENT_ACCOUNT_NAME': os.getenv('GERRIT_EVENT_ACCOUNT_NAME'), \
                                      'GERRIT_NEWREV': os.getenv('GERRIT_NEWREV'), \
                                      'GERRIT_REFNAME': os.getenv('GERRIT_REFNAME', None), \
                                      'GERRIT_CHANGENUMBER': os.getenv('GERRIT_CHANGENUMBER', None), \
                                      'GERRIT_BRANCH': os.getenv('GERRIT_BRANCH', None), \
                                      'GERRIT_REFSPEC': os.getenv('GERRIT_REFSPEC', None), \
                                      'GERRIT_PATCHSET_REVISION': os.getenv('GERRIT_PATCHSET_REVISION', None), \
                                     } , \
                            'gerrit_infra': gerrit_infra
                            }
            trigger_data.update(derived_data)

            index += 1
            # Forward it to build job
            trigger_next('ABS_BUILD_%d_%d_%s' \
                         % (int(os.getenv('BUILD_NUMBER')), index, derived_data.get('obs_package')), \
                         trigger_data, extra_params={'BACKEND_SELECTION': 'ABS'})

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

