blob: cf94ce038d62524f8a92e3dd1c085433dce05952 [file] [log] [blame]
import argparse
import os
import json
import sys
from tools import localpaths
from six import iteritems
from . import virtualenv
here = os.path.dirname(__file__)
wpt_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir))
def load_commands():
rv = {}
with open(os.path.join(here, "paths"), "r") as f:
paths = [item.strip().replace("/", os.path.sep) for item in f if item.strip()]
for path in paths:
abs_path = os.path.join(wpt_root, path, "commands.json")
base_dir = os.path.dirname(abs_path)
with open(abs_path, "r") as f:
data = json.load(f)
for command, props in iteritems(data):
assert "path" in props
assert "script" in props
rv[command] = {
"path": os.path.join(base_dir, props["path"]),
"script": props["script"],
"parser": props.get("parser"),
"parse_known": props.get("parse_known", False),
"help": props.get("help"),
"virtualenv": props.get("virtualenv", True),
"install": props.get("install", []),
"requirements": [os.path.join(base_dir, item)
for item in props.get("requirements", [])]
}
return rv
def parse_args(argv, commands):
parser = argparse.ArgumentParser()
parser.add_argument("--venv", action="store", help="Path to an existing virtualenv to use")
parser.add_argument("--debug", action="store_true", help="Run the debugger in case of an exception")
subparsers = parser.add_subparsers(dest="command")
for command, props in iteritems(commands):
sub_parser = subparsers.add_parser(command, help=props["help"], add_help=False)
args, extra = parser.parse_known_args(argv)
return args, extra
def import_command(prog, command, props):
# This currently requires the path to be a module,
# which probably isn't ideal but it means that relative
# imports inside the script work
rel_path = os.path.relpath(props["path"], wpt_root)
parts = os.path.splitext(rel_path)[0].split(os.path.sep)
mod_name = ".".join(parts)
mod = __import__(mod_name)
for part in parts[1:]:
mod = getattr(mod, part)
script = getattr(mod, props["script"])
if props["parser"] is not None:
parser = getattr(mod, props["parser"])()
parser.prog = "%s %s" % (os.path.basename(prog), command)
else:
parser = None
return script, parser
def setup_virtualenv(path, props):
if path is None:
path = os.path.join(wpt_root, "_venv")
venv = virtualenv.Virtualenv(path)
venv.start()
for name in props["install"]:
venv.install(name)
for path in props["requirements"]:
venv.install_requirements(path)
return venv
def main(prog=None, argv=None):
if prog is None:
prog = sys.argv[0]
if argv is None:
argv = sys.argv[1:]
commands = load_commands()
main_args, command_args = parse_args(argv, commands)
if not(len(argv) and argv[0] in commands):
sys.exit(1)
command = main_args.command
props = commands[command]
venv = None
if props["virtualenv"]:
venv = setup_virtualenv(main_args.venv, props)
script, parser = import_command(prog, command, props)
if parser:
if props["parse_known"]:
kwargs, extras = parser.parse_known_args(command_args)
extras = (extras,)
kwargs = vars(kwargs)
else:
extras = ()
kwargs = vars(parser.parse_args(command_args))
else:
extras = ()
kwargs = {}
if venv is not None:
args = (venv,) + extras
else:
args = extras
if script:
try:
rv = script(*args, **kwargs)
if rv is not None:
sys.exit(int(rv))
except Exception:
if main_args.debug:
import pdb
pdb.post_mortem()
else:
raise
sys.exit(0)
if __name__ == "__main__":
main()