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 |
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 |
11 # gclient fetch | 11 # gclient fetch |
12 | 12 |
13 import argparse | 13 import argparse |
14 import csv | 14 import csv |
15 import itertools | 15 import itertools |
16 import json | 16 import json |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
129 self.PrepareBranch() | 129 self.PrepareBranch() |
130 | 130 |
131 | 131 |
132 class RetrieveV8Releases(Step): | 132 class RetrieveV8Releases(Step): |
133 MESSAGE = "Retrieve all V8 releases." | 133 MESSAGE = "Retrieve all V8 releases." |
134 | 134 |
135 def ExceedsMax(self, releases): | 135 def ExceedsMax(self, releases): |
136 return (self._options.max_releases > 0 | 136 return (self._options.max_releases > 0 |
137 and len(releases) > self._options.max_releases) | 137 and len(releases) > self._options.max_releases) |
138 | 138 |
139 def GetBleedingEdgeGitFromPush(self, title): | 139 def GetMasterHashFromPush(self, title): |
140 return MatchSafe(PUSH_MSG_GIT_RE.match(title)) | 140 return MatchSafe(PUSH_MSG_GIT_RE.match(title)) |
141 | 141 |
142 def GetMergedPatches(self, body): | 142 def GetMergedPatches(self, body): |
143 patches = MatchSafe(MERGE_MESSAGE_RE.search(body)) | 143 patches = MatchSafe(MERGE_MESSAGE_RE.search(body)) |
144 if not patches: | 144 if not patches: |
145 patches = MatchSafe(ROLLBACK_MESSAGE_RE.search(body)) | 145 patches = MatchSafe(ROLLBACK_MESSAGE_RE.search(body)) |
146 if patches: | 146 if patches: |
147 # Indicate reverted patches with a "-". | 147 # Indicate reverted patches with a "-". |
148 patches = "-%s" % patches | 148 patches = "-%s" % patches |
149 return patches | 149 return patches |
150 | 150 |
151 def GetMergedPatchesGit(self, body): | 151 def GetMergedPatchesGit(self, body): |
152 patches = [] | 152 patches = [] |
153 for line in body.splitlines(): | 153 for line in body.splitlines(): |
154 patch = MatchSafe(MERGE_MESSAGE_GIT_RE.match(line)) | 154 patch = MatchSafe(MERGE_MESSAGE_GIT_RE.match(line)) |
155 if patch: | 155 if patch: |
156 patches.append(patch) | 156 patches.append(patch) |
157 patch = MatchSafe(ROLLBACK_MESSAGE_GIT_RE.match(line)) | 157 patch = MatchSafe(ROLLBACK_MESSAGE_GIT_RE.match(line)) |
158 if patch: | 158 if patch: |
159 patches.append("-%s" % patch) | 159 patches.append("-%s" % patch) |
160 return ", ".join(patches) | 160 return ", ".join(patches) |
161 | 161 |
162 | 162 |
163 def GetReleaseDict( | 163 def GetReleaseDict( |
164 self, git_hash, bleeding_edge_rev, bleeding_edge_git, branch, version, | 164 self, git_hash, master_position, master_hash, branch, version, |
165 patches, cl_body): | 165 patches, cl_body): |
166 revision = self.GetCommitPositionNumber(git_hash) | 166 revision = self.GetCommitPositionNumber(git_hash) |
167 return { | 167 return { |
168 # The cr commit position number on the branch. | 168 # The cr commit position number on the branch. |
169 "revision": revision, | 169 "revision": revision, |
170 # The git revision on the branch. | 170 # The git revision on the branch. |
171 "revision_git": git_hash, | 171 "revision_git": git_hash, |
172 # The cr commit position number on master. | 172 # The cr commit position number on master. |
173 "bleeding_edge": bleeding_edge_rev, | 173 "bleeding_edge": master_position, |
tandrii(chromium)
2015/01/26 14:31:14
i guess, this key can't be changed :(
| |
174 # The same for git. | 174 # The same for git. |
175 "bleeding_edge_git": bleeding_edge_git, | 175 "bleeding_edge_git": master_hash, |
176 # The branch name. | 176 # The branch name. |
177 "branch": branch, | 177 "branch": branch, |
178 # The version for displaying in the form 3.26.3 or 3.26.3.12. | 178 # The version for displaying in the form 3.26.3 or 3.26.3.12. |
179 "version": version, | 179 "version": version, |
180 # The date of the commit. | 180 # The date of the commit. |
181 "date": self.GitLog(n=1, format="%ci", git_hash=git_hash), | 181 "date": self.GitLog(n=1, format="%ci", git_hash=git_hash), |
182 # Merged patches if available in the form 'r1234, r2345'. | 182 # Merged patches if available in the form 'r1234, r2345'. |
183 "patches_merged": patches, | 183 "patches_merged": patches, |
184 # Default for easier output formatting. | 184 # Default for easier output formatting. |
185 "chromium_revision": "", | 185 "chromium_revision": "", |
186 # Default for easier output formatting. | 186 # Default for easier output formatting. |
187 "chromium_branch": "", | 187 "chromium_branch": "", |
188 # Link to the CL on code review. Trunk pushes are not uploaded, so this | 188 # Link to the CL on code review. Candiates pushes are not uploaded, |
189 # field will be populated below with the recent roll CL link. | 189 # so this field will be populated below with the recent roll CL link. |
190 "review_link": MatchSafe(REVIEW_LINK_RE.search(cl_body)), | 190 "review_link": MatchSafe(REVIEW_LINK_RE.search(cl_body)), |
191 # Link to the commit message on google code. | 191 # Link to the commit message on google code. |
192 "revision_link": ("https://code.google.com/p/v8/source/detail?r=%s" | 192 "revision_link": ("https://code.google.com/p/v8/source/detail?r=%s" |
193 % revision), | 193 % revision), |
194 } | 194 } |
195 | 195 |
196 def GetRelease(self, git_hash, branch): | 196 def GetRelease(self, git_hash, branch): |
197 self.ReadAndPersistVersion() | 197 self.ReadAndPersistVersion() |
198 base_version = [self["major"], self["minor"], self["build"]] | 198 base_version = [self["major"], self["minor"], self["build"]] |
199 version = ".".join(base_version) | 199 version = ".".join(base_version) |
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 title = self.GitLog(n=1, format="%s", git_hash=git_hash) |
211 bleeding_edge_git = self.GetBleedingEdgeGitFromPush(title) | 211 master_hash = self.GetMasterHashFromPush(title) |
212 bleeding_edge_position = "" | 212 master_position = "" |
213 if bleeding_edge_git: | 213 if master_hash: |
214 bleeding_edge_position = self.GetCommitPositionNumber(bleeding_edge_git) | 214 master_position = self.GetCommitPositionNumber(master_hash) |
215 # TODO(machenbach): Add the commit position number. | 215 # TODO(machenbach): Add the commit position number. |
216 return self.GetReleaseDict( | 216 return self.GetReleaseDict( |
217 git_hash, bleeding_edge_position, bleeding_edge_git, branch, version, | 217 git_hash, master_position, master_hash, branch, version, |
218 patches, body), self["patch"] | 218 patches, body), self["patch"] |
219 | 219 |
220 def GetReleasesFromMaster(self): | 220 def GetReleasesFromMaster(self): |
221 # TODO(machenbach): Implement this in git as soon as we tag again on | 221 # TODO(machenbach): Implement this in git as soon as we tag again on |
222 # master. | 222 # master. |
223 # tag_text = self.SVN("log https://v8.googlecode.com/svn/tags -v | 223 # tag_text = self.SVN("log https://v8.googlecode.com/svn/tags -v |
224 # --limit 20") | 224 # --limit 20") |
225 # releases = [] | 225 # releases = [] |
226 # for (tag, revision) in re.findall(BLEEDING_EDGE_TAGS_RE, tag_text): | 226 # for (tag, revision) in re.findall(BLEEDING_EDGE_TAGS_RE, tag_text): |
227 # git_hash = self.vc.SvnGit(revision) | 227 # git_hash = self.vc.SvnGit(revision) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 | 263 |
264 # Clean up checked-out version file. | 264 # Clean up checked-out version file. |
265 self.GitCheckoutFileSafe(VERSION_FILE, "HEAD") | 265 self.GitCheckoutFileSafe(VERSION_FILE, "HEAD") |
266 return releases | 266 return releases |
267 | 267 |
268 def RunStep(self): | 268 def RunStep(self): |
269 self.GitCreateBranch(self._config["BRANCHNAME"]) | 269 self.GitCreateBranch(self._config["BRANCHNAME"]) |
270 branches = self.vc.GetBranches() | 270 branches = self.vc.GetBranches() |
271 releases = [] | 271 releases = [] |
272 if self._options.branch == 'recent': | 272 if self._options.branch == 'recent': |
273 # Get only recent development on trunk, beta and stable. | 273 # Get only recent development on candidates, beta and stable. |
274 if self._options.max_releases == 0: # pragma: no cover | 274 if self._options.max_releases == 0: # pragma: no cover |
275 self._options.max_releases = 10 | 275 self._options.max_releases = 10 |
276 beta, stable = SortBranches(branches)[0:2] | 276 beta, stable = SortBranches(branches)[0:2] |
277 releases += self.GetReleasesFromBranch(stable) | 277 releases += self.GetReleasesFromBranch(stable) |
278 releases += self.GetReleasesFromBranch(beta) | 278 releases += self.GetReleasesFromBranch(beta) |
279 releases += self.GetReleasesFromBranch(self.vc.CandidateBranch()) | 279 releases += self.GetReleasesFromBranch(self.vc.CandidateBranch()) |
280 releases += self.GetReleasesFromBranch(self.vc.MasterBranch()) | 280 releases += self.GetReleasesFromBranch(self.vc.MasterBranch()) |
281 elif self._options.branch == 'all': # pragma: no cover | 281 elif self._options.branch == 'all': # pragma: no cover |
282 # Retrieve the full release history. | 282 # Retrieve the full release history. |
283 for branch in branches: | 283 for branch in branches: |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
366 if int(v8_rev) < oldest_v8_rev - 100: | 366 if int(v8_rev) < oldest_v8_rev - 100: |
367 break # pragma: no cover | 367 break # pragma: no cover |
368 | 368 |
369 # Allow Ctrl-C interrupt. | 369 # Allow Ctrl-C interrupt. |
370 except (KeyboardInterrupt, SystemExit): # pragma: no cover | 370 except (KeyboardInterrupt, SystemExit): # pragma: no cover |
371 pass | 371 pass |
372 | 372 |
373 # Clean up. | 373 # Clean up. |
374 self.GitCheckoutFileSafe("DEPS", "HEAD", cwd=cwd) | 374 self.GitCheckoutFileSafe("DEPS", "HEAD", cwd=cwd) |
375 | 375 |
376 # Add the chromium ranges to the v8 trunk and bleeding_edge releases. | 376 # Add the chromium ranges to the v8 candidates and master releases. |
377 all_ranges = BuildRevisionRanges(cr_releases) | 377 all_ranges = BuildRevisionRanges(cr_releases) |
378 releases_dict = dict((r["revision"], r) for r in releases) | 378 releases_dict = dict((r["revision"], r) for r in releases) |
379 for revision, ranges in all_ranges.iteritems(): | 379 for revision, ranges in all_ranges.iteritems(): |
380 releases_dict.get(revision, {})["chromium_revision"] = ranges | 380 releases_dict.get(revision, {})["chromium_revision"] = ranges |
381 | 381 |
382 | 382 |
383 # TODO(machenbach): Unify common code with method above. | 383 # TODO(machenbach): Unify common code with method above. |
384 class RietrieveChromiumBranches(Step): | 384 class RietrieveChromiumBranches(Step): |
385 MESSAGE = "Retrieve Chromium branch information." | 385 MESSAGE = "Retrieve Chromium branch information." |
386 | 386 |
387 def RunStep(self): | 387 def RunStep(self): |
388 cwd = self._options.chromium | 388 cwd = self._options.chromium |
389 trunk_releases = filter(lambda r: r["branch"] == self.vc.CandidateBranch(), | 389 cand_releases = filter(lambda r: r["branch"] == self.vc.CandidateBranch(), |
390 self["releases"]) | 390 self["releases"]) |
391 if not trunk_releases: # pragma: no cover | 391 if not cand_releases: # pragma: no cover |
392 print "No trunk releases detected. Skipping chromium history." | 392 print "No candidates releases detected. Skipping chromium history." |
393 return True | 393 return True |
394 | 394 |
395 oldest_v8_rev = int(trunk_releases[-1]["revision"]) | 395 oldest_v8_rev = int(cand_releases[-1]["revision"]) |
396 | 396 |
397 # Filter out irrelevant branches. | 397 # Filter out irrelevant branches. |
398 branches = filter(lambda r: re.match(r"branch-heads/\d+", r), | 398 branches = filter(lambda r: re.match(r"branch-heads/\d+", r), |
399 self.GitRemotes(cwd=cwd)) | 399 self.GitRemotes(cwd=cwd)) |
400 | 400 |
401 # Transform into pure branch numbers. | 401 # Transform into pure branch numbers. |
402 branches = map(lambda r: int(re.match(r"branch-heads/(\d+)", r).group(1)), | 402 branches = map(lambda r: int(re.match(r"branch-heads/(\d+)", r).group(1)), |
403 branches) | 403 branches) |
404 | 404 |
405 branches = sorted(branches, reverse=True) | 405 branches = sorted(branches, reverse=True) |
(...skipping 17 matching lines...) Expand all Loading... | |
423 if int(v8_rev) < oldest_v8_rev - 100: | 423 if int(v8_rev) < oldest_v8_rev - 100: |
424 break # pragma: no cover | 424 break # pragma: no cover |
425 | 425 |
426 # Allow Ctrl-C interrupt. | 426 # Allow Ctrl-C interrupt. |
427 except (KeyboardInterrupt, SystemExit): # pragma: no cover | 427 except (KeyboardInterrupt, SystemExit): # pragma: no cover |
428 pass | 428 pass |
429 | 429 |
430 # Clean up. | 430 # Clean up. |
431 self.GitCheckoutFileSafe("DEPS", "HEAD", cwd=cwd) | 431 self.GitCheckoutFileSafe("DEPS", "HEAD", cwd=cwd) |
432 | 432 |
433 # Add the chromium branches to the v8 trunk releases. | 433 # Add the chromium branches to the v8 candidate releases. |
434 all_ranges = BuildRevisionRanges(cr_branches) | 434 all_ranges = BuildRevisionRanges(cr_branches) |
435 trunk_dict = dict((r["revision"], r) for r in trunk_releases) | 435 cand_dict = dict((r["revision"], r) for r in cand_releases) |
436 for revision, ranges in all_ranges.iteritems(): | 436 for revision, ranges in all_ranges.iteritems(): |
437 trunk_dict.get(revision, {})["chromium_branch"] = ranges | 437 cand_dict.get(revision, {})["chromium_branch"] = ranges |
438 | 438 |
439 | 439 |
440 class CleanUp(Step): | 440 class CleanUp(Step): |
441 MESSAGE = "Clean up." | 441 MESSAGE = "Clean up." |
442 | 442 |
443 def RunStep(self): | 443 def RunStep(self): |
444 self.GitCheckout("master", cwd=self._options.chromium) | 444 self.GitCheckout("master", cwd=self._options.chromium) |
445 self.GitDeleteBranch(self.Config("BRANCHNAME"), cwd=self._options.chromium) | 445 self.GitDeleteBranch(self.Config("BRANCHNAME"), cwd=self._options.chromium) |
446 self.CommonCleanup() | 446 self.CommonCleanup() |
447 | 447 |
(...skipping 16 matching lines...) Expand all Loading... | |
464 f.write(json.dumps(self["releases"])) | 464 f.write(json.dumps(self["releases"])) |
465 if not self._options.csv and not self._options.json: | 465 if not self._options.csv and not self._options.json: |
466 print self["releases"] # pragma: no cover | 466 print self["releases"] # pragma: no cover |
467 | 467 |
468 | 468 |
469 class Releases(ScriptsBase): | 469 class Releases(ScriptsBase): |
470 def _PrepareOptions(self, parser): | 470 def _PrepareOptions(self, parser): |
471 parser.add_argument("-b", "--branch", default="recent", | 471 parser.add_argument("-b", "--branch", default="recent", |
472 help=("The branch to analyze. If 'all' is specified, " | 472 help=("The branch to analyze. If 'all' is specified, " |
473 "analyze all branches. If 'recent' (default) " | 473 "analyze all branches. If 'recent' (default) " |
474 "is specified, track beta, stable and trunk.")) | 474 "is specified, track beta, stable and " |
475 "candidates.")) | |
475 parser.add_argument("-c", "--chromium", | 476 parser.add_argument("-c", "--chromium", |
476 help=("The path to your Chromium src/ " | 477 help=("The path to your Chromium src/ " |
477 "directory to automate the V8 roll.")) | 478 "directory to automate the V8 roll.")) |
478 parser.add_argument("--csv", help="Path to a CSV file for export.") | 479 parser.add_argument("--csv", help="Path to a CSV file for export.") |
479 parser.add_argument("-m", "--max-releases", type=int, default=0, | 480 parser.add_argument("-m", "--max-releases", type=int, default=0, |
480 help="The maximum number of releases to track.") | 481 help="The maximum number of releases to track.") |
481 parser.add_argument("--json", help="Path to a JSON file for export.") | 482 parser.add_argument("--json", help="Path to a JSON file for export.") |
482 | 483 |
483 def _ProcessOptions(self, options): # pragma: no cover | 484 def _ProcessOptions(self, options): # pragma: no cover |
484 return True | 485 return True |
(...skipping 12 matching lines...) Expand all Loading... | |
497 UpdateChromiumCheckout, | 498 UpdateChromiumCheckout, |
498 RetrieveChromiumV8Releases, | 499 RetrieveChromiumV8Releases, |
499 RietrieveChromiumBranches, | 500 RietrieveChromiumBranches, |
500 CleanUp, | 501 CleanUp, |
501 WriteOutput, | 502 WriteOutput, |
502 ] | 503 ] |
503 | 504 |
504 | 505 |
505 if __name__ == "__main__": # pragma: no cover | 506 if __name__ == "__main__": # pragma: no cover |
506 sys.exit(Releases().Run()) | 507 sys.exit(Releases().Run()) |
OLD | NEW |