Chromium Code Reviews| 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 13 matching lines...) Expand all Loading... | |
| 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 os | 29 import os |
| 30 import re | 30 import re |
| 31 import subprocess | 31 import subprocess |
| 32 import sys | 32 import sys |
| 33 import textwrap | 33 import textwrap |
| 34 import time | |
| 34 import urllib2 | 35 import urllib2 |
| 35 | 36 |
| 36 PERSISTFILE_BASENAME = "PERSISTFILE_BASENAME" | 37 PERSISTFILE_BASENAME = "PERSISTFILE_BASENAME" |
| 37 TEMP_BRANCH = "TEMP_BRANCH" | 38 TEMP_BRANCH = "TEMP_BRANCH" |
| 38 BRANCHNAME = "BRANCHNAME" | 39 BRANCHNAME = "BRANCHNAME" |
| 39 DOT_GIT_LOCATION = "DOT_GIT_LOCATION" | 40 DOT_GIT_LOCATION = "DOT_GIT_LOCATION" |
| 40 VERSION_FILE = "VERSION_FILE" | 41 VERSION_FILE = "VERSION_FILE" |
| 41 CHANGELOG_FILE = "CHANGELOG_FILE" | 42 CHANGELOG_FILE = "CHANGELOG_FILE" |
| 42 CHANGELOG_ENTRY_FILE = "CHANGELOG_ENTRY_FILE" | 43 CHANGELOG_ENTRY_FILE = "CHANGELOG_ENTRY_FILE" |
| 43 COMMITMSG_FILE = "COMMITMSG_FILE" | 44 COMMITMSG_FILE = "COMMITMSG_FILE" |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 166 | 167 |
| 167 if len(bug_groups) > 0: | 168 if len(bug_groups) > 0: |
| 168 return "(%s)" % ", ".join(bug_groups) | 169 return "(%s)" % ", ".join(bug_groups) |
| 169 else: | 170 else: |
| 170 return "" | 171 return "" |
| 171 | 172 |
| 172 | 173 |
| 173 # Some commands don't like the pipe, e.g. calling vi from within the script or | 174 # Some commands don't like the pipe, e.g. calling vi from within the script or |
| 174 # from subscripts like git cl upload. | 175 # from subscripts like git cl upload. |
| 175 def Command(cmd, args="", prefix="", pipe=True): | 176 def Command(cmd, args="", prefix="", pipe=True): |
| 177 # TODO(machenbach): Use timeout. | |
| 176 cmd_line = "%s %s %s" % (prefix, cmd, args) | 178 cmd_line = "%s %s %s" % (prefix, cmd, args) |
| 177 print "Command: %s" % cmd_line | 179 print "Command: %s" % cmd_line |
| 178 try: | 180 try: |
| 179 if pipe: | 181 if pipe: |
| 180 return subprocess.check_output(cmd_line, shell=True) | 182 return subprocess.check_output(cmd_line, shell=True) |
| 181 else: | 183 else: |
| 182 return subprocess.check_call(cmd_line, shell=True) | 184 return subprocess.check_call(cmd_line, shell=True) |
| 183 except subprocess.CalledProcessError: | 185 except subprocess.CalledProcessError: |
| 184 return None | 186 return None |
| 185 | 187 |
| 186 | 188 |
| 187 # Wrapper for side effects. | 189 # Wrapper for side effects. |
| 188 class SideEffectHandler(object): | 190 class SideEffectHandler(object): |
| 189 def Command(self, cmd, args="", prefix="", pipe=True): | 191 def Command(self, cmd, args="", prefix="", pipe=True): |
| 190 return Command(cmd, args, prefix, pipe) | 192 return Command(cmd, args, prefix, pipe) |
| 191 | 193 |
| 192 def ReadLine(self): | 194 def ReadLine(self): |
| 193 return sys.stdin.readline().strip() | 195 return sys.stdin.readline().strip() |
| 194 | 196 |
| 195 def ReadURL(self, url): | 197 def ReadURL(self, url): |
| 196 # pylint: disable=E1121 | 198 # pylint: disable=E1121 |
| 197 url_fh = urllib2.urlopen(url, None, 60) | 199 url_fh = urllib2.urlopen(url, None, 60) |
| 198 try: | 200 try: |
| 199 return url_fh.read() | 201 return url_fh.read() |
| 200 finally: | 202 finally: |
| 201 url_fh.close() | 203 url_fh.close() |
| 202 | 204 |
| 205 def Sleep(seconds): | |
| 206 time.sleep(seconds) | |
| 207 | |
| 203 DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler() | 208 DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler() |
| 204 | 209 |
| 205 | 210 |
| 206 class Step(object): | 211 class Step(object): |
| 207 def __init__(self, text, requires, number, config, state, options, handler): | 212 def __init__(self, text, requires, number, config, state, options, handler): |
| 208 self._text = text | 213 self._text = text |
| 209 self._requires = requires | 214 self._requires = requires |
| 210 self._number = number | 215 self._number = number |
| 211 self._config = config | 216 self._config = config |
| 212 self._state = state | 217 self._state = state |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 224 if self._requires: | 229 if self._requires: |
| 225 self.RestoreIfUnset(self._requires) | 230 self.RestoreIfUnset(self._requires) |
| 226 if not self._state[self._requires]: | 231 if not self._state[self._requires]: |
| 227 return | 232 return |
| 228 print ">>> Step %d: %s" % (self._number, self._text) | 233 print ">>> Step %d: %s" % (self._number, self._text) |
| 229 self.RunStep() | 234 self.RunStep() |
| 230 | 235 |
| 231 def RunStep(self): | 236 def RunStep(self): |
| 232 raise NotImplementedError | 237 raise NotImplementedError |
| 233 | 238 |
| 239 def Retry(self, cb, retry_on=None, wait_plan=None): | |
| 240 """ Retry a function. | |
| 241 Params: | |
| 242 cb: The function to retry. | |
| 243 retry_on: A callback that takes the result of the function and returns Tru e | |
|
Jakob Kummerow
2013/11/28 13:47:27
nit: 80col
Michael Achenbach
2013/11/28 14:28:17
Done.
| |
| 244 if the function should be retried. A function throwing an | |
| 245 exception is always retried. | |
| 246 wait_plan: A list of waiting delays between retries in seconds. The maximu m | |
|
Jakob Kummerow
2013/11/28 13:47:27
nit: 80col
Michael Achenbach
2013/11/28 14:28:17
Done.
| |
| 247 number of retries is len(wait_plan). | |
| 248 """ | |
| 249 retry_on = retry_on or (lambda x: False) | |
| 250 wait_plan = list(wait_plan or []) | |
|
Jakob Kummerow
2013/11/28 13:47:27
I don't think the explicit list() conversion is ne
Michael Achenbach
2013/11/28 14:28:17
I'd rather keep it, since the method has side effe
| |
| 251 # Sentinel for the first try. | |
|
Jakob Kummerow
2013/11/28 13:47:27
s/first/last/! This is seriously misleading.
Here
Michael Achenbach
2013/11/28 14:28:17
I take it :) Just added an initialization of got_e
| |
| 252 wait_plan.append(0) | |
| 253 wait_plan.reverse() | |
| 254 while wait_plan: | |
| 255 got_exception = False | |
| 256 try: | |
| 257 result = cb() | |
| 258 except Exception: | |
| 259 got_exception = True | |
| 260 if got_exception or retry_on(result): | |
| 261 wait_time = wait_plan.pop() | |
| 262 print "Waiting for %f seconds." % wait_time | |
| 263 self._side_effect_handler.Sleep(wait_time) | |
| 264 print "Retrying..." | |
| 265 else: | |
| 266 return result | |
| 267 raise Exception("Retried too often. Giving up.") | |
| 268 | |
| 234 def ReadLine(self, default=None): | 269 def ReadLine(self, default=None): |
| 235 # Don't prompt in forced mode. | 270 # Don't prompt in forced mode. |
| 236 if self._options and self._options.f and default is not None: | 271 if self._options and self._options.f and default is not None: |
| 237 print "%s (forced)" % default | 272 print "%s (forced)" % default |
| 238 return default | 273 return default |
| 239 else: | 274 else: |
| 240 return self._side_effect_handler.ReadLine() | 275 return self._side_effect_handler.ReadLine() |
| 241 | 276 |
| 242 def Git(self, args="", prefix="", pipe=True): | 277 def Git(self, args="", prefix="", pipe=True, retry_on=None): |
| 243 return self._side_effect_handler.Command("git", args, prefix, pipe) | 278 cmd = lambda: self._side_effect_handler.Command("git", args, prefix, pipe) |
| 279 return self.Retry(cmd, retry_on, [5, 30]) | |
| 244 | 280 |
| 245 def Editor(self, args): | 281 def Editor(self, args): |
| 246 return self._side_effect_handler.Command(os.environ["EDITOR"], args, | 282 return self._side_effect_handler.Command(os.environ["EDITOR"], args, |
| 247 pipe=False) | 283 pipe=False) |
| 248 | 284 |
| 249 def ReadURL(self, url): | 285 def ReadURL(self, url, retry_on=None, wait_plan=None): |
| 250 return self._side_effect_handler.ReadURL(url) | 286 wait_plan = wait_plan or [3, 10, 30] |
|
Jakob Kummerow
2013/11/28 13:47:27
I'd give the server much more time. Maybe [3, 60,
Michael Achenbach
2013/11/28 14:28:17
Done.
| |
| 287 cmd = lambda: self._side_effect_handler.ReadURL(url) | |
| 288 return self.Retry(cmd, retry_on, wait_plan) | |
| 251 | 289 |
| 252 def Die(self, msg=""): | 290 def Die(self, msg=""): |
| 253 if msg != "": | 291 if msg != "": |
| 254 print "Error: %s" % msg | 292 print "Error: %s" % msg |
| 255 print "Exiting" | 293 print "Exiting" |
| 256 raise Exception(msg) | 294 raise Exception(msg) |
| 257 | 295 |
| 258 def DieInForcedMode(self, msg=""): | 296 def DieInForcedMode(self, msg=""): |
| 259 if self._options and self._options.f: | 297 if self._options and self._options.f: |
| 260 msg = msg or "Not implemented in forced mode." | 298 msg = msg or "Not implemented in forced mode." |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 440 options, | 478 options, |
| 441 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): | 479 side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER): |
| 442 state = {} | 480 state = {} |
| 443 steps = [] | 481 steps = [] |
| 444 for (number, step_class) in enumerate(step_classes): | 482 for (number, step_class) in enumerate(step_classes): |
| 445 steps.append(MakeStep(step_class, number, state, config, | 483 steps.append(MakeStep(step_class, number, state, config, |
| 446 options, side_effect_handler)) | 484 options, side_effect_handler)) |
| 447 | 485 |
| 448 for step in steps[options.s:]: | 486 for step in steps[options.s:]: |
| 449 step.Run() | 487 step.Run() |
| OLD | NEW |