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 | 6 # This script retrieves the history of all V8 branches 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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 | 63 |
64 def SortBranches(branches): | 64 def SortBranches(branches): |
65 """Sort branches with version number names.""" | 65 """Sort branches with version number names.""" |
66 return sorted(branches, key=SortingKey, reverse=True) | 66 return sorted(branches, key=SortingKey, reverse=True) |
67 | 67 |
68 | 68 |
69 def FilterDuplicatesAndReverse(cr_releases): | 69 def FilterDuplicatesAndReverse(cr_releases): |
70 """Returns the chromium releases in reverse order filtered by v8 revision | 70 """Returns the chromium releases in reverse order filtered by v8 revision |
71 duplicates. | 71 duplicates. |
72 | 72 |
73 cr_releases is a list of [cr_rev, v8_rev] reverse-sorted by cr_rev. | 73 cr_releases is a list of [cr_rev, v8_hsh] reverse-sorted by cr_rev. |
74 """ | 74 """ |
75 last = "" | 75 last = "" |
76 result = [] | 76 result = [] |
77 for release in reversed(cr_releases): | 77 for release in reversed(cr_releases): |
78 if last == release[1]: | 78 if last == release[1]: |
79 continue | 79 continue |
80 last = release[1] | 80 last = release[1] |
81 result.append(release) | 81 result.append(release) |
82 return result | 82 return result |
83 | 83 |
84 | 84 |
85 def BuildRevisionRanges(cr_releases): | 85 def BuildRevisionRanges(cr_releases): |
86 """Returns a mapping of v8 revision -> chromium ranges. | 86 """Returns a mapping of v8 revision -> chromium ranges. |
87 The ranges are comma-separated, each range has the form R1:R2. The newest | 87 The ranges are comma-separated, each range has the form R1:R2. The newest |
88 entry is the only one of the form R1, as there is no end range. | 88 entry is the only one of the form R1, as there is no end range. |
89 | 89 |
90 cr_releases is a list of [cr_rev, v8_rev] reverse-sorted by cr_rev. | 90 cr_releases is a list of [cr_rev, v8_hsh] reverse-sorted by cr_rev. |
91 cr_rev either refers to a chromium svn revision or a chromium branch number. | 91 cr_rev either refers to a chromium commit position or a chromium branch |
| 92 number. |
92 """ | 93 """ |
93 range_lists = {} | 94 range_lists = {} |
94 cr_releases = FilterDuplicatesAndReverse(cr_releases) | 95 cr_releases = FilterDuplicatesAndReverse(cr_releases) |
95 | 96 |
96 # Visit pairs of cr releases from oldest to newest. | 97 # Visit pairs of cr releases from oldest to newest. |
97 for cr_from, cr_to in itertools.izip( | 98 for cr_from, cr_to in itertools.izip( |
98 cr_releases, itertools.islice(cr_releases, 1, None)): | 99 cr_releases, itertools.islice(cr_releases, 1, None)): |
99 | 100 |
100 # Assume the chromium revisions are all different. | 101 # Assume the chromium revisions are all different. |
101 assert cr_from[0] != cr_to[0] | 102 assert cr_from[0] != cr_to[0] |
102 | 103 |
103 # TODO(machenbach): Subtraction is not git friendly. | |
104 ran = "%s:%d" % (cr_from[0], int(cr_to[0]) - 1) | 104 ran = "%s:%d" % (cr_from[0], int(cr_to[0]) - 1) |
105 | 105 |
106 # Collect the ranges in lists per revision. | 106 # Collect the ranges in lists per revision. |
107 range_lists.setdefault(cr_from[1], []).append(ran) | 107 range_lists.setdefault(cr_from[1], []).append(ran) |
108 | 108 |
109 # Add the newest revision. | 109 # Add the newest revision. |
110 if cr_releases: | 110 if cr_releases: |
111 range_lists.setdefault(cr_releases[-1][1], []).append(cr_releases[-1][0]) | 111 range_lists.setdefault(cr_releases[-1][1], []).append(cr_releases[-1][0]) |
112 | 112 |
113 # Stringify and comma-separate the range lists. | 113 # Stringify and comma-separate the range lists. |
114 return dict((rev, ", ".join(ran)) for rev, ran in range_lists.iteritems()) | 114 return dict((hsh, ", ".join(ran)) for hsh, ran in range_lists.iteritems()) |
115 | 115 |
116 | 116 |
117 def MatchSafe(match): | 117 def MatchSafe(match): |
118 if match: | 118 if match: |
119 return match.group(1) | 119 return match.group(1) |
120 else: | 120 else: |
121 return "" | 121 return "" |
122 | 122 |
123 | 123 |
124 class Preparation(Step): | 124 class Preparation(Step): |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 body = self.GitLog(n=1, format="%B", git_hash=git_hash) | 200 body = self.GitLog(n=1, format="%B", git_hash=git_hash) |
201 | 201 |
202 patches = "" | 202 patches = "" |
203 if self["patch"] != "0": | 203 if self["patch"] != "0": |
204 version += ".%s" % self["patch"] | 204 version += ".%s" % self["patch"] |
205 if CHERRY_PICK_TITLE_GIT_RE.match(body.splitlines()[0]): | 205 if CHERRY_PICK_TITLE_GIT_RE.match(body.splitlines()[0]): |
206 patches = self.GetMergedPatchesGit(body) | 206 patches = self.GetMergedPatchesGit(body) |
207 else: | 207 else: |
208 patches = self.GetMergedPatches(body) | 208 patches = self.GetMergedPatches(body) |
209 | 209 |
210 title = self.GitLog(n=1, format="%s", git_hash=git_hash) | 210 if SortingKey("4.2.69") <= SortingKey(version): |
211 master_hash = self.GetMasterHashFromPush(title) | 211 master_hash = self.GetLatestReleaseBase(version=version) |
| 212 else: |
| 213 # Legacy: Before version 4.2.69, the master revision was determined |
| 214 # by commit message. |
| 215 title = self.GitLog(n=1, format="%s", git_hash=git_hash) |
| 216 master_hash = self.GetMasterHashFromPush(title) |
212 master_position = "" | 217 master_position = "" |
213 if master_hash: | 218 if master_hash: |
214 master_position = self.GetCommitPositionNumber(master_hash) | 219 master_position = self.GetCommitPositionNumber(master_hash) |
215 # TODO(machenbach): Add the commit position number. | |
216 return self.GetReleaseDict( | 220 return self.GetReleaseDict( |
217 git_hash, master_position, master_hash, branch, version, | 221 git_hash, master_position, master_hash, branch, version, |
218 patches, body), self["patch"] | 222 patches, body), self["patch"] |
219 | 223 |
220 def GetReleasesFromBranch(self, branch): | 224 def GetReleasesFromBranch(self, branch): |
221 self.GitReset(self.vc.RemoteBranch(branch)) | 225 self.GitReset(self.vc.RemoteBranch(branch)) |
222 if branch == self.vc.MasterBranch(): | 226 if branch == self.vc.MasterBranch(): |
223 return self.GetReleasesFromMaster() | 227 return self.GetReleasesFromMaster() |
224 | 228 |
225 releases = [] | 229 releases = [] |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 not self.GitCheckoutFileSafe(VERSION_FILE, revision)): | 261 not self.GitCheckoutFileSafe(VERSION_FILE, revision)): |
258 print "Skipping revision %s" % revision | 262 print "Skipping revision %s" % revision |
259 return [] # pragma: no cover | 263 return [] # pragma: no cover |
260 | 264 |
261 branches = map( | 265 branches = map( |
262 str.strip, | 266 str.strip, |
263 self.Git("branch -r --contains %s" % revision).strip().splitlines(), | 267 self.Git("branch -r --contains %s" % revision).strip().splitlines(), |
264 ) | 268 ) |
265 branch = "" | 269 branch = "" |
266 for b in branches: | 270 for b in branches: |
267 if b == "origin/candidates": | 271 if b.startswith("origin/"): |
268 branch = "candidates" | 272 branch = b.split("origin/")[1] |
269 break | 273 break |
270 if b.startswith("branch-heads/"): | 274 if b.startswith("branch-heads/"): |
271 branch = b.split("branch-heads/")[1] | 275 branch = b.split("branch-heads/")[1] |
272 break | 276 break |
273 else: | 277 else: |
274 print "Could not determine branch for %s" % revision | 278 print "Could not determine branch for %s" % revision |
275 | 279 |
276 release, _ = self.GetRelease(revision, branch) | 280 release, _ = self.GetRelease(revision, branch) |
277 releases.append(release) | 281 releases.append(release) |
278 | 282 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 return revision | 343 return revision |
340 return step.GetCommitPositionNumber( | 344 return step.GetCommitPositionNumber( |
341 revision, cwd=os.path.join(step._options.chromium, "v8")) | 345 revision, cwd=os.path.join(step._options.chromium, "v8")) |
342 | 346 |
343 | 347 |
344 class RetrieveChromiumV8Releases(Step): | 348 class RetrieveChromiumV8Releases(Step): |
345 MESSAGE = "Retrieve V8 releases from Chromium DEPS." | 349 MESSAGE = "Retrieve V8 releases from Chromium DEPS." |
346 | 350 |
347 def RunStep(self): | 351 def RunStep(self): |
348 cwd = self._options.chromium | 352 cwd = self._options.chromium |
349 releases = filter( | |
350 lambda r: r["branch"] in [self.vc.CandidateBranch(), | |
351 self.vc.MasterBranch()], | |
352 self["releases"]) | |
353 if not releases: # pragma: no cover | |
354 print "No releases detected. Skipping chromium history." | |
355 return True | |
356 | 353 |
357 # Update v8 checkout in chromium. | 354 # Update v8 checkout in chromium. |
358 self.GitFetchOrigin(cwd=os.path.join(cwd, "v8")) | 355 self.GitFetchOrigin(cwd=os.path.join(cwd, "v8")) |
359 | 356 |
360 oldest_v8_rev = int(releases[-1]["revision"]) | 357 # All v8 revisions we are interested in. |
| 358 releases_dict = dict((r["revision_git"], r) for r in self["releases"]) |
361 | 359 |
362 cr_releases = [] | 360 cr_releases = [] |
363 try: | 361 try: |
364 for git_hash in self.GitLog( | 362 for git_hash in self.GitLog( |
365 format="%H", grep="V8", cwd=cwd).splitlines(): | 363 format="%H", grep="V8", cwd=cwd).splitlines(): |
366 if "DEPS" not in self.GitChangedFiles(git_hash, cwd=cwd): | 364 if "DEPS" not in self.GitChangedFiles(git_hash, cwd=cwd): |
367 continue | 365 continue |
368 if not self.GitCheckoutFileSafe("DEPS", git_hash, cwd=cwd): | 366 if not self.GitCheckoutFileSafe("DEPS", git_hash, cwd=cwd): |
369 break # pragma: no cover | 367 break # pragma: no cover |
370 deps = FileToText(os.path.join(cwd, "DEPS")) | 368 deps = FileToText(os.path.join(cwd, "DEPS")) |
371 match = DEPS_RE.search(deps) | 369 match = DEPS_RE.search(deps) |
372 if match: | 370 if match: |
373 cr_rev = self.GetCommitPositionNumber(git_hash, cwd=cwd) | 371 cr_rev = self.GetCommitPositionNumber(git_hash, cwd=cwd) |
374 if cr_rev: | 372 if cr_rev: |
375 v8_rev = ConvertToCommitNumber(self, match.group(1)) | 373 v8_hsh = match.group(1) |
376 cr_releases.append([cr_rev, v8_rev]) | 374 cr_releases.append([cr_rev, v8_hsh]) |
377 | 375 |
378 # Stop after reaching beyond the last v8 revision we want to update. | 376 # Stop as soon as we find a v8 revision that we didn't fetch in the |
379 # We need a small buffer for possible revert/reland frenzies. | 377 # v8-revision-retrieval part above (i.e. a revision that's too old). |
380 # TODO(machenbach): Subtraction is not git friendly. | 378 if v8_hsh not in releases_dict: |
381 if int(v8_rev) < oldest_v8_rev - 100: | |
382 break # pragma: no cover | 379 break # pragma: no cover |
383 | 380 |
384 # Allow Ctrl-C interrupt. | 381 # Allow Ctrl-C interrupt. |
385 except (KeyboardInterrupt, SystemExit): # pragma: no cover | 382 except (KeyboardInterrupt, SystemExit): # pragma: no cover |
386 pass | 383 pass |
387 | 384 |
388 # Clean up. | 385 # Clean up. |
389 self.GitCheckoutFileSafe("DEPS", "HEAD", cwd=cwd) | 386 self.GitCheckoutFileSafe("DEPS", "HEAD", cwd=cwd) |
390 | 387 |
391 # Add the chromium ranges to the v8 candidates and master releases. | 388 # Add the chromium ranges to the v8 candidates and master releases. |
392 all_ranges = BuildRevisionRanges(cr_releases) | 389 all_ranges = BuildRevisionRanges(cr_releases) |
393 releases_dict = dict((r["revision"], r) for r in releases) | 390 |
394 for revision, ranges in all_ranges.iteritems(): | 391 for hsh, ranges in all_ranges.iteritems(): |
395 releases_dict.get(revision, {})["chromium_revision"] = ranges | 392 releases_dict.get(hsh, {})["chromium_revision"] = ranges |
396 | 393 |
397 | 394 |
398 # TODO(machenbach): Unify common code with method above. | 395 # TODO(machenbach): Unify common code with method above. |
399 class RietrieveChromiumBranches(Step): | 396 class RietrieveChromiumBranches(Step): |
400 MESSAGE = "Retrieve Chromium branch information." | 397 MESSAGE = "Retrieve Chromium branch information." |
401 | 398 |
402 def RunStep(self): | 399 def RunStep(self): |
403 cwd = self._options.chromium | 400 cwd = self._options.chromium |
404 cand_releases = filter(lambda r: r["branch"] == self.vc.CandidateBranch(), | |
405 self["releases"]) | |
406 if not cand_releases: # pragma: no cover | |
407 print "No candidates releases detected. Skipping chromium history." | |
408 return True | |
409 | 401 |
410 oldest_v8_rev = int(cand_releases[-1]["revision"]) | 402 # All v8 revisions we are interested in. |
| 403 releases_dict = dict((r["revision_git"], r) for r in self["releases"]) |
411 | 404 |
412 # Filter out irrelevant branches. | 405 # Filter out irrelevant branches. |
413 branches = filter(lambda r: re.match(r"branch-heads/\d+", r), | 406 branches = filter(lambda r: re.match(r"branch-heads/\d+", r), |
414 self.GitRemotes(cwd=cwd)) | 407 self.GitRemotes(cwd=cwd)) |
415 | 408 |
416 # Transform into pure branch numbers. | 409 # Transform into pure branch numbers. |
417 branches = map(lambda r: int(re.match(r"branch-heads/(\d+)", r).group(1)), | 410 branches = map(lambda r: int(re.match(r"branch-heads/(\d+)", r).group(1)), |
418 branches) | 411 branches) |
419 | 412 |
420 branches = sorted(branches, reverse=True) | 413 branches = sorted(branches, reverse=True) |
421 | 414 |
422 cr_branches = [] | 415 cr_branches = [] |
423 try: | 416 try: |
424 for branch in branches: | 417 for branch in branches: |
425 if not self.GitCheckoutFileSafe("DEPS", | 418 if not self.GitCheckoutFileSafe("DEPS", |
426 "branch-heads/%d" % branch, | 419 "branch-heads/%d" % branch, |
427 cwd=cwd): | 420 cwd=cwd): |
428 break # pragma: no cover | 421 break # pragma: no cover |
429 deps = FileToText(os.path.join(cwd, "DEPS")) | 422 deps = FileToText(os.path.join(cwd, "DEPS")) |
430 match = DEPS_RE.search(deps) | 423 match = DEPS_RE.search(deps) |
431 if match: | 424 if match: |
432 v8_rev = ConvertToCommitNumber(self, match.group(1)) | 425 v8_hsh = match.group(1) |
433 cr_branches.append([str(branch), v8_rev]) | 426 cr_branches.append([str(branch), v8_hsh]) |
434 | 427 |
435 # Stop after reaching beyond the last v8 revision we want to update. | 428 # Stop as soon as we find a v8 revision that we didn't fetch in the |
436 # We need a small buffer for possible revert/reland frenzies. | 429 # v8-revision-retrieval part above (i.e. a revision that's too old). |
437 # TODO(machenbach): Subtraction is not git friendly. | 430 if v8_hsh not in releases_dict: |
438 if int(v8_rev) < oldest_v8_rev - 100: | |
439 break # pragma: no cover | 431 break # pragma: no cover |
440 | 432 |
441 # Allow Ctrl-C interrupt. | 433 # Allow Ctrl-C interrupt. |
442 except (KeyboardInterrupt, SystemExit): # pragma: no cover | 434 except (KeyboardInterrupt, SystemExit): # pragma: no cover |
443 pass | 435 pass |
444 | 436 |
445 # Clean up. | 437 # Clean up. |
446 self.GitCheckoutFileSafe("DEPS", "HEAD", cwd=cwd) | 438 self.GitCheckoutFileSafe("DEPS", "HEAD", cwd=cwd) |
447 | 439 |
448 # Add the chromium branches to the v8 candidate releases. | 440 # Add the chromium branches to the v8 candidate releases. |
449 all_ranges = BuildRevisionRanges(cr_branches) | 441 all_ranges = BuildRevisionRanges(cr_branches) |
450 cand_dict = dict((r["revision"], r) for r in cand_releases) | |
451 for revision, ranges in all_ranges.iteritems(): | 442 for revision, ranges in all_ranges.iteritems(): |
452 cand_dict.get(revision, {})["chromium_branch"] = ranges | 443 releases_dict.get(revision, {})["chromium_branch"] = ranges |
453 | 444 |
454 | 445 |
455 class CleanUp(Step): | 446 class CleanUp(Step): |
456 MESSAGE = "Clean up." | 447 MESSAGE = "Clean up." |
457 | 448 |
458 def RunStep(self): | 449 def RunStep(self): |
459 self.GitCheckout("master", cwd=self._options.chromium) | 450 self.GitCheckout("master", cwd=self._options.chromium) |
460 self.GitDeleteBranch(self.Config("BRANCHNAME"), cwd=self._options.chromium) | 451 self.GitDeleteBranch(self.Config("BRANCHNAME"), cwd=self._options.chromium) |
461 self.CommonCleanup() | 452 self.CommonCleanup() |
462 | 453 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
513 UpdateChromiumCheckout, | 504 UpdateChromiumCheckout, |
514 RetrieveChromiumV8Releases, | 505 RetrieveChromiumV8Releases, |
515 RietrieveChromiumBranches, | 506 RietrieveChromiumBranches, |
516 CleanUp, | 507 CleanUp, |
517 WriteOutput, | 508 WriteOutput, |
518 ] | 509 ] |
519 | 510 |
520 | 511 |
521 if __name__ == "__main__": # pragma: no cover | 512 if __name__ == "__main__": # pragma: no cover |
522 sys.exit(Releases().Run()) | 513 sys.exit(Releases().Run()) |
OLD | NEW |