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

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

Issue 173983002: Refactoring: Redesign option parsing in push and merge scripts. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 10 months 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
« no previous file with comments | « tools/push-to-trunk/common_includes.py ('k') | tools/push-to-trunk/push_to_trunk.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2014 the V8 project authors. All rights reserved. 2 # Copyright 2014 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 from collections import OrderedDict 29 from collections import OrderedDict
30 import optparse 30 import argparse
31 import sys 31 import sys
32 32
33 from common_includes import * 33 from common_includes import *
34 34
35 ALREADY_MERGING_SENTINEL_FILE = "ALREADY_MERGING_SENTINEL_FILE" 35 ALREADY_MERGING_SENTINEL_FILE = "ALREADY_MERGING_SENTINEL_FILE"
36 COMMIT_HASHES_FILE = "COMMIT_HASHES_FILE" 36 COMMIT_HASHES_FILE = "COMMIT_HASHES_FILE"
37 TEMPORARY_PATCH_FILE = "TEMPORARY_PATCH_FILE" 37 TEMPORARY_PATCH_FILE = "TEMPORARY_PATCH_FILE"
38 38
39 CONFIG = { 39 CONFIG = {
40 BRANCHNAME: "prepare-merge", 40 BRANCHNAME: "prepare-merge",
41 PERSISTFILE_BASENAME: "/tmp/v8-merge-to-branch-tempfile", 41 PERSISTFILE_BASENAME: "/tmp/v8-merge-to-branch-tempfile",
42 ALREADY_MERGING_SENTINEL_FILE: 42 ALREADY_MERGING_SENTINEL_FILE:
43 "/tmp/v8-merge-to-branch-tempfile-already-merging", 43 "/tmp/v8-merge-to-branch-tempfile-already-merging",
44 TEMP_BRANCH: "prepare-merge-temporary-branch-created-by-script", 44 TEMP_BRANCH: "prepare-merge-temporary-branch-created-by-script",
45 DOT_GIT_LOCATION: ".git", 45 DOT_GIT_LOCATION: ".git",
46 VERSION_FILE: "src/version.cc", 46 VERSION_FILE: "src/version.cc",
47 TEMPORARY_PATCH_FILE: "/tmp/v8-prepare-merge-tempfile-temporary-patch", 47 TEMPORARY_PATCH_FILE: "/tmp/v8-prepare-merge-tempfile-temporary-patch",
48 COMMITMSG_FILE: "/tmp/v8-prepare-merge-tempfile-commitmsg", 48 COMMITMSG_FILE: "/tmp/v8-prepare-merge-tempfile-commitmsg",
49 COMMIT_HASHES_FILE: "/tmp/v8-merge-to-branch-tempfile-PATCH_COMMIT_HASHES", 49 COMMIT_HASHES_FILE: "/tmp/v8-merge-to-branch-tempfile-PATCH_COMMIT_HASHES",
50 } 50 }
51 51
52 52
53 class MergeToBranchOptions(CommonOptions):
54 def __init__(self, options, args):
55 super(MergeToBranchOptions, self).__init__(options, True)
56 self.requires_editor = True
57 self.wait_for_lgtm = True
58 self.delete_sentinel = options.f
59 self.message = getattr(options, "message", "")
60 self.revert = getattr(options, "r", False)
61 self.revert_bleeding_edge = getattr(options, "revert_bleeding_edge", False)
62 self.patch = getattr(options, "p", "")
63 self.args = args
64
65
66 class Preparation(Step): 53 class Preparation(Step):
67 MESSAGE = "Preparation." 54 MESSAGE = "Preparation."
68 55
69 def RunStep(self): 56 def RunStep(self):
70 if os.path.exists(self.Config(ALREADY_MERGING_SENTINEL_FILE)): 57 if os.path.exists(self.Config(ALREADY_MERGING_SENTINEL_FILE)):
71 if self._options.delete_sentinel: 58 if self._options.force:
72 os.remove(self.Config(ALREADY_MERGING_SENTINEL_FILE)) 59 os.remove(self.Config(ALREADY_MERGING_SENTINEL_FILE))
73 elif self._options.s == 0: 60 elif self._options.step == 0:
74 self.Die("A merge is already in progress") 61 self.Die("A merge is already in progress")
75 open(self.Config(ALREADY_MERGING_SENTINEL_FILE), "a").close() 62 open(self.Config(ALREADY_MERGING_SENTINEL_FILE), "a").close()
76 63
77 self.InitialEnvironmentChecks() 64 self.InitialEnvironmentChecks()
78 if self._options.revert_bleeding_edge: 65 if self._options.revert_bleeding_edge:
79 self["merge_to_branch"] = "bleeding_edge" 66 self["merge_to_branch"] = "bleeding_edge"
80 elif self._options.args[0]: 67 elif self._options.branch:
81 self["merge_to_branch"] = self._options.args[0] 68 self["merge_to_branch"] = self._options.branch
82 self._options.args = self._options.args[1:]
83 else: 69 else:
84 self.Die("Please specify a branch to merge to") 70 self.Die("Please specify a branch to merge to")
85 71
86 self.CommonPrepare() 72 self.CommonPrepare()
87 self.PrepareBranch() 73 self.PrepareBranch()
88 74
89 75
90 class CreateBranch(Step): 76 class CreateBranch(Step):
91 MESSAGE = "Create a fresh branch for the patch." 77 MESSAGE = "Create a fresh branch for the patch."
92 78
93 def RunStep(self): 79 def RunStep(self):
94 self.GitCreateBranch(self.Config(BRANCHNAME), 80 self.GitCreateBranch(self.Config(BRANCHNAME),
95 "svn/%s" % self["merge_to_branch"]) 81 "svn/%s" % self["merge_to_branch"])
96 82
97 83
98 class SearchArchitecturePorts(Step): 84 class SearchArchitecturePorts(Step):
99 MESSAGE = "Search for corresponding architecture ports." 85 MESSAGE = "Search for corresponding architecture ports."
100 86
101 def RunStep(self): 87 def RunStep(self):
102 self["full_revision_list"] = list(OrderedDict.fromkeys(self._options.args)) 88 self["full_revision_list"] = list(
89 OrderedDict.fromkeys(self._options.revisions))
103 port_revision_list = [] 90 port_revision_list = []
104 for revision in self["full_revision_list"]: 91 for revision in self["full_revision_list"]:
105 # Search for commits which matches the "Port rXXX" pattern. 92 # Search for commits which matches the "Port rXXX" pattern.
106 git_hashes = self.GitLog(reverse=True, format="%H", 93 git_hashes = self.GitLog(reverse=True, format="%H",
107 grep="Port r%d" % int(revision), 94 grep="Port r%d" % int(revision),
108 branch="svn/bleeding_edge") 95 branch="svn/bleeding_edge")
109 for git_hash in git_hashes.splitlines(): 96 for git_hash in git_hashes.splitlines():
110 svn_revision = self.GitSVNFindSVNRev(git_hash, "svn/bleeding_edge") 97 svn_revision = self.GitSVNFindSVNRev(git_hash, "svn/bleeding_edge")
111 if not svn_revision: 98 if not svn_revision:
112 self.Die("Cannot determine svn revision for %s" % git_hash) 99 self.Die("Cannot determine svn revision for %s" % git_hash)
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 self.CommonCleanup() 267 self.CommonCleanup()
281 if not self._options.revert_bleeding_edge: 268 if not self._options.revert_bleeding_edge:
282 print "*** SUMMARY ***" 269 print "*** SUMMARY ***"
283 print "version: %s" % self["version"] 270 print "version: %s" % self["version"]
284 print "branch: %s" % self["to_url"] 271 print "branch: %s" % self["to_url"]
285 print "svn revision: %s" % self["svn_revision"] 272 print "svn revision: %s" % self["svn_revision"]
286 if self["revision_list"]: 273 if self["revision_list"]:
287 print "patches: %s" % self["revision_list"] 274 print "patches: %s" % self["revision_list"]
288 275
289 276
290 def RunMergeToBranch(config, 277 class MergeToBranch(ScriptsBase):
291 options, 278 def _Description(self):
292 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 279 return ("Performs the necessary steps to merge revisions from "
293 step_classes = [ 280 "bleeding_edge to other branches, including trunk.")
294 Preparation,
295 CreateBranch,
296 SearchArchitecturePorts,
297 FindGitRevisions,
298 ApplyPatches,
299 PrepareVersion,
300 IncrementVersion,
301 CommitLocal,
302 UploadStep,
303 CommitRepository,
304 PrepareSVN,
305 TagRevision,
306 CleanUp,
307 ]
308 281
309 RunScript(step_classes, config, options, side_effect_handler) 282 def _PrepareOptions(self, parser):
283 group = parser.add_mutually_exclusive_group(required=True)
284 group.add_argument("--branch", help="The branch to merge to.")
285 group.add_argument("-R", "--revert-bleeding-edge",
286 help="Revert specified patches from bleeding edge.",
287 default=False, action="store_true")
288 parser.add_argument("revisions", nargs="*",
289 help="The revisions to merge.")
290 parser.add_argument("-f", "--force",
291 help="Delete sentinel file.",
292 default=False, action="store_true")
293 parser.add_argument("-m", "--message",
294 help="A commit message for the patch.")
295 parser.add_argument("--revert",
296 help="Revert specified patches.",
297 default=False, action="store_true")
298 parser.add_argument("-p", "--patch",
299 help="A patch file to apply as part of the merge.")
300
301 def _ProcessOptions(self, options):
302 # TODO(machenbach): Add a test that covers revert from bleeding_edge
303 if len(options.revisions) < 1:
304 if not options.patch:
305 print "Either a patch file or revision numbers must be specified"
306 return False
307 if not options.message:
308 print "You must specify a merge comment if no patches are specified"
309 return False
310 return True
311
312 def _Steps(self):
313 return [
314 Preparation,
315 CreateBranch,
316 SearchArchitecturePorts,
317 FindGitRevisions,
318 ApplyPatches,
319 PrepareVersion,
320 IncrementVersion,
321 CommitLocal,
322 UploadStep,
323 CommitRepository,
324 PrepareSVN,
325 TagRevision,
326 CleanUp,
327 ]
310 328
311 329
312 def BuildOptions():
313 result = optparse.OptionParser()
314 result.set_usage("""%prog [OPTIONS]... [BRANCH] [REVISION]...
315
316 Performs the necessary steps to merge revisions from bleeding_edge
317 to other branches, including trunk.""")
318 result.add_option("-f",
319 help="Delete sentinel file.",
320 default=False, action="store_true")
321 result.add_option("-m", "--message",
322 help="Specify a commit message for the patch.")
323 result.add_option("-r", "--revert",
324 help="Revert specified patches.",
325 default=False, action="store_true")
326 result.add_option("-R", "--revert-bleeding-edge",
327 help="Revert specified patches from bleeding edge.",
328 default=False, action="store_true")
329 result.add_option("-p", "--patch", dest="p",
330 help="Specify a patch file to apply as part of the merge.")
331 result.add_option("-s", "--step", dest="s",
332 help="Specify the step where to start work. Default: 0.",
333 default=0, type="int")
334 return result
335
336
337 def ProcessOptions(options, args):
338 revert_from_bleeding_edge = 1 if options.revert_bleeding_edge else 0
339 min_exp_args = 2 - revert_from_bleeding_edge
340 if len(args) < min_exp_args:
341 if not options.p:
342 print "Either a patch file or revision numbers must be specified"
343 return False
344 if not options.message:
345 print "You must specify a merge comment if no patches are specified"
346 return False
347 if options.s < 0:
348 print "Bad step number %d" % options.s
349 return False
350 return True
351
352
353 def Main():
354 parser = BuildOptions()
355 (options, args) = parser.parse_args()
356 if not ProcessOptions(options, args):
357 parser.print_help()
358 return 1
359 RunMergeToBranch(CONFIG, MergeToBranchOptions(options, args))
360
361 if __name__ == "__main__": 330 if __name__ == "__main__":
362 sys.exit(Main()) 331 sys.exit(MergeToBranch(CONFIG).Run())
OLDNEW
« no previous file with comments | « tools/push-to-trunk/common_includes.py ('k') | tools/push-to-trunk/push_to_trunk.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698