#!/bin/env python

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import re
import os
import shlex
import shutil
import subprocess
import sys

"""
Invoke as:

    thrift/compiler/test/build_fixtures [$BUILDDIR]

where $BUILDDIR/thrift/compiler/thrift is the thrift compiler.

If using Buck to build the thrift compiler, the $BUILDDIR default will work.
"""

def ascend_find_exe(path, target):
    if not os.path.isdir(path):
        path = os.path.dirname(path)
    while True:
        test = os.path.join(path, target)
        if os.access(test, os.X_OK):
            return test
        parent = os.path.dirname(path)
        if os.path.samefile(parent, path):
            return None
        path = parent

def ascend_find_dir(path, target):
    if not os.path.isdir(path):
        path = os.path.dirname(path)
    while True:
        test = os.path.join(path, target)
        if os.path.isdir(test):
            return test
        parent = os.path.dirname(path)
        if os.path.samefile(parent, path):
            return None
        path = parent

def read_lines(path):
    with open(path, 'r') as f:
        return f.readlines()

exe = os.path.join(os.getcwd(), sys.argv[0])
buck_out = 'buck-out/gen'
buildDir = sys.argv[1] if len(sys.argv) > 1 else buck_out
thriftRel = os.path.join(buildDir, 'thrift/compiler/thrift')
if buildDir == buck_out:
    templatesRel = subprocess.check_output([
        'buck',
        'targets',
        '--show-output',
        '//thrift/compiler/generate:templates',
    ]).split()[1]
else:
    templatesRel = os.path.join(buildDir,
                                'thrift/compiler/generate/templates/templates')
templates = ascend_find_dir(exe, templatesRel)
thrift = ascend_find_exe(exe, thriftRel)
fixtureDir = ascend_find_dir(exe, 'thrift/compiler/test/fixtures')
fixtureNames = [sys.argv[2]] if len(sys.argv) > 2 else sorted([
    f
    for f in os.listdir(fixtureDir)
    if os.path.isfile(os.path.join(fixtureDir, f, 'cmd'))
])

processes = []
hasErrors = False

msgFormat = "Building fixture {{0:>{w}}}/{{1}}: {{2}}".format(
    w=len(str(len(fixtureNames))))
for name, index in zip(fixtureNames, range(len(fixtureNames))):
    msg = msgFormat.format(index + 1, len(fixtureNames), name)
    print(msg, file=sys.stderr)
    cwd = os.path.join(fixtureDir, name)
    for fn in set(os.listdir(cwd)) - set(['cmd', 'src']):
        if fn.startswith('.'):
            continue
        shutil.rmtree(os.path.join(cwd, fn))
    cmds = read_lines(os.path.join(cwd, 'cmd'))
    for cmd in cmds:
        if re.match(r"^\s*#", cmd):
            continue
        args = shlex.split(cmd.strip())
        base_args = [thrift, "-r", "--templates", templates, "--gen"]
        if "cpp" in args[0]:
            path = os.path.join("thrift/compiler/test/fixtures", name)
            extra = "include_prefix=" + path
            join = "," if ":" in args[0] else ":"
            args[0] = args[0] + join + extra
        if ("cpp2" in args[0] or "schema" in args[0]):
            # do not recurse in py generators. This is a hack because there is a
            # bug in the python generator that appears hard to fix. This is a
            # workaround. In future, we will use mstch, and the mstch
            # generator does not have this issue.
            base_args.remove('-r')
        p = subprocess.Popen(
            base_args + args,
            cwd=cwd,
            close_fds=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
        # run all processes in parallel
        processes.append(p)

# now join results
for p in processes:
    out, err = p.communicate()
    sys.stdout.write(out.decode(sys.stdout.encoding))
    if p.returncode != 0:
        hasErrors = True
        sys.stderr.write(err.decode(sys.stderr.encoding))


sys.exit(int(hasErrors))
