| 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 |
| 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 |
| 17 import os | 17 import os |
| 18 import re | 18 import re |
| 19 import sys | 19 import sys |
| 20 | 20 |
| 21 from common_includes import * | 21 from common_includes import * |
| 22 | 22 |
| 23 DEPS_FILE = "DEPS_FILE" | |
| 24 CHROMIUM = "CHROMIUM" | 23 CHROMIUM = "CHROMIUM" |
| 25 | 24 |
| 26 CONFIG = { | 25 CONFIG = { |
| 27 BRANCHNAME: "retrieve-v8-releases", | 26 BRANCHNAME: "retrieve-v8-releases", |
| 28 PERSISTFILE_BASENAME: "/tmp/v8-releases-tempfile", | 27 PERSISTFILE_BASENAME: "/tmp/v8-releases-tempfile", |
| 29 DOT_GIT_LOCATION: ".git", | 28 DOT_GIT_LOCATION: ".git", |
| 30 VERSION_FILE: "src/version.cc", | 29 VERSION_FILE: "src/version.cc", |
| 31 DEPS_FILE: "DEPS", | |
| 32 } | 30 } |
| 33 | 31 |
| 34 # Expression for retrieving the bleeding edge revision from a commit message. | 32 # Expression for retrieving the bleeding edge revision from a commit message. |
| 35 PUSH_MESSAGE_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$") | 33 PUSH_MESSAGE_RE = re.compile(r".* \(based on bleeding_edge revision r(\d+)\)$") |
| 36 | 34 |
| 37 # Expression for retrieving the merged patches from a merge commit message | 35 # Expression for retrieving the merged patches from a merge commit message |
| 38 # (old and new format). | 36 # (old and new format). |
| 39 MERGE_MESSAGE_RE = re.compile(r"^.*[M|m]erged (.+)(\)| into).*$", re.M) | 37 MERGE_MESSAGE_RE = re.compile(r"^.*[M|m]erged (.+)(\)| into).*$", re.M) |
| 40 | 38 |
| 41 # Expression for retrieving reverted patches from a commit message (old and | 39 # Expression for retrieving reverted patches from a commit message (old and |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 else: # pragma: no cover | 259 else: # pragma: no cover |
| 262 # Retrieve history for a specified branch. | 260 # Retrieve history for a specified branch. |
| 263 assert self._options.branch in branches + ["trunk", "bleeding_edge"] | 261 assert self._options.branch in branches + ["trunk", "bleeding_edge"] |
| 264 releases += self.GetReleasesFromBranch(self._options.branch) | 262 releases += self.GetReleasesFromBranch(self._options.branch) |
| 265 | 263 |
| 266 self["releases"] = sorted(releases, | 264 self["releases"] = sorted(releases, |
| 267 key=lambda r: SortingKey(r["version"]), | 265 key=lambda r: SortingKey(r["version"]), |
| 268 reverse=True) | 266 reverse=True) |
| 269 | 267 |
| 270 | 268 |
| 271 # TODO(machenbach): Parts of the Chromium setup are c/p from the chromium_roll | |
| 272 # script -> unify. | |
| 273 class CheckChromium(Step): | |
| 274 MESSAGE = "Check the chromium checkout." | |
| 275 | |
| 276 def Run(self): | |
| 277 self["chrome_path"] = self._options.chromium | |
| 278 | |
| 279 | |
| 280 class SwitchChromium(Step): | 269 class SwitchChromium(Step): |
| 281 MESSAGE = "Switch to Chromium checkout." | 270 MESSAGE = "Switch to Chromium checkout." |
| 282 REQUIRES = "chrome_path" | |
| 283 | 271 |
| 284 def RunStep(self): | 272 def RunStep(self): |
| 285 self["v8_path"] = os.getcwd() | 273 cwd = self._options.chromium |
| 286 os.chdir(self["chrome_path"]) | |
| 287 # Check for a clean workdir. | 274 # Check for a clean workdir. |
| 288 if not self.GitIsWorkdirClean(): # pragma: no cover | 275 if not self.GitIsWorkdirClean(cwd=cwd): # pragma: no cover |
| 289 self.Die("Workspace is not clean. Please commit or undo your changes.") | 276 self.Die("Workspace is not clean. Please commit or undo your changes.") |
| 290 # Assert that the DEPS file is there. | 277 # Assert that the DEPS file is there. |
| 291 if not os.path.exists(self.Config(DEPS_FILE)): # pragma: no cover | 278 if not os.path.exists(os.path.join(cwd, "DEPS")): # pragma: no cover |
| 292 self.Die("DEPS file not present.") | 279 self.Die("DEPS file not present.") |
| 293 | 280 |
| 294 | 281 |
| 295 class UpdateChromiumCheckout(Step): | 282 class UpdateChromiumCheckout(Step): |
| 296 MESSAGE = "Update the checkout and create a new branch." | 283 MESSAGE = "Update the checkout and create a new branch." |
| 297 REQUIRES = "chrome_path" | |
| 298 | 284 |
| 299 def RunStep(self): | 285 def RunStep(self): |
| 300 os.chdir(self["chrome_path"]) | 286 cwd = self._options.chromium |
| 301 self.GitCheckout("master") | 287 self.GitCheckout("master", cwd=cwd) |
| 302 self.GitPull() | 288 self.GitPull(cwd=cwd) |
| 303 self.GitCreateBranch(self.Config(BRANCHNAME)) | 289 self.GitCreateBranch(self.Config(BRANCHNAME), cwd=cwd) |
| 304 | 290 |
| 305 | 291 |
| 306 def ConvertToCommitNumber(step, revision): | 292 def ConvertToCommitNumber(step, revision): |
| 307 # Simple check for git hashes. | 293 # Simple check for git hashes. |
| 308 if revision.isdigit() and len(revision) < 8: | 294 if revision.isdigit() and len(revision) < 8: |
| 309 return revision | 295 return revision |
| 310 try: | 296 return step.GitConvertToSVNRevision( |
| 311 # TODO(machenbach): Add cwd to git calls. | 297 revision, cwd=os.path.join(step._options.chromium, "v8")) |
| 312 os.chdir(os.path.join(step["chrome_path"], "v8")) | |
| 313 return step.GitConvertToSVNRevision(revision) | |
| 314 finally: | |
| 315 os.chdir(step["chrome_path"]) | |
| 316 | 298 |
| 317 | 299 |
| 318 class RetrieveChromiumV8Releases(Step): | 300 class RetrieveChromiumV8Releases(Step): |
| 319 MESSAGE = "Retrieve V8 releases from Chromium DEPS." | 301 MESSAGE = "Retrieve V8 releases from Chromium DEPS." |
| 320 REQUIRES = "chrome_path" | |
| 321 | 302 |
| 322 def RunStep(self): | 303 def RunStep(self): |
| 323 os.chdir(self["chrome_path"]) | 304 cwd = self._options.chromium |
| 324 | |
| 325 releases = filter( | 305 releases = filter( |
| 326 lambda r: r["branch"] in ["trunk", "bleeding_edge"], self["releases"]) | 306 lambda r: r["branch"] in ["trunk", "bleeding_edge"], self["releases"]) |
| 327 if not releases: # pragma: no cover | 307 if not releases: # pragma: no cover |
| 328 print "No releases detected. Skipping chromium history." | 308 print "No releases detected. Skipping chromium history." |
| 329 return True | 309 return True |
| 330 | 310 |
| 331 # Update v8 checkout in chromium. | 311 # Update v8 checkout in chromium. |
| 332 try: | 312 self.GitFetchOrigin(cwd=os.path.join(cwd, "v8")) |
| 333 # TODO(machenbach): Add cwd to git calls. | |
| 334 os.chdir(os.path.join(self["chrome_path"], "v8")) | |
| 335 self.GitFetchOrigin() | |
| 336 finally: | |
| 337 os.chdir(self["chrome_path"]) | |
| 338 | 313 |
| 339 oldest_v8_rev = int(releases[-1]["revision"]) | 314 oldest_v8_rev = int(releases[-1]["revision"]) |
| 340 | 315 |
| 341 cr_releases = [] | 316 cr_releases = [] |
| 342 try: | 317 try: |
| 343 for git_hash in self.GitLog(format="%H", grep="V8").splitlines(): | 318 for git_hash in self.GitLog( |
| 344 if self._config[DEPS_FILE] not in self.GitChangedFiles(git_hash): | 319 format="%H", grep="V8", cwd=cwd).splitlines(): |
| 320 if "DEPS" not in self.GitChangedFiles(git_hash, cwd=cwd): |
| 345 continue | 321 continue |
| 346 if not self.GitCheckoutFileSafe(self._config[DEPS_FILE], git_hash): | 322 if not self.GitCheckoutFileSafe("DEPS", git_hash, cwd=cwd): |
| 347 break # pragma: no cover | 323 break # pragma: no cover |
| 348 deps = FileToText(self.Config(DEPS_FILE)) | 324 deps = FileToText(os.path.join(cwd, "DEPS")) |
| 349 match = DEPS_RE.search(deps) | 325 match = DEPS_RE.search(deps) |
| 350 if match: | 326 if match: |
| 351 cr_rev = self.GetCommitPositionNumber(git_hash) | 327 cr_rev = self.GetCommitPositionNumber(git_hash, cwd=cwd) |
| 352 if cr_rev: | 328 if cr_rev: |
| 353 v8_rev = ConvertToCommitNumber(self, match.group(1)) | 329 v8_rev = ConvertToCommitNumber(self, match.group(1)) |
| 354 cr_releases.append([cr_rev, v8_rev]) | 330 cr_releases.append([cr_rev, v8_rev]) |
| 355 | 331 |
| 356 # Stop after reaching beyond the last v8 revision we want to update. | 332 # Stop after reaching beyond the last v8 revision we want to update. |
| 357 # We need a small buffer for possible revert/reland frenzies. | 333 # We need a small buffer for possible revert/reland frenzies. |
| 358 # TODO(machenbach): Subtraction is not git friendly. | 334 # TODO(machenbach): Subtraction is not git friendly. |
| 359 if int(v8_rev) < oldest_v8_rev - 100: | 335 if int(v8_rev) < oldest_v8_rev - 100: |
| 360 break # pragma: no cover | 336 break # pragma: no cover |
| 361 | 337 |
| 362 # Allow Ctrl-C interrupt. | 338 # Allow Ctrl-C interrupt. |
| 363 except (KeyboardInterrupt, SystemExit): # pragma: no cover | 339 except (KeyboardInterrupt, SystemExit): # pragma: no cover |
| 364 pass | 340 pass |
| 365 | 341 |
| 366 # Clean up. | 342 # Clean up. |
| 367 self.GitCheckoutFileSafe(self._config[DEPS_FILE], "HEAD") | 343 self.GitCheckoutFileSafe("DEPS", "HEAD", cwd=cwd) |
| 368 | 344 |
| 369 # Add the chromium ranges to the v8 trunk and bleeding_edge releases. | 345 # Add the chromium ranges to the v8 trunk and bleeding_edge releases. |
| 370 all_ranges = BuildRevisionRanges(cr_releases) | 346 all_ranges = BuildRevisionRanges(cr_releases) |
| 371 releases_dict = dict((r["revision"], r) for r in releases) | 347 releases_dict = dict((r["revision"], r) for r in releases) |
| 372 for revision, ranges in all_ranges.iteritems(): | 348 for revision, ranges in all_ranges.iteritems(): |
| 373 releases_dict.get(revision, {})["chromium_revision"] = ranges | 349 releases_dict.get(revision, {})["chromium_revision"] = ranges |
| 374 | 350 |
| 375 | 351 |
| 376 # TODO(machenbach): Unify common code with method above. | 352 # TODO(machenbach): Unify common code with method above. |
| 377 class RietrieveChromiumBranches(Step): | 353 class RietrieveChromiumBranches(Step): |
| 378 MESSAGE = "Retrieve Chromium branch information." | 354 MESSAGE = "Retrieve Chromium branch information." |
| 379 REQUIRES = "chrome_path" | |
| 380 | 355 |
| 381 def RunStep(self): | 356 def RunStep(self): |
| 382 os.chdir(self["chrome_path"]) | 357 cwd = self._options.chromium |
| 383 | |
| 384 trunk_releases = filter(lambda r: r["branch"] == "trunk", self["releases"]) | 358 trunk_releases = filter(lambda r: r["branch"] == "trunk", self["releases"]) |
| 385 if not trunk_releases: # pragma: no cover | 359 if not trunk_releases: # pragma: no cover |
| 386 print "No trunk releases detected. Skipping chromium history." | 360 print "No trunk releases detected. Skipping chromium history." |
| 387 return True | 361 return True |
| 388 | 362 |
| 389 oldest_v8_rev = int(trunk_releases[-1]["revision"]) | 363 oldest_v8_rev = int(trunk_releases[-1]["revision"]) |
| 390 | 364 |
| 391 # Filter out irrelevant branches. | 365 # Filter out irrelevant branches. |
| 392 branches = filter(lambda r: re.match(r"branch-heads/\d+", r), | 366 branches = filter(lambda r: re.match(r"branch-heads/\d+", r), |
| 393 self.GitRemotes()) | 367 self.GitRemotes(cwd=cwd)) |
| 394 | 368 |
| 395 # Transform into pure branch numbers. | 369 # Transform into pure branch numbers. |
| 396 branches = map(lambda r: int(re.match(r"branch-heads/(\d+)", r).group(1)), | 370 branches = map(lambda r: int(re.match(r"branch-heads/(\d+)", r).group(1)), |
| 397 branches) | 371 branches) |
| 398 | 372 |
| 399 branches = sorted(branches, reverse=True) | 373 branches = sorted(branches, reverse=True) |
| 400 | 374 |
| 401 cr_branches = [] | 375 cr_branches = [] |
| 402 try: | 376 try: |
| 403 for branch in branches: | 377 for branch in branches: |
| 404 if not self.GitCheckoutFileSafe(self._config[DEPS_FILE], | 378 if not self.GitCheckoutFileSafe("DEPS", |
| 405 "branch-heads/%d" % branch): | 379 "branch-heads/%d" % branch, |
| 380 cwd=cwd): |
| 406 break # pragma: no cover | 381 break # pragma: no cover |
| 407 deps = FileToText(self.Config(DEPS_FILE)) | 382 deps = FileToText(os.path.join(cwd, "DEPS")) |
| 408 match = DEPS_RE.search(deps) | 383 match = DEPS_RE.search(deps) |
| 409 if match: | 384 if match: |
| 410 v8_rev = ConvertToCommitNumber(self, match.group(1)) | 385 v8_rev = ConvertToCommitNumber(self, match.group(1)) |
| 411 cr_branches.append([str(branch), v8_rev]) | 386 cr_branches.append([str(branch), v8_rev]) |
| 412 | 387 |
| 413 # Stop after reaching beyond the last v8 revision we want to update. | 388 # Stop after reaching beyond the last v8 revision we want to update. |
| 414 # We need a small buffer for possible revert/reland frenzies. | 389 # We need a small buffer for possible revert/reland frenzies. |
| 415 # TODO(machenbach): Subtraction is not git friendly. | 390 # TODO(machenbach): Subtraction is not git friendly. |
| 416 if int(v8_rev) < oldest_v8_rev - 100: | 391 if int(v8_rev) < oldest_v8_rev - 100: |
| 417 break # pragma: no cover | 392 break # pragma: no cover |
| 418 | 393 |
| 419 # Allow Ctrl-C interrupt. | 394 # Allow Ctrl-C interrupt. |
| 420 except (KeyboardInterrupt, SystemExit): # pragma: no cover | 395 except (KeyboardInterrupt, SystemExit): # pragma: no cover |
| 421 pass | 396 pass |
| 422 | 397 |
| 423 # Clean up. | 398 # Clean up. |
| 424 self.GitCheckoutFileSafe(self._config[DEPS_FILE], "HEAD") | 399 self.GitCheckoutFileSafe("DEPS", "HEAD", cwd=cwd) |
| 425 | 400 |
| 426 # Add the chromium branches to the v8 trunk releases. | 401 # Add the chromium branches to the v8 trunk releases. |
| 427 all_ranges = BuildRevisionRanges(cr_branches) | 402 all_ranges = BuildRevisionRanges(cr_branches) |
| 428 trunk_dict = dict((r["revision"], r) for r in trunk_releases) | 403 trunk_dict = dict((r["revision"], r) for r in trunk_releases) |
| 429 for revision, ranges in all_ranges.iteritems(): | 404 for revision, ranges in all_ranges.iteritems(): |
| 430 trunk_dict.get(revision, {})["chromium_branch"] = ranges | 405 trunk_dict.get(revision, {})["chromium_branch"] = ranges |
| 431 | 406 |
| 432 | 407 |
| 433 class SwitchV8(Step): | |
| 434 MESSAGE = "Returning to V8 checkout." | |
| 435 REQUIRES = "chrome_path" | |
| 436 | |
| 437 def RunStep(self): | |
| 438 self.GitCheckout("master") | |
| 439 self.GitDeleteBranch(self.Config(BRANCHNAME)) | |
| 440 os.chdir(self["v8_path"]) | |
| 441 | |
| 442 | |
| 443 class CleanUp(Step): | 408 class CleanUp(Step): |
| 444 MESSAGE = "Clean up." | 409 MESSAGE = "Clean up." |
| 445 | 410 |
| 446 def RunStep(self): | 411 def RunStep(self): |
| 412 self.GitCheckout("master", cwd=self._options.chromium) |
| 413 self.GitDeleteBranch(self.Config(BRANCHNAME), cwd=self._options.chromium) |
| 447 self.CommonCleanup() | 414 self.CommonCleanup() |
| 448 | 415 |
| 449 | 416 |
| 450 class WriteOutput(Step): | 417 class WriteOutput(Step): |
| 451 MESSAGE = "Print output." | 418 MESSAGE = "Print output." |
| 452 | 419 |
| 453 def Run(self): | 420 def Run(self): |
| 454 if self._options.csv: | 421 if self._options.csv: |
| 455 with open(self._options.csv, "w") as f: | 422 with open(self._options.csv, "w") as f: |
| 456 writer = csv.DictWriter(f, | 423 writer = csv.DictWriter(f, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 481 help="The maximum number of releases to track.") | 448 help="The maximum number of releases to track.") |
| 482 parser.add_argument("--json", help="Path to a JSON file for export.") | 449 parser.add_argument("--json", help="Path to a JSON file for export.") |
| 483 | 450 |
| 484 def _ProcessOptions(self, options): # pragma: no cover | 451 def _ProcessOptions(self, options): # pragma: no cover |
| 485 return True | 452 return True |
| 486 | 453 |
| 487 def _Steps(self): | 454 def _Steps(self): |
| 488 return [ | 455 return [ |
| 489 Preparation, | 456 Preparation, |
| 490 RetrieveV8Releases, | 457 RetrieveV8Releases, |
| 491 CheckChromium, | |
| 492 SwitchChromium, | 458 SwitchChromium, |
| 493 UpdateChromiumCheckout, | 459 UpdateChromiumCheckout, |
| 494 RetrieveChromiumV8Releases, | 460 RetrieveChromiumV8Releases, |
| 495 RietrieveChromiumBranches, | 461 RietrieveChromiumBranches, |
| 496 SwitchV8, | |
| 497 CleanUp, | 462 CleanUp, |
| 498 WriteOutput, | 463 WriteOutput, |
| 499 ] | 464 ] |
| 500 | 465 |
| 501 | 466 |
| 502 if __name__ == "__main__": # pragma: no cover | 467 if __name__ == "__main__": # pragma: no cover |
| 503 sys.exit(Releases(CONFIG).Run()) | 468 sys.exit(Releases(CONFIG).Run()) |
| OLD | NEW |