OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2013 the V8 project authors. All rights reserved. | 2 # Copyright 2013 the V8 project authors. All rights reserved. |
3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
5 # met: | 5 # met: |
6 # | 6 # |
7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
10 # copyright notice, this list of conditions and the following | 10 # copyright notice, this list of conditions and the following |
11 # disclaimer in the documentation and/or other materials provided | 11 # disclaimer in the documentation and/or other materials provided |
12 # with the distribution. | 12 # with the distribution. |
13 # * Neither the name of Google Inc. nor the names of its | 13 # * Neither the name of Google Inc. nor the names of its |
14 # contributors may be used to endorse or promote products derived | 14 # contributors may be used to endorse or promote products derived |
15 # from this software without specific prior written permission. | 15 # from this software without specific prior written permission. |
16 # | 16 # |
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | 28 |
| 29 import argparse |
29 import datetime | 30 import datetime |
30 import json | 31 import json |
31 import os | 32 import os |
32 import re | 33 import re |
33 import subprocess | 34 import subprocess |
34 import sys | 35 import sys |
35 import textwrap | 36 import textwrap |
36 import time | 37 import time |
37 import urllib2 | 38 import urllib2 |
38 | 39 |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 | 220 |
220 | 221 |
221 class NoRetryException(Exception): | 222 class NoRetryException(Exception): |
222 pass | 223 pass |
223 | 224 |
224 | 225 |
225 class GitFailedException(Exception): | 226 class GitFailedException(Exception): |
226 pass | 227 pass |
227 | 228 |
228 | 229 |
229 class CommonOptions(object): | |
230 def __init__(self, options, manual=True): | |
231 self.requires_editor = True | |
232 self.wait_for_lgtm = True | |
233 self.step = options.step | |
234 self.force_readline_defaults = not manual | |
235 self.force_upload = not manual | |
236 self.manual = manual | |
237 self.reviewer = getattr(options, 'reviewer', "") | |
238 self.author = getattr(options, 'author', "") | |
239 | |
240 | |
241 class Step(GitRecipesMixin): | 230 class Step(GitRecipesMixin): |
242 def __init__(self, text, requires, number, config, state, options, handler): | 231 def __init__(self, text, requires, number, config, state, options, handler): |
243 self._text = text | 232 self._text = text |
244 self._requires = requires | 233 self._requires = requires |
245 self._number = number | 234 self._number = number |
246 self._config = config | 235 self._config = config |
247 self._state = state | 236 self._state = state |
248 self._options = options | 237 self._options = options |
249 self._side_effect_handler = handler | 238 self._side_effect_handler = handler |
250 assert self._number >= 0 | 239 assert self._number >= 0 |
251 assert self._config is not None | 240 assert self._config is not None |
252 assert self._state is not None | 241 assert self._state is not None |
253 assert self._side_effect_handler is not None | 242 assert self._side_effect_handler is not None |
254 assert isinstance(options, CommonOptions) | |
255 | 243 |
256 def __getitem__(self, key): | 244 def __getitem__(self, key): |
257 # Convenience method to allow direct [] access on step classes for | 245 # Convenience method to allow direct [] access on step classes for |
258 # manipulating the backed state dict. | 246 # manipulating the backed state dict. |
259 return self._state[key] | 247 return self._state[key] |
260 | 248 |
261 def __setitem__(self, key, value): | 249 def __setitem__(self, key, value): |
262 # Convenience method to allow direct [] access on step classes for | 250 # Convenience method to allow direct [] access on step classes for |
263 # manipulating the backed state dict. | 251 # manipulating the backed state dict. |
264 self._state[key] = value | 252 self._state[key] = value |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 try: | 483 try: |
496 requires = step_class.REQUIRES | 484 requires = step_class.REQUIRES |
497 except AttributeError: | 485 except AttributeError: |
498 requires = None | 486 requires = None |
499 | 487 |
500 return step_class(message, requires, number=number, config=config, | 488 return step_class(message, requires, number=number, config=config, |
501 state=state, options=options, | 489 state=state, options=options, |
502 handler=side_effect_handler) | 490 handler=side_effect_handler) |
503 | 491 |
504 | 492 |
505 def RunScript(step_classes, | 493 class ScriptsBase(object): |
506 config, | 494 # TODO(machenbach): Move static config here. |
507 options, | 495 def __init__(self, config, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER, |
508 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): | 496 state=None): |
509 state_file = "%s-state.json" % config[PERSISTFILE_BASENAME] | 497 self._config = config |
510 if options.step == 0 and os.path.exists(state_file): | 498 self._side_effect_handler = side_effect_handler |
511 os.remove(state_file) | 499 self._state = state if state is not None else {} |
512 state = {} | |
513 steps = [] | |
514 for (number, step_class) in enumerate(step_classes): | |
515 steps.append(MakeStep(step_class, number, state, config, | |
516 options, side_effect_handler)) | |
517 | 500 |
518 for step in steps[options.step:]: | 501 def _Description(self): |
519 step.Run() | 502 return None |
| 503 |
| 504 def _PrepareOptions(self, parser): |
| 505 pass |
| 506 |
| 507 def _ProcessOptions(self, options): |
| 508 return True |
| 509 |
| 510 def _Steps(self): |
| 511 raise Exception("Not implemented.") |
| 512 |
| 513 def MakeOptions(self, args=None): |
| 514 parser = argparse.ArgumentParser(description=self._Description()) |
| 515 parser.add_argument("-a", "--author", default="", |
| 516 help="The author email used for rietveld.") |
| 517 parser.add_argument("-r", "--reviewer", default="", |
| 518 help="The account name to be used for reviews.") |
| 519 parser.add_argument("-s", "--step", |
| 520 help="Specify the step where to start work. Default: 0.", |
| 521 default=0, type=int) |
| 522 |
| 523 self._PrepareOptions(parser) |
| 524 |
| 525 if args is None: |
| 526 options = parser.parse_args() |
| 527 else: |
| 528 options = parser.parse_args(args) |
| 529 |
| 530 # Process common options. |
| 531 if options.step < 0: |
| 532 print "Bad step number %d" % options.step |
| 533 parser.print_help() |
| 534 return None |
| 535 |
| 536 # Defaults for options, common to all scripts. |
| 537 options.manual = getattr(options, "manual", True) |
| 538 options.force = getattr(options, "force", False) |
| 539 |
| 540 # Derived options. |
| 541 options.requires_editor = not options.force |
| 542 options.wait_for_lgtm = not options.force |
| 543 options.force_readline_defaults = not options.manual |
| 544 options.force_upload = not options.manual |
| 545 |
| 546 # Process script specific options. |
| 547 if not self._ProcessOptions(options): |
| 548 parser.print_help() |
| 549 return None |
| 550 return options |
| 551 |
| 552 def RunSteps(self, step_classes, args=None): |
| 553 options = self.MakeOptions(args) |
| 554 if not options: |
| 555 return 1 |
| 556 |
| 557 state_file = "%s-state.json" % self._config[PERSISTFILE_BASENAME] |
| 558 if options.step == 0 and os.path.exists(state_file): |
| 559 os.remove(state_file) |
| 560 |
| 561 steps = [] |
| 562 for (number, step_class) in enumerate(step_classes): |
| 563 steps.append(MakeStep(step_class, number, self._state, self._config, |
| 564 options, self._side_effect_handler)) |
| 565 for step in steps[options.step:]: |
| 566 step.Run() |
| 567 return 0 |
| 568 |
| 569 def Run(self, args=None): |
| 570 return self.RunSteps(self._Steps(), args) |
OLD | NEW |