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 |