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

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

Issue 114203002: Add named options to push-to-trunk script. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
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
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 205
206 def Sleep(self, seconds): 206 def Sleep(self, seconds):
207 time.sleep(seconds) 207 time.sleep(seconds)
208 208
209 def GetDate(self): 209 def GetDate(self):
210 return datetime.date.today().strftime("%Y-%m-%d") 210 return datetime.date.today().strftime("%Y-%m-%d")
211 211
212 DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler() 212 DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler()
213 213
214 214
215 class NoRetryException(Exception):
216 pass
217
218 class CommonOptions(object):
219 def __init__(self, options, manual=True):
220 self.requires_editor = True
221 self.wait_for_lgtm = True
222 self.s = options.s
223 self.force_readline_defaults = not manual
224 self.force_upload = not manual
225 self.manual = manual
226
227
215 class Step(object): 228 class Step(object):
216 def __init__(self, text, requires, number, config, state, options, handler): 229 def __init__(self, text, requires, number, config, state, options, handler):
217 self._text = text 230 self._text = text
218 self._requires = requires 231 self._requires = requires
219 self._number = number 232 self._number = number
220 self._config = config 233 self._config = config
221 self._state = state 234 self._state = state
222 self._options = options 235 self._options = options
223 self._side_effect_handler = handler 236 self._side_effect_handler = handler
224 assert self._number >= 0 237 assert self._number >= 0
225 assert self._config is not None 238 assert self._config is not None
226 assert self._state is not None 239 assert self._state is not None
227 assert self._side_effect_handler is not None 240 assert self._side_effect_handler is not None
241 assert isinstance(options, CommonOptions)
228 242
229 def Config(self, key): 243 def Config(self, key):
230 return self._config[key] 244 return self._config[key]
231 245
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
238 def Run(self): 246 def Run(self):
239 if self._requires: 247 if self._requires:
240 self.RestoreIfUnset(self._requires) 248 self.RestoreIfUnset(self._requires)
241 if not self._state[self._requires]: 249 if not self._state[self._requires]:
242 return 250 return
243 print ">>> Step %d: %s" % (self._number, self._text) 251 print ">>> Step %d: %s" % (self._number, self._text)
244 self.RunStep() 252 self.RunStep()
245 253
246 def RunStep(self): 254 def RunStep(self):
247 raise NotImplementedError 255 raise NotImplementedError
248 256
249 def Retry(self, cb, retry_on=None, wait_plan=None): 257 def Retry(self, cb, retry_on=None, wait_plan=None):
250 """ Retry a function. 258 """ Retry a function.
251 Params: 259 Params:
252 cb: The function to retry. 260 cb: The function to retry.
253 retry_on: A callback that takes the result of the function and returns 261 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 262 True if the function should be retried. A function throwing an
255 exception is always retried. 263 exception is always retried.
256 wait_plan: A list of waiting delays between retries in seconds. The 264 wait_plan: A list of waiting delays between retries in seconds. The
257 maximum number of retries is len(wait_plan). 265 maximum number of retries is len(wait_plan).
258 """ 266 """
259 retry_on = retry_on or (lambda x: False) 267 retry_on = retry_on or (lambda x: False)
260 wait_plan = list(wait_plan or []) 268 wait_plan = list(wait_plan or [])
261 wait_plan.reverse() 269 wait_plan.reverse()
262 while True: 270 while True:
263 got_exception = False 271 got_exception = False
264 try: 272 try:
265 result = cb() 273 result = cb()
274 except NoRetryException, e:
275 raise e
266 except Exception: 276 except Exception:
267 got_exception = True 277 got_exception = True
268 if got_exception or retry_on(result): 278 if got_exception or retry_on(result):
269 if not wait_plan: 279 if not wait_plan:
270 raise Exception("Retried too often. Giving up.") 280 raise Exception("Retried too often. Giving up.")
271 wait_time = wait_plan.pop() 281 wait_time = wait_plan.pop()
272 print "Waiting for %f seconds." % wait_time 282 print "Waiting for %f seconds." % wait_time
273 self._side_effect_handler.Sleep(wait_time) 283 self._side_effect_handler.Sleep(wait_time)
274 print "Retrying..." 284 print "Retrying..."
275 else: 285 else:
276 return result 286 return result
277 287
278 def ReadLine(self, default=None): 288 def ReadLine(self, default=None):
279 # Don't prompt in forced mode. 289 # Don't prompt in forced mode.
280 if not self.IsManual() and default is not None: 290 if self._options.force_readline_defaults and default is not None:
281 print "%s (forced)" % default 291 print "%s (forced)" % default
282 return default 292 return default
283 else: 293 else:
284 return self._side_effect_handler.ReadLine() 294 return self._side_effect_handler.ReadLine()
285 295
286 def Git(self, args="", prefix="", pipe=True, retry_on=None): 296 def Git(self, args="", prefix="", pipe=True, retry_on=None):
287 cmd = lambda: self._side_effect_handler.Command("git", args, prefix, pipe) 297 cmd = lambda: self._side_effect_handler.Command("git", args, prefix, pipe)
288 return self.Retry(cmd, retry_on, [5, 30]) 298 return self.Retry(cmd, retry_on, [5, 30])
289 299
290 def Editor(self, args): 300 def Editor(self, args):
291 if not self.IsForced(): 301 if self._options.requires_editor:
292 return self._side_effect_handler.Command(os.environ["EDITOR"], args, 302 return self._side_effect_handler.Command(os.environ["EDITOR"], args,
293 pipe=False) 303 pipe=False)
294 304
295 def ReadURL(self, url, retry_on=None, wait_plan=None): 305 def ReadURL(self, url, retry_on=None, wait_plan=None):
296 wait_plan = wait_plan or [3, 60, 600] 306 wait_plan = wait_plan or [3, 60, 600]
297 cmd = lambda: self._side_effect_handler.ReadURL(url) 307 cmd = lambda: self._side_effect_handler.ReadURL(url)
298 return self.Retry(cmd, retry_on, wait_plan) 308 return self.Retry(cmd, retry_on, wait_plan)
299 309
300 def GetDate(self): 310 def GetDate(self):
301 return self._side_effect_handler.GetDate() 311 return self._side_effect_handler.GetDate()
302 312
303 def Die(self, msg=""): 313 def Die(self, msg=""):
304 if msg != "": 314 if msg != "":
305 print "Error: %s" % msg 315 print "Error: %s" % msg
306 print "Exiting" 316 print "Exiting"
307 raise Exception(msg) 317 raise Exception(msg)
308 318
309 def DieNoManualMode(self, msg=""): 319 def DieNoManualMode(self, msg=""):
310 if not self.IsManual(): 320 if not self._options.manual:
311 msg = msg or "Only available in manual mode." 321 msg = msg or "Only available in manual mode."
312 self.Die(msg) 322 self.Die(msg)
313 323
314 def Confirm(self, msg): 324 def Confirm(self, msg):
315 print "%s [Y/n] " % msg, 325 print "%s [Y/n] " % msg,
316 answer = self.ReadLine(default="Y") 326 answer = self.ReadLine(default="Y")
317 return answer == "" or answer == "Y" or answer == "y" 327 return answer == "" or answer == "Y" or answer == "y"
318 328
319 def DeleteBranch(self, name): 329 def DeleteBranch(self, name):
320 git_result = self.Git("branch").strip() 330 git_result = self.Git("branch").strip()
(...skipping 20 matching lines...) Expand all
341 def RestoreIfUnset(self, var_name): 351 def RestoreIfUnset(self, var_name):
342 if self._state.get(var_name) is None: 352 if self._state.get(var_name) is None:
343 self._state[var_name] = self.Restore(var_name) 353 self._state[var_name] = self.Restore(var_name)
344 354
345 def InitialEnvironmentChecks(self): 355 def InitialEnvironmentChecks(self):
346 # Cancel if this is not a git checkout. 356 # Cancel if this is not a git checkout.
347 if not os.path.exists(self._config[DOT_GIT_LOCATION]): 357 if not os.path.exists(self._config[DOT_GIT_LOCATION]):
348 self.Die("This is not a git checkout, this script won't work for you.") 358 self.Die("This is not a git checkout, this script won't work for you.")
349 359
350 # Cancel if EDITOR is unset or not executable. 360 # Cancel if EDITOR is unset or not executable.
351 if (not self.IsForced() and (not os.environ.get("EDITOR") or 361 if (self._options.requires_editor and (not os.environ.get("EDITOR") or
352 Command("which", os.environ["EDITOR"]) is None)): 362 Command("which", os.environ["EDITOR"]) is None)):
353 self.Die("Please set your EDITOR environment variable, you'll need it.") 363 self.Die("Please set your EDITOR environment variable, you'll need it.")
354 364
355 def CommonPrepare(self): 365 def CommonPrepare(self):
356 # Check for a clean workdir. 366 # Check for a clean workdir.
357 if self.Git("status -s -uno").strip() != "": 367 if self.Git("status -s -uno").strip() != "":
358 self.Die("Workspace is not clean. Please commit or undo your changes.") 368 self.Die("Workspace is not clean. Please commit or undo your changes.")
359 369
360 # Persist current branch. 370 # Persist current branch.
361 current_branch = "" 371 current_branch = ""
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 self.RestoreIfUnset("%s%s" % (prefix, v)) 421 self.RestoreIfUnset("%s%s" % (prefix, v))
412 422
413 def WaitForLGTM(self): 423 def WaitForLGTM(self):
414 print ("Please wait for an LGTM, then type \"LGTM<Return>\" to commit " 424 print ("Please wait for an LGTM, then type \"LGTM<Return>\" to commit "
415 "your change. (If you need to iterate on the patch or double check " 425 "your change. (If you need to iterate on the patch or double check "
416 "that it's sane, do so in another shell, but remember to not " 426 "that it's sane, do so in another shell, but remember to not "
417 "change the headline of the uploaded CL.") 427 "change the headline of the uploaded CL.")
418 answer = "" 428 answer = ""
419 while answer != "LGTM": 429 while answer != "LGTM":
420 print "> ", 430 print "> ",
421 answer = self.ReadLine("LGTM" if self.IsForced() else None) 431 answer = self.ReadLine(None if self._options.wait_for_lgtm else "LGTM")
422 if answer != "LGTM": 432 if answer != "LGTM":
423 print "That was not 'LGTM'." 433 print "That was not 'LGTM'."
424 434
425 def WaitForResolvingConflicts(self, patch_file): 435 def WaitForResolvingConflicts(self, patch_file):
426 print("Applying the patch \"%s\" failed. Either type \"ABORT<Return>\", " 436 print("Applying the patch \"%s\" failed. Either type \"ABORT<Return>\", "
427 "or resolve the conflicts, stage *all* touched files with " 437 "or resolve the conflicts, stage *all* touched files with "
428 "'git add', and type \"RESOLVED<Return>\"") 438 "'git add', and type \"RESOLVED<Return>\"")
429 self.DieNoManualMode() 439 self.DieNoManualMode()
430 answer = "" 440 answer = ""
431 while answer != "RESOLVED": 441 while answer != "RESOLVED":
(...skipping 15 matching lines...) Expand all
447 MESSAGE = "Upload for code review." 457 MESSAGE = "Upload for code review."
448 458
449 def RunStep(self): 459 def RunStep(self):
450 if self._options.r: 460 if self._options.r:
451 print "Using account %s for review." % self._options.r 461 print "Using account %s for review." % self._options.r
452 reviewer = self._options.r 462 reviewer = self._options.r
453 else: 463 else:
454 print "Please enter the email address of a V8 reviewer for your patch: ", 464 print "Please enter the email address of a V8 reviewer for your patch: ",
455 self.DieNoManualMode("A reviewer must be specified in forced mode.") 465 self.DieNoManualMode("A reviewer must be specified in forced mode.")
456 reviewer = self.ReadLine() 466 reviewer = self.ReadLine()
457 force_flag = " -f" if not self.IsManual() else "" 467 force_flag = " -f" if self._options.force_upload else ""
458 args = "cl upload -r \"%s\" --send-mail%s" % (reviewer, force_flag) 468 args = "cl upload -r \"%s\" --send-mail%s" % (reviewer, force_flag)
459 # TODO(machenbach): Check output in forced mode. Verify that all required 469 # TODO(machenbach): Check output in forced mode. Verify that all required
460 # base files were uploaded, if not retry. 470 # base files were uploaded, if not retry.
461 if self.Git(args, pipe=False) is None: 471 if self.Git(args, pipe=False) is None:
462 self.Die("'git cl upload' failed, please try again.") 472 self.Die("'git cl upload' failed, please try again.")
463 473
464 474
465 def MakeStep(step_class=Step, number=0, state=None, config=None, 475 def MakeStep(step_class=Step, number=0, state=None, config=None,
466 options=None, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 476 options=None, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
467 # Allow to pass in empty dictionaries. 477 # Allow to pass in empty dictionaries.
(...skipping 19 matching lines...) Expand all
487 options, 497 options,
488 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): 498 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
489 state = {} 499 state = {}
490 steps = [] 500 steps = []
491 for (number, step_class) in enumerate(step_classes): 501 for (number, step_class) in enumerate(step_classes):
492 steps.append(MakeStep(step_class, number, state, config, 502 steps.append(MakeStep(step_class, number, state, config,
493 options, side_effect_handler)) 503 options, side_effect_handler))
494 504
495 for step in steps[options.s:]: 505 for step in steps[options.s:]:
496 step.Run() 506 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