Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(480)

Side by Side Diff: tools/push-to-trunk/common_includes.py

Issue 716153002: Switch release scripts to pure git. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Review. Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 265
266 def Fetch(self): 266 def Fetch(self):
267 raise NotImplementedError() 267 raise NotImplementedError()
268 268
269 def GetTags(self): 269 def GetTags(self):
270 raise NotImplementedError() 270 raise NotImplementedError()
271 271
272 def GetBranches(self): 272 def GetBranches(self):
273 raise NotImplementedError() 273 raise NotImplementedError()
274 274
275 def GitSvn(self, hsh, branch=""):
276 raise NotImplementedError()
277
278 def SvnGit(self, rev, branch=""):
279 raise NotImplementedError()
280
281 def MasterBranch(self): 275 def MasterBranch(self):
282 raise NotImplementedError() 276 raise NotImplementedError()
283 277
284 def CandidateBranch(self): 278 def CandidateBranch(self):
285 raise NotImplementedError() 279 raise NotImplementedError()
286 280
287 def RemoteMasterBranch(self): 281 def RemoteMasterBranch(self):
288 raise NotImplementedError() 282 raise NotImplementedError()
289 283
290 def RemoteCandidateBranch(self): 284 def RemoteCandidateBranch(self):
291 raise NotImplementedError() 285 raise NotImplementedError()
292 286
293 def RemoteBranch(self, name): 287 def RemoteBranch(self, name):
294 raise NotImplementedError() 288 raise NotImplementedError()
295 289
296 def Land(self): 290 def Land(self):
297 raise NotImplementedError() 291 raise NotImplementedError()
298 292
299 def CLLand(self): 293 def CLLand(self):
300 raise NotImplementedError() 294 raise NotImplementedError()
301 295
302 # TODO(machenbach): There is some svn knowledge in this interface. In svn,
303 # tag and commit are different remote commands, while in git we would commit
304 # and tag locally and then push/land in one unique step.
305 def Tag(self, tag, remote, message): 296 def Tag(self, tag, remote, message):
306 """Sets a tag for the current commit. 297 """Sets a tag for the current commit.
307 298
308 Assumptions: The commit already landed and the commit message is unique. 299 Assumptions: The commit already landed and the commit message is unique.
309 """ 300 """
310 raise NotImplementedError() 301 raise NotImplementedError()
311 302
312 303
313 class GitSvnInterface(VCInterface): 304 class GitInterface(VCInterface):
314 def Pull(self):
315 self.step.GitSVNRebase()
316
317 def Fetch(self):
318 self.step.GitSVNFetch()
319
320 def GetTags(self):
321 # Get remote tags.
322 tags = filter(lambda s: re.match(r"^svn/tags/[\d+\.]+$", s),
323 self.step.GitRemotes())
324
325 # Remove 'svn/tags/' prefix.
326 return map(lambda s: s[9:], tags)
327
328 def GetBranches(self):
329 # Get relevant remote branches, e.g. "svn/3.25".
330 branches = filter(lambda s: re.match(r"^svn/\d+\.\d+$", s),
331 self.step.GitRemotes())
332 # Remove 'svn/' prefix.
333 return map(lambda s: s[4:], branches)
334
335 def GitSvn(self, hsh, branch=""):
336 return self.step.GitSVNFindSVNRev(hsh, branch)
337
338 def SvnGit(self, rev, branch=""):
339 return self.step.GitSVNFindGitHash(rev, branch)
340
341 def MasterBranch(self):
342 return "bleeding_edge"
343
344 def CandidateBranch(self):
345 return "trunk"
346
347 def RemoteMasterBranch(self):
348 return "svn/bleeding_edge"
349
350 def RemoteCandidateBranch(self):
351 return "svn/trunk"
352
353 def RemoteBranch(self, name):
354 return "svn/%s" % name
355
356 def Land(self):
357 self.step.GitSVNDCommit()
358
359 def CLLand(self):
360 self.step.GitDCommit()
361
362 def Tag(self, tag, remote, _):
363 self.step.GitSVNFetch()
364 self.step.Git("rebase %s" % remote)
365 self.step.GitSVNTag(tag)
366
367
368 class GitTagsOnlyMixin(VCInterface):
369 def Pull(self): 305 def Pull(self):
370 self.step.GitPull() 306 self.step.GitPull()
371 307
372 def Fetch(self): 308 def Fetch(self):
373 self.step.Git("fetch") 309 self.step.Git("fetch")
374 self.step.GitSVNFetch()
375 310
376 def GetTags(self): 311 def GetTags(self):
377 return self.step.Git("tag").strip().splitlines() 312 return self.step.Git("tag").strip().splitlines()
378 313
379 def GetBranches(self): 314 def GetBranches(self):
380 # Get relevant remote branches, e.g. "branch-heads/3.25". 315 # Get relevant remote branches, e.g. "branch-heads/3.25".
381 branches = filter( 316 branches = filter(
382 lambda s: re.match(r"^branch\-heads/\d+\.\d+$", s), 317 lambda s: re.match(r"^branch\-heads/\d+\.\d+$", s),
383 self.step.GitRemotes()) 318 self.step.GitRemotes())
384 # Remove 'branch-heads/' prefix. 319 # Remove 'branch-heads/' prefix.
385 return map(lambda s: s[13:], branches) 320 return map(lambda s: s[13:], branches)
386 321
387 def MasterBranch(self): 322 def MasterBranch(self):
388 return "master" 323 return "master"
389 324
390 def CandidateBranch(self): 325 def CandidateBranch(self):
391 return "candidates" 326 return "candidates"
392 327
393 def RemoteMasterBranch(self): 328 def RemoteMasterBranch(self):
394 return "origin/master" 329 return "origin/master"
395 330
396 def RemoteCandidateBranch(self): 331 def RemoteCandidateBranch(self):
397 return "origin/candidates" 332 return "origin/candidates"
398 333
399 def RemoteBranch(self, name): 334 def RemoteBranch(self, name):
400 if name in ["candidates", "master"]: 335 if name in ["candidates", "master"]:
401 return "origin/%s" % name 336 return "origin/%s" % name
402 return "branch-heads/%s" % name 337 return "branch-heads/%s" % name
403 338
404 def PushRef(self, ref):
405 self.step.Git("push origin %s" % ref)
406
407 def Tag(self, tag, remote, message): 339 def Tag(self, tag, remote, message):
408 # Wait for the commit to appear. Assumes unique commit message titles (this 340 # Wait for the commit to appear. Assumes unique commit message titles (this
409 # is the case for all automated merge and push commits - also no title is 341 # is the case for all automated merge and push commits - also no title is
410 # the prefix of another title). 342 # the prefix of another title).
411 commit = None 343 commit = None
412 for wait_interval in [3, 7, 15, 35, 45, 60]: 344 for wait_interval in [3, 7, 15, 35, 45, 60]:
413 self.step.Git("fetch") 345 self.step.Git("fetch")
414 commit = self.step.GitLog(n=1, format="%H", grep=message, branch=remote) 346 commit = self.step.GitLog(n=1, format="%H", grep=message, branch=remote)
415 if commit: 347 if commit:
416 break 348 break
417 print("The commit has not replicated to git. Waiting for %s seconds." % 349 print("The commit has not replicated to git. Waiting for %s seconds." %
418 wait_interval) 350 wait_interval)
419 self.step._side_effect_handler.Sleep(wait_interval) 351 self.step._side_effect_handler.Sleep(wait_interval)
420 else: 352 else:
421 self.step.Die("Couldn't determine commit for setting the tag. Maybe the " 353 self.step.Die("Couldn't determine commit for setting the tag. Maybe the "
422 "git updater is lagging behind?") 354 "git updater is lagging behind?")
423 355
424 self.step.Git("tag %s %s" % (tag, commit)) 356 self.step.Git("tag %s %s" % (tag, commit))
425 self.PushRef(tag) 357 self.step.Git("push origin %s" % tag)
426
427
428 class GitReadSvnWriteInterface(GitTagsOnlyMixin, GitSvnInterface):
429 pass
430
431
432 class GitInterface(GitTagsOnlyMixin):
433 def Fetch(self):
434 self.step.Git("fetch")
435
436 def GitSvn(self, hsh, branch=""):
437 return ""
438
439 def SvnGit(self, rev, branch=""):
440 raise NotImplementedError()
441 358
442 def Land(self): 359 def Land(self):
443 # FIXME(machenbach): This will not work with checkouts from bot_update
444 # after flag day because it will push to the cache. Investigate if it
445 # will work with "cl land".
446 self.step.Git("push origin") 360 self.step.Git("push origin")
447 361
448 def CLLand(self): 362 def CLLand(self):
449 self.step.GitCLLand() 363 self.step.GitCLLand()
450 364
451 def PushRef(self, ref):
452 self.step.Git("push https://chromium.googlesource.com/v8/v8 %s" % ref)
453
454
455 VC_INTERFACES = {
456 "git_svn": GitSvnInterface,
457 "git_read_svn_write": GitReadSvnWriteInterface,
458 "git": GitInterface,
459 }
460
461 365
462 class Step(GitRecipesMixin): 366 class Step(GitRecipesMixin):
463 def __init__(self, text, number, config, state, options, handler): 367 def __init__(self, text, number, config, state, options, handler):
464 self._text = text 368 self._text = text
465 self._number = number 369 self._number = number
466 self._config = config 370 self._config = config
467 self._state = state 371 self._state = state
468 self._options = options 372 self._options = options
469 self._side_effect_handler = handler 373 self._side_effect_handler = handler
470 self.vc = VC_INTERFACES[options.vc_interface]() 374 self.vc = GitInterface()
471 self.vc.InjectStep(self) 375 self.vc.InjectStep(self)
472 376
473 # The testing configuration might set a different default cwd. 377 # The testing configuration might set a different default cwd.
474 self.default_cwd = (self._config.get("DEFAULT_CWD") or 378 self.default_cwd = (self._config.get("DEFAULT_CWD") or
475 os.path.join(self._options.work_dir, "v8")) 379 os.path.join(self._options.work_dir, "v8"))
476 380
477 assert self._number >= 0 381 assert self._number >= 0
478 assert self._config is not None 382 assert self._config is not None
479 assert self._state is not None 383 assert self._state is not None
480 assert self._side_effect_handler is not None 384 assert self._side_effect_handler is not None
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 return self.Retry(cmd, None, [5]) 458 return self.Retry(cmd, None, [5])
555 459
556 def Git(self, args="", prefix="", pipe=True, retry_on=None, cwd=None): 460 def Git(self, args="", prefix="", pipe=True, retry_on=None, cwd=None):
557 cmd = lambda: self._side_effect_handler.Command( 461 cmd = lambda: self._side_effect_handler.Command(
558 "git", args, prefix, pipe, cwd=cwd or self.default_cwd) 462 "git", args, prefix, pipe, cwd=cwd or self.default_cwd)
559 result = self.Retry(cmd, retry_on, [5, 30]) 463 result = self.Retry(cmd, retry_on, [5, 30])
560 if result is None: 464 if result is None:
561 raise GitFailedException("'git %s' failed." % args) 465 raise GitFailedException("'git %s' failed." % args)
562 return result 466 return result
563 467
564 def SVN(self, args="", prefix="", pipe=True, retry_on=None, cwd=None):
565 cmd = lambda: self._side_effect_handler.Command(
566 "svn", args, prefix, pipe, cwd=cwd or self.default_cwd)
567 return self.Retry(cmd, retry_on, [5, 30])
568
569 def Editor(self, args): 468 def Editor(self, args):
570 if self._options.requires_editor: 469 if self._options.requires_editor:
571 return self._side_effect_handler.Command( 470 return self._side_effect_handler.Command(
572 os.environ["EDITOR"], 471 os.environ["EDITOR"],
573 args, 472 args,
574 pipe=False, 473 pipe=False,
575 cwd=self.default_cwd) 474 cwd=self.default_cwd)
576 475
577 def ReadURL(self, url, params=None, retry_on=None, wait_plan=None): 476 def ReadURL(self, url, params=None, retry_on=None, wait_plan=None):
578 wait_plan = wait_plan or [3, 60, 600] 477 wait_plan = wait_plan or [3, 60, 600]
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
720 line = re.sub("\d+$", self[prefix + "major"], line) 619 line = re.sub("\d+$", self[prefix + "major"], line)
721 elif line.startswith("#define MINOR_VERSION"): 620 elif line.startswith("#define MINOR_VERSION"):
722 line = re.sub("\d+$", self[prefix + "minor"], line) 621 line = re.sub("\d+$", self[prefix + "minor"], line)
723 elif line.startswith("#define BUILD_NUMBER"): 622 elif line.startswith("#define BUILD_NUMBER"):
724 line = re.sub("\d+$", self[prefix + "build"], line) 623 line = re.sub("\d+$", self[prefix + "build"], line)
725 elif line.startswith("#define PATCH_LEVEL"): 624 elif line.startswith("#define PATCH_LEVEL"):
726 line = re.sub("\d+$", self[prefix + "patch"], line) 625 line = re.sub("\d+$", self[prefix + "patch"], line)
727 output += "%s\n" % line 626 output += "%s\n" % line
728 TextToFile(output, version_file) 627 TextToFile(output, version_file)
729 628
730 def SVNCommit(self, root, commit_message):
731 patch = self.GitDiff("HEAD^", "HEAD")
732 TextToFile(patch, self._config["PATCH_FILE"])
733 self.Command("svn", "update", cwd=self._options.svn)
734 if self.Command("svn", "status", cwd=self._options.svn) != "":
735 self.Die("SVN checkout not clean.")
736 if not self.Command("patch", "-d %s -p1 -i %s" %
737 (root, self._config["PATCH_FILE"]),
738 cwd=self._options.svn):
739 self.Die("Could not apply patch.")
740 for line in self.Command(
741 "svn", "status", cwd=self._options.svn).splitlines():
742 # Check for added and removed items. Svn status has seven status columns.
743 # The first contains ? for unknown and ! for missing.
744 match = re.match(r"^(.)...... (.*)$", line)
745 if match and match.group(1) == "?":
746 self.Command("svn", "add --force %s" % match.group(2),
747 cwd=self._options.svn)
748 if match and match.group(1) == "!":
749 self.Command("svn", "delete --force %s" % match.group(2),
750 cwd=self._options.svn)
751
752 self.Command(
753 "svn",
754 "commit --non-interactive --username=%s --config-dir=%s -m \"%s\"" %
755 (self._options.author, self._options.svn_config, commit_message),
756 cwd=self._options.svn)
757
758 629
759 class BootstrapStep(Step): 630 class BootstrapStep(Step):
760 MESSAGE = "Bootstapping v8 checkout." 631 MESSAGE = "Bootstapping v8 checkout."
761 632
762 def RunStep(self): 633 def RunStep(self):
763 if os.path.realpath(self.default_cwd) == os.path.realpath(V8_BASE): 634 if os.path.realpath(self.default_cwd) == os.path.realpath(V8_BASE):
764 self.Die("Can't use v8 checkout with calling script as work checkout.") 635 self.Die("Can't use v8 checkout with calling script as work checkout.")
765 # Directory containing the working v8 checkout. 636 # Directory containing the working v8 checkout.
766 if not os.path.exists(self._options.work_dir): 637 if not os.path.exists(self._options.work_dir):
767 os.makedirs(self._options.work_dir) 638 os.makedirs(self._options.work_dir)
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
866 parser.add_argument("--dry-run", default=False, action="store_true", 737 parser.add_argument("--dry-run", default=False, action="store_true",
867 help="Perform only read-only actions.") 738 help="Perform only read-only actions.")
868 parser.add_argument("-g", "--googlers-mapping", 739 parser.add_argument("-g", "--googlers-mapping",
869 help="Path to the script mapping google accounts.") 740 help="Path to the script mapping google accounts.")
870 parser.add_argument("-r", "--reviewer", default="", 741 parser.add_argument("-r", "--reviewer", default="",
871 help="The account name to be used for reviews.") 742 help="The account name to be used for reviews.")
872 parser.add_argument("--sheriff", default=False, action="store_true", 743 parser.add_argument("--sheriff", default=False, action="store_true",
873 help=("Determine current sheriff to review CLs. On " 744 help=("Determine current sheriff to review CLs. On "
874 "success, this will overwrite the reviewer " 745 "success, this will overwrite the reviewer "
875 "option.")) 746 "option."))
876 parser.add_argument("--svn",
877 help=("Optional full svn checkout for the commit."
878 "The folder needs to be the svn root."))
879 parser.add_argument("--svn-config",
880 help=("Optional folder used as svn --config-dir."))
881 parser.add_argument("-s", "--step", 747 parser.add_argument("-s", "--step",
882 help="Specify the step where to start work. Default: 0.", 748 help="Specify the step where to start work. Default: 0.",
883 default=0, type=int) 749 default=0, type=int)
884 parser.add_argument("--vc-interface",
885 help=("Choose VC interface out of git_svn|"
886 "git_read_svn_write."))
887 parser.add_argument("--work-dir", 750 parser.add_argument("--work-dir",
888 help=("Location where to bootstrap a working v8 " 751 help=("Location where to bootstrap a working v8 "
889 "checkout.")) 752 "checkout."))
890 self._PrepareOptions(parser) 753 self._PrepareOptions(parser)
891 754
892 if args is None: # pragma: no cover 755 if args is None: # pragma: no cover
893 options = parser.parse_args() 756 options = parser.parse_args()
894 else: 757 else:
895 options = parser.parse_args(args) 758 options = parser.parse_args(args)
896 759
897 # Process common options. 760 # Process common options.
898 if options.step < 0: # pragma: no cover 761 if options.step < 0: # pragma: no cover
899 print "Bad step number %d" % options.step 762 print "Bad step number %d" % options.step
900 parser.print_help() 763 parser.print_help()
901 return None 764 return None
902 if options.sheriff and not options.googlers_mapping: # pragma: no cover 765 if options.sheriff and not options.googlers_mapping: # pragma: no cover
903 print "To determine the current sheriff, requires the googler mapping" 766 print "To determine the current sheriff, requires the googler mapping"
904 parser.print_help() 767 parser.print_help()
905 return None 768 return None
906 if options.svn and not options.svn_config:
907 print "Using pure svn for committing requires also --svn-config"
908 parser.print_help()
909 return None
910 769
911 # Defaults for options, common to all scripts. 770 # Defaults for options, common to all scripts.
912 options.manual = getattr(options, "manual", True) 771 options.manual = getattr(options, "manual", True)
913 options.force = getattr(options, "force", False) 772 options.force = getattr(options, "force", False)
914 options.bypass_upload_hooks = False 773 options.bypass_upload_hooks = False
915 774
916 # Derived options. 775 # Derived options.
917 options.requires_editor = not options.force 776 options.requires_editor = not options.force
918 options.wait_for_lgtm = not options.force 777 options.wait_for_lgtm = not options.force
919 options.force_readline_defaults = not options.manual 778 options.force_readline_defaults = not options.manual
920 options.force_upload = not options.manual 779 options.force_upload = not options.manual
921 780
922 # Process script specific options. 781 # Process script specific options.
923 if not self._ProcessOptions(options): 782 if not self._ProcessOptions(options):
924 parser.print_help() 783 parser.print_help()
925 return None 784 return None
926 785
927 if not options.vc_interface:
928 options.vc_interface = "git_read_svn_write"
929 if not options.work_dir: 786 if not options.work_dir:
930 options.work_dir = "/tmp/v8-release-scripts-work-dir" 787 options.work_dir = "/tmp/v8-release-scripts-work-dir"
931 return options 788 return options
932 789
933 def RunSteps(self, step_classes, args=None): 790 def RunSteps(self, step_classes, args=None):
934 options = self.MakeOptions(args) 791 options = self.MakeOptions(args)
935 if not options: 792 if not options:
936 return 1 793 return 1
937 794
938 state_file = "%s-state.json" % self._config["PERSISTFILE_BASENAME"] 795 state_file = "%s-state.json" % self._config["PERSISTFILE_BASENAME"]
939 if options.step == 0 and os.path.exists(state_file): 796 if options.step == 0 and os.path.exists(state_file):
940 os.remove(state_file) 797 os.remove(state_file)
941 798
942 steps = [] 799 steps = []
943 for (number, step_class) in enumerate([BootstrapStep] + step_classes): 800 for (number, step_class) in enumerate([BootstrapStep] + step_classes):
944 steps.append(MakeStep(step_class, number, self._state, self._config, 801 steps.append(MakeStep(step_class, number, self._state, self._config,
945 options, self._side_effect_handler)) 802 options, self._side_effect_handler))
946 for step in steps[options.step:]: 803 for step in steps[options.step:]:
947 if step.Run(): 804 if step.Run():
948 return 0 805 return 0
949 return 0 806 return 0
950 807
951 def Run(self, args=None): 808 def Run(self, args=None):
952 return self.RunSteps(self._Steps(), args) 809 return self.RunSteps(self._Steps(), args)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698