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 |