diff --git a/python/mach/mach/base.py b/python/mach/mach/base.py index 7f6674f5a9f..b2ef404191e 100644 --- a/python/mach/mach/base.py +++ b/python/mach/mach/base.py @@ -80,13 +80,17 @@ class MethodHandler(object): # in a given context. 'conditions', + # argparse.ArgumentParser instance to use as the basis for command + # arguments. + 'parser', + # Arguments added to this command's parser. This is a 2-tuple of # positional and named arguments, respectively. 'arguments', ) def __init__(self, cls, method, name, category=None, description=None, - allow_all_arguments=False, conditions=None, arguments=None, + allow_all_arguments=False, conditions=None, parser=None, arguments=None, pass_context=False): self.cls = cls @@ -96,6 +100,7 @@ class MethodHandler(object): self.description = description self.allow_all_arguments = allow_all_arguments self.conditions = conditions or [] + self.parser = parser self.arguments = arguments or [] self.pass_context = pass_context diff --git a/python/mach/mach/decorators.py b/python/mach/mach/decorators.py index 8889f28dd77..cb9a67428e7 100644 --- a/python/mach/mach/decorators.py +++ b/python/mach/mach/decorators.py @@ -56,8 +56,8 @@ def CommandProvider(cls): if not isinstance(value, types.FunctionType): continue - command_name, category, description, allow_all, conditions = getattr( - value, '_mach_command', (None, None, None, None, None)) + command_name, category, description, allow_all, conditions, parser = getattr( + value, '_mach_command', (None, None, None, None, None, None)) if command_name is None: continue @@ -83,7 +83,7 @@ def CommandProvider(cls): handler = MethodHandler(cls, attr, command_name, category=category, description=description, allow_all_arguments=allow_all, - conditions=conditions, arguments=arguments, + conditions=conditions, parser=parser, arguments=arguments, pass_context=pass_context) Registrar.register_command_handler(handler) @@ -105,6 +105,9 @@ class Command(object): allow_all_args -- Bool indicating whether to allow unknown arguments through to the command. + parser -- an optional argparse.ArgumentParser instance to use as + the basis for the command arguments. + For example: @Command('foo', category='misc', description='Run the foo action') @@ -112,16 +115,17 @@ class Command(object): pass """ def __init__(self, name, category=None, description=None, - allow_all_args=False, conditions=None): + allow_all_args=False, conditions=None, parser=None): self._name = name self._category = category self._description = description self._allow_all_args = allow_all_args self._conditions = conditions + self._parser = parser def __call__(self, func): func._mach_command = (self._name, self._category, self._description, - self._allow_all_args, self._conditions) + self._allow_all_args, self._conditions, self._parser) return func diff --git a/python/mach/mach/dispatcher.py b/python/mach/mach/dispatcher.py index 5ac3a37d7b4..e15bf75201c 100644 --- a/python/mach/mach/dispatcher.py +++ b/python/mach/mach/dispatcher.py @@ -123,7 +123,10 @@ class CommandAction(argparse.Action): if handler.allow_all_arguments: parser_args['prefix_chars'] = '+' - subparser = argparse.ArgumentParser(**parser_args) + if handler.parser: + subparser = handler.parser + else: + subparser = argparse.ArgumentParser(**parser_args) for arg in handler.arguments: subparser.add_argument(*arg[0], **arg[1]) @@ -216,9 +219,25 @@ class CommandAction(argparse.Action): if handler.allow_all_arguments: parser_args['prefix_chars'] = '+' - c_parser = argparse.ArgumentParser(**parser_args) - - group = c_parser.add_argument_group('Command Arguments') + if handler.parser: + c_parser = handler.parser + c_parser.formatter_class = NoUsageFormatter + try: + # By default argparse adds two groups called "positional arguments" + # and "optional arguments". We want to rename these to reflect standard + # mach terminology. + c_parser._action_groups[0].title = 'Command Parameters' + c_parser._action_groups[1].title = 'Command Arguments' + except: + # If argparse changes the internal data structures here continue; + # this will just make the output more ugly + pass + if not handler.description: + handler.description = c_parser.description + c_parser.description = None + else: + c_parser = argparse.ArgumentParser(**parser_args) + group = c_parser.add_argument_group('Command Arguments') for arg in handler.arguments: group.add_argument(*arg[0], **arg[1]) @@ -234,3 +253,6 @@ class CommandAction(argparse.Action): print('') c_parser.print_help() +class NoUsageFormatter(argparse.HelpFormatter): + def _format_usage(self, *args, **kwargs): + return ""