[LNT] r309010 - admin: Rework commandline/click handling
Matthias Braun via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 25 12:42:42 PDT 2017
Author: matze
Date: Tue Jul 25 12:42:41 2017
New Revision: 309010
URL: http://llvm.org/viewvc/llvm-project?rev=309010&view=rev
Log:
admin: Rework commandline/click handling
Change code to use click in a more canonical way: Push common options to
the `lnt admin` level and pass a config object down to subcommands.
Modified:
lnt/trunk/lnt/lnttool/admin.py
Modified: lnt/trunk/lnt/lnttool/admin.py
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/lnttool/admin.py?rev=309010&r1=309009&r2=309010&view=diff
==============================================================================
--- lnt/trunk/lnt/lnttool/admin.py (original)
+++ lnt/trunk/lnt/lnttool/admin.py Tue Jul 25 12:42:41 2017
@@ -1,8 +1,6 @@
#!/usr/bin/env python
import click
-_config_filename = 'lntadmin.yaml'
-
def _load_dependencies():
global yaml, sys, requests, json, os, httplib
@@ -23,55 +21,70 @@ def _fatal(msg):
sys.exit(1)
-def _check_normalize_config(config, need_auth_token):
- '''Verify whether config is correct and complete. Also normalizes the
- server URL if necessary.'''
- lnt_url = config.get('lnt_url', None)
- if lnt_url is None:
- _fatal('No lnt_url specified in config or commandline\n'
- 'Tip: Use `create-config` for an example configuration')
- if lnt_url.endswith('/'):
- lnt_url = lnt_url[:-1]
- config['lnt_url'] = lnt_url
- database = config.get('database', None)
- if database is None:
- _fatal('No database specified in config or commandline')
- testsuite = config.get('testsuite', None)
- if testsuite is None:
- config['testsuite'] = 'nts'
-
- session = requests.Session()
- user = config.get('user', None)
- password = config.get('password', None)
- if user is not None and password is not None:
- session.auth = (user, password)
+_default_config_filename = './lntadmin.yaml'
+
+
+class AdminConfig(object):
+ def __init__(self, **args):
+ self._set('verbose', args['verbose'])
+ self._try_load_config(args['config'])
+ for key, value in args.items():
+ self._set(key, value)
+ self._check_and_normalize()
+
+ def _set(self, key, value):
+ '''Set attribute `key` of object to `value`. If `value` is None
+ then only set the attribute if it doesn't exist yet.'''
+ if value is None and hasattr(self, key):
+ return
+ setattr(self, key, value)
+
+ @property
+ def dict(self):
+ return self.__dict__
+
+ def _try_load_config(self, filename):
+ try:
+ config = yaml.load(open(filename))
+ for key, value in config.items():
+ self._set(key, value)
+ except IOError as e:
+ if self.verbose or filename != _default_config_filename:
+ _error("Could not load configuration file '%s': %s\n" %
+ (filename, e))
+
+ def _check_and_normalize(self):
+ lnt_url = self.lnt_url
+ if lnt_url is None:
+ _fatal('No lnt_url specified in config or commandline\n'
+ 'Tip: Use `create-config` for an example configuration')
+ if lnt_url.endswith('/'):
+ lnt_url = lnt_url[:-1]
+ self.lnt_url = lnt_url
+ if self.database is None:
+ self.database = 'default'
+ if self.testsuite is None:
+ self.testsuite = 'nts'
+
+ session = requests.Session()
+ user = self.dict.get('user', None)
+ password = self.dict.get('password', None)
+ if user is not None and password is not None:
+ session.auth = (user, password)
+
+ self._set('auth_token', None)
+ auth_token = self.auth_token
+ if auth_token is not None:
+ session.headers.update({'AuthToken': auth_token})
+ self.session = session
+
+
+_pass_config = click.make_pass_decorator(AdminConfig)
+
- auth_token = config.get('auth_token', None)
- if need_auth_token and auth_token is None:
+def _check_auth_token(config):
+ if config.auth_token is None:
_fatal('No auth_token specified in config')
- else:
- session.headers.update({'AuthToken': auth_token})
- config['session'] = session
-
-
-def _make_config(kwargs, need_auth_token=False):
- '''Load configuration from yaml file, merges it with the commandline
- options and verifies the resulting configuration.'''
- verbose = kwargs.get('verbose', False)
- # Load config file
- config = {}
- try:
- config = yaml.load(open(_config_filename))
- except IOError:
- if verbose:
- _error("Could not load configuration file '%s'\n" %
- _config_filename)
- for key, value in kwargs.items():
- if value is None:
- continue
- config[key] = value
- _check_normalize_config(config, need_auth_token=need_auth_token)
- return config
def _check_response(response):
@@ -97,50 +110,35 @@ def _print_run_info(run, indent=''):
sys.stdout.write('%s%s: %s\n' % (indent, key, value))
-def _common_options(func):
- func = click.option("--lnt-url", help="URL of LNT server")(func)
- func = click.option("--database", help="database to use")(func)
- func = click.option("--testsuite", help="testsuite to use")(func)
- func = click.option("--verbose", "-v", is_flag=True,
- help="verbose output")(func)
- return func
-
-
@click.command("list-machines")
- at _common_options
-def action_list_machines(**kwargs):
+ at _pass_config
+def action_list_machines(config):
"""List machines and their id numbers."""
- config = _make_config(kwargs)
-
url = ('{lnt_url}/api/db_{database}/v4/{testsuite}/machines'
- .format(**config))
- session = config['session']
- response = session.get(url)
+ .format(**config.dict))
+ response = config.session.get(url)
_check_response(response)
data = json.loads(response.text)
for machine in data['machines']:
id = machine.get('id', None)
name = machine.get('name', None)
sys.stdout.write("%s:%s\n" % (name, id))
- if config['verbose']:
+ if config.verbose:
_print_machine_info(machine, indent='\t')
@click.command("get-machine")
+ at _pass_config
@click.argument("machine")
- at _common_options
-def action_get_machine(**kwargs):
+def action_get_machine(config, machine):
"""Download machine information and run list."""
- config = _make_config(kwargs)
-
- filename = 'machine_%s.json' % config['machine']
+ filename = 'machine_%s.json' % machine
if os.path.exists(filename):
_fatal("'%s' already exists" % filename)
url = ('{lnt_url}/api/db_{database}/v4/{testsuite}/machines/{machine}'
- .format(**config))
- session = config['session']
- response = session.get(url)
+ .format(machine=machine, **config.dict))
+ response = config.session.get(url)
_check_response(response)
data = json.loads(response.text)
assert len(data['machines']) == 1
@@ -158,16 +156,15 @@ def action_get_machine(**kwargs):
@click.command("rm-machine")
+ at _pass_config
@click.argument("machine")
- at _common_options
-def action_rm_machine(**kwargs):
+def action_rm_machine(config, machine):
"""Remove machine and related data."""
- config = _make_config(kwargs, need_auth_token=True)
+ _check_auth_token(config)
url = ('{lnt_url}/api/db_{database}/v4/{testsuite}/machines/{machine}'
- .format(**config))
- session = config['session']
- response = session.delete(url, stream=True)
+ .format(machine=machine, **config.dict))
+ response = config.session.delete(url, stream=True)
_check_response(response)
for line in response.iter_lines():
sys.stdout.write(line + '\n')
@@ -175,52 +172,54 @@ def action_rm_machine(**kwargs):
@click.command("rename-machine")
+ at _pass_config
@click.argument("machine")
@click.argument("new-name")
- at _common_options
-def action_rename_machine(**kwargs):
+def action_rename_machine(config, machine, new_name):
"""Rename machine."""
- config = _make_config(kwargs, need_auth_token=True)
+ _check_auth_token(config)
url = ('{lnt_url}/api/db_{database}/v4/{testsuite}/machines/{machine}'
- .format(**config))
- session = config['session']
- response = session.post(url, data=(('action', 'rename'),
- ('name', config['new_name'])))
+ .format(machine=machine, **config.dict))
+ post_data = {
+ 'action': 'rename',
+ 'name': new_name,
+ }
+ response = config.session.post(url, data=post_data)
_check_response(response)
@click.command("merge-machine-into")
+ at _pass_config
@click.argument("machine")
@click.argument("into")
- at _common_options
-def action_merge_machine_into(**kwargs):
+def action_merge_machine_into(config, machine, into):
"""Merge machine into another machine."""
- config = _make_config(kwargs, need_auth_token=True)
+ _check_auth_token(config)
url = ('{lnt_url}/api/db_{database}/v4/{testsuite}/machines/{machine}'
- .format(**config))
+ .format(machine=machine, **config.dict))
session = config['session']
- response = session.post(url, data=(('action', 'merge'),
- ('into', config['into'])))
+ post_data = {
+ 'action': 'merge',
+ 'into': into
+ }
+ response = config.session.post(url, data=post_data)
_check_response(response)
@click.command("list-runs")
+ at _pass_config
@click.argument("machine")
- at _common_options
-def action_list_runs(**kwargs):
+def action_list_runs(config, machine):
"""List runs of a machine."""
- config = _make_config(kwargs)
-
url = ('{lnt_url}/api/db_{database}/v4/{testsuite}/machines/{machine}'
- .format(**config))
- session = config['session']
- response = session.get(url)
+ .format(machine=machine, **config.dict))
+ response = config.session.get(url)
_check_response(response)
data = json.loads(response.text)
runs = data['runs']
- if config['verbose']:
+ if config.verbose:
sys.stdout.write("order run-id\n")
sys.stdout.write("------------\n")
for run in runs:
@@ -229,28 +228,24 @@ def action_list_runs(**kwargs):
for field in order_by:
orders.append("%s=%s" % (field, run[field]))
sys.stdout.write("%s %s\n" % (";".join(orders), run['id']))
- if config['verbose']:
+ if config.verbose:
_print_run_info(run, indent='\t')
@click.command("get-run")
+ at _pass_config
@click.argument("runs", nargs=-1, required=True)
- at _common_options
-def action_get_run(**kwargs):
+def action_get_run(config, runs):
"""Download runs and save as report files."""
- config = _make_config(kwargs)
-
- runs = config['runs']
for run in runs:
filename = 'run_%s.json' % run
if os.path.exists(filename):
_fatal("'%s' already exists" % filename)
- session = config['session']
for run in runs:
url = ('{lnt_url}/api/db_{database}/v4/{testsuite}/runs/{run}'
- .format(run=run, **config))
- response = session.get(url)
+ .format(run=run, **config.dict))
+ response = config.session.get(url)
_check_response(response)
data = json.loads(response.text)
@@ -261,51 +256,47 @@ def action_get_run(**kwargs):
@click.command("rm-run")
+ at _pass_config
@click.argument("runs", nargs=-1, required=True)
- at _common_options
-def action_rm_run(**kwargs):
+def action_rm_run(config, runs):
"""Remove runs and related data."""
- config = _make_config(kwargs, need_auth_token=True)
+ _check_auth_token(config)
- session = config['session']
- runs = config['runs']
for run in runs:
url = ('{lnt_url}/api/db_{database}/v4/{testsuite}/runs/{run}'
- .format(run=run, **config))
- response = session.delete(url)
+ .format(run=run, **config.dict))
+ response = config.session.delete(url)
_check_response(response)
@click.command("post-run")
+ at _pass_config
@click.argument("datafiles", nargs=-1, type=click.Path(exists=True),
required=True)
- at _common_options
@click.option("--update-machine", is_flag=True, help="Update machine fields")
@click.option("--merge", default="replace", show_default=True,
type=click.Choice(['reject', 'replace', 'merge']),
help="Merge strategy when run already exists")
-def action_post_run(**kwargs):
+def action_post_run(config, datafiles, update_machine, merge):
"""Submit report files to server."""
- config = _make_config(kwargs, need_auth_token=True)
+ _check_auth_token(config)
- session = config['session']
- datafiles = config['datafiles']
for datafile in datafiles:
with open(datafile, "r") as datafile:
data = datafile.read()
url = ('{lnt_url}/api/db_{database}/v4/{testsuite}/runs'
- .format(**config))
+ .format(**config.dict))
url_params = {
- 'update_machine': 1 if config['update_machine'] else 0,
- 'merge': config['merge'],
+ 'update_machine': 1 if update_machine else 0,
+ 'merge': merge,
}
- response = session.post(url, params=url_params, data=data,
- allow_redirects=False)
+ response = config.session.post(url, params=url_params, data=data,
+ allow_redirects=False)
_check_response(response)
if response.status_code == 301:
sys.stdout.write(response.headers.get('Location') + '\n')
- if config['verbose']:
+ if config.verbose:
try:
response_data = json.loads(response.text)
json.dump(response_data, sys.stderr, response_data, indent=2)
@@ -317,9 +308,9 @@ def action_post_run(**kwargs):
@click.command('create-config')
def action_create_config():
"""Create example configuration."""
- if os.path.exists(_config_filename):
- _fatal("'%s' already exists" % _config_filename)
- with open(_config_filename, "w") as out:
+ if os.path.exists(_default_config_filename):
+ _fatal("'%s' already exists" % _default_config_filename)
+ with open(_default_config_filename, "w") as out:
out.write('''\
lnt_url: "http://localhost:8000"
database: default
@@ -328,7 +319,7 @@ testsuite: nts
# password: 'http_password'
# auth_token: 'secret'
''')
- sys.stderr.write("Created '%s'\n" % _config_filename)
+ sys.stderr.write("Created '%s'\n" % _default_config_filename)
class AdminCLI(click.MultiCommand):
@@ -358,5 +349,16 @@ class AdminCLI(click.MultiCommand):
@click.group("admin", cls=AdminCLI, no_args_is_help=True)
-def group_admin():
+ at click.option("--config", "-C", help="Config File", type=click.Path(),
+ default=_default_config_filename, show_default=True)
+ at click.option("--lnt-url", help="URL of LNT server", metavar="URL")
+ at click.option("--database", help="database to use", metavar="DBNAME")
+ at click.option("--testsuite", help="testsuite to use", metavar="SUITE")
+ at click.option("--verbose", "-v", is_flag=True, help="verbose output")
+ at click.pass_context
+def group_admin(ctx, **kwargs):
"""LNT server admin client."""
+ command = ctx.invoked_subcommand
+ if command is None or command == "create-config" or '--help' in sys.argv:
+ return
+ ctx.obj = AdminConfig(**kwargs)
More information about the llvm-commits
mailing list