qvm-template: Better args parsing: Use subparsers and complain about unknown args if the operation is not "remove".

This commit is contained in:
WillyPillow 2020-08-04 01:34:14 +08:00
parent 377e2a77ff
commit bf0635218a
No known key found for this signature in database
GPG Key ID: 3839E194B1415A9C

View File

@ -36,50 +36,99 @@ def qubes_release():
return subprocess.check_output(['lsb_release', '-sr'], return subprocess.check_output(['lsb_release', '-sr'],
encoding='UTF-8').strip() encoding='UTF-8').strip()
parser = argparse.ArgumentParser(description='Qubes Template Manager') def parser_gen():
parser.add_argument('operation', type=str) formatter = argparse.ArgumentDefaultsHelpFormatter
parser.add_argument('templates', nargs='*') parser_main = argparse.ArgumentParser(description='Qubes Template Manager',
formatter_class=formatter)
subparsers = parser_main.add_subparsers(dest='operation', required=True,
description='Command to run.')
# qrexec related def parser_add_command(cmd, help_str, add_help=True):
parser.add_argument('--repo-files', action='append', return subparsers.add_parser(cmd, formatter_class=formatter,
default=['/etc/yum.repos.d/qubes-templates.repo'], help=help_str, description=help_str, add_help=add_help)
help='Specify files containing DNF repository configuration.')
parser.add_argument('--updatevm', default='sys-firewall', # qrexec/DNF related
help='Specify VM to download updates from.') parser_main.add_argument('--repo-files', action='append',
# DNF-related options default=['/etc/yum.repos.d/qubes-templates.repo'],
parser.add_argument('--enablerepo', action='append', help='Specify files containing DNF repository configuration.')
help='Enable additional repositories.') parser_main.add_argument('--updatevm', default='sys-firewall',
parser.add_argument('--disablerepo', action='append', help='Specify VM to download updates from.')
help='Disable certain repositories.') parser_main.add_argument('--enablerepo', action='append', default=[],
parser.add_argument('--repoid', action='append', help='Enable additional repositories.')
help='Enable just specific repositories.') parser_main.add_argument('--disablerepo', action='append', default=[],
parser.add_argument('--releasever', default=qubes_release(), help='Disable certain repositories.')
help='Override distro release version.') parser_main.add_argument('--repoid', action='append', default=[],
parser.add_argument('--refresh', action='store_true', help='Enable just specific repositories.')
help='Set repository metadata as expired before running the command.') parser_main.add_argument('--releasever', default=qubes_release(),
parser.add_argument('--cachedir', default=CACHE_DIR, help='Override distro release version.')
help='Override cache directory.') parser_main.add_argument('--refresh', action='store_true',
# qvm-template install help='Set repository metadata as expired before running the command.')
parser.add_argument('--nogpgcheck', action='store_true', parser_main.add_argument('--cachedir', default=CACHE_DIR,
help='Disable signature checks.') help='Specify cache directory.')
parser.add_argument('--allow-pv', action='store_true', # qvm-template download
help='Allow setting virt_mode to pv in configuration file.') parser_download = parser_add_command('download',
parser.add_argument('--pool', help_str='Download template package.')
help='Specify pool to store created VMs in.') parser_download.add_argument('--downloaddir', default='.',
# qvm-template download help='Specify download directory.')
parser.add_argument('--downloaddir', default='.', parser_download.add_argument('--retries', default=5, type=int,
help='Override download directory.') help='Specify number of retries for downloads.')
parser.add_argument('--retries', default=5, type=int, parser_download.add_argument('templates', nargs='*', metavar='TEMPLATE')
help='Override number of retries for downloads.') # qvm-template {install,reinstall,downgrade,upgrade}
# qvm-template list parser_install = parser_add_command('install',
parser.add_argument('--all', action='store_true') help_str='Install template packages.')
parser.add_argument('--installed', action='store_true') parser_install.add_argument('--pool',
parser.add_argument('--available', action='store_true') help='Specify pool to store created VMs in.')
parser.add_argument('--extras', action='store_true') parser_reinstall = parser_add_command('reinstall',
parser.add_argument('--upgrades', action='store_true') help_str='Reinstall template packages.')
# qvm-template search parser_downgrade = parser_add_command('downgrade',
# Already defined above help_str='Downgrade template packages.')
#parser.add_argument('--all', action='store_true') parser_upgrade = parser_add_command('upgrade',
help_str='Upgrade template packages.')
for parser_x in [parser_install, parser_reinstall,
parser_downgrade, parser_upgrade]:
parser_x.add_argument('--nogpgcheck', action='store_true',
help='Disable signature checks.')
parser_x.add_argument('--allow-pv', action='store_true',
help='Allow setting virt_mode to pv in configuration file.')
parser_x.add_argument('templates', nargs='*', metavar='TEMPLATE')
# qvm-template {list,info}
parser_list = parser_add_command('list',
help_str='List templates.')
parser_info = parser_add_command('info',
help_str='Display details about templates.')
for parser_x in [parser_list, parser_info]:
parser_x.add_argument('--all', action='store_true',
help='Show all templates (default).')
parser_x.add_argument('--installed', action='store_true',
help='Show installed templates.')
parser_x.add_argument('--available', action='store_true',
help='Show available templates.')
parser_x.add_argument('--extras', action='store_true',
help=('Show extras (e.g., ones that exists'
' locally but not in repos) templates.'))
parser_x.add_argument('--upgrades', action='store_true',
help='Show upgradable templates.')
parser_x.add_argument('templates', nargs='*', metavar='TEMPLATE')
# qvm-template search
parser_search = parser_add_command('search',
help_str='Search template details for the given string.')
parser_search.add_argument('--all', action='store_true',
help=('Search also in template description and URL. In addition,'
' the criterion are evaluated with OR instead of AND.'))
parser_search.add_argument('templates', nargs='*', metavar='PATTERN')
# qvm-template remove
parser_remove = parser_add_command('remove',
help_str='Remove installed templates.',
add_help=False) # Forward --help to qvm-remove
_ = parser_remove # unused
# qvm-template clean
parser_clean = parser_add_command('clean',
help_str='Remove cached data.')
_ = parser_clean # unused
return parser_main
parser = parser_gen()
class TemplateState(enum.Enum): class TemplateState(enum.Enum):
INSTALLED = 'installed' INSTALLED = 'installed'
@ -205,13 +254,13 @@ def qrexec_payload(args, app, spec, refresh):
" argument should not contain '\\n'.") " argument should not contain '\\n'.")
payload = '' payload = ''
for repo in args.enablerepo if args.enablerepo else []: for repo in args.enablerepo:
check_newline(repo, '--enablerepo') check_newline(repo, '--enablerepo')
payload += '--enablerepo=%s\n' % repo payload += '--enablerepo=%s\n' % repo
for repo in args.disablerepo if args.disablerepo else []: for repo in args.disablerepo:
check_newline(repo, '--disablerepo') check_newline(repo, '--disablerepo')
payload += '--disablerepo=%s\n' % repo payload += '--disablerepo=%s\n' % repo
for repo in args.repoid if args.repoid else []: for repo in args.repoid:
check_newline(repo, '--repoid') check_newline(repo, '--repoid')
payload += '--repoid=%s\n' % repo payload += '--repoid=%s\n' % repo
if refresh: if refresh:
@ -791,7 +840,16 @@ def clean(args, app):
shutil.rmtree(args.cachedir) shutil.rmtree(args.cachedir)
def main(args=None, app=None): def main(args=None, app=None):
args, _ = parser.parse_known_args(args) raw_args = args
args, unk_args = parser.parse_known_args(raw_args)
if args.operation != 'remove' and unk_args:
args = parser.parse_args(raw_args) # this should result in an error
assert False and 'This line should not be executed.'
# FIXME: Currently doing things this way as we have to forward
# arguments to qvm-remove. While argparse.REMAINDER should be able to
# solve this, there's a bug (issue 17050) that prevents it from working
# on inputs where the first argument is an option, like 'qvm-template
# remove --help'. The bug should be fixed in Python 3.9.
if app is None: if app is None:
app = qubesadmin.Qubes() app = qubesadmin.Qubes()