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

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

Issue 112863002: Merge bleeding_edge 18021:18297 (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 7 years 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/auto_roll.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 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 datetime
29 import os 30 import os
30 import re 31 import re
31 import subprocess 32 import subprocess
32 import sys 33 import sys
33 import textwrap 34 import textwrap
35 import time
34 import urllib2 36 import urllib2
35 37
36 PERSISTFILE_BASENAME = "PERSISTFILE_BASENAME" 38 PERSISTFILE_BASENAME = "PERSISTFILE_BASENAME"
37 TEMP_BRANCH = "TEMP_BRANCH" 39 TEMP_BRANCH = "TEMP_BRANCH"
38 BRANCHNAME = "BRANCHNAME" 40 BRANCHNAME = "BRANCHNAME"
39 DOT_GIT_LOCATION = "DOT_GIT_LOCATION" 41 DOT_GIT_LOCATION = "DOT_GIT_LOCATION"
40 VERSION_FILE = "VERSION_FILE" 42 VERSION_FILE = "VERSION_FILE"
41 CHANGELOG_FILE = "CHANGELOG_FILE" 43 CHANGELOG_FILE = "CHANGELOG_FILE"
42 CHANGELOG_ENTRY_FILE = "CHANGELOG_ENTRY_FILE" 44 CHANGELOG_ENTRY_FILE = "CHANGELOG_ENTRY_FILE"
43 COMMITMSG_FILE = "COMMITMSG_FILE" 45 COMMITMSG_FILE = "COMMITMSG_FILE"
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
92 94
93 def StripComments(text): 95 def StripComments(text):
94 # Use split not splitlines to keep terminal newlines. 96 # Use split not splitlines to keep terminal newlines.
95 return "\n".join(filter(lambda x: not x.startswith("#"), text.split("\n"))) 97 return "\n".join(filter(lambda x: not x.startswith("#"), text.split("\n")))
96 98
97 99
98 def MakeChangeLogBody(commit_messages, auto_format=False): 100 def MakeChangeLogBody(commit_messages, auto_format=False):
99 result = "" 101 result = ""
100 added_titles = set() 102 added_titles = set()
101 for (title, body, author) in commit_messages: 103 for (title, body, author) in commit_messages:
102 # TODO(machenbach): Reload the commit description from rietveld in order to 104 # TODO(machenbach): Better check for reverts. A revert should remove the
103 # catch late changes. 105 # original CL from the actual log entry.
104 title = title.strip() 106 title = title.strip()
105 if auto_format: 107 if auto_format:
106 # Only add commits that set the LOG flag correctly. 108 # Only add commits that set the LOG flag correctly.
107 log_exp = r"^[ \t]*LOG[ \t]*=[ \t]*(?:Y(?:ES)?)|TRUE" 109 log_exp = r"^[ \t]*LOG[ \t]*=[ \t]*(?:(?:Y(?:ES)?)|TRUE)"
108 if not re.search(log_exp, body, flags=re.I | re.M): 110 if not re.search(log_exp, body, flags=re.I | re.M):
109 continue 111 continue
110 # Never include reverts. 112 # Never include reverts.
111 if title.startswith("Revert "): 113 if title.startswith("Revert "):
112 continue 114 continue
113 # Don't include duplicates. 115 # Don't include duplicates.
114 if title in added_titles: 116 if title in added_titles:
115 continue 117 continue
116 118
117 # TODO(machenbach): Let python do all formatting. Get raw git title, attach 119 # Add and format the commit's title and bug reference. Move dot to the end.
118 # issue and add/move dot to the end - all in one line. Make formatting and
119 # indentation afterwards.
120
121 # Add the commit's title line.
122 result += "%s\n" % Fill80(title)
123 added_titles.add(title) 120 added_titles.add(title)
124 121 raw_title = re.sub(r"(\.|\?|!)$", "", title)
125 # Add bug references. 122 bug_reference = MakeChangeLogBugReference(body)
126 result += MakeChangeLogBugReference(body) 123 space = " " if bug_reference else ""
124 result += "%s\n" % Fill80("%s%s%s." % (raw_title, space, bug_reference))
127 125
128 # Append the commit's author for reference if not in auto-format mode. 126 # Append the commit's author for reference if not in auto-format mode.
129 if not auto_format: 127 if not auto_format:
130 result += "%s\n" % Fill80("(%s)" % author.strip()) 128 result += "%s\n" % Fill80("(%s)" % author.strip())
131 129
132 result += "\n" 130 result += "\n"
133 return result 131 return result
134 132
135 133
136 def MakeChangeLogBugReference(body): 134 def MakeChangeLogBugReference(body):
(...skipping 25 matching lines...) Expand all
162 bug_groups = [] 160 bug_groups = []
163 def FormatIssues(prefix, bugs): 161 def FormatIssues(prefix, bugs):
164 if len(bugs) > 0: 162 if len(bugs) > 0:
165 plural = "s" if len(bugs) > 1 else "" 163 plural = "s" if len(bugs) > 1 else ""
166 bug_groups.append("%sissue%s %s" % (prefix, plural, ", ".join(bugs))) 164 bug_groups.append("%sissue%s %s" % (prefix, plural, ", ".join(bugs)))
167 165
168 FormatIssues("", v8bugs) 166 FormatIssues("", v8bugs)
169 FormatIssues("Chromium ", crbugs) 167 FormatIssues("Chromium ", crbugs)
170 168
171 if len(bug_groups) > 0: 169 if len(bug_groups) > 0:
172 # Format with 8 characters indentation and max 80 character lines. 170 return "(%s)" % ", ".join(bug_groups)
173 return "%s\n" % Fill80("(%s)" % ", ".join(bug_groups))
174 else: 171 else:
175 return "" 172 return ""
176 173
177 174
178 # Some commands don't like the pipe, e.g. calling vi from within the script or 175 # Some commands don't like the pipe, e.g. calling vi from within the script or
179 # from subscripts like git cl upload. 176 # from subscripts like git cl upload.
180 def Command(cmd, args="", prefix="", pipe=True): 177 def Command(cmd, args="", prefix="", pipe=True):
178 # TODO(machenbach): Use timeout.
181 cmd_line = "%s %s %s" % (prefix, cmd, args) 179 cmd_line = "%s %s %s" % (prefix, cmd, args)
182 print "Command: %s" % cmd_line 180 print "Command: %s" % cmd_line
183 try: 181 try:
184 if pipe: 182 if pipe:
185 return subprocess.check_output(cmd_line, shell=True) 183 return subprocess.check_output(cmd_line, shell=True)
186 else: 184 else:
187 return subprocess.check_call(cmd_line, shell=True) 185 return subprocess.check_call(cmd_line, shell=True)
188 except subprocess.CalledProcessError: 186 except subprocess.CalledProcessError:
189 return None 187 return None
190 188
191 189
192 # Wrapper for side effects. 190 # Wrapper for side effects.
193 class SideEffectHandler(object): 191 class SideEffectHandler(object):
194 def Command(self, cmd, args="", prefix="", pipe=True): 192 def Command(self, cmd, args="", prefix="", pipe=True):
195 return Command(cmd, args, prefix, pipe) 193 return Command(cmd, args, prefix, pipe)
196 194
197 def ReadLine(self): 195 def ReadLine(self):
198 return sys.stdin.readline().strip() 196 return sys.stdin.readline().strip()
199 197
200 def ReadURL(self, url): 198 def ReadURL(self, url):
201 # pylint: disable=E1121 199 # pylint: disable=E1121
202 url_fh = urllib2.urlopen(url, None, 60) 200 url_fh = urllib2.urlopen(url, None, 60)
203 try: 201 try:
204 return url_fh.read() 202 return url_fh.read()
205 finally: 203 finally:
206 url_fh.close() 204 url_fh.close()
207 205
206 def Sleep(self, seconds):
207 time.sleep(seconds)
208
209 def GetDate(self):
210 return datetime.date.today().strftime("%Y-%m-%d")
211
208 DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler() 212 DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler()
209 213
210 214
211 class Step(object): 215 class Step(object):
212 def __init__(self, text, requires, number, config, state, options, handler): 216 def __init__(self, text, requires, number, config, state, options, handler):
213 self._text = text 217 self._text = text
214 self._requires = requires 218 self._requires = requires
215 self._number = number 219 self._number = number
216 self._config = config 220 self._config = config
217 self._state = state 221 self._state = state
218 self._options = options 222 self._options = options
219 self._side_effect_handler = handler 223 self._side_effect_handler = handler
220 assert self._number >= 0 224 assert self._number >= 0
221 assert self._config is not None 225 assert self._config is not None
222 assert self._state is not None 226 assert self._state is not None
223 assert self._side_effect_handler is not None 227 assert self._side_effect_handler is not None
224 228
225 def Config(self, key): 229 def Config(self, key):
226 return self._config[key] 230 return self._config[key]
227 231
232 def IsForced(self):
233 return self._options and self._options.f
234
235 def IsManual(self):
236 return self._options and self._options.m
237
228 def Run(self): 238 def Run(self):
229 if self._requires: 239 if self._requires:
230 self.RestoreIfUnset(self._requires) 240 self.RestoreIfUnset(self._requires)
231 if not self._state[self._requires]: 241 if not self._state[self._requires]:
232 return 242 return
233 print ">>> Step %d: %s" % (self._number, self._text) 243 print ">>> Step %d: %s" % (self._number, self._text)
234 self.RunStep() 244 self.RunStep()
235 245
236 def RunStep(self): 246 def RunStep(self):
237 raise NotImplementedError 247 raise NotImplementedError
238 248
249 def Retry(self, cb, retry_on=None, wait_plan=None):
250 """ Retry a function.
251 Params:
252 cb: The function to retry.
253 retry_on: A callback that takes the result of the function and returns
254 True if the function should be retried. A function throwing an
255 exception is always retried.
256 wait_plan: A list of waiting delays between retries in seconds. The
257 maximum number of retries is len(wait_plan).
258 """
259 retry_on = retry_on or (lambda x: False)
260 wait_plan = list(wait_plan or [])
261 wait_plan.reverse()
262 while True:
263 got_exception = False
264 try:
265 result = cb()
266 except Exception:
267 got_exception = True
268 if got_exception or retry_on(result):
269 if not wait_plan:
270 raise Exception("Retried too often. Giving up.")
271 wait_time = wait_plan.pop()
272 print "Waiting for %f seconds." % wait_time
273 self._side_effect_handler.Sleep(wait_time)
274 print "Retrying..."
275 else:
276 return result
277
239 def ReadLine(self, default=None): 278 def ReadLine(self, default=None):
240 # Don't prompt in forced mode. 279 # Don't prompt in forced mode.
241 if self._options and self._options.f and default is not None: 280 if not self.IsManual() and default is not None:
242 print "%s (forced)" % default 281 print "%s (forced)" % default
243 return default 282 return default
244 else: 283 else:
245 return self._side_effect_handler.ReadLine() 284 return self._side_effect_handler.ReadLine()
246 285
247 def Git(self, args="", prefix="", pipe=True): 286 def Git(self, args="", prefix="", pipe=True, retry_on=None):
248 return self._side_effect_handler.Command("git", args, prefix, pipe) 287 cmd = lambda: self._side_effect_handler.Command("git", args, prefix, pipe)
288 return self.Retry(cmd, retry_on, [5, 30])
249 289
250 def Editor(self, args): 290 def Editor(self, args):
251 return self._side_effect_handler.Command(os.environ["EDITOR"], args, 291 if not self.IsForced():
252 pipe=False) 292 return self._side_effect_handler.Command(os.environ["EDITOR"], args,
293 pipe=False)
253 294
254 def ReadURL(self, url): 295 def ReadURL(self, url, retry_on=None, wait_plan=None):
255 return self._side_effect_handler.ReadURL(url) 296 wait_plan = wait_plan or [3, 60, 600]
297 cmd = lambda: self._side_effect_handler.ReadURL(url)
298 return self.Retry(cmd, retry_on, wait_plan)
299
300 def GetDate(self):
301 return self._side_effect_handler.GetDate()
256 302
257 def Die(self, msg=""): 303 def Die(self, msg=""):
258 if msg != "": 304 if msg != "":
259 print "Error: %s" % msg 305 print "Error: %s" % msg
260 print "Exiting" 306 print "Exiting"
261 raise Exception(msg) 307 raise Exception(msg)
262 308
263 def DieInForcedMode(self, msg=""): 309 def DieNoManualMode(self, msg=""):
264 if self._options and self._options.f: 310 if not self.IsManual():
265 msg = msg or "Not implemented in forced mode." 311 msg = msg or "Only available in manual mode."
266 self.Die(msg) 312 self.Die(msg)
267 313
268 def Confirm(self, msg): 314 def Confirm(self, msg):
269 print "%s [Y/n] " % msg, 315 print "%s [Y/n] " % msg,
270 answer = self.ReadLine(default="Y") 316 answer = self.ReadLine(default="Y")
271 return answer == "" or answer == "Y" or answer == "y" 317 return answer == "" or answer == "Y" or answer == "y"
272 318
273 def DeleteBranch(self, name): 319 def DeleteBranch(self, name):
274 git_result = self.Git("branch").strip() 320 git_result = self.Git("branch").strip()
275 for line in git_result.splitlines(): 321 for line in git_result.splitlines():
(...skipping 18 matching lines...) Expand all
294 340
295 def RestoreIfUnset(self, var_name): 341 def RestoreIfUnset(self, var_name):
296 if self._state.get(var_name) is None: 342 if self._state.get(var_name) is None:
297 self._state[var_name] = self.Restore(var_name) 343 self._state[var_name] = self.Restore(var_name)
298 344
299 def InitialEnvironmentChecks(self): 345 def InitialEnvironmentChecks(self):
300 # Cancel if this is not a git checkout. 346 # Cancel if this is not a git checkout.
301 if not os.path.exists(self._config[DOT_GIT_LOCATION]): 347 if not os.path.exists(self._config[DOT_GIT_LOCATION]):
302 self.Die("This is not a git checkout, this script won't work for you.") 348 self.Die("This is not a git checkout, this script won't work for you.")
303 349
304 # TODO(machenbach): Don't use EDITOR in forced mode as soon as script is
305 # well tested.
306 # Cancel if EDITOR is unset or not executable. 350 # Cancel if EDITOR is unset or not executable.
307 if (not os.environ.get("EDITOR") or 351 if (not self.IsForced() and (not os.environ.get("EDITOR") or
308 Command("which", os.environ["EDITOR"]) is None): 352 Command("which", os.environ["EDITOR"]) is None)):
309 self.Die("Please set your EDITOR environment variable, you'll need it.") 353 self.Die("Please set your EDITOR environment variable, you'll need it.")
310 354
311 def CommonPrepare(self): 355 def CommonPrepare(self):
312 # Check for a clean workdir. 356 # Check for a clean workdir.
313 if self.Git("status -s -uno").strip() != "": 357 if self.Git("status -s -uno").strip() != "":
314 self.Die("Workspace is not clean. Please commit or undo your changes.") 358 self.Die("Workspace is not clean. Please commit or undo your changes.")
315 359
316 # Persist current branch. 360 # Persist current branch.
317 current_branch = "" 361 current_branch = ""
318 git_result = self.Git("status -s -b -uno").strip() 362 git_result = self.Git("status -s -b -uno").strip()
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 self.RestoreIfUnset("%s%s" % (prefix, v)) 411 self.RestoreIfUnset("%s%s" % (prefix, v))
368 412
369 def WaitForLGTM(self): 413 def WaitForLGTM(self):
370 print ("Please wait for an LGTM, then type \"LGTM<Return>\" to commit " 414 print ("Please wait for an LGTM, then type \"LGTM<Return>\" to commit "
371 "your change. (If you need to iterate on the patch or double check " 415 "your change. (If you need to iterate on the patch or double check "
372 "that it's sane, do so in another shell, but remember to not " 416 "that it's sane, do so in another shell, but remember to not "
373 "change the headline of the uploaded CL.") 417 "change the headline of the uploaded CL.")
374 answer = "" 418 answer = ""
375 while answer != "LGTM": 419 while answer != "LGTM":
376 print "> ", 420 print "> ",
377 # TODO(machenbach): Add default="LGTM" to avoid prompt when script is 421 answer = self.ReadLine("LGTM" if self.IsForced() else None)
378 # well tested and when prepare push cl has TBR flag.
379 answer = self.ReadLine()
380 if answer != "LGTM": 422 if answer != "LGTM":
381 print "That was not 'LGTM'." 423 print "That was not 'LGTM'."
382 424
383 def WaitForResolvingConflicts(self, patch_file): 425 def WaitForResolvingConflicts(self, patch_file):
384 print("Applying the patch \"%s\" failed. Either type \"ABORT<Return>\", " 426 print("Applying the patch \"%s\" failed. Either type \"ABORT<Return>\", "
385 "or resolve the conflicts, stage *all* touched files with " 427 "or resolve the conflicts, stage *all* touched files with "
386 "'git add', and type \"RESOLVED<Return>\"") 428 "'git add', and type \"RESOLVED<Return>\"")
387 self.DieInForcedMode() 429 self.DieNoManualMode()
388 answer = "" 430 answer = ""
389 while answer != "RESOLVED": 431 while answer != "RESOLVED":
390 if answer == "ABORT": 432 if answer == "ABORT":
391 self.Die("Applying the patch failed.") 433 self.Die("Applying the patch failed.")
392 if answer != "": 434 if answer != "":
393 print "That was not 'RESOLVED' or 'ABORT'." 435 print "That was not 'RESOLVED' or 'ABORT'."
394 print "> ", 436 print "> ",
395 answer = self.ReadLine() 437 answer = self.ReadLine()
396 438
397 # Takes a file containing the patch to apply as first argument. 439 # Takes a file containing the patch to apply as first argument.
398 def ApplyPatch(self, patch_file, reverse_patch=""): 440 def ApplyPatch(self, patch_file, reverse_patch=""):
399 args = "apply --index --reject %s \"%s\"" % (reverse_patch, patch_file) 441 args = "apply --index --reject %s \"%s\"" % (reverse_patch, patch_file)
400 if self.Git(args) is None: 442 if self.Git(args) is None:
401 self.WaitForResolvingConflicts(patch_file) 443 self.WaitForResolvingConflicts(patch_file)
402 444
403 445
404 class UploadStep(Step): 446 class UploadStep(Step):
405 MESSAGE = "Upload for code review." 447 MESSAGE = "Upload for code review."
406 448
407 def RunStep(self): 449 def RunStep(self):
408 if self._options.r: 450 if self._options.r:
409 print "Using account %s for review." % self._options.r 451 print "Using account %s for review." % self._options.r
410 reviewer = self._options.r 452 reviewer = self._options.r
411 else: 453 else:
412 print "Please enter the email address of a V8 reviewer for your patch: ", 454 print "Please enter the email address of a V8 reviewer for your patch: ",
413 self.DieInForcedMode("A reviewer must be specified in forced mode.") 455 self.DieNoManualMode("A reviewer must be specified in forced mode.")
414 reviewer = self.ReadLine() 456 reviewer = self.ReadLine()
415 force_flag = " -f" if self._options.f else "" 457 force_flag = " -f" if not self.IsManual() else ""
416 args = "cl upload -r \"%s\" --send-mail%s" % (reviewer, force_flag) 458 args = "cl upload -r \"%s\" --send-mail%s" % (reviewer, force_flag)
417 # TODO(machenbach): Check output in forced mode. Verify that all required 459 # TODO(machenbach): Check output in forced mode. Verify that all required
418 # base files were uploaded, if not retry. 460 # base files were uploaded, if not retry.
419 if self.Git(args, pipe=False) is None: 461 if self.Git(args, pipe=False) is None:
420 self.Die("'git cl upload' failed, please try again.") 462 self.Die("'git cl upload' failed, please try again.")
421 463
422 464
423 def MakeStep(step_class=Step, number=0, state=None, config=None, 465 def MakeStep(step_class=Step, number=0, state=None, config=None,
424 options=None, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 466 options=None, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
425 # Allow to pass in empty dictionaries. 467 # Allow to pass in empty dictionaries.
(...skipping 19 matching lines...) Expand all
445 options, 487 options,
446 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 488 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
447 state = {} 489 state = {}
448 steps = [] 490 steps = []
449 for (number, step_class) in enumerate(step_classes): 491 for (number, step_class) in enumerate(step_classes):
450 steps.append(MakeStep(step_class, number, state, config, 492 steps.append(MakeStep(step_class, number, state, config,
451 options, side_effect_handler)) 493 options, side_effect_handler))
452 494
453 for step in steps[options.s:]: 495 for step in steps[options.s:]:
454 step.Run() 496 step.Run()
OLDNEW
« no previous file with comments | « tools/push-to-trunk/auto_roll.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