qvm-template: use QubesArgumentParser

It produces consistent help for subcommands and already handles
--verbose/--quiet.
This commit is contained in:
Marek Marczykowski-Górecki 2021-02-04 14:03:10 +01:00
parent 6980e7ba14
commit e0063d8808
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724

View File

@ -85,9 +85,11 @@ def qubes_release() -> str:
def get_parser() -> argparse.ArgumentParser: def get_parser() -> argparse.ArgumentParser:
"""Generate argument parser for the application.""" """Generate argument parser for the application."""
formatter = argparse.ArgumentDefaultsHelpFormatter formatter = argparse.ArgumentDefaultsHelpFormatter
parser_main = argparse.ArgumentParser(description='Qubes Template Manager', parser_main = qubesadmin.tools.QubesArgumentParser(description=__doc__,
formatter_class=formatter) formatter_class=formatter)
subparsers = parser_main.add_subparsers(dest='operation', parser_main.register('action', 'parsers',
qubesadmin.tools.AliasedSubParsersAction)
subparsers = parser_main.add_subparsers(dest='command',
description='Command to run.') description='Command to run.')
def parser_add_command(cmd, help_str): def parser_add_command(cmd, help_str):
@ -124,12 +126,10 @@ def get_parser() -> argparse.ArgumentParser:
help='Set repository metadata as expired before running the command.') help='Set repository metadata as expired before running the command.')
parser_main.add_argument('--cachedir', default=CACHE_DIR, parser_main.add_argument('--cachedir', default=CACHE_DIR,
help='Specify cache directory.') help='Specify cache directory.')
parser_main.add_argument('--keep-cache', default=False, parser_main.add_argument('--keep-cache', action='store_true', default=False,
help='Keep downloaded packages in cache dir') help='Keep downloaded packages in cache dir')
parser_main.add_argument('--yes', action='store_true', parser_main.add_argument('--yes', action='store_true',
help='Assume "yes" to questions.') help='Assume "yes" to questions.')
parser_main.add_argument('--quiet', action='store_true',
help='Decrease verbosity.')
# qvm-template {install,reinstall,downgrade,upgrade} # qvm-template {install,reinstall,downgrade,upgrade}
parser_install = parser_add_command('install', parser_install = parser_add_command('install',
help_str='Install template packages.') help_str='Install template packages.')
@ -359,7 +359,7 @@ def confirm_action(msg: str, affected: typing.List[str]) -> None:
while confirm != 'y': while confirm != 'y':
confirm = input('Are you sure? [y/N] ').lower() confirm = input('Are you sure? [y/N] ').lower()
if confirm == 'n': if confirm == 'n':
print('Operation cancelled.') print('command cancelled.')
sys.exit(1) sys.exit(1)
def qrexec_popen( def qrexec_popen(
@ -988,12 +988,12 @@ def install(
os.remove(rpmfile) os.remove(rpmfile)
def list_templates(args: argparse.Namespace, def list_templates(args: argparse.Namespace,
app: qubesadmin.app.QubesBase, operation: str) -> None: app: qubesadmin.app.QubesBase, command: str) -> None:
"""Command that lists templates. """Command that lists templates.
:param args: Arguments received by the application. :param args: Arguments received by the application.
:param app: Qubes application object :param app: Qubes application object
:param operation: If set to ``list``, display a listing similar to ``dnf :param command: If set to ``list``, display a listing similar to ``dnf
list``. If set to ``info``, display detailed template information list``. If set to ``info``, display detailed template information
similar to ``dnf info``. Otherwise, an ``AssertionError`` is raised. similar to ``dnf info``. Otherwise, an ``AssertionError`` is raised.
""" """
@ -1080,12 +1080,12 @@ def list_templates(args: argparse.Namespace,
outputs[status.value] = output outputs[status.value] = output
return outputs return outputs
if operation == 'list': if command == 'list':
append = append_list append = append_list
elif operation == 'info': elif command == 'info':
append = append_info append = append_info
else: else:
assert False and 'Unknown operation' assert False and 'Unknown command'
def append_vm(vm, status): def append_vm(vm, status):
append(query_local(vm), status, vm.features['template-installtime']) append(query_local(vm), status, vm.features['template-installtime'])
@ -1143,24 +1143,24 @@ def list_templates(args: argparse.Namespace,
parser.error('No matching templates to list') parser.error('No matching templates to list')
if args.machine_readable: if args.machine_readable:
if operation == 'info': if command == 'info':
tpl_list_dict = info_to_machine_output(tpl_list) tpl_list_dict = info_to_machine_output(tpl_list)
elif operation == 'list': elif command == 'list':
tpl_list_dict = list_to_machine_output(tpl_list) tpl_list_dict = list_to_machine_output(tpl_list)
for status, grp in tpl_list_dict.items(): for status, grp in tpl_list_dict.items():
for line in grp: for line in grp:
print('|'.join([status] + list(line.values()))) print('|'.join([status] + list(line.values())))
elif args.machine_readable_json: elif args.machine_readable_json:
if operation == 'info': if command == 'info':
tpl_list_dict = \ tpl_list_dict = \
info_to_machine_output(tpl_list, replace_newline=False) info_to_machine_output(tpl_list, replace_newline=False)
elif operation == 'list': elif command == 'list':
tpl_list_dict = list_to_machine_output(tpl_list) tpl_list_dict = list_to_machine_output(tpl_list)
print(json.dumps(tpl_list_dict)) print(json.dumps(tpl_list_dict))
else: else:
if operation == 'info': if command == 'info':
tpl_list = info_to_human_output(tpl_list) tpl_list = info_to_human_output(tpl_list)
elif operation == 'list': elif command == 'list':
tpl_list = list_to_human_output(tpl_list) tpl_list = list_to_human_output(tpl_list)
for status, grp in tpl_list: for status, grp in tpl_list:
print(status.title()) print(status.title())
@ -1416,8 +1416,8 @@ def main(args: typing.Optional[typing.Sequence[str]] = None,
""" """
p_args = parser.parse_args(args) p_args = parser.parse_args(args)
if not p_args.operation: if not p_args.command:
parser.error('An operation needs to be specified.') parser.error('A command needs to be specified.')
# If the user specified other repo files... # If the user specified other repo files...
if len(p_args.repo_files) > 1: if len(p_args.repo_files) > 1:
@ -1433,35 +1433,35 @@ def main(args: typing.Optional[typing.Sequence[str]] = None,
if p_args.refresh: if p_args.refresh:
qrexec_repoquery(p_args, app, refresh=True) qrexec_repoquery(p_args, app, refresh=True)
if p_args.operation == 'download': if p_args.command == 'download':
download(p_args, app) download(p_args, app)
elif p_args.operation == 'install': elif p_args.command == 'install':
install(p_args, app) install(p_args, app)
elif p_args.operation == 'reinstall': elif p_args.command == 'reinstall':
install(p_args, app, version_selector=VersionSelector.REINSTALL, install(p_args, app, version_selector=VersionSelector.REINSTALL,
override_existing=True) override_existing=True)
elif p_args.operation == 'downgrade': elif p_args.command == 'downgrade':
install(p_args, app, version_selector=VersionSelector.LATEST_LOWER, install(p_args, app, version_selector=VersionSelector.LATEST_LOWER,
override_existing=True) override_existing=True)
elif p_args.operation == 'upgrade': elif p_args.command == 'upgrade':
install(p_args, app, version_selector=VersionSelector.LATEST_HIGHER, install(p_args, app, version_selector=VersionSelector.LATEST_HIGHER,
override_existing=True) override_existing=True)
elif p_args.operation == 'list': elif p_args.command == 'list':
list_templates(p_args, app, 'list') list_templates(p_args, app, 'list')
elif p_args.operation == 'info': elif p_args.command == 'info':
list_templates(p_args, app, 'info') list_templates(p_args, app, 'info')
elif p_args.operation == 'search': elif p_args.command == 'search':
search(p_args, app) search(p_args, app)
elif p_args.operation == 'remove': elif p_args.command == 'remove':
remove(p_args, app, disassoc=p_args.disassoc) remove(p_args, app, disassoc=p_args.disassoc)
elif p_args.operation == 'purge': elif p_args.command == 'purge':
remove(p_args, app, purge=True) remove(p_args, app, purge=True)
elif p_args.operation == 'clean': elif p_args.command == 'clean':
clean(p_args, app) clean(p_args, app)
elif p_args.operation == 'repolist': elif p_args.command == 'repolist':
repolist(p_args, app) repolist(p_args, app)
else: else:
parser.error('Operation \'%s\' not supported.' % p_args.operation) parser.error('Command \'%s\' not supported.' % p_args.command)
return 0 return 0