OLD | NEW |
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 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 # This script retrieves the history of all V8 branches and trunk revisions and | 6 # This script retrieves the history of all V8 branches and trunk revisions and |
7 # their corresponding Chromium revisions. | 7 # their corresponding Chromium revisions. |
8 | 8 |
9 # Requires a chromium checkout with branch heads: | 9 # Requires a chromium checkout with branch heads: |
10 # gclient sync --with_branch_heads | 10 # gclient sync --with_branch_heads |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 DEPS_RE = re.compile(r'^\s*(?:"v8_revision": "' | 50 DEPS_RE = re.compile(r'^\s*(?:"v8_revision": "' |
51 '|\(Var\("googlecode_url"\) % "v8"\) \+ "\/trunk@' | 51 '|\(Var\("googlecode_url"\) % "v8"\) \+ "\/trunk@' |
52 '|"http\:\/\/v8\.googlecode\.com\/svn\/trunk@)' | 52 '|"http\:\/\/v8\.googlecode\.com\/svn\/trunk@)' |
53 '([0-9]+)".*$', re.M) | 53 '([0-9]+)".*$', re.M) |
54 | 54 |
55 # Expression to pick tag and revision for bleeding edge tags. To be used with | 55 # Expression to pick tag and revision for bleeding edge tags. To be used with |
56 # output of 'svn log'. | 56 # output of 'svn log'. |
57 BLEEDING_EDGE_TAGS_RE = re.compile( | 57 BLEEDING_EDGE_TAGS_RE = re.compile( |
58 r"A \/tags\/([^\s]+) \(from \/branches\/bleeding_edge\:(\d+)\)") | 58 r"A \/tags\/([^\s]+) \(from \/branches\/bleeding_edge\:(\d+)\)") |
59 | 59 |
| 60 # Regular expression that matches a single commit footer line. |
| 61 COMMIT_FOOTER_ENTRY_RE = re.compile(r'([^:]+):\s+(.+)') |
| 62 |
| 63 # Footer metadata key for commit position. |
| 64 COMMIT_POSITION_FOOTER_KEY = 'Cr-Commit-Position' |
| 65 |
| 66 # Regular expression to parse a commit position |
| 67 COMMIT_POSITION_RE = re.compile(r'(.+)@\{#(\d+)\}') |
| 68 |
| 69 # Key for the 'git-svn' ID metadata commit footer entry. |
| 70 GIT_SVN_ID_FOOTER_KEY = 'git-svn-id' |
| 71 |
| 72 # e.g., git-svn-id: https://v8.googlecode.com/svn/trunk@23117 |
| 73 # ce2b1a6d-e550-0410-aec6-3dcde31c8c00 |
| 74 GIT_SVN_ID_RE = re.compile(r'((?:\w+)://[^@]+)@(\d+)\s+(?:[a-zA-Z0-9\-]+)') |
| 75 |
| 76 |
| 77 # Copied from bot_update.py. |
| 78 def GetCommitMessageFooterMap(message): |
| 79 """Returns: (dict) A dictionary of commit message footer entries. |
| 80 """ |
| 81 footers = {} |
| 82 |
| 83 # Extract the lines in the footer block. |
| 84 lines = [] |
| 85 for line in message.strip().splitlines(): |
| 86 line = line.strip() |
| 87 if len(line) == 0: |
| 88 del(lines[:]) |
| 89 continue |
| 90 lines.append(line) |
| 91 |
| 92 # Parse the footer |
| 93 for line in lines: |
| 94 m = COMMIT_FOOTER_ENTRY_RE.match(line) |
| 95 if not m: |
| 96 # If any single line isn't valid, the entire footer is invalid. |
| 97 footers.clear() |
| 98 return footers |
| 99 footers[m.group(1)] = m.group(2).strip() |
| 100 return footers |
| 101 |
| 102 |
| 103 # Copied from bot_update.py and modified for svn-like numbers only. |
| 104 def GetCommitPositionNumber(step, git_hash): |
| 105 """Dumps the 'git' log for a specific revision and parses out the commit |
| 106 position number. |
| 107 |
| 108 If a commit position metadata key is found, its number will be returned. |
| 109 |
| 110 Otherwise, we will search for a 'git-svn' metadata entry. If one is found, |
| 111 its SVN revision value is returned. |
| 112 """ |
| 113 git_log = step.GitLog(format='%B', n=1, git_hash=git_hash) |
| 114 footer_map = GetCommitMessageFooterMap(git_log) |
| 115 |
| 116 # Search for commit position metadata |
| 117 value = footer_map.get(COMMIT_POSITION_FOOTER_KEY) |
| 118 if value: |
| 119 match = COMMIT_POSITION_RE.match(value) |
| 120 if match: |
| 121 return match.group(2) |
| 122 |
| 123 # Extract the svn revision from 'git-svn' metadata |
| 124 value = footer_map.get(GIT_SVN_ID_FOOTER_KEY) |
| 125 if value: |
| 126 match = GIT_SVN_ID_RE.match(value) |
| 127 if match: |
| 128 return match.group(2) |
| 129 return None |
| 130 |
60 | 131 |
61 def SortBranches(branches): | 132 def SortBranches(branches): |
62 """Sort branches with version number names.""" | 133 """Sort branches with version number names.""" |
63 return sorted(branches, key=SortingKey, reverse=True) | 134 return sorted(branches, key=SortingKey, reverse=True) |
64 | 135 |
65 | 136 |
66 def FilterDuplicatesAndReverse(cr_releases): | 137 def FilterDuplicatesAndReverse(cr_releases): |
67 """Returns the chromium releases in reverse order filtered by v8 revision | 138 """Returns the chromium releases in reverse order filtered by v8 revision |
68 duplicates. | 139 duplicates. |
69 | 140 |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 self.GitCreateBranch(self.Config(BRANCHNAME)) | 374 self.GitCreateBranch(self.Config(BRANCHNAME)) |
304 | 375 |
305 | 376 |
306 class RetrieveChromiumV8Releases(Step): | 377 class RetrieveChromiumV8Releases(Step): |
307 MESSAGE = "Retrieve V8 releases from Chromium DEPS." | 378 MESSAGE = "Retrieve V8 releases from Chromium DEPS." |
308 REQUIRES = "chrome_path" | 379 REQUIRES = "chrome_path" |
309 | 380 |
310 def RunStep(self): | 381 def RunStep(self): |
311 os.chdir(self["chrome_path"]) | 382 os.chdir(self["chrome_path"]) |
312 | 383 |
313 trunk_releases = filter(lambda r: r["branch"] == "trunk", self["releases"]) | 384 releases = filter( |
314 if not trunk_releases: # pragma: no cover | 385 lambda r: r["branch"] in ["trunk", "bleeding_edge"], self["releases"]) |
315 print "No trunk releases detected. Skipping chromium history." | 386 if not releases: # pragma: no cover |
| 387 print "No releases detected. Skipping chromium history." |
316 return True | 388 return True |
317 | 389 |
318 oldest_v8_rev = int(trunk_releases[-1]["revision"]) | 390 oldest_v8_rev = int(releases[-1]["revision"]) |
319 | 391 |
320 cr_releases = [] | 392 cr_releases = [] |
321 try: | 393 try: |
322 for git_hash in self.GitLog(format="%H", grep="V8").splitlines(): | 394 for git_hash in self.GitLog(format="%H", grep="V8").splitlines(): |
323 if self._config[DEPS_FILE] not in self.GitChangedFiles(git_hash): | 395 if self._config[DEPS_FILE] not in self.GitChangedFiles(git_hash): |
324 continue | 396 continue |
325 if not self.GitCheckoutFileSafe(self._config[DEPS_FILE], git_hash): | 397 if not self.GitCheckoutFileSafe(self._config[DEPS_FILE], git_hash): |
326 break # pragma: no cover | 398 break # pragma: no cover |
327 deps = FileToText(self.Config(DEPS_FILE)) | 399 deps = FileToText(self.Config(DEPS_FILE)) |
328 match = DEPS_RE.search(deps) | 400 match = DEPS_RE.search(deps) |
329 if match: | 401 if match: |
330 svn_rev = self.GitSVNFindSVNRev(git_hash) | 402 cr_rev = GetCommitPositionNumber(self, git_hash) |
331 v8_rev = match.group(1) | 403 if cr_rev: |
332 cr_releases.append([svn_rev, v8_rev]) | 404 v8_rev = match.group(1) |
| 405 cr_releases.append([cr_rev, v8_rev]) |
333 | 406 |
334 # Stop after reaching beyond the last v8 revision we want to update. | 407 # Stop after reaching beyond the last v8 revision we want to update. |
335 # We need a small buffer for possible revert/reland frenzies. | 408 # We need a small buffer for possible revert/reland frenzies. |
336 # TODO(machenbach): Subtraction is not git friendly. | 409 # TODO(machenbach): Subtraction is not git friendly. |
337 if int(v8_rev) < oldest_v8_rev - 100: | 410 if int(v8_rev) < oldest_v8_rev - 100: |
338 break # pragma: no cover | 411 break # pragma: no cover |
339 | 412 |
340 # Allow Ctrl-C interrupt. | 413 # Allow Ctrl-C interrupt. |
341 except (KeyboardInterrupt, SystemExit): # pragma: no cover | 414 except (KeyboardInterrupt, SystemExit): # pragma: no cover |
342 pass | 415 pass |
343 | 416 |
344 # Clean up. | 417 # Clean up. |
345 self.GitCheckoutFileSafe(self._config[DEPS_FILE], "HEAD") | 418 self.GitCheckoutFileSafe(self._config[DEPS_FILE], "HEAD") |
346 | 419 |
347 # Add the chromium ranges to the v8 trunk releases. | 420 # Add the chromium ranges to the v8 trunk and bleeding_edge releases. |
348 all_ranges = BuildRevisionRanges(cr_releases) | 421 all_ranges = BuildRevisionRanges(cr_releases) |
349 trunk_dict = dict((r["revision"], r) for r in trunk_releases) | 422 releases_dict = dict((r["revision"], r) for r in releases) |
350 for revision, ranges in all_ranges.iteritems(): | 423 for revision, ranges in all_ranges.iteritems(): |
351 trunk_dict.get(revision, {})["chromium_revision"] = ranges | 424 releases_dict.get(revision, {})["chromium_revision"] = ranges |
352 | 425 |
353 | 426 |
354 # TODO(machenbach): Unify common code with method above. | 427 # TODO(machenbach): Unify common code with method above. |
355 class RietrieveChromiumBranches(Step): | 428 class RietrieveChromiumBranches(Step): |
356 MESSAGE = "Retrieve Chromium branch information." | 429 MESSAGE = "Retrieve Chromium branch information." |
357 REQUIRES = "chrome_path" | 430 REQUIRES = "chrome_path" |
358 | 431 |
359 def RunStep(self): | 432 def RunStep(self): |
360 os.chdir(self["chrome_path"]) | 433 os.chdir(self["chrome_path"]) |
361 | 434 |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 RetrieveChromiumV8Releases, | 545 RetrieveChromiumV8Releases, |
473 RietrieveChromiumBranches, | 546 RietrieveChromiumBranches, |
474 SwitchV8, | 547 SwitchV8, |
475 CleanUp, | 548 CleanUp, |
476 WriteOutput, | 549 WriteOutput, |
477 ] | 550 ] |
478 | 551 |
479 | 552 |
480 if __name__ == "__main__": # pragma: no cover | 553 if __name__ == "__main__": # pragma: no cover |
481 sys.exit(Releases(CONFIG).Run()) | 554 sys.exit(Releases(CONFIG).Run()) |
OLD | NEW |