from __future__ import nested_scopes, generators, division, absolute_import, with_statement, print_function, unicode_literals
import json, base64, os, subprocess, select, requests, sys

GH_TOKEN = os.environ['STATUS_APIKEY']
COMMIT = os.environ['TRAVIS_COMMIT']
TESTDATA = 'testdemos'

def create_gist(text):
    res = requests.post('https://api.github.com/gists', data=json.dumps({
        "description": "Autogenerated by brofiler.py",
        "public": True,
        "files": {
            "report.txt": {
                "content": text
            }
        }
    }).encode('utf-8'))
    return json.loads(res.text)['files']['report.txt']['raw_url']

def set_status(sha, state, desc, ctx, url=None):
    request = {
        'state': state,
        'description': desc,
        'context': 'profiling/' + ctx
    }

    if url:
        request['target_url'] = url

    res = requests.post('https://api.github.com/repos/moritzuehling/demoinfo-public/statuses/' + sha,
                        headers={'Authorization': 'token ' + GH_TOKEN}, data=json.dumps(request).encode('utf-8'))
    return res.text

def invoke(script, dem, report_progress=False):
    pipe_rfd, pipe_wfd = os.pipe()
    p = subprocess.Popen(
        ['/bin/bash', script, dem, str(pipe_wfd)],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        shell=False,
        close_fds=False,
        preexec_fn = lambda: os.close(pipe_rfd),
    )

    pipe_chunks = []
    stdout_chunks = []
    stderr_chunks = []
    stdout_rfd, stderr_rfd = p.stdout.fileno(), p.stderr.fileno()
    pending = [pipe_rfd, stdout_rfd, stderr_rfd]
    while len(pending) > 1:
        rready, _, _ = select.select(pending, [], [])
        fd = rready[0]
        chunk = os.read(fd, 4096)
        if report_progress and fd is pipe_rfd:
            print('\r%03d%%' % (int(chunk),), end='')
            sys.stdout.flush()
        elif len(chunk) == 0:
            # end of stream
            pending.remove(fd)
        else:
            (pipe_chunks if fd is pipe_rfd else stdout_chunks if fd is stdout_rfd else stderr_chunks).append(chunk.decode('utf-8'))
    retval = p.wait()
    print('\r%s return value %d' % (dem, retval))
    err_text = ''.join(stderr_chunks)
    out_text = ''.join(stdout_chunks)
    pipe_text = ''.join(pipe_chunks)
    return retval, out_text, err_text, pipe_text

SEP_LEN = 25
SEP_CHAR = '-'
def maybe_append(buf, piece, title):
    if len(piece) > 0:
        req_sep = SEP_LEN - (len(title) + 2)
        buf += '\n' + (SEP_CHAR * (req_sep // 2)) + ' ' + title + ' ' + (SEP_CHAR * ((req_sep + 1) // 2)) + '\n'
        buf += piece
        buf += '\n' + (SEP_CHAR * SEP_LEN) + '\n'
    return buf

demos = [dem for dem in os.listdir(TESTDATA) if dem.endswith('.dem')]


if sys.argv[1] == 'cleanup':
    for dem in demos:
        set_status(COMMIT, 'error', '???', dem)
    sys.exit(0)
elif sys.argv[1] == 'verify':
    how_many_failures = 0
    # start by setting all of them to Preparing
    for dem in demos:
        set_status(COMMIT, 'pending', 'Preparing', dem)

    # now run verification
    for dem in demos:
        retval, out_text, err_text, _ = invoke('ci/verify.sh', dem, True) # pipe not in use
        if retval == 0 and not out_text and not err_text:
            set_status(COMMIT, 'pending', 'Verify success', dem)
        else:
            how_many_failures += 1
            gistlink = create_gist(maybe_append(maybe_append(
                'return code ' + str(retval), err_text, 'stderr'), out_text, 'stdout'))
            set_status(COMMIT, 'failure', 'Verification failed', dem, gistlink)
            print('Failure info posted to: ' + gistlink)
            os.unlink(TESTDATA + '/' + dem)

    sys.exit(how_many_failures)
elif sys.argv[1] != 'run':
    raise ValueError('Illegal parameter')



failure_count = 0
# now actually run profiling
for dem in demos:
    set_status(COMMIT, 'pending', 'Running', dem)
    retval, out_text, err_text, pipe_text = invoke('ci/profile.sh', dem)
    os.unlink(TESTDATA + '/' + dem)

    gist_text = '' if retval == 0 else 'return code %d' % (retval,)
    pipe_text = '\n'.join([x for x in pipe_text.split('\n') if not x.startswith('unmatched leave at stack pos')])
    gist_text = maybe_append(gist_text, err_text, 'stderr')
    gist_text = maybe_append(gist_text, out_text, 'stdout')
    if gist_text:
        gist_text = maybe_append(gist_text, pipe_text, 'results')
    else:
        gist_text = pipe_text # no need for bars if it's the only output
    gistlink = create_gist(gist_text)
    print('Profiling results posted to: ' + gistlink)
    set_status(COMMIT, 'success' if retval is 0 else 'failure', 'Completed', dem, gistlink)
    if retval != 0:
        failure_count += 1

sys.exit(failure_count)
