OLD | NEW |
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 Loading... |
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 Loading... |
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:])) |
OLD | NEW |