#!/usr/bin/python
# -*- encoding: utf-8 -*-

import sys
import os

sys.path.insert(0, '/opt/direct-py/startrek-python-client-sni-fix')
from startrek_client import Startrek

import yaml
import json
import re
import subprocess
import time

pathlist = ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin", "/usr/games", "/usr/local/games"]
os.environ["PATH"] = os.pathsep.join(pathlist)

HOSTNAME = subprocess.check_output(['hostname', '-f']).strip()
SCRIPT_NAME = os.path.basename(__file__)
SIGN = u"----\nСкрипт %s с машины %s" % (SCRIPT_NAME, HOSTNAME)

STARTREK_TOKEN_FILE = '/etc/direct-tokens/startrek'

ST_QUERY = u'Queue: DIRECT Type: Release Status: "RM Acceptance", "Ready to Deploy", "Ждем подтверждения" "Sort by": key desc'

APPS_CONF_FILE = "/etc/yandex-direct/direct-apps.conf.yaml"

startrek_token = open(STARTREK_TOKEN_FILE).readline().rstrip()
startrek_client = Startrek(token=startrek_token, useragent=SCRIPT_NAME)

apps_dict = yaml.load(open(APPS_CONF_FILE))['apps']
component2app = {apps_dict[app]['tracker-component'] : app for app in apps_dict if 'tracker-component' in apps_dict[app]}

sleep_time = 5 # секунд
retries = 5 # количество ретраев


def run_command(cmd):
    for i in xrange(retries):
        try:
            output = subprocess.check_output(cmd)
            return output

        except:
            time.sleep(sleep_time)
    raise Exception("cmd %s died" % cmd)


"""
находит, в каком бранче находится на дисте пакет package версии version
"""
def get_state(package, version):
    output = run_command(['ssh', '-o', 'StrictHostKeyChecking=no', 'dupload.dist', 'find_package', '-j', '%s_%s' % (package, version)])
    # 2019-02-25: скрипт стал падать и ругаться на позицию в output, где перевод строки. 
    # Непонятно, какой json раньше отдавался, но если сейчас заменять переводы строк пробелами -- становится лучше
    output = re.sub('\n', ' ', output)
    json_output = json.loads(output)
    if json_output and 'result' in json_output and len(json_output['result']) == 1:
        return json_output['result'][0]['environment']
    
    sys.stderr.write(u"дист недоступен\n")
    exit(1)
        
    return ''


def get_version(ticket):
    version = re.search(r'[0-9]+\..+$', ticket.summary)
    if version:
        return version.group(0)
    else:
        return None


def get_app_name(ticket):
    global component2app

    app = None
    for component in ticket.components:
        if component.name in component2app:
            app = component2app[component.name]
            break

    return app


def release_checked(ticket):
    global apps_dict, startrek_client

    comments = startrek_client.issues[ticket.key].comments.get_all()

    version = get_version(ticket)
    app = get_app_name(ticket)

    if not version or not app:
        return True

    for comment in comments:
        if re.search(ur"Пакет %s версии %s передвинут из .+ в stable" % (apps_dict[app]['package'], version), comment.text, re.I | re.U) and comment.createdBy.id == u'ppc':
            return True

    return False


def run():
    issues = [issue for issue in startrek_client.issues.find(ST_QUERY) if not release_checked(issue)]

    for ticket in issues:
        app = get_app_name(ticket)
        if not app or apps_dict[app].get('deploy_type', '') != 'deb':
            continue
        
        version = get_version(ticket)
        if not version:
            continue

        state = get_state(apps_dict[app]['package'], version)
        if not state or state == 'stable':
            continue

        FNULL = open(os.devnull, 'w')

        if state == 'unstable':
            run_command(['beta-update', 'dmove_testing -r direct-trusty %s=%s' % (apps_dict[app]['package'], version)])

        if state == 'unstable' or state == 'testing':
            run_command(['beta-update', 'dmove_stable -r direct-trusty %s=%s' % (apps_dict[app]['package'], version)])

        FNULL.close()

        new_state = get_state(apps_dict[app]['package'], version)

        if not new_state:
            continue

        if state != new_state:
            comment = u'Пакет %s версии %s передвинут из %s в %s' % (apps_dict[app]['package'], version, state, new_state)
        else:
            comment = u'Пакет %s версии %s из %s передвинуть не удалось' % (apps_dict[app]['package'], version, state)

        # независимо от исхода перемещения основного пакета пробуем передвинуть зависимости (даже если была ошибка с главным, хуже вроде не будет)
        if apps_dict[app]['type'] in ['svn-perl', 'arcadia-java']:
            try:
                output = run_command(['direct-release', '--app', app, '-s', 'stable', 'show-state'])
                stable_ticket = u''
                search_result = re.search(r'"ticket": "([^"]+)', output)
                if search_result:
                    stable_ticket = search_result.group(1)

                if stable_ticket == ticket.key:
                    dependencies = run_command(['direct-release', '--app', app, '-s', 'stable', 'dmove-dependencies'])
                    if dependencies:
                        delim = ">>>>>>>>>>>>>"
                        dependencies = dependencies[dependencies.find(delim) + len(delim) + 1:]
                        dependencies = dependencies[:dependencies.find(delim)]

                    if any(line and not line.startswith("#") for line in dependencies.split("\n")):
                        comment += u'\n\nПакеты, которые были передвинуты по зависимостям:\n%s' % dependencies
                    else:
                        comment += u"\n\nЗависимостей не нашлось"

            except Exception as e:
                comment += u'\n!!**При передвижении зависимостей произошла ошибка:**!!\n' + str(e)
                pass
        else:
            comment += u"\nПеремещение зависимостей для этого приложения не поддерживается"
        
        comment += u"\n%s" % SIGN

        ticket.comments.create(text=comment)

    return


if __name__ == '__main__':
    run()
