#!/usr/bin/python

import datetime
import fcntl
import github3
import gzip
import json
import os
import re
import select
import socket
import subprocess
import sys
import time

import mysql.connector


TARGET_VM = 'devosa'
TARGET_IP_BLOCK = '192.168.53.0/24'


with open(os.path.expanduser('~/.github_automation'), 'r') as f:
    config = json.loads(f.read())


ISSUE_URL_RE = re.compile('https://api.github.com/repos/(.*)/(.*)/issues/(.*)')
def github_comment(issue_url, comment):
    if not issue_url:
        return

    g = github3.login(config['github_user'], config['github_password'])
    m = ISSUE_URL_RE.match(issue_url)
    if not m:
        print 'Could not parse issue URL!'
        return

    issue = g.issue(m.group(1), m.group(2), int(m.group(3)))
    issue.create_comment(comment)


def process(job):
    ostrich_sha = job['sha']
    if job['project'] != 'ostrich':
        ostrich_sha = 'master'

    state = {}
    with open('state.json.%s' % job['flavour'], 'r') as f:
        state = json.loads(f.read())
    state['complete']['osa-branch'] = job['branch']
    state['complete']['ironic-ip-block'] = TARGET_IP_BLOCK
    with open('state.json', 'w') as f:
        f.write(json.dumps(state, indent=4, sort_keys=True))

    short_branch = job['branch'].replace('stable/', '')
    now = datetime.datetime.now()
    job_id = ('%04d%02d%02d-%02d%02d-%s-%s-%s'
              %(now.year, now.month, now.day, now.hour, now.minute,
                job['project'], short_branch, job['sha']))

    job['short_branch'] = short_branch
    job['job_id'] = job_id
    job['timestamp'] = job['timestamp'].isoformat()
    with open('job.json', 'w') as f:
        f.write(json.dumps(job, indent=4, sort_keys=True))

    with gzip.open('%s.log.gz' % job_id, 'w') as f:
        rc = execute('sudo ./reset_osa.sh %s %s %s %s %s'
                     %(TARGET_VM, job['distro'], ostrich_sha, job_id,
                       job['project']), f)

    return (rc, job_id)


def execute(command, logfile):
    print('Running %s' % command)

    obj = subprocess.Popen(command,
                           stdin=subprocess.PIPE,
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE,
                           shell=True)

    flags = fcntl.fcntl(obj.stdout, fcntl.F_GETFL)
    fcntl.fcntl(obj.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)

    flags = fcntl.fcntl(obj.stderr, fcntl.F_GETFL)
    fcntl.fcntl(obj.stderr, fcntl.F_SETFL, flags | os.O_NONBLOCK)

    obj.stdin.close()
    while obj.poll() is None:
        readable, _, _ = select.select([obj.stderr, obj.stdout], [], [], 10)
        for f in readable:
            d = os.read(f.fileno(), 10000)
            sys.stdout.write(d)
            logfile.write(d)
            logfile.flush()

    print('... process complete')
    returncode = obj.returncode
    print('... exit code %d' % returncode)
    return returncode


def main():
    while True:
        conn = mysql.connector.connect(**config['db'])
        cursor = conn.cursor(dictionary=True, buffered=True)
        cursor.execute('select * from jobs where processed=0 and '
                       'machine is null order by timestamp;')
        if cursor.rowcount == 0:
            print '%s No work, sleeping' % datetime.datetime.now()
            time.sleep(60)
            continue

        job = cursor.fetchone()
        cursor.execute('update jobs set machine=%(machine)s where '
                       'uuid=%(uuid)s and machine is null;',
                       {
                           'machine': socket.gethostname(),
                           'uuid': job['uuid']
                       })
        if cursor.rowcount == 0:
            print 'My job got stolen (id %s)!' % job['uuid']
            continue
        cursor.execute('commit;')

        start_time = time.time()
        rc, job_id = process(job)
        end_time = time.time()

        conn = mysql.connector.connect(**config['db'])
        cursor = conn.cursor(dictionary=True, buffered=True)
        cursor.execute('update jobs set processed=1, outcome=%(outcome)s, '
                       'log_url=%(log_url)s '
                       'where uuid=%(uuid)s;',
                       {
                           'outcome': rc,
                           'log_url': ('http://molokai.stillhq.com/lab/logs/%s/'
                                       % job_id),
                           'uuid': job['uuid']
                       })
        cursor.execute('commit;')

        cursor.execute('select * from jobs where event_uuid=%(event_uuid)s;',
                       {'event_uuid': job['event_uuid']})
        report = []
        unrun = 0
        for job in cursor:
            outcome = ''
            if str(job['outcome']) == '0':
                outcome = 'passed'
            elif job['outcome']:
                outcome = 'failed'
            else:
                unrun += 1
                outcome = 'not yet run'

            logs = ''
            if job['log_url']:
                logs = ', logs at %s' % job['log_url']

            report.append('%s on %s %s%s' %(job['branch'], job['distro'],
                                            outcome, logs))

        comment = 'Tests run on %s:' % job['sha']
        for r in report:
            comment += ('\n    %s' % r)
        print 'Unrun: %d' % unrun
        print comment

        if unrun == 0:
            github_comment(job['issue_url'], comment)

        #if rc != 0:
        #    print 'Failed test run, stopping to debug'
        #    sys.exit(1)

        if job['type'] == 'manual':
            print 'Manual job, stopping for user to operate'
            sys.exit(1)


if __name__ == '__main__':
    main()
