Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 """Access the commit queue from the command line. | |
| 7 """ | |
| 8 | |
| 9 __version__ = '0.1' | |
| 10 | |
| 11 import functools | |
| 12 import logging | |
| 13 import optparse | |
| 14 import os | |
| 15 import sys | |
| 16 import urllib2 | |
| 17 | |
| 18 import breakpad # pylint: disable=W0611 | |
| 19 | |
| 20 import fix_encoding | |
| 21 import rietveld | |
| 22 | |
| 23 | |
| 24 def usage(more): | |
| 25 def hook(fn): | |
| 26 fn.func_usage_more = more | |
| 27 return fn | |
| 28 return hook | |
| 29 | |
| 30 | |
| 31 def need_issue(fn): | |
| 32 """Post-parse args to create a Rietveld object.""" | |
| 33 @functools.wraps(fn) | |
| 34 def hook(parser, args, *extra_args, **kwargs): | |
| 35 old_parse_args = parser.parse_args | |
| 36 | |
| 37 def new_parse_args(args): | |
| 38 options, args = old_parse_args(args) | |
| 39 if not options.issue: | |
| 40 parser.error('Require --issue') | |
| 41 obj = rietveld.Rietveld(options.server, options.user, None) | |
| 42 return options, args, obj | |
| 43 | |
| 44 parser.parse_args = new_parse_args | |
| 45 | |
| 46 parser.add_option( | |
| 47 '-u', '--user', | |
| 48 metavar='U', | |
| 49 default=os.environ.get('EMAIL_ADDRESS', None), | |
| 50 help='Email address, default: %default') | |
| 51 parser.add_option( | |
| 52 '-i', '--issue', | |
| 53 metavar='I', | |
| 54 type='int', | |
| 55 help='Rietveld issue number') | |
| 56 parser.add_option( | |
| 57 '-s', | |
| 58 '--server', | |
| 59 metavar='S', | |
| 60 default='http://codereview.chromium.org', | |
| 61 help='Rietveld server, default: %default') | |
| 62 | |
| 63 # Call the original function with the modified parser. | |
| 64 return fn(parser, args, *extra_args, **kwargs) | |
| 65 | |
| 66 hook.func_usage_more = '[options]' | |
| 67 return hook | |
| 68 | |
| 69 | |
| 70 def set_commit(obj, issue, flag): | |
| 71 """Sets the commit bit flag on an issue.""" | |
| 72 try: | |
| 73 patchset = obj.get_issue_properties(issue, False)['patchsets'][-1] | |
| 74 print obj.set_flag(issue, patchset, 'commit', flag) | |
| 75 except urllib2.HTTPError, e: | |
| 76 if e.code == 404: | |
| 77 print >> sys.stderr, 'Issue %d doesn\'t exist.' % issue | |
| 78 elif e.code == 403: | |
| 79 print >> sys.stderr, 'Access denied to issue %d.' % issue | |
| 80 else: | |
| 81 raise | |
| 82 return 1 | |
| 83 | |
| 84 @need_issue | |
| 85 def CMDset(parser, args): | |
| 86 """Sets the commit bit.""" | |
| 87 options, args, obj = parser.parse_args(args) | |
| 88 if args: | |
| 89 parser.error('Unrecognized args: %s' % ' '.join(args)) | |
| 90 return set_commit(obj, options.issue, '1') | |
| 91 | |
| 92 | |
| 93 @need_issue | |
| 94 def CMDreset(parser, args): | |
| 95 """Resets the commit bit.""" | |
|
Dirk Pranke
2011/05/30 20:06:37
I might find 'clear' or 'unset' a little easier to
| |
| 96 options, args, obj = parser.parse_args(args) | |
| 97 if args: | |
| 98 parser.error('Unrecognized args: %s' % ' '.join(args)) | |
| 99 return set_commit(obj, options.issue, '0') | |
| 100 | |
| 101 | |
| 102 ############################################################################### | |
| 103 ## Boilerplate code | |
| 104 | |
| 105 | |
| 106 def gen_parser(): | |
| 107 """Returns an OptionParser instance with default options. | |
| 108 | |
| 109 It should be then processed with gen_usage() before being used. | |
| 110 """ | |
| 111 parser = optparse.OptionParser(version=__version__) | |
| 112 # Remove description formatting | |
| 113 parser.format_description = lambda x: parser.description | |
| 114 # Add common parsing. | |
| 115 old_parser_args = parser.parse_args | |
| 116 | |
| 117 def Parse(*args, **kwargs): | |
| 118 options, args = old_parser_args(*args, **kwargs) | |
| 119 logging.basicConfig( | |
| 120 level=[logging.WARNING, logging.INFO, logging.DEBUG][ | |
| 121 min(2, options.verbose)], | |
| 122 format='%(levelname)s %(filename)s(%(lineno)d): %(message)s') | |
| 123 return options, args | |
| 124 | |
| 125 parser.parse_args = Parse | |
| 126 | |
| 127 parser.add_option( | |
| 128 '-v', '--verbose', action='count', default=0, | |
| 129 help='Use multiple times to increase logging level') | |
| 130 return parser | |
| 131 | |
| 132 | |
| 133 def Command(name): | |
| 134 return getattr(sys.modules[__name__], 'CMD' + name, None) | |
| 135 | |
| 136 | |
| 137 @usage('<command>') | |
| 138 def CMDhelp(parser, args): | |
| 139 """Print list of commands or use 'help <command>'.""" | |
| 140 # Strip out the help command description and replace it with the module | |
| 141 # docstring. | |
| 142 parser.description = sys.modules[__name__].__doc__ | |
| 143 parser.description += '\nCommands are:\n' + '\n'.join( | |
| 144 ' %-12s %s' % ( | |
| 145 fn[3:], Command(fn[3:]).__doc__.split('\n', 1)[0].rstrip('.')) | |
| 146 for fn in dir(sys.modules[__name__]) if fn.startswith('CMD')) | |
| 147 | |
| 148 _, args = parser.parse_args(args) | |
| 149 if len(args) == 1 and args[0] != 'help': | |
| 150 return main(args + ['--help']) | |
| 151 parser.print_help() | |
| 152 return 0 | |
| 153 | |
| 154 | |
| 155 def gen_usage(parser, command): | |
| 156 """Modifies an OptionParser object with the command's documentation. | |
| 157 | |
| 158 The documentation is taken from the function's docstring. | |
| 159 """ | |
| 160 obj = Command(command) | |
| 161 more = getattr(obj, 'func_usage_more') | |
| 162 # OptParser.description prefer nicely non-formatted strings. | |
| 163 parser.description = obj.__doc__ + '\n' | |
| 164 parser.set_usage('usage: %%prog %s %s' % (command, more)) | |
| 165 | |
| 166 | |
| 167 def main(args=None): | |
| 168 # Do it late so all commands are listed. | |
| 169 # pylint: disable=E1101 | |
| 170 parser = gen_parser() | |
| 171 if args is None: | |
| 172 args = sys.argv[1:] | |
| 173 if args: | |
| 174 command = Command(args[0]) | |
| 175 if command: | |
| 176 # "fix" the usage and the description now that we know the subcommand. | |
| 177 gen_usage(parser, args[0]) | |
| 178 return command(parser, args[1:]) | |
| 179 | |
| 180 # Not a known command. Default to help. | |
| 181 gen_usage(parser, 'help') | |
| 182 return CMDhelp(parser, args) | |
| 183 | |
| 184 | |
| 185 if __name__ == "__main__": | |
| 186 fix_encoding.fix_encoding() | |
| 187 sys.exit(main()) | |
| OLD | NEW |