Merge branch 'improved-tools-messages'
* improved-tools-messages: tools: suppress full traceback in console tools tools: add SubParsersHelpAction, which include subcommands details in --help
This commit is contained in:
commit
a99acc68da
@ -339,7 +339,7 @@ class QubesArgumentParser(argparse.ArgumentParser):
|
|||||||
def __init__(self, want_app=True, want_app_no_instance=False,
|
def __init__(self, want_app=True, want_app_no_instance=False,
|
||||||
vmname_nargs=None, **kwargs):
|
vmname_nargs=None, **kwargs):
|
||||||
|
|
||||||
super(QubesArgumentParser, self).__init__(**kwargs)
|
super(QubesArgumentParser, self).__init__(add_help=False, **kwargs)
|
||||||
|
|
||||||
self._want_app = want_app
|
self._want_app = want_app
|
||||||
self._want_app_no_instance = want_app_no_instance
|
self._want_app_no_instance = want_app_no_instance
|
||||||
@ -360,6 +360,9 @@ class QubesArgumentParser(argparse.ArgumentParser):
|
|||||||
self.add_argument('--force-root', action='store_true',
|
self.add_argument('--force-root', action='store_true',
|
||||||
default=False, help=argparse.SUPPRESS)
|
default=False, help=argparse.SUPPRESS)
|
||||||
|
|
||||||
|
self.add_argument('--help', '-h', action=SubParsersHelpAction,
|
||||||
|
help='show this help message and exit')
|
||||||
|
|
||||||
if self._vmname_nargs in [argparse.ZERO_OR_MORE, argparse.ONE_OR_MORE]:
|
if self._vmname_nargs in [argparse.ZERO_OR_MORE, argparse.ONE_OR_MORE]:
|
||||||
vm_name_group = VmNameGroup(self,
|
vm_name_group = VmNameGroup(self,
|
||||||
required=(self._vmname_nargs
|
required=(self._vmname_nargs
|
||||||
@ -436,6 +439,37 @@ class QubesArgumentParser(argparse.ArgumentParser):
|
|||||||
print(*args, file=sys.stderr, **kwargs)
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class SubParsersHelpAction(argparse._HelpAction):
|
||||||
|
''' Print help for all options _and all subparsers_ '''
|
||||||
|
# source https://stackoverflow.com/a/24122778
|
||||||
|
# pylint: disable=protected-access,too-few-public-methods
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _indent(indent, text):
|
||||||
|
'''Indent *text* by *indent* spaces'''
|
||||||
|
return '\n'.join((' ' * indent) + l for l in text.splitlines())
|
||||||
|
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
parser.print_help()
|
||||||
|
|
||||||
|
# retrieve subparsers from parser
|
||||||
|
subparsers_actions = [
|
||||||
|
action for action in parser._actions
|
||||||
|
if isinstance(action, argparse._SubParsersAction)]
|
||||||
|
# there will probably only be one subparser_action,
|
||||||
|
# but better save than sorry
|
||||||
|
for subparsers_action in subparsers_actions:
|
||||||
|
# get all subparsers and print help
|
||||||
|
for pseudo_action in subparsers_action._choices_actions:
|
||||||
|
choice = pseudo_action.dest.split(' ', 1)[0]
|
||||||
|
subparser = subparsers_action.choices[choice]
|
||||||
|
print("\nCommand '{}':".format(choice))
|
||||||
|
choice_help = subparser.format_usage()
|
||||||
|
choice_help = self._indent(2, choice_help)
|
||||||
|
print(choice_help)
|
||||||
|
parser.exit()
|
||||||
|
|
||||||
|
|
||||||
class AliasedSubParsersAction(argparse._SubParsersAction):
|
class AliasedSubParsersAction(argparse._SubParsersAction):
|
||||||
'''SubParser with support for action aliases'''
|
'''SubParser with support for action aliases'''
|
||||||
# source https://gist.github.com/sampsyo/471779
|
# source https://gist.github.com/sampsyo/471779
|
||||||
|
@ -157,9 +157,13 @@ def main(args=None, app=None):
|
|||||||
else:
|
else:
|
||||||
profile_name = args.profile
|
profile_name = args.profile
|
||||||
|
|
||||||
|
try:
|
||||||
backup_summary = args.app.qubesd_call(
|
backup_summary = args.app.qubesd_call(
|
||||||
'dom0', 'admin.backup.Info', profile_name)
|
'dom0', 'admin.backup.Info', profile_name)
|
||||||
print(backup_summary.decode())
|
print(backup_summary.decode())
|
||||||
|
except QubesException as err:
|
||||||
|
print('\nBackup preparation error: {}'.format(err), file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
if not args.yes:
|
if not args.yes:
|
||||||
if input("Do you want to proceed? [y/N] ").upper() != "Y":
|
if input("Do you want to proceed? [y/N] ").upper() != "Y":
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import qubesadmin.exc
|
||||||
from qubesadmin.tools import QubesArgumentParser
|
from qubesadmin.tools import QubesArgumentParser
|
||||||
|
|
||||||
parser = QubesArgumentParser(description=__doc__, vmname_nargs=1)
|
parser = QubesArgumentParser(description=__doc__, vmname_nargs=1)
|
||||||
@ -70,7 +71,10 @@ def main(args=None, app=None):
|
|||||||
parser.error(
|
parser.error(
|
||||||
'Pool argument must be of form: -P volume_name=pool_name')
|
'Pool argument must be of form: -P volume_name=pool_name')
|
||||||
|
|
||||||
|
try:
|
||||||
app.clone_vm(src_vm, new_name, new_cls=args.cls, pool=pool, pools=pools)
|
app.clone_vm(src_vm, new_name, new_cls=args.cls, pool=pool, pools=pools)
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sys.exit(main())
|
sys.exit(main())
|
||||||
|
@ -63,8 +63,11 @@ def main(args=None, app=None):
|
|||||||
if args.delete:
|
if args.delete:
|
||||||
parser.error('--unset requires a feature')
|
parser.error('--unset requires a feature')
|
||||||
|
|
||||||
|
try:
|
||||||
features = [(feat, vm.features[feat]) for feat in vm.features]
|
features = [(feat, vm.features[feat]) for feat in vm.features]
|
||||||
qubesadmin.tools.print_table(features)
|
qubesadmin.tools.print_table(features)
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
|
|
||||||
elif args.delete:
|
elif args.delete:
|
||||||
if args.value is not None:
|
if args.value is not None:
|
||||||
@ -73,6 +76,8 @@ def main(args=None, app=None):
|
|||||||
del vm.features[args.feature]
|
del vm.features[args.feature]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
|
|
||||||
elif args.value is None:
|
elif args.value is None:
|
||||||
try:
|
try:
|
||||||
@ -80,8 +85,13 @@ def main(args=None, app=None):
|
|||||||
return 0
|
return 0
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return 1
|
return 1
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
vm.features[args.feature] = args.value
|
vm.features[args.feature] = args.value
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -168,6 +168,8 @@ def main(args=None, app=None):
|
|||||||
args.app.remove_pool(args.name)
|
args.app.remove_pool(args.name)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
parser.print_error('no such pool %s\n' % args.name)
|
parser.print_error('no such pool %s\n' % args.name)
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error('failed to remove pool %s: %s\n' % (args.name, str(e)))
|
||||||
elif args.command == 'info':
|
elif args.command == 'info':
|
||||||
for pool in args.pools:
|
for pool in args.pools:
|
||||||
pool_info(pool)
|
pool_info(pool)
|
||||||
|
@ -116,6 +116,8 @@ def process_actions(parser, args, target):
|
|||||||
setattr(target, args.property, args.value)
|
setattr(target, args.property, args.value)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
parser.error('no such property: {!r}'.format(args.property))
|
parser.error('no such property: {!r}'.format(args.property))
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if args.delete:
|
if args.delete:
|
||||||
@ -123,6 +125,8 @@ def process_actions(parser, args, target):
|
|||||||
delattr(target, args.property)
|
delattr(target, args.property)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
parser.error('no such property: {!r}'.format(args.property))
|
parser.error('no such property: {!r}'.format(args.property))
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -131,6 +135,8 @@ def process_actions(parser, args, target):
|
|||||||
print(str(value))
|
print(str(value))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
parser.error('no such property: {!r}'.format(args.property))
|
parser.error('no such property: {!r}'.format(args.property))
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import qubesadmin.exc
|
||||||
from qubesadmin.tools import QubesArgumentParser
|
from qubesadmin.tools import QubesArgumentParser
|
||||||
|
|
||||||
parser = QubesArgumentParser(description=__doc__,
|
parser = QubesArgumentParser(description=__doc__,
|
||||||
@ -44,7 +45,10 @@ def main(args=None, app=None): # pylint: disable=missing-docstring
|
|||||||
|
|
||||||
if args.no_confirm or go_ahead == "Y":
|
if args.no_confirm or go_ahead == "Y":
|
||||||
for vm in args.domains:
|
for vm in args.domains:
|
||||||
|
try:
|
||||||
del args.app.domains[vm.name]
|
del args.app.domains[vm.name]
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
retcode = 0
|
retcode = 0
|
||||||
else:
|
else:
|
||||||
print("Remove cancelled.")
|
print("Remove cancelled.")
|
||||||
|
@ -92,6 +92,8 @@ def main(args=None, app=None): # pylint: disable=missing-docstring
|
|||||||
except qubesadmin.exc.QubesVMNotStartedError:
|
except qubesadmin.exc.QubesVMNotStartedError:
|
||||||
# already shut down
|
# already shut down
|
||||||
pass
|
pass
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
else:
|
else:
|
||||||
timeout = args.timeout
|
timeout = args.timeout
|
||||||
current_vms = list(sorted(this_round_domains))
|
current_vms = list(sorted(this_round_domains))
|
||||||
@ -114,6 +116,8 @@ def main(args=None, app=None): # pylint: disable=missing-docstring
|
|||||||
except qubesadmin.exc.QubesVMNotStartedError:
|
except qubesadmin.exc.QubesVMNotStartedError:
|
||||||
# already shut down
|
# already shut down
|
||||||
pass
|
pass
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
|
|
||||||
if args.wait:
|
if args.wait:
|
||||||
if have_events:
|
if have_events:
|
||||||
|
@ -26,6 +26,7 @@ from __future__ import print_function
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import qubesadmin
|
import qubesadmin
|
||||||
|
import qubesadmin.exc
|
||||||
import qubesadmin.tools
|
import qubesadmin.tools
|
||||||
|
|
||||||
def mode_query(args):
|
def mode_query(args):
|
||||||
@ -101,7 +102,10 @@ def main(args=None, app=None):
|
|||||||
|
|
||||||
parser = get_parser()
|
parser = get_parser()
|
||||||
args = parser.parse_args(args, app=app)
|
args = parser.parse_args(args, app=app)
|
||||||
|
try:
|
||||||
return args.func(args)
|
return args.func(args)
|
||||||
|
except qubesadmin.exc.QubesException as e:
|
||||||
|
parser.error_runtime(e)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Loading…
Reference in New Issue
Block a user