#!/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 code is called by jenkins jobs triggered by OBS events.
"""

import os
import sys
import re
import datetime
import ast

from common.repomaker import RepoMaker, RepoMakerError
from common.buildtrigger import trigger_info, trigger_next
from common.buildservice import BuildService
from common.backenddb import BackendDB
from common.snapshot import Snapshot, SnapshotError, snapshot_project_enabled
from common.utils import make_latest_link
from common.send_mail import prepare_mail

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


def prepare_trigger_data(images, build_id, path_repo, project,
                           url_pub_base):
    """
    prepare_trigger_data:
        Prepare the trigger data
    Args:
         images_ks (truple list): [(ks_file_name, ks_file_content),]
         build_id (str): the prerelease repo build_id
    """
    download_host = os.getenv('DOWNLOAD_HOST')
    gbsfullbuild_dl_postfix = os.getenv('GBSFULLBUILD_DL_POSTFIX')
    trigger_data = {} #trigger job_imager
    trigger_snapdiff = {}

    for repo_name in images:
        trigger_data[repo_name] = []
        trigger_snapdiff[repo_name] = []
        for ksname, kickstart in images[repo_name].ksi.items():
            #temprary
#            if ksname.find('mobile-wayland-armv7l-tm1') == -1 and ksname.find('common-headless-2parts-armv7l-rpi3') == -1:
#            if ksname.find('iot-headless-2parts-armv7l-rpi3') == -1:
#                continue
            name = ksname.replace('.ks', '')

            ks_temp=''
            for line in kickstart.split('\n'):
                if line.find('snapshots/tizen') != -1 and line.find('base/') == -1:
                    line=line.replace('/snapshots/tizen/','/snapshots/'+gbsfullbuild_dl_postfix+'/tizen/')
                ks_temp+=line+'\n'
            kickstart=ks_temp

            if download_host:
                # replace host name
                kickstart = re.sub('^(repo .*--baseurl=[^:]+://)[^/]+(/.*)',
                                   '\\1%s\\2' % download_host, kickstart,
                                   count=1, flags=re.MULTILINE)
            data = {'name': name,
                    'kickstart': kickstart,
                    'buildid': build_id,
                    'images_path': os.path.join("images", repo_name, name),
                    'project': project,
                    'repo': repo_name,
                    'repo_path': path_repo,
                    'url_pub_base': url_pub_base
                    }

            trigger_data[repo_name].append(data)
            data_snapdiff = data.copy()
            data_snapdiff.pop('kickstart')
            trigger_snapdiff[repo_name].append(data_snapdiff)

    return trigger_data, trigger_snapdiff


def trigger_image_creation(trigger_data):
    """Trigger the image_creation jobs"""
    count = 0
    for repo in trigger_data.keys():
        for index, data in enumerate(trigger_data[repo]):
            trigger_next('gbsfullbuild_image_trigger_%s_%s' % (repo, index), data)
            count += 1
    # Request number of imager nodes
    if os.getenv("ONDEMAND_SLAVE_CONFIGURATION_ENABLED", "0") == "1":
        if count > 0:
            trigger_next("SLAVE_BUILDER", {"data":"dummy"}, \
                         extra_params={"ACTION": "REQUEST_WORKER", \
                                       "PURPOSE": "JENKINS_IMAGER", \
                                       "REQUESTED_NUM_EXECUTORS": "%d" % count})


def make_repo(project, backenddb, base_path, live_repo_base):
    """
    make repo.

    Args:
        project (str): OBS prerelease project name
        repo (str): name of the OBS live repository
        backenddb (BackendDB): backenddb instance
        base_path (str): path to the location of snapshot
        live_repo_base (str): path to live repo
    Raises:
        LocalError if can't create repos or can't find image configurations
    """

    try:
        snapshot = Snapshot(backenddb, base_path, obs_project=project)

        # Increment snapshot
        snapshot.inc()

        # Store variables into local rather than accessing Snapshot() instance.
        local_build_id = snapshot.build_id
        local_targets  = snapshot.targets
        local_path     = snapshot.path
        local_dir      = snapshot.dir

        # Delete Snapshot() instance.
        del snapshot

        print 'We are working on:'
        print '\t%s\n\t%s\n\t%s\n\t%s\n\n' % (local_build_id, local_targets, local_path, local_dir)
        sys.stdout.flush()
    except SnapshotError, err:
        raise LocalError("Error getting snapshot info: %s" % str(err))

    targets = local_targets
    live_repo_path = os.path.join(live_repo_base,
                                  project.replace(':', ':/'))
    repos = {}
    imagedatas = {}

    # Convert live repo to download structure
    for repo in targets:
        repomaker = RepoMaker(local_build_id, local_path)

        # Get specific repo buildconf from OBS, put the buildconf together with
        # repo-md
        build = BuildService(os.getenv("OBS_API_URL"),
                             os.getenv("OBS_API_USERNAME"),
                             os.getenv("OBS_API_PASSWD"))
        buildconf = build.get_repo_config(project, repo['Name'])

        try:
            repomaker.add_repo(live_repo_path, repo['Name'],
                               repo['Architectures'],
                               buildconf=buildconf, move=False)
        except RepoMakerError, err:
            raise LocalError("Unable to create download repo: %s" % err)

        if not repomaker.imagedata:
            if buildmonitor_enabled:
                print '[%s][LocalError] bm_project(%s)\n' % (__file__, project)
                #buildmonitor.update_fail_create_snapshot_for_sr_stage(bm_project)
                bm_stage = 'Post_Snap_Fail'
                bm_data = {"bm_stage" : bm_stage,
                           "bm_snapshot_name" : local_build_id,
                          }
                trigger_next("BUILD-MONITOR-5-%s" % bm_stage, bm_data)
            raise LocalError("Image configuration not found in %s" %
                              local_path)

        repos.update(repomaker.repos)
        imagedatas[repo['Name']] = repomaker.imagedata

        # Generate image info to builddata/ dir
        repomaker.gen_image_info()

        # Generate repo manifest
        manifest_items = repomaker.gen_manifest_info(repo['Name'],
                                    os.getenv('GERRIT_FETCH_URL'),
                                    os.getenv('GERRIT_REVIEW_URL'))
        repomaker.gen_manifest_info_app_from_rpm(repo['Name'],
                                    os.getenv('GERRIT_FETCH_URL'),
                                    os.getenv('GERRIT_REVIEW_URL'),
                                    live_repo_path, repo['Architectures'])
        # Check duplicated items
        path_list = [ t.keys()[0] for t in manifest_items if t.keys()[0] ]
        duplicated = set([x for x in path_list if path_list.count(x) > 1])
        if len(duplicated) >= 1:
            prepare_mail('error_report_manifest.env', \
                         'Snapshot %s have duplicated packages' % (local_build_id), \
                         '\nDuplicated items: %s' % duplicated, \
                         os.getenv('NOREPLY_EMAIL_SENDER'), \
                         os.getenv('MAILINGLIST_SYSTEM').split(','))

    return {'project': project,
            'repo': repos,
            'repo_path': os.path.join(local_dir, local_build_id),
            'build_id': local_build_id,
            'imagedata': imagedatas
        }

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

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

    base_url = os.getenv("URL_PUBLIC_REPO_BASE")
    base_path = os.getenv('PATH_REPO_BASE')
    live_repo_base = os.path.join(os.getenv('PATH_LIVE_REPO_BASE'),os.getenv('GBSFULLBUILD_DL_POSTFIX'))

    fields = trigger_info(os.getenv("TRIGGER_INFO"))
    event = fields['event']
    snapshot_name = fields['snapshot_name']
    project = fields['obs_prj']

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

    repo_data = make_repo(project, backenddb, base_path, live_repo_base)

    # update/create the latest repo link
    make_latest_link(os.path.join(base_path, repo_data['repo_path']))

    # prepare trigger data for image creation jobs and snapdiff sync jobs
    trigger_data, trigger_snapdiff = prepare_trigger_data(
                                        repo_data['imagedata'],
                                        repo_data['build_id'],
                                        repo_data['repo_path'],
                                        project, base_url)

    # trigger image creation jobs
    trigger_image_creation(trigger_data)

    # trigger post snapshot creation job with repo data
    data = repo_data.copy()
    # remove unused item
    data.pop('imagedata')
    trigger_next("gbsfullbuild-buildlogs", data)

    # TRIGGER NEXT BUILD-MONITOR-Success
    update_message="Succeeded"
    if len(update_message) < 119:
        trigger_next("BUILD-MONITOR-Success", \
                {'bm_stage':'GBSFULLBUILD_SNAPSHOT',
                 'snapshot_name':snapshot_name,
                 'gbsfullbuild_string': update_message})

    # TRIGGER NEXT BUILD-MONITOR-Fail
    update_message="Image Creation Failed"
    if len(update_message) < 119:
        trigger_next("BUILD-MONITOR-Failed", \
                {'bm_stage':'GBSFULLBUILD_SNAPSHOT',
                 'snapshot_name':snapshot_name,
                 'gbsfullbuild_string': update_message})

    gbsmeta_data = {"event": event,
                      "triggered_from": 'gbs_ref_fullbuild',
                      }
    trigger_next("update-gbs-meta",gbsmeta_data)


if __name__ == '__main__':
    try:
        sys.exit(main())
    except LocalError, error:
        print error
        sys.exit(1)

