...
 
Commits (2)
......@@ -12,7 +12,7 @@ buildPythonApplication {
shellHook = ''
root_dir=$(git rev-parse --show-toplevel)
alias dev-cli="${python}/bin/python $root_dir/hydra_cli/__init__.py --dev"
alias dev-cli="${python}/bin/python $root_dir/hydra_cli/__init__.py"
alias reformat="find {setup.py,hydra_cli,tests} -regex ".*\.py$" | xargs autopep8 --in-place --aggressive --aggressive"
export PYTHONPATH="$PYTHONPATH:$root_dir"
'';
......
......@@ -24,7 +24,7 @@ class Cache():
if not os.path.exists(self.cache_dir):
os.mkdir(self.cache_dir)
def ensure_cache_entry(self, cache_path: str, provider: Callable[[], Response], mode: int):
def ensure_cache_entry(self, cache_path: str, provider: Callable[[], Response], mode: int) -> str:
"""
Ensures that a given cache path exists and optionally invokes the `provider`
which returns an iterable object (i.e. a response from `requests`) and its content
......@@ -39,3 +39,4 @@ class Cache():
for chunk in provider():
cache_entry.write(chunk)
os.chmod(path, mode)
return path
......@@ -6,9 +6,10 @@ from typing import List, Any, Dict
import sys
import os
from urllib.parse import urlparse
from hydra_cli.api import perform_api_call, perform_api_call_json, transform_host_name
from hydra_cli.cache import Cache
from hydra_cli.tables import render_table
from hydra_cli.commands.project import ProjectParser
from hydra_cli.api import transform_host_name
from hydra_cli.commands.reproduce_build import ReproduceBuildParser
class Application():
......@@ -30,109 +31,50 @@ class Application():
]
parser = argparse.ArgumentParser(cmd, description="Query Hydra API")
parser.add_argument(
'-H',
'--host',
help='The host for Hydra',
default='https://hydra.nixos.org',
type=transform_host_name
)
parser.add_argument(
'-p',
'--plain',
help='Whether to use a plain table output easily parseable. Useful with scripts.',
default=False,
action='store_true'
)
parser.add_argument(
'-d',
'--dev',
help='Development mode: show full traces in case of errors thrown',
default=False,
action='store_true'
)
subparsers = parser.add_subparsers(dest="command")
project = subparsers.add_parser('project')
reproduce_build = subparsers.add_parser('reproduce-build')
project.add_argument(
'-f',
'--fields',
help='Which fields to display',
default=['name'],
choices=self.project_choices,
nargs='*'
)
project.add_argument(
'--verbose',
help='Verbose view: show all properties',
action='store_true'
)
project.add_argument(
'show',
help='Display information about a single project',
nargs='?',
default=None
)
self.cache = Cache()
self.cache.init_cache()
reproduce_build.add_argument('build_nr', help='The build ID to reproduce locally', type=int)
subparsers = parser.add_subparsers(dest="command")
subparsers.required = True
project = ProjectParser(self.project_choices)
project_parser = project.create_subcli(subparsers)
reproduce_build = ReproduceBuildParser(self.cache)
reproduce_build_parser = reproduce_build.create_subcli(subparsers)
for x in [project_parser, reproduce_build_parser]:
x.add_argument(
'-H',
'--host',
help='The host for Hydra',
default='https://hydra.nixos.org',
type=transform_host_name
)
x.add_argument(
'-p',
'--plain',
help='Whether to use a plain table output easily parseable. Useful with scripts.',
default=False,
action='store_true'
)
x.add_argument(
'-d',
'--dev',
help='Development mode: show full traces in case of errors thrown',
default=False,
action='store_true'
)
# only retrieve top-level command
argv = parser.parse_args(args)
if argv.command:
cmd = argv.command.replace("-", "_")
if not hasattr(self, cmd):
print("Unrecognized command %s" % argv.command, file=sys.stderr)
parser.print_help()
exit(1)
else:
parser.print_help()
exit(1)
self.cache = Cache()
self.cache.init_cache()
try:
getattr(self, cmd)(argv)
argv.func(argv)
except Exception as err:
if not argv.dev:
print("Aborted program: %s" % err, file=sys.stderr)
exit(1)
else:
raise err
def project(self, argv: Dict[str, Any]):
"""
Show available build projects from Hydra (mainly list projects or show details).
"""
fields = argv['fields']
if argv['verbose']:
fields = self.project_choices
is_single = argv['show'] is not None
path = "/project/%s" % argv['show'] if is_single else "/"
print(render_table(
argv['plain'],
perform_api_call_json(argv['host'], path, fields, is_single)
))
def reproduce_build(self, argv: Dict[str, Any]):
"""
Calls the reproduce build functionality from Hydra for a given build ID.
"""
host = '{uri.netloc}'.format(uri=urlparse(argv['host']))
script_path = 'reproduce-build-%s-%d' % (host, argv['build_nr'])
self.cache.ensure_cache_entry(
script_path,
lambda: perform_api_call(argv['host'], '/build/%d/reproduce' % argv['build_nr']),
0o775
)
# https://bugs.python.org/issue421250
os.execvp(script_path, [script_path])
"""
CLI parser and handler for the `project` sub-command
"""
from typing import Dict, Any, List
from argparse import _SubParsersAction, ArgumentParser, Namespace
from hydra_cli.api import perform_api_call_json
from hydra_cli.tables import render_table
class ProjectParser():
"""
Helper class for the `project` subcommand.
"""
def __init__(self, project_choices: List[str]) -> None:
self.project_choices = project_choices
def create_subcli(self, subparse: _SubParsersAction) -> ArgumentParser:
project = subparse.add_parser('project')
project.add_argument(
'-f',
'--fields',
help='Which fields to display',
default=['name'],
choices=self.project_choices,
nargs='*'
)
project.add_argument(
'--verbose',
help='Verbose view: show all properties',
action='store_true'
)
project.add_argument(
'show',
help='Display information about a single project',
nargs='?',
default=None
)
project.set_defaults(func=self.run_command)
return project
def run_command(self, argv: Namespace):
"""
Show available build projects from Hydra (mainly list projects or show details).
"""
fields = argv.fields
if argv.verbose:
fields = self.project_choices
is_single = argv.show is not None
path = "/project/%s" % argv.show if is_single else "/"
print(render_table(
argv.plain,
perform_api_call_json(argv.host, path, fields, is_single)
))
"""
CLI parser and handler for the `reproduce-build` sub-command
"""
from argparse import _SubParsersAction, ArgumentParser, Namespace
import os
from urllib.parse import urlparse
from hydra_cli.cache import Cache
from hydra_cli.api import perform_api_call
class ReproduceBuildParser():
"""
Helper class for the `reproduce-build` sub-command.
"""
def __init__(self, cache: Cache) -> None:
self.cache = cache
def create_subcli(self, subparse: _SubParsersAction) -> ArgumentParser:
reproduce_build = subparse.add_parser('reproduce-build')
reproduce_build.add_argument('build_nr', help='The build ID to reproduce locally', type=int)
reproduce_build.set_defaults(func=self.run_command)
return reproduce_build
def run_command(self, argv: Namespace):
"""
Calls the reproduce build functionality from Hydra for a given build ID.
"""
host = '{uri.netloc}'.format(uri=urlparse(argv.host))
script_path = 'reproduce-build-%s-%d' % (host, argv.build_nr)
full_path = self.cache.ensure_cache_entry(
script_path,
lambda: perform_api_call(argv.host, '/build/%d/reproduce' % argv.build_nr),
0o775
)
# https://bugs.python.org/issue421250
os.execvp(full_path, [script_path])