зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #4080 - Update mach to latest changes from mozilla-central (from mttr:mach_update); r=jdm
Updates the way mach mixes unrecognized arguments and predefined arguments (see [mozilla bug 1076649](https://bugzilla.mozilla.org/show_bug.cgi?id=1076649) for details on this change), and also adds support for argument groupings (see [1077272](https://bugzilla.mozilla.org/show_bug.cgi?id=1077272)). I was running into some annoyances when trying to implement a change that would allow a `--debug` flag to be used in `./mach run` for running Servo through a debugger (basically, the same behavior described under "How do I run Mozilla under gdb?" [here](https://developer.mozilla.org/en-US/docs/Debugging_Mozilla_with_gdb)). This change should make those annoyances go away, and as far as I can tell, it doesn't have an impact on the way any of the existing commands are used. Source-Repo: https://github.com/servo/servo Source-Revision: 4a257bc27152bef98068cfdc1433549aab05c5de
This commit is contained in:
Родитель
a60d53dbbf
Коммит
361a2f04e2
|
@ -77,9 +77,6 @@ class MethodHandler(object):
|
|||
# Description of the purpose of this command.
|
||||
'description',
|
||||
|
||||
# Whether to allow all arguments from the parser.
|
||||
'allow_all_arguments',
|
||||
|
||||
# Functions used to 'skip' commands if they don't meet the conditions
|
||||
# in a given context.
|
||||
'conditions',
|
||||
|
@ -91,20 +88,23 @@ class MethodHandler(object):
|
|||
# Arguments added to this command's parser. This is a 2-tuple of
|
||||
# positional and named arguments, respectively.
|
||||
'arguments',
|
||||
|
||||
# Argument groups added to this command's parser.
|
||||
'argument_group_names',
|
||||
)
|
||||
|
||||
def __init__(self, cls, method, name, category=None, description=None,
|
||||
allow_all_arguments=False, conditions=None, parser=None, arguments=None,
|
||||
pass_context=False):
|
||||
conditions=None, parser=None, arguments=None,
|
||||
argument_group_names=None, pass_context=False):
|
||||
|
||||
self.cls = cls
|
||||
self.method = method
|
||||
self.name = name
|
||||
self.category = category
|
||||
self.description = description
|
||||
self.allow_all_arguments = allow_all_arguments
|
||||
self.conditions = conditions or []
|
||||
self.parser = parser
|
||||
self.arguments = arguments or []
|
||||
self.argument_group_names = argument_group_names or []
|
||||
self.pass_context = pass_context
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import argparse
|
||||
import collections
|
||||
import inspect
|
||||
import types
|
||||
|
@ -56,8 +57,8 @@ def CommandProvider(cls):
|
|||
if not isinstance(value, types.FunctionType):
|
||||
continue
|
||||
|
||||
command_name, category, description, allow_all, conditions, parser = getattr(
|
||||
value, '_mach_command', (None, None, None, None, None, None))
|
||||
command_name, category, description, conditions, parser = getattr(
|
||||
value, '_mach_command', (None, None, None, None, None))
|
||||
|
||||
if command_name is None:
|
||||
continue
|
||||
|
@ -81,9 +82,11 @@ def CommandProvider(cls):
|
|||
|
||||
arguments = getattr(value, '_mach_command_args', None)
|
||||
|
||||
argument_group_names = getattr(value, '_mach_command_arg_group_names', None)
|
||||
|
||||
handler = MethodHandler(cls, attr, command_name, category=category,
|
||||
description=description, allow_all_arguments=allow_all,
|
||||
conditions=conditions, parser=parser, arguments=arguments,
|
||||
description=description, conditions=conditions, parser=parser,
|
||||
arguments=arguments, argument_group_names=argument_group_names,
|
||||
pass_context=pass_context)
|
||||
|
||||
Registrar.register_command_handler(handler)
|
||||
|
@ -102,9 +105,6 @@ class Command(object):
|
|||
|
||||
description -- A brief description of what the command does.
|
||||
|
||||
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.
|
||||
|
||||
|
@ -114,18 +114,17 @@ class Command(object):
|
|||
def foo(self):
|
||||
pass
|
||||
"""
|
||||
def __init__(self, name, category=None, description=None,
|
||||
allow_all_args=False, conditions=None, parser=None):
|
||||
def __init__(self, name, category=None, description=None, 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._parser)
|
||||
self._conditions, self._parser)
|
||||
|
||||
return func
|
||||
|
||||
|
@ -145,6 +144,11 @@ class CommandArgument(object):
|
|||
pass
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
if kwargs.get('nargs') == argparse.REMAINDER:
|
||||
# These are the assertions we make in dispatcher.py about
|
||||
# those types of CommandArguments.
|
||||
assert len(args) == 1
|
||||
assert all(k in ('default', 'nargs', 'help', 'group') for k in kwargs)
|
||||
self._command_args = (args, kwargs)
|
||||
|
||||
def __call__(self, func):
|
||||
|
@ -157,6 +161,39 @@ class CommandArgument(object):
|
|||
return func
|
||||
|
||||
|
||||
class CommandArgumentGroup(object):
|
||||
"""Decorator for additional argument groups to mach subcommands.
|
||||
|
||||
This decorator should be used to add arguments groups to mach commands.
|
||||
Arguments to the decorator are proxied to
|
||||
ArgumentParser.add_argument_group().
|
||||
|
||||
For example:
|
||||
|
||||
@Command('foo', helps='Run the foo action')
|
||||
@CommandArgumentGroup('group1')
|
||||
@CommandArgument('-b', '--bar', group='group1', action='store_true',
|
||||
default=False, help='Enable bar mode.')
|
||||
def foo(self):
|
||||
pass
|
||||
|
||||
The name should be chosen so that it makes sense as part of the phrase
|
||||
'Command Arguments for <name>' because that's how it will be shown in the
|
||||
help message.
|
||||
"""
|
||||
def __init__(self, group_name):
|
||||
self._group_name = group_name
|
||||
|
||||
def __call__(self, func):
|
||||
command_arg_group_names = getattr(func, '_mach_command_arg_group_names', [])
|
||||
|
||||
command_arg_group_names.insert(0, self._group_name)
|
||||
|
||||
func._mach_command_arg_group_names = command_arg_group_names
|
||||
|
||||
return func
|
||||
|
||||
|
||||
def SettingsProvider(cls):
|
||||
"""Class decorator to denote that this class provides Mach settings.
|
||||
|
||||
|
|
|
@ -135,19 +135,32 @@ class CommandAction(argparse.Action):
|
|||
parser_args = {
|
||||
'add_help': False,
|
||||
'usage': '%(prog)s [global arguments] ' + command +
|
||||
' command arguments]',
|
||||
' [command arguments]',
|
||||
}
|
||||
|
||||
if handler.allow_all_arguments:
|
||||
parser_args['prefix_chars'] = '+'
|
||||
|
||||
if handler.parser:
|
||||
subparser = handler.parser
|
||||
else:
|
||||
subparser = argparse.ArgumentParser(**parser_args)
|
||||
|
||||
remainder = None
|
||||
|
||||
for arg in handler.arguments:
|
||||
subparser.add_argument(*arg[0], **arg[1])
|
||||
# Remove our group keyword; it's not needed here.
|
||||
group_name = arg[1].get('group')
|
||||
if group_name:
|
||||
del arg[1]['group']
|
||||
|
||||
if arg[1].get('nargs') == argparse.REMAINDER:
|
||||
# parse_known_args expects all argparse.REMAINDER ('...')
|
||||
# arguments to be all stuck together. Instead, we want them to
|
||||
# pick any extra argument, wherever they are.
|
||||
# Assume a limited CommandArgument for those arguments.
|
||||
assert len(arg[0]) == 1
|
||||
assert all(k in ('default', 'nargs', 'help') for k in arg[1])
|
||||
remainder = arg
|
||||
else:
|
||||
subparser.add_argument(*arg[0], **arg[1])
|
||||
|
||||
# We define the command information on the main parser result so as to
|
||||
# not interfere with arguments passed to the command.
|
||||
|
@ -156,7 +169,32 @@ class CommandAction(argparse.Action):
|
|||
|
||||
command_namespace, extra = subparser.parse_known_args(args)
|
||||
setattr(namespace, 'command_args', command_namespace)
|
||||
if extra:
|
||||
if remainder:
|
||||
(name,), options = remainder
|
||||
# parse_known_args usefully puts all arguments after '--' in
|
||||
# extra, but also puts '--' there. We don't want to pass it down
|
||||
# to the command handler. Note that if multiple '--' are on the
|
||||
# command line, only the first one is removed, so that subsequent
|
||||
# ones are passed down.
|
||||
if '--' in extra:
|
||||
extra.remove('--')
|
||||
|
||||
# Commands with argparse.REMAINDER arguments used to force the
|
||||
# other arguments to be '+' prefixed. If a user now passes such
|
||||
# an argument, if will silently end up in extra. So, check if any
|
||||
# of the allowed arguments appear in a '+' prefixed form, and error
|
||||
# out if that's the case.
|
||||
for args, _ in handler.arguments:
|
||||
for arg in args:
|
||||
arg = arg.replace('-', '+', 1)
|
||||
if arg in extra:
|
||||
raise UnrecognizedArgumentError(command, [arg])
|
||||
|
||||
if extra:
|
||||
setattr(command_namespace, name, extra)
|
||||
else:
|
||||
setattr(command_namespace, name, options.get('default', []))
|
||||
elif extra:
|
||||
raise UnrecognizedArgumentError(command, extra)
|
||||
|
||||
def _handle_main_help(self, parser, verbose):
|
||||
|
@ -234,9 +272,6 @@ class CommandAction(argparse.Action):
|
|||
'add_help': False,
|
||||
}
|
||||
|
||||
if handler.allow_all_arguments:
|
||||
parser_args['prefix_chars'] = '+'
|
||||
|
||||
if handler.parser:
|
||||
c_parser = handler.parser
|
||||
c_parser.formatter_class = NoUsageFormatter
|
||||
|
@ -258,7 +293,18 @@ class CommandAction(argparse.Action):
|
|||
c_parser = argparse.ArgumentParser(**parser_args)
|
||||
group = c_parser.add_argument_group('Command Arguments')
|
||||
|
||||
extra_groups = {}
|
||||
for group_name in handler.argument_group_names:
|
||||
group_full_name = 'Command Arguments for ' + group_name
|
||||
extra_groups[group_name] = \
|
||||
c_parser.add_argument_group(group_full_name)
|
||||
|
||||
for arg in handler.arguments:
|
||||
# Apply our group keyword.
|
||||
group_name = arg[1].get('group')
|
||||
if group_name:
|
||||
del arg[1]['group']
|
||||
group = extra_groups[group_name]
|
||||
group.add_argument(*arg[0], **arg[1])
|
||||
|
||||
# This will print the description of the command below the usage.
|
||||
|
|
|
@ -16,8 +16,7 @@ from servo.command_base import CommandBase, cd
|
|||
class MachCommands(CommandBase):
|
||||
@Command('cargo',
|
||||
description='Run Cargo',
|
||||
category='devenv',
|
||||
allow_all_args=True)
|
||||
category='devenv')
|
||||
@CommandArgument(
|
||||
'params', default=None, nargs='...',
|
||||
help="Command-line arguments to be passed through to Cargo")
|
||||
|
@ -27,8 +26,7 @@ class MachCommands(CommandBase):
|
|||
|
||||
@Command('update-cargo',
|
||||
description='Update Cargo dependencies',
|
||||
category='devenv',
|
||||
allow_all_args=True)
|
||||
category='devenv')
|
||||
@CommandArgument(
|
||||
'params', default=None, nargs='...',
|
||||
help='Command-line arguments to be passed through to cargo update')
|
||||
|
@ -45,8 +43,7 @@ class MachCommands(CommandBase):
|
|||
|
||||
@Command('rustc',
|
||||
description='Run the Rust compiler',
|
||||
category='devenv',
|
||||
allow_all_args=True)
|
||||
category='devenv')
|
||||
@CommandArgument(
|
||||
'params', default=None, nargs='...',
|
||||
help="Command-line arguments to be passed through to rustc")
|
||||
|
|
|
@ -20,10 +20,9 @@ from servo.command_base import CommandBase
|
|||
class MachCommands(CommandBase):
|
||||
@Command('run',
|
||||
description='Run Servo',
|
||||
category='post-build',
|
||||
allow_all_args=True)
|
||||
category='post-build')
|
||||
@CommandArgument(
|
||||
'params', default=None, nargs='...',
|
||||
'params', nargs='...',
|
||||
help="Command-line arguments to be passed through to Servo")
|
||||
def run(self, params):
|
||||
env = self.build_env()
|
||||
|
@ -33,8 +32,7 @@ class MachCommands(CommandBase):
|
|||
|
||||
@Command('doc',
|
||||
description='Generate documentation',
|
||||
category='post-build',
|
||||
allow_all_args=True)
|
||||
category='post-build')
|
||||
@CommandArgument(
|
||||
'params', default=None, nargs='...',
|
||||
help="Command-line arguments to be passed through to cargo doc")
|
||||
|
@ -45,8 +43,7 @@ class MachCommands(CommandBase):
|
|||
|
||||
@Command('serve-docs',
|
||||
description='Locally serve Servo and Rust documentation',
|
||||
category='post-build',
|
||||
allow_all_args=True)
|
||||
category='post-build')
|
||||
@CommandArgument(
|
||||
'port', default=8888, nargs='?', type=int, metavar='PORT',
|
||||
help="Port to serve documentation at (default is 8888)")
|
||||
|
|
|
@ -55,8 +55,7 @@ class MachCommands(CommandBase):
|
|||
|
||||
@Command('test-unit',
|
||||
description='Run unit tests',
|
||||
category='testing',
|
||||
allow_all_args=True)
|
||||
category='testing')
|
||||
@CommandArgument('test_name', default=None, nargs="...",
|
||||
help="Only run tests that match this pattern")
|
||||
def test_unit(self, test_name=None):
|
||||
|
@ -113,8 +112,7 @@ class MachCommands(CommandBase):
|
|||
|
||||
@Command('test-content',
|
||||
description='Run the content tests',
|
||||
category='testing',
|
||||
allow_all_args=True)
|
||||
category='testing')
|
||||
@CommandArgument('test_name', default=None, nargs="?",
|
||||
help="Only run tests that match this pattern")
|
||||
def test_content(self, test_name=None):
|
||||
|
@ -142,8 +140,7 @@ class MachCommands(CommandBase):
|
|||
|
||||
@Command('test-wpt',
|
||||
description='Run the web platform tests',
|
||||
category='testing',
|
||||
allow_all_args=True)
|
||||
category='testing')
|
||||
@CommandArgument(
|
||||
'params', default=None, nargs='...',
|
||||
help="Command-line arguments to be passed through to wpt/run.sh")
|
||||
|
|
Загрузка…
Ссылка в новой задаче