Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1218)

Side by Side Diff: git_cl.py

Issue 17272002: Make git cl smarter about subcommands typos. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Use 0.3 instead of 0.1 as minimum difference Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 # Copyright (C) 2008 Evan Martin <martine@danga.com> 6 # Copyright (C) 2008 Evan Martin <martine@danga.com>
7 7
8 """A git-command for integrating reviews on Rietveld.""" 8 """A git-command for integrating reviews on Rietveld."""
9 9
10 import difflib
10 import json 11 import json
11 import logging 12 import logging
12 import optparse 13 import optparse
13 import os 14 import os
14 import re 15 import re
15 import stat 16 import stat
16 import sys 17 import sys
17 import textwrap 18 import textwrap
19 import urllib2
18 import urlparse 20 import urlparse
19 import urllib2
20 21
21 try: 22 try:
22 import readline # pylint: disable=F0401,W0611 23 import readline # pylint: disable=F0401,W0611
23 except ImportError: 24 except ImportError:
24 pass 25 pass
25 26
26 27
27 from third_party import colorama 28 from third_party import colorama
28 from third_party import upload 29 from third_party import upload
29 import breakpad # pylint: disable=W0611 30 import breakpad # pylint: disable=W0611
(...skipping 1982 matching lines...) Expand 10 before | Expand all | Expand 10 after
2012 cfd_path = os.path.join('/usr', 'lib', 'clang-format', 2013 cfd_path = os.path.join('/usr', 'lib', 'clang-format',
2013 'clang-format-diff.py') 2014 'clang-format-diff.py')
2014 if not os.path.exists(cfd_path): 2015 if not os.path.exists(cfd_path):
2015 DieWithError('Could not find clang-format-diff at %s.' % cfd_path) 2016 DieWithError('Could not find clang-format-diff at %s.' % cfd_path)
2016 cmd = [sys.executable, cfd_path, '-style', 'Chromium'] 2017 cmd = [sys.executable, cfd_path, '-style', 'Chromium']
2017 RunCommand(cmd, stdin=diff_output) 2018 RunCommand(cmd, stdin=diff_output)
2018 2019
2019 return 0 2020 return 0
2020 2021
2021 2022
2023 ### Glue code for subcommand handling.
2024
2025
2026 def Commands():
2027 """Returns a dict of command and their handling function."""
2028 module = sys.modules[__name__]
2029 cmds = (fn[3:] for fn in dir(module) if fn.startswith('CMD'))
2030 return dict((cmd, getattr(module, 'CMD' + cmd)) for cmd in cmds)
2031
2032
2022 def Command(name): 2033 def Command(name):
2023 return getattr(sys.modules[__name__], 'CMD' + name, None) 2034 """Retrieves the function to handle a command."""
2035 commands = Commands()
2036 if name in commands:
2037 return commands[name]
2038
2039 # Try to be smart and look if there's something similar.
2040 commands_with_prefix = [c for c in commands if c.startswith(name)]
2041 if len(commands_with_prefix) == 1:
2042 return commands[commands_with_prefix[0]]
2043
2044 # A #closeenough approximation of levenshtein distance.
2045 def close_enough(a, b):
2046 return difflib.SequenceMatcher(a=a, b=b).ratio()
2047
2048 hamming_commands = sorted(
2049 ((close_enough(c, name), c) for c in commands),
2050 reverse=True)
2051 if (hamming_commands[0][0] - hamming_commands[1][0]) < 0.3:
2052 # Too ambiguous.
2053 return
2054
2055 if hamming_commands[0][0] < 0.8:
2056 # Not similar enough. Don't be a fool and run a random command.
2057 return
2058
2059 return commands[hamming_commands[0][1]]
2024 2060
2025 2061
2026 def CMDhelp(parser, args): 2062 def CMDhelp(parser, args):
2027 """print list of commands or help for a specific command""" 2063 """print list of commands or help for a specific command"""
2028 _, args = parser.parse_args(args) 2064 _, args = parser.parse_args(args)
2029 if len(args) == 1: 2065 if len(args) == 1:
2030 return main(args + ['--help']) 2066 return main(args + ['--help'])
2031 parser.print_help() 2067 parser.print_help()
2032 return 0 2068 return 0
2033 2069
2034 2070
2035 def GenUsage(parser, command): 2071 def GenUsage(parser, command):
2036 """Modify an OptParse object with the function's documentation.""" 2072 """Modify an OptParse object with the function's documentation."""
2037 obj = Command(command) 2073 obj = Command(command)
2074 # Get back the real command name in case Command() guess the actual command
2075 # name.
2076 command = obj.__name__[3:]
2038 more = getattr(obj, 'usage_more', '') 2077 more = getattr(obj, 'usage_more', '')
2039 if command == 'help': 2078 if command == 'help':
2040 command = '<command>' 2079 command = '<command>'
2041 else: 2080 else:
2042 # OptParser.description prefer nicely non-formatted strings. 2081 # OptParser.description prefer nicely non-formatted strings.
2043 parser.description = re.sub('[\r\n ]{2,}', ' ', obj.__doc__) 2082 parser.description = re.sub('[\r\n ]{2,}', ' ', obj.__doc__)
2044 parser.set_usage('usage: %%prog %s [options] %s' % (command, more)) 2083 parser.set_usage('usage: %%prog %s [options] %s' % (command, more))
2045 2084
2046 2085
2047 def main(argv): 2086 def main(argv):
2048 """Doesn't parse the arguments here, just find the right subcommand to 2087 """Doesn't parse the arguments here, just find the right subcommand to
2049 execute.""" 2088 execute."""
2050 if sys.hexversion < 0x02060000: 2089 if sys.hexversion < 0x02060000:
2051 print >> sys.stderr, ( 2090 print >> sys.stderr, (
2052 '\nYour python version %s is unsupported, please upgrade.\n' % 2091 '\nYour python version %s is unsupported, please upgrade.\n' %
2053 sys.version.split(' ', 1)[0]) 2092 sys.version.split(' ', 1)[0])
2054 return 2 2093 return 2
2055 2094
2056 # Reload settings. 2095 # Reload settings.
2057 global settings 2096 global settings
2058 settings = Settings() 2097 settings = Settings()
2059 2098
2060 # Do it late so all commands are listed. 2099 # Do it late so all commands are listed.
2061 CMDhelp.usage_more = ('\n\nCommands are:\n' + '\n'.join([ 2100 commands = Commands()
2062 ' %-10s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip()) 2101 length = max(len(c) for c in commands)
2063 for fn in dir(sys.modules[__name__]) if fn.startswith('CMD')])) 2102 docs = sorted(
2103 (name, handler.__doc__.split('\n')[0].strip())
2104 for name, handler in commands.iteritems())
2105 CMDhelp.usage_more = ('\n\nCommands are:\n' + '\n'.join(
2106 ' %-*s %s' % (length, name, doc) for name, doc in docs))
2064 2107
2065 # Create the option parse and add --verbose support. 2108 # Create the option parse and add --verbose support.
2066 parser = optparse.OptionParser() 2109 parser = optparse.OptionParser()
2067 parser.add_option( 2110 parser.add_option(
2068 '-v', '--verbose', action='count', default=0, 2111 '-v', '--verbose', action='count', default=0,
2069 help='Use 2 times for more debugging info') 2112 help='Use 2 times for more debugging info')
2070 old_parser_args = parser.parse_args 2113 old_parser_args = parser.parse_args
2071 def Parse(args): 2114 def Parse(args):
2072 options, args = old_parser_args(args) 2115 options, args = old_parser_args(args)
2073 if options.verbose >= 2: 2116 if options.verbose >= 2:
(...skipping 23 matching lines...) Expand all
2097 GenUsage(parser, 'help') 2140 GenUsage(parser, 'help')
2098 return CMDhelp(parser, argv) 2141 return CMDhelp(parser, argv)
2099 2142
2100 2143
2101 if __name__ == '__main__': 2144 if __name__ == '__main__':
2102 # These affect sys.stdout so do it outside of main() to simplify mocks in 2145 # These affect sys.stdout so do it outside of main() to simplify mocks in
2103 # unit testing. 2146 # unit testing.
2104 fix_encoding.fix_encoding() 2147 fix_encoding.fix_encoding()
2105 colorama.init() 2148 colorama.init()
2106 sys.exit(main(sys.argv[1:])) 2149 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698