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 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 try: | 185 try: |
186 if pipe: | 186 if pipe: |
187 return subprocess.check_output(cmd_line, shell=True) | 187 return subprocess.check_output(cmd_line, shell=True) |
188 else: | 188 else: |
189 return subprocess.check_call(cmd_line, shell=True) | 189 return subprocess.check_call(cmd_line, shell=True) |
190 except subprocess.CalledProcessError: | 190 except subprocess.CalledProcessError: |
191 return None | 191 return None |
192 | 192 |
193 | 193 |
194 # Wrapper for side effects. | 194 # Wrapper for side effects. |
195 class SideEffectHandler(object): | 195 class SideEffectHandler(object): # pragma: no cover |
196 def Call(self, fun, *args, **kwargs): | 196 def Call(self, fun, *args, **kwargs): |
197 return fun(*args, **kwargs) | 197 return fun(*args, **kwargs) |
198 | 198 |
199 def Command(self, cmd, args="", prefix="", pipe=True): | 199 def Command(self, cmd, args="", prefix="", pipe=True): |
200 return Command(cmd, args, prefix, pipe) | 200 return Command(cmd, args, prefix, pipe) |
201 | 201 |
202 def ReadLine(self): | 202 def ReadLine(self): |
203 return sys.stdin.readline().strip() | 203 return sys.stdin.readline().strip() |
204 | 204 |
205 def ReadURL(self, url, params=None): | 205 def ReadURL(self, url, params=None): |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 # Skip step if requirement is not met. | 263 # Skip step if requirement is not met. |
264 if self._requires and not self._state.get(self._requires): | 264 if self._requires and not self._state.get(self._requires): |
265 return | 265 return |
266 | 266 |
267 print ">>> Step %d: %s" % (self._number, self._text) | 267 print ">>> Step %d: %s" % (self._number, self._text) |
268 self.RunStep() | 268 self.RunStep() |
269 | 269 |
270 # Persist state. | 270 # Persist state. |
271 TextToFile(json.dumps(self._state), state_file) | 271 TextToFile(json.dumps(self._state), state_file) |
272 | 272 |
273 def RunStep(self): | 273 def RunStep(self): # pragma: no cover |
274 raise NotImplementedError | 274 raise NotImplementedError |
275 | 275 |
276 def Retry(self, cb, retry_on=None, wait_plan=None): | 276 def Retry(self, cb, retry_on=None, wait_plan=None): |
277 """ Retry a function. | 277 """ Retry a function. |
278 Params: | 278 Params: |
279 cb: The function to retry. | 279 cb: The function to retry. |
280 retry_on: A callback that takes the result of the function and returns | 280 retry_on: A callback that takes the result of the function and returns |
281 True if the function should be retried. A function throwing an | 281 True if the function should be retried. A function throwing an |
282 exception is always retried. | 282 exception is always retried. |
283 wait_plan: A list of waiting delays between retries in seconds. The | 283 wait_plan: A list of waiting delays between retries in seconds. The |
284 maximum number of retries is len(wait_plan). | 284 maximum number of retries is len(wait_plan). |
285 """ | 285 """ |
286 retry_on = retry_on or (lambda x: False) | 286 retry_on = retry_on or (lambda x: False) |
287 wait_plan = list(wait_plan or []) | 287 wait_plan = list(wait_plan or []) |
288 wait_plan.reverse() | 288 wait_plan.reverse() |
289 while True: | 289 while True: |
290 got_exception = False | 290 got_exception = False |
291 try: | 291 try: |
292 result = cb() | 292 result = cb() |
293 except NoRetryException, e: | 293 except NoRetryException, e: |
294 raise e | 294 raise e |
295 except Exception: | 295 except Exception: |
296 got_exception = True | 296 got_exception = True |
297 if got_exception or retry_on(result): | 297 if got_exception or retry_on(result): |
298 if not wait_plan: | 298 if not wait_plan: # pragma: no cover |
299 raise Exception("Retried too often. Giving up.") | 299 raise Exception("Retried too often. Giving up.") |
300 wait_time = wait_plan.pop() | 300 wait_time = wait_plan.pop() |
301 print "Waiting for %f seconds." % wait_time | 301 print "Waiting for %f seconds." % wait_time |
302 self._side_effect_handler.Sleep(wait_time) | 302 self._side_effect_handler.Sleep(wait_time) |
303 print "Retrying..." | 303 print "Retrying..." |
304 else: | 304 else: |
305 return result | 305 return result |
306 | 306 |
307 def ReadLine(self, default=None): | 307 def ReadLine(self, default=None): |
308 # Don't prompt in forced mode. | 308 # Don't prompt in forced mode. |
(...skipping 27 matching lines...) Expand all Loading... |
336 def GetDate(self): | 336 def GetDate(self): |
337 return self._side_effect_handler.GetDate() | 337 return self._side_effect_handler.GetDate() |
338 | 338 |
339 def Die(self, msg=""): | 339 def Die(self, msg=""): |
340 if msg != "": | 340 if msg != "": |
341 print "Error: %s" % msg | 341 print "Error: %s" % msg |
342 print "Exiting" | 342 print "Exiting" |
343 raise Exception(msg) | 343 raise Exception(msg) |
344 | 344 |
345 def DieNoManualMode(self, msg=""): | 345 def DieNoManualMode(self, msg=""): |
346 if not self._options.manual: | 346 if not self._options.manual: # pragma: no cover |
347 msg = msg or "Only available in manual mode." | 347 msg = msg or "Only available in manual mode." |
348 self.Die(msg) | 348 self.Die(msg) |
349 | 349 |
350 def Confirm(self, msg): | 350 def Confirm(self, msg): |
351 print "%s [Y/n] " % msg, | 351 print "%s [Y/n] " % msg, |
352 answer = self.ReadLine(default="Y") | 352 answer = self.ReadLine(default="Y") |
353 return answer == "" or answer == "Y" or answer == "y" | 353 return answer == "" or answer == "Y" or answer == "y" |
354 | 354 |
355 def DeleteBranch(self, name): | 355 def DeleteBranch(self, name): |
356 for line in self.GitBranch().splitlines(): | 356 for line in self.GitBranch().splitlines(): |
357 if re.match(r".*\s+%s$" % name, line): | 357 if re.match(r".*\s+%s$" % name, line): |
358 msg = "Branch %s exists, do you want to delete it?" % name | 358 msg = "Branch %s exists, do you want to delete it?" % name |
359 if self.Confirm(msg): | 359 if self.Confirm(msg): |
360 self.GitDeleteBranch(name) | 360 self.GitDeleteBranch(name) |
361 print "Branch %s deleted." % name | 361 print "Branch %s deleted." % name |
362 else: | 362 else: |
363 msg = "Can't continue. Please delete branch %s and try again." % name | 363 msg = "Can't continue. Please delete branch %s and try again." % name |
364 self.Die(msg) | 364 self.Die(msg) |
365 | 365 |
366 def InitialEnvironmentChecks(self): | 366 def InitialEnvironmentChecks(self): |
367 # Cancel if this is not a git checkout. | 367 # Cancel if this is not a git checkout. |
368 if not os.path.exists(self._config[DOT_GIT_LOCATION]): | 368 if not os.path.exists(self._config[DOT_GIT_LOCATION]): # pragma: no cover |
369 self.Die("This is not a git checkout, this script won't work for you.") | 369 self.Die("This is not a git checkout, this script won't work for you.") |
370 | 370 |
371 # Cancel if EDITOR is unset or not executable. | 371 # Cancel if EDITOR is unset or not executable. |
372 if (self._options.requires_editor and (not os.environ.get("EDITOR") or | 372 if (self._options.requires_editor and (not os.environ.get("EDITOR") or |
373 Command("which", os.environ["EDITOR"]) is None)): | 373 Command("which", os.environ["EDITOR"]) is None)): # pragma: no cover |
374 self.Die("Please set your EDITOR environment variable, you'll need it.") | 374 self.Die("Please set your EDITOR environment variable, you'll need it.") |
375 | 375 |
376 def CommonPrepare(self): | 376 def CommonPrepare(self): |
377 # Check for a clean workdir. | 377 # Check for a clean workdir. |
378 if not self.GitIsWorkdirClean(): | 378 if not self.GitIsWorkdirClean(): # pragma: no cover |
379 self.Die("Workspace is not clean. Please commit or undo your changes.") | 379 self.Die("Workspace is not clean. Please commit or undo your changes.") |
380 | 380 |
381 # Persist current branch. | 381 # Persist current branch. |
382 self["current_branch"] = self.GitCurrentBranch() | 382 self["current_branch"] = self.GitCurrentBranch() |
383 | 383 |
384 # Fetch unfetched revisions. | 384 # Fetch unfetched revisions. |
385 self.GitSVNFetch() | 385 self.GitSVNFetch() |
386 | 386 |
387 def PrepareBranch(self): | 387 def PrepareBranch(self): |
388 # Get ahold of a safe temporary branch and check it out. | 388 # Get ahold of a safe temporary branch and check it out. |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 | 500 |
501 def _Description(self): | 501 def _Description(self): |
502 return None | 502 return None |
503 | 503 |
504 def _PrepareOptions(self, parser): | 504 def _PrepareOptions(self, parser): |
505 pass | 505 pass |
506 | 506 |
507 def _ProcessOptions(self, options): | 507 def _ProcessOptions(self, options): |
508 return True | 508 return True |
509 | 509 |
510 def _Steps(self): | 510 def _Steps(self): # pragma: no cover |
511 raise Exception("Not implemented.") | 511 raise Exception("Not implemented.") |
512 | 512 |
513 def MakeOptions(self, args=None): | 513 def MakeOptions(self, args=None): |
514 parser = argparse.ArgumentParser(description=self._Description()) | 514 parser = argparse.ArgumentParser(description=self._Description()) |
515 parser.add_argument("-a", "--author", default="", | 515 parser.add_argument("-a", "--author", default="", |
516 help="The author email used for rietveld.") | 516 help="The author email used for rietveld.") |
517 parser.add_argument("-r", "--reviewer", default="", | 517 parser.add_argument("-r", "--reviewer", default="", |
518 help="The account name to be used for reviews.") | 518 help="The account name to be used for reviews.") |
519 parser.add_argument("-s", "--step", | 519 parser.add_argument("-s", "--step", |
520 help="Specify the step where to start work. Default: 0.", | 520 help="Specify the step where to start work. Default: 0.", |
521 default=0, type=int) | 521 default=0, type=int) |
522 | 522 |
523 self._PrepareOptions(parser) | 523 self._PrepareOptions(parser) |
524 | 524 |
525 if args is None: | 525 if args is None: # pragma: no cover |
526 options = parser.parse_args() | 526 options = parser.parse_args() |
527 else: | 527 else: |
528 options = parser.parse_args(args) | 528 options = parser.parse_args(args) |
529 | 529 |
530 # Process common options. | 530 # Process common options. |
531 if options.step < 0: | 531 if options.step < 0: # pragma: no cover |
532 print "Bad step number %d" % options.step | 532 print "Bad step number %d" % options.step |
533 parser.print_help() | 533 parser.print_help() |
534 return None | 534 return None |
535 | 535 |
536 # Defaults for options, common to all scripts. | 536 # Defaults for options, common to all scripts. |
537 options.manual = getattr(options, "manual", True) | 537 options.manual = getattr(options, "manual", True) |
538 options.force = getattr(options, "force", False) | 538 options.force = getattr(options, "force", False) |
539 | 539 |
540 # Derived options. | 540 # Derived options. |
541 options.requires_editor = not options.force | 541 options.requires_editor = not options.force |
(...skipping 19 matching lines...) Expand all Loading... |
561 steps = [] | 561 steps = [] |
562 for (number, step_class) in enumerate(step_classes): | 562 for (number, step_class) in enumerate(step_classes): |
563 steps.append(MakeStep(step_class, number, self._state, self._config, | 563 steps.append(MakeStep(step_class, number, self._state, self._config, |
564 options, self._side_effect_handler)) | 564 options, self._side_effect_handler)) |
565 for step in steps[options.step:]: | 565 for step in steps[options.step:]: |
566 step.Run() | 566 step.Run() |
567 return 0 | 567 return 0 |
568 | 568 |
569 def Run(self, args=None): | 569 def Run(self, args=None): |
570 return self.RunSteps(self._Steps(), args) | 570 return self.RunSteps(self._Steps(), args) |
OLD | NEW |