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

description = """
Закоммитить ресурс известной sandbox таски
dt-update-yadeploy-stage -s direct-logviewer-test -t 770008556 --commit

Закоммитить и дождаться выкладки ресурсов из известной сандбоксовой таски:
dt-update-yadeploy-stage -s direct-logviewer-test -t 770008556 --commit --wait

Дождаться окончания выкладки по определенному деплойному тикету:
dt-update-yadeploy-stage -s direct-logviewer-test -d SANDBOX-770008556-testing-direct-logviewer-test-rule --wait
"""

import sys

import argparse
import re
import subprocess
import time



def parse_options():
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument("-s", "--stage", dest="yadeploy_stage", help="yadeploy stage", type=str)
    parser.add_argument("-t", "--sandbox-task", dest="sandbox_task", help="sandbox task", type=str)
    parser.add_argument("-d", "--deploy-ticket", dest="deploy_ticket", help="deploy ticket id", type=str)
    parser.add_argument("-m", "--deploy-message", dest="deploy_message", default='comit from dctl', help="deploy message", type=str)
    parser.add_argument("-c", "--commit", dest="commit", help="commit deploy ticket", action="store_true")
    parser.add_argument("-w", "--wait", dest="wait", help="wait for ticket to close", action="store_true")
    parser.add_argument("-h", "--help", dest="help", help="Справка", action="store_true")
    opts, extra = parser.parse_known_args()

    if opts.help:
        print description
        print parser.format_help()
        exit(0)

    if len(extra) > 0:
        exit("unexpected params %s" % extra)

    opts.extra = extra

    if not opts.yadeploy_stage:
        exit("expecting --stage <yadeploy stage id, e.g. direct-logviewer-test>")

    if not opts.sandbox_task and not opts.deploy_ticket:
        exit("expecting --sandbox-task <task id> or --deploy-ticket <ticket id>")

    if opts.sandbox_task and opts.deploy_ticket:
        exit("--sandbox-task can't be used with --deploy-ticket")

    if not opts.wait and not opts.commit:
        exit("expected --wait, --commit, or both")

    # чтобы не усложнять выбор тикета если отсутствует --commit
    if opts.sandbox_task and opts.wait and not opts.commit:
        exit("cant wait for sandbox task without commiting it, use --commit")

    return opts


def run_and_parse(cmd, re_string):
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    for line in p.stdout:
        match = re.search(re_string, line)
        if match:
            return match
    return None


def stage2release_rule(yadeploy_stage):
    #TODO перебирать все правила из стейджа
    cmd = ['dctl', 'list', 'release_rule', '-s', yadeploy_stage, '-l', '1000']
    regexp = r'([\w\-]+)\s*\|\s*(%s)' % yadeploy_stage
    # | direct-java-alw-production-rule  |  direct-java-alw-production | DIRECT_YA_PACKAGE |        |          |          NONE         |
    match = run_and_parse(cmd, regexp)
    if not match:
        exit("can't find release rules for stage %s" % yadeploy_stage)
    return match.group(1)


def find_deploy_ticket(release_rule, sandbox_task):
    # надо будет убрать лимиты в DIRECT-152315
    cmd = ['dctl', 'list', 'deploy_ticket', '--release-rule', release_rule, '-l', '1000']
    regexp = r'(SANDBOX-%s-\S*).*Pending' % sandbox_task
    #| SANDBOX-757753704-stable-direct-logviewer-test-rule  | direct-logviewer-test |  SANDBOX-757753704-stable | direct-logviewer-test-rule | Pending |

    # 120 seconds
    DELAY = 10
    for _ in range(12):
        deploy_ticket = run_and_parse(cmd, regexp)

        if deploy_ticket is not None:
            return deploy_ticket.group(1)
        
        sys.stderr.write("sleeping for %d seconds...\n" % DELAY)
        sys.stderr.flush()
        time.sleep(DELAY)

    return None


def commit_deploy_ticket( deploy_ticket_id, message):
    cmd = [ 'dctl', 'commit', 'deploy_ticket', deploy_ticket_id, '-m', message]
    subprocess.check_call(cmd)


def wait_deploy_ticket_close( release_rule, deploy_ticket_id ):
    DELAY = 30
    completed = False
    for _ in range(120):
        cmd = ['dctl', 'list', 'deploy_ticket', '--release-rule', release_rule, '-l', '1000']
        regexp = r'(%s).*Closed' % deploy_ticket_id
        #| SANDBOX-757753704-stable-direct-logviewer-test-rule  | direct-logviewer-test |  SANDBOX-757753704-stable | direct-logviewer-test-rule | Closed |
        m = run_and_parse(cmd, regexp)
        if m:
            completed = True
            break
        if completed:
            break
        sys.stderr.write("sleeping for %d seconds...\n" % DELAY)
        sys.stderr.flush()
        time.sleep(DELAY)

    if not completed:
        exit("Timed out. See `dctl list deploy_ticket --release-rule %s |grep %s` for current status" % (release_rule, deploy_ticket_id))

    sys.stderr.write("success\n")
    sys.stderr.flush()


def run():
    opts = parse_options()

    release_rule = stage2release_rule(opts.yadeploy_stage)

    if opts.sandbox_task:
        deploy_ticket_id = find_deploy_ticket(release_rule, opts.sandbox_task)

        if deploy_ticket_id is None:
            exit("can't find pending deploy ticket for task %s, release rule %s" % (sandbox_task, release_rule))
    elif opts.deploy_ticket: 
        deploy_ticket_id = opts.deploy_ticket

    if opts.commit:
        commit_deploy_ticket(deploy_ticket_id, opts.deploy_message)
        print "committed: %s\n%s" % (deploy_ticket_id, opts.deploy_message)

    if opts.wait:
        wait_deploy_ticket_close(release_rule, deploy_ticket_id)


if __name__ == '__main__':
    run()

