mirror of
https://chromium.googlesource.com/chromium/tools/depot_tools.git
synced 2026-01-11 18:51:29 +00:00
Formalizes support for '-' in command names.
This officially drops support for '_' in command names, which is ugly as hell. '_' was very rarely used so it shouldn't affect too much users. Refactor the code to be more readable. R=stip@chromium.org BUG= Review URL: https://codereview.chromium.org/1040503003 git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@294660 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
@@ -37,6 +37,7 @@ Explanation:
|
||||
will result in oldname not being documented but supported and redirecting to
|
||||
newcmd. Make it a real function that calls the old function if you want it
|
||||
to be documented.
|
||||
- CMDfoo_bar will be command 'foo-bar'.
|
||||
"""
|
||||
|
||||
import difflib
|
||||
@@ -82,6 +83,11 @@ def _get_color_module():
|
||||
return sys.modules.get('colorama') or sys.modules.get('third_party.colorama')
|
||||
|
||||
|
||||
def _function_to_name(name):
|
||||
"""Returns the name of a CMD function."""
|
||||
return name[3:].replace('_', '-')
|
||||
|
||||
|
||||
class CommandDispatcher(object):
|
||||
def __init__(self, module):
|
||||
"""module is the name of the main python module where to look for commands.
|
||||
@@ -103,32 +109,31 @@ class CommandDispatcher(object):
|
||||
|
||||
Automatically adds 'help' if not already defined.
|
||||
|
||||
Normalizes '_' in the commands to '-'.
|
||||
|
||||
A command can be effectively disabled by defining a global variable to None,
|
||||
e.g.:
|
||||
CMDhelp = None
|
||||
"""
|
||||
cmds = dict(
|
||||
(fn[3:], getattr(self.module, fn))
|
||||
for fn in dir(self.module) if fn.startswith('CMD'))
|
||||
(_function_to_name(name), getattr(self.module, name))
|
||||
for name in dir(self.module) if name.startswith('CMD'))
|
||||
cmds.setdefault('help', CMDhelp)
|
||||
return cmds
|
||||
|
||||
def find_nearest_command(self, name):
|
||||
"""Retrieves the function to handle a command.
|
||||
def find_nearest_command(self, name_asked):
|
||||
"""Retrieves the function to handle a command as supplied by the user.
|
||||
|
||||
It automatically tries to guess the intended command by handling typos or
|
||||
incomplete names.
|
||||
It automatically tries to guess the _intended command_ by handling typos
|
||||
and/or incomplete names.
|
||||
"""
|
||||
# Implicitly replace foo-bar to foo_bar since foo-bar is not a valid python
|
||||
# symbol but it's faster to type.
|
||||
name = name.replace('-', '_')
|
||||
commands = self.enumerate_commands()
|
||||
if name in commands:
|
||||
return commands[name]
|
||||
if name_asked in commands:
|
||||
return commands[name_asked]
|
||||
|
||||
# An exact match was not found. Try to be smart and look if there's
|
||||
# something similar.
|
||||
commands_with_prefix = [c for c in commands if c.startswith(name)]
|
||||
commands_with_prefix = [c for c in commands if c.startswith(name_asked)]
|
||||
if len(commands_with_prefix) == 1:
|
||||
return commands[commands_with_prefix[0]]
|
||||
|
||||
@@ -137,7 +142,7 @@ class CommandDispatcher(object):
|
||||
return difflib.SequenceMatcher(a=a, b=b).ratio()
|
||||
|
||||
hamming_commands = sorted(
|
||||
((close_enough(c, name), c) for c in commands),
|
||||
((close_enough(c, name_asked), c) for c in commands),
|
||||
reverse=True)
|
||||
if (hamming_commands[0][0] - hamming_commands[1][0]) < 0.3:
|
||||
# Too ambiguous.
|
||||
@@ -153,8 +158,8 @@ class CommandDispatcher(object):
|
||||
"""Generates the short list of supported commands."""
|
||||
commands = self.enumerate_commands()
|
||||
docs = sorted(
|
||||
(name, self._create_command_summary(name, handler))
|
||||
for name, handler in commands.iteritems())
|
||||
(cmd_name, self._create_command_summary(cmd_name, handler))
|
||||
for cmd_name, handler in commands.iteritems())
|
||||
# Skip commands without a docstring.
|
||||
docs = [i for i in docs if i[1]]
|
||||
# Then calculate maximum length for alignment:
|
||||
@@ -169,14 +174,14 @@ class CommandDispatcher(object):
|
||||
return (
|
||||
'Commands are:\n' +
|
||||
''.join(
|
||||
' %s%-*s%s %s\n' % (green, length, name, reset, doc)
|
||||
for name, doc in docs))
|
||||
' %s%-*s%s %s\n' % (green, length, cmd_name, reset, doc)
|
||||
for cmd_name, doc in docs))
|
||||
|
||||
def _add_command_usage(self, parser, command):
|
||||
"""Modifies an OptionParser object with the function's documentation."""
|
||||
name = command.__name__[3:]
|
||||
if name == 'help':
|
||||
name = '<command>'
|
||||
cmd_name = _function_to_name(command.__name__)
|
||||
if cmd_name == 'help':
|
||||
cmd_name = '<command>'
|
||||
# Use the module's docstring as the description for the 'help' command if
|
||||
# available.
|
||||
parser.description = (self.module.__doc__ or '').rstrip()
|
||||
@@ -200,14 +205,15 @@ class CommandDispatcher(object):
|
||||
parser.epilog = '\n' + parser.epilog.strip() + '\n'
|
||||
|
||||
more = getattr(command, 'usage_more', '')
|
||||
parser.set_usage(
|
||||
'usage: %%prog %s [options]%s' % (name, '' if not more else ' ' + more))
|
||||
extra = '' if not more else ' ' + more
|
||||
parser.set_usage('usage: %%prog %s [options]%s' % (cmd_name, extra))
|
||||
|
||||
@staticmethod
|
||||
def _create_command_summary(name, command):
|
||||
"""Creates a oneline summary from the command's docstring."""
|
||||
if name != command.__name__[3:]:
|
||||
# Skip aliases.
|
||||
def _create_command_summary(cmd_name, command):
|
||||
"""Creates a oneliner summary from the command's docstring."""
|
||||
if cmd_name != _function_to_name(command.__name__):
|
||||
# Skip aliases. For example using at module level:
|
||||
# CMDfoo = CMDbar
|
||||
return ''
|
||||
doc = command.__doc__ or ''
|
||||
line = doc.split('\n', 1)[0].rstrip('.')
|
||||
|
||||
Reference in New Issue
Block a user