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 |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 def GetDate(self): | 213 def GetDate(self): |
214 return datetime.date.today().strftime("%Y-%m-%d") | 214 return datetime.date.today().strftime("%Y-%m-%d") |
215 | 215 |
216 DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler() | 216 DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler() |
217 | 217 |
218 | 218 |
219 class NoRetryException(Exception): | 219 class NoRetryException(Exception): |
220 pass | 220 pass |
221 | 221 |
222 | 222 |
| 223 class GitFailedException(Exception): |
| 224 pass |
| 225 |
| 226 |
223 class CommonOptions(object): | 227 class CommonOptions(object): |
224 def __init__(self, options, manual=True): | 228 def __init__(self, options, manual=True): |
225 self.requires_editor = True | 229 self.requires_editor = True |
226 self.wait_for_lgtm = True | 230 self.wait_for_lgtm = True |
227 self.s = options.s | 231 self.s = options.s |
228 self.force_readline_defaults = not manual | 232 self.force_readline_defaults = not manual |
229 self.force_upload = not manual | 233 self.force_upload = not manual |
230 self.manual = manual | 234 self.manual = manual |
231 self.reviewer = getattr(options, 'reviewer', None) | 235 self.reviewer = getattr(options, 'reviewer', None) |
232 self.author = getattr(options, 'a', None) | 236 self.author = getattr(options, 'a', None) |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 def ReadLine(self, default=None): | 317 def ReadLine(self, default=None): |
314 # Don't prompt in forced mode. | 318 # Don't prompt in forced mode. |
315 if self._options.force_readline_defaults and default is not None: | 319 if self._options.force_readline_defaults and default is not None: |
316 print "%s (forced)" % default | 320 print "%s (forced)" % default |
317 return default | 321 return default |
318 else: | 322 else: |
319 return self._side_effect_handler.ReadLine() | 323 return self._side_effect_handler.ReadLine() |
320 | 324 |
321 def Git(self, args="", prefix="", pipe=True, retry_on=None): | 325 def Git(self, args="", prefix="", pipe=True, retry_on=None): |
322 cmd = lambda: self._side_effect_handler.Command("git", args, prefix, pipe) | 326 cmd = lambda: self._side_effect_handler.Command("git", args, prefix, pipe) |
323 return self.Retry(cmd, retry_on, [5, 30]) | 327 result = self.Retry(cmd, retry_on, [5, 30]) |
| 328 if result is None: |
| 329 raise GitFailedException("'git %s' failed." % args) |
| 330 return result |
324 | 331 |
325 def SVN(self, args="", prefix="", pipe=True, retry_on=None): | 332 def SVN(self, args="", prefix="", pipe=True, retry_on=None): |
326 cmd = lambda: self._side_effect_handler.Command("svn", args, prefix, pipe) | 333 cmd = lambda: self._side_effect_handler.Command("svn", args, prefix, pipe) |
327 return self.Retry(cmd, retry_on, [5, 30]) | 334 return self.Retry(cmd, retry_on, [5, 30]) |
328 | 335 |
329 def Editor(self, args): | 336 def Editor(self, args): |
330 if self._options.requires_editor: | 337 if self._options.requires_editor: |
331 return self._side_effect_handler.Command(os.environ["EDITOR"], args, | 338 return self._side_effect_handler.Command(os.environ["EDITOR"], args, |
332 pipe=False) | 339 pipe=False) |
333 | 340 |
(...skipping 20 matching lines...) Expand all Loading... |
354 print "%s [Y/n] " % msg, | 361 print "%s [Y/n] " % msg, |
355 answer = self.ReadLine(default="Y") | 362 answer = self.ReadLine(default="Y") |
356 return answer == "" or answer == "Y" or answer == "y" | 363 return answer == "" or answer == "Y" or answer == "y" |
357 | 364 |
358 def DeleteBranch(self, name): | 365 def DeleteBranch(self, name): |
359 git_result = self.Git("branch").strip() | 366 git_result = self.Git("branch").strip() |
360 for line in git_result.splitlines(): | 367 for line in git_result.splitlines(): |
361 if re.match(r".*\s+%s$" % name, line): | 368 if re.match(r".*\s+%s$" % name, line): |
362 msg = "Branch %s exists, do you want to delete it?" % name | 369 msg = "Branch %s exists, do you want to delete it?" % name |
363 if self.Confirm(msg): | 370 if self.Confirm(msg): |
364 if self.Git("branch -D %s" % name) is None: | 371 self.Git("branch -D %s" % name) |
365 self.Die("Deleting branch '%s' failed." % name) | |
366 print "Branch %s deleted." % name | 372 print "Branch %s deleted." % name |
367 else: | 373 else: |
368 msg = "Can't continue. Please delete branch %s and try again." % name | 374 msg = "Can't continue. Please delete branch %s and try again." % name |
369 self.Die(msg) | 375 self.Die(msg) |
370 | 376 |
371 def InitialEnvironmentChecks(self): | 377 def InitialEnvironmentChecks(self): |
372 # Cancel if this is not a git checkout. | 378 # Cancel if this is not a git checkout. |
373 if not os.path.exists(self._config[DOT_GIT_LOCATION]): | 379 if not os.path.exists(self._config[DOT_GIT_LOCATION]): |
374 self.Die("This is not a git checkout, this script won't work for you.") | 380 self.Die("This is not a git checkout, this script won't work for you.") |
375 | 381 |
(...skipping 10 matching lines...) Expand all Loading... |
386 # Persist current branch. | 392 # Persist current branch. |
387 self["current_branch"] = "" | 393 self["current_branch"] = "" |
388 git_result = self.Git("status -s -b -uno").strip() | 394 git_result = self.Git("status -s -b -uno").strip() |
389 for line in git_result.splitlines(): | 395 for line in git_result.splitlines(): |
390 match = re.match(r"^## (.+)", line) | 396 match = re.match(r"^## (.+)", line) |
391 if match: | 397 if match: |
392 self["current_branch"] = match.group(1) | 398 self["current_branch"] = match.group(1) |
393 break | 399 break |
394 | 400 |
395 # Fetch unfetched revisions. | 401 # Fetch unfetched revisions. |
396 if self.Git("svn fetch") is None: | 402 self.Git("svn fetch") |
397 self.Die("'git svn fetch' failed.") | |
398 | 403 |
399 def PrepareBranch(self): | 404 def PrepareBranch(self): |
400 # Get ahold of a safe temporary branch and check it out. | 405 # Get ahold of a safe temporary branch and check it out. |
401 if self["current_branch"] != self._config[TEMP_BRANCH]: | 406 if self["current_branch"] != self._config[TEMP_BRANCH]: |
402 self.DeleteBranch(self._config[TEMP_BRANCH]) | 407 self.DeleteBranch(self._config[TEMP_BRANCH]) |
403 self.Git("checkout -b %s" % self._config[TEMP_BRANCH]) | 408 self.Git("checkout -b %s" % self._config[TEMP_BRANCH]) |
404 | 409 |
405 # Delete the branch that will be created later if it exists already. | 410 # Delete the branch that will be created later if it exists already. |
406 self.DeleteBranch(self._config[BRANCHNAME]) | 411 self.DeleteBranch(self._config[BRANCHNAME]) |
407 | 412 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 if answer == "ABORT": | 455 if answer == "ABORT": |
451 self.Die("Applying the patch failed.") | 456 self.Die("Applying the patch failed.") |
452 if answer != "": | 457 if answer != "": |
453 print "That was not 'RESOLVED' or 'ABORT'." | 458 print "That was not 'RESOLVED' or 'ABORT'." |
454 print "> ", | 459 print "> ", |
455 answer = self.ReadLine() | 460 answer = self.ReadLine() |
456 | 461 |
457 # Takes a file containing the patch to apply as first argument. | 462 # Takes a file containing the patch to apply as first argument. |
458 def ApplyPatch(self, patch_file, reverse_patch=""): | 463 def ApplyPatch(self, patch_file, reverse_patch=""): |
459 args = "apply --index --reject %s \"%s\"" % (reverse_patch, patch_file) | 464 args = "apply --index --reject %s \"%s\"" % (reverse_patch, patch_file) |
460 if self.Git(args) is None: | 465 try: |
| 466 self.Git(args) |
| 467 except GitFailedException: |
461 self.WaitForResolvingConflicts(patch_file) | 468 self.WaitForResolvingConflicts(patch_file) |
462 | 469 |
463 def FindLastTrunkPush(self): | 470 def FindLastTrunkPush(self): |
464 push_pattern = "^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based" | 471 push_pattern = "^Version [[:digit:]]*\.[[:digit:]]*\.[[:digit:]]* (based" |
465 args = "log -1 --format=%%H --grep=\"%s\" svn/trunk" % push_pattern | 472 args = "log -1 --format=%%H --grep=\"%s\" svn/trunk" % push_pattern |
466 return self.Git(args).strip() | 473 return self.Git(args).strip() |
467 | 474 |
468 | 475 |
469 class UploadStep(Step): | 476 class UploadStep(Step): |
470 MESSAGE = "Upload for code review." | 477 MESSAGE = "Upload for code review." |
471 | 478 |
472 def RunStep(self): | 479 def RunStep(self): |
473 if self._options.reviewer: | 480 if self._options.reviewer: |
474 print "Using account %s for review." % self._options.reviewer | 481 print "Using account %s for review." % self._options.reviewer |
475 reviewer = self._options.reviewer | 482 reviewer = self._options.reviewer |
476 else: | 483 else: |
477 print "Please enter the email address of a V8 reviewer for your patch: ", | 484 print "Please enter the email address of a V8 reviewer for your patch: ", |
478 self.DieNoManualMode("A reviewer must be specified in forced mode.") | 485 self.DieNoManualMode("A reviewer must be specified in forced mode.") |
479 reviewer = self.ReadLine() | 486 reviewer = self.ReadLine() |
480 author_option = self._options.author | 487 author_option = self._options.author |
481 author = " --email \"%s\"" % author_option if author_option else "" | 488 author = " --email \"%s\"" % author_option if author_option else "" |
482 force_flag = " -f" if self._options.force_upload else "" | 489 force_flag = " -f" if self._options.force_upload else "" |
483 args = ("cl upload%s -r \"%s\" --send-mail%s" | 490 args = ("cl upload%s -r \"%s\" --send-mail%s" |
484 % (author, reviewer, force_flag)) | 491 % (author, reviewer, force_flag)) |
485 # TODO(machenbach): Check output in forced mode. Verify that all required | 492 # TODO(machenbach): Check output in forced mode. Verify that all required |
486 # base files were uploaded, if not retry. | 493 # base files were uploaded, if not retry. |
487 if self.Git(args, pipe=False) is None: | 494 self.Git(args, pipe=False) |
488 self.Die("'git cl upload' failed, please try again.") | |
489 | 495 |
490 | 496 |
491 def MakeStep(step_class=Step, number=0, state=None, config=None, | 497 def MakeStep(step_class=Step, number=0, state=None, config=None, |
492 options=None, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): | 498 options=None, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): |
493 # Allow to pass in empty dictionaries. | 499 # Allow to pass in empty dictionaries. |
494 state = state if state is not None else {} | 500 state = state if state is not None else {} |
495 config = config if config is not None else {} | 501 config = config if config is not None else {} |
496 | 502 |
497 try: | 503 try: |
498 message = step_class.MESSAGE | 504 message = step_class.MESSAGE |
(...skipping 17 matching lines...) Expand all Loading... |
516 if options.s == 0 and os.path.exists(state_file): | 522 if options.s == 0 and os.path.exists(state_file): |
517 os.remove(state_file) | 523 os.remove(state_file) |
518 state = {} | 524 state = {} |
519 steps = [] | 525 steps = [] |
520 for (number, step_class) in enumerate(step_classes): | 526 for (number, step_class) in enumerate(step_classes): |
521 steps.append(MakeStep(step_class, number, state, config, | 527 steps.append(MakeStep(step_class, number, state, config, |
522 options, side_effect_handler)) | 528 options, side_effect_handler)) |
523 | 529 |
524 for step in steps[options.s:]: | 530 for step in steps[options.s:]: |
525 step.Run() | 531 step.Run() |
OLD | NEW |