| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium 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 import collections | |
| 7 import datetime | 6 import datetime |
| 8 import json | |
| 9 import optparse | 7 import optparse |
| 10 import os | 8 import os |
| 11 import re | 9 import re |
| 12 import sys | 10 import sys |
| 13 import urllib2 | |
| 14 import urlparse | 11 import urlparse |
| 15 | 12 |
| 16 import breakpad # pylint: disable=W0611 | 13 import breakpad # pylint: disable=W0611 |
| 17 | 14 |
| 18 import gclient_utils | 15 import gclient_utils |
| 19 import subprocess2 | 16 import subprocess2 |
| 20 | 17 |
| 21 USAGE = """ | 18 USAGE = """ |
| 22 WARNING: Please use this tool in an empty directory | 19 WARNING: Please use this tool in an empty directory |
| 23 (or at least one that you don't mind clobbering.) | 20 (or at least one that you don't mind clobbering.) |
| 24 | 21 |
| 25 REQUIRES: SVN 1.5+ | 22 REQUIRES: SVN 1.5+ |
| 26 NOTE: NO NEED TO CHECKOUT ANYTHING IN ADVANCE OF USING THIS TOOL. | 23 NOTE: NO NEED TO CHECKOUT ANYTHING IN ADVANCE OF USING THIS TOOL. |
| 27 Valid parameters: | 24 Valid parameters: |
| 28 | 25 |
| 29 [Merge from trunk to branch] | 26 [Merge from trunk to branch] |
| 30 --merge <revision> --branch <branch_num> | 27 --merge <revision> --branch <branch_num> |
| 31 Example: %(app)s --merge 12345 --branch 187 | 28 Example: %(app)s --merge 12345 --branch 187 |
| 32 | 29 |
| 33 [Merge from trunk to milestone] | |
| 34 --merge <revision> --milestone <milestone_num> | |
| 35 Example: %(app)s --merge 12345 --milestone 16 | |
| 36 | |
| 37 [Merge from trunk to local copy] | 30 [Merge from trunk to local copy] |
| 38 --merge <revision> --local | 31 --merge <revision> --local |
| 39 Example: %(app)s --merge 12345 --local | 32 Example: %(app)s --merge 12345 --local |
| 40 | 33 |
| 41 [Merge from branch to branch] | 34 [Merge from branch to branch] |
| 42 --merge <revision> --sbranch <branch_num> --branch <branch_num> | 35 --merge <revision> --sbranch <branch_num> --branch <branch_num> |
| 43 Example: %(app)s --merge 12345 --sbranch 248 --branch 249 | 36 Example: %(app)s --merge 12345 --sbranch 248 --branch 249 |
| 44 | 37 |
| 45 [Revert from trunk] | 38 [Revert from trunk] |
| 46 --revert <revision> | 39 --revert <revision> |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 | 356 |
| 364 def getAllFilesInRevision(files_info): | 357 def getAllFilesInRevision(files_info): |
| 365 """Checks for existing files in the revision. | 358 """Checks for existing files in the revision. |
| 366 | 359 |
| 367 Anything that's A will require special treatment (either a merge or an | 360 Anything that's A will require special treatment (either a merge or an |
| 368 export + add) | 361 export + add) |
| 369 """ | 362 """ |
| 370 return ['%s/%s' % (f[2], f[3]) for f in files_info] | 363 return ['%s/%s' % (f[2], f[3]) for f in files_info] |
| 371 | 364 |
| 372 | 365 |
| 373 def getBranchForMilestone(milestone): | |
| 374 """Queries omahaproxy.appspot.com for the branch number given |milestone|. | |
| 375 """ | |
| 376 OMAHA_PROXY_URL = "https://omahaproxy.appspot.com/all?json=1" | |
| 377 try: | |
| 378 response = urllib2.urlopen(OMAHA_PROXY_URL) | |
| 379 except urllib2.HTTPError, e: | |
| 380 print "Failed to query %s: %d" % (OMAHA_PROXY_URL, e.code) | |
| 381 return None | |
| 382 | |
| 383 # Response is in the form of: | |
| 384 # [{ os: "os_name", versions: [{ channel: "canary", true_branch: "1490" }] }] | |
| 385 os_versions = json.load(response) | |
| 386 | |
| 387 branches = collections.defaultdict(list) | |
| 388 for os_version in os_versions: | |
| 389 for version in os_version['versions']: | |
| 390 if not version['true_branch'] or not version['version']: | |
| 391 continue | |
| 392 branch = version['true_branch'] | |
| 393 mstone = version['version'].split('.') | |
| 394 if not branch[0].isdigit() or mstone[0] != str(milestone): | |
| 395 continue | |
| 396 branches[branch] += [os_version['os']] | |
| 397 | |
| 398 if not branches: | |
| 399 return None | |
| 400 | |
| 401 if len(branches) == 1: | |
| 402 return branches.keys()[0] | |
| 403 | |
| 404 choices = ('-(%s): %s' % (b, ', '.join(o)) for b, o in branches.iteritems()) | |
| 405 print >> sys.stderr, ("\nNot all platforms have same branch number for M%d.\n" | |
| 406 "\nHere's a list of platforms on each branch:\n" | |
| 407 "%s") % (milestone, '\n'.join(choices)) | |
| 408 | |
| 409 errors = 0 | |
| 410 while errors < 3: | |
| 411 user_input = raw_input("Which branch? ('q' to cancel) ").strip().lower() | |
| 412 if user_input in branches: | |
| 413 return user_input | |
| 414 if user_input.startswith('q'): | |
| 415 break | |
| 416 errors += 1 | |
| 417 | |
| 418 return None | |
| 419 | |
| 420 def getSVNAuthInfo(folder=None): | 366 def getSVNAuthInfo(folder=None): |
| 421 """Fetches SVN authorization information in the subversion auth folder and | 367 """Fetches SVN authorization information in the subversion auth folder and |
| 422 returns it as a dictionary of dictionaries.""" | 368 returns it as a dictionary of dictionaries.""" |
| 423 if not folder: | 369 if not folder: |
| 424 if sys.platform == 'win32': | 370 if sys.platform == 'win32': |
| 425 folder = '%%APPDATA%\\Subversion\\auth' | 371 folder = '%%APPDATA%\\Subversion\\auth' |
| 426 else: | 372 else: |
| 427 folder = '~/.subversion/auth' | 373 folder = '~/.subversion/auth' |
| 428 folder = os.path.expandvars(os.path.expanduser(folder)) | 374 folder = os.path.expandvars(os.path.expanduser(folder)) |
| 429 svn_simple_folder = os.path.join(folder, 'svn.simple') | 375 svn_simple_folder = os.path.join(folder, 'svn.simple') |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 BASE_URL = "svn://svn.chromium.org/chrome" | 426 BASE_URL = "svn://svn.chromium.org/chrome" |
| 481 REVERT_ALT_URLS = ['svn://svn.chromium.org/blink', | 427 REVERT_ALT_URLS = ['svn://svn.chromium.org/blink', |
| 482 'svn://svn.chromium.org/chrome-internal', | 428 'svn://svn.chromium.org/chrome-internal', |
| 483 'svn://svn.chromium.org/native_client'] | 429 'svn://svn.chromium.org/native_client'] |
| 484 TRUNK_URL = BASE_URL + "/trunk/src" | 430 TRUNK_URL = BASE_URL + "/trunk/src" |
| 485 BRANCH_URL = BASE_URL + "/branches/$branch/src" | 431 BRANCH_URL = BASE_URL + "/branches/$branch/src" |
| 486 SKIP_CHECK_WORKING = True | 432 SKIP_CHECK_WORKING = True |
| 487 PROMPT_FOR_AUTHOR = False | 433 PROMPT_FOR_AUTHOR = False |
| 488 NO_ALT_URLS = options.no_alt_urls | 434 NO_ALT_URLS = options.no_alt_urls |
| 489 | 435 |
| 490 # Translate a given milestone to the appropriate branch number. | |
| 491 if options.milestone: | |
| 492 options.branch = getBranchForMilestone(options.milestone) | |
| 493 if not options.branch: | |
| 494 return 1 | |
| 495 | |
| 496 DEFAULT_WORKING = "drover_" + str(revision) | 436 DEFAULT_WORKING = "drover_" + str(revision) |
| 497 if options.branch: | 437 if options.branch: |
| 498 DEFAULT_WORKING += ("_" + options.branch) | 438 DEFAULT_WORKING += ("_" + options.branch) |
| 499 | 439 |
| 500 if not isMinimumSVNVersion(1, 5): | 440 if not isMinimumSVNVersion(1, 5): |
| 501 print "You need to use at least SVN version 1.5.x" | 441 print "You need to use at least SVN version 1.5.x" |
| 502 return 1 | 442 return 1 |
| 503 | 443 |
| 504 # Override the default properties if there is a drover.properties file. | 444 # Override the default properties if there is a drover.properties file. |
| 505 global file_pattern_ | 445 global file_pattern_ |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 658 else: | 598 else: |
| 659 return 0 | 599 return 0 |
| 660 | 600 |
| 661 | 601 |
| 662 def main(): | 602 def main(): |
| 663 option_parser = optparse.OptionParser(usage=USAGE % {"app": sys.argv[0]}) | 603 option_parser = optparse.OptionParser(usage=USAGE % {"app": sys.argv[0]}) |
| 664 option_parser.add_option('-m', '--merge', type="int", | 604 option_parser.add_option('-m', '--merge', type="int", |
| 665 help='Revision to merge from trunk to branch') | 605 help='Revision to merge from trunk to branch') |
| 666 option_parser.add_option('-b', '--branch', | 606 option_parser.add_option('-b', '--branch', |
| 667 help='Branch to revert or merge from') | 607 help='Branch to revert or merge from') |
| 668 option_parser.add_option('-M', '--milestone', type="int", | |
| 669 help='Milestone to revert or merge from') | |
| 670 option_parser.add_option('-l', '--local', action='store_true', | 608 option_parser.add_option('-l', '--local', action='store_true', |
| 671 help='Local working copy to merge to') | 609 help='Local working copy to merge to') |
| 672 option_parser.add_option('-s', '--sbranch', | 610 option_parser.add_option('-s', '--sbranch', |
| 673 help='Source branch for merge') | 611 help='Source branch for merge') |
| 674 option_parser.add_option('-r', '--revert', type="int", | 612 option_parser.add_option('-r', '--revert', type="int", |
| 675 help='Revision to revert') | 613 help='Revision to revert') |
| 676 option_parser.add_option('-w', '--workdir', | 614 option_parser.add_option('-w', '--workdir', |
| 677 help='subdir to use for the revert') | 615 help='subdir to use for the revert') |
| 678 option_parser.add_option('-u', '--url', | 616 option_parser.add_option('-u', '--url', |
| 679 help='svn url to use for the revert') | 617 help='svn url to use for the revert') |
| 680 option_parser.add_option('-a', '--auditor', | 618 option_parser.add_option('-a', '--auditor', |
| 681 help='overrides the author for reviewer') | 619 help='overrides the author for reviewer') |
| 682 option_parser.add_option('--revertbot', action='store_true', | 620 option_parser.add_option('--revertbot', action='store_true', |
| 683 default=False) | 621 default=False) |
| 684 option_parser.add_option('--no-alt-urls', action='store_true', | 622 option_parser.add_option('--no-alt-urls', action='store_true', |
| 685 help='Disable heuristics used to determine svn url') | 623 help='Disable heuristics used to determine svn url') |
| 686 option_parser.add_option('--revertbot-commit', action='store_true', | 624 option_parser.add_option('--revertbot-commit', action='store_true', |
| 687 default=False) | 625 default=False) |
| 688 option_parser.add_option('--revertbot-reviewers') | 626 option_parser.add_option('--revertbot-reviewers') |
| 689 options, args = option_parser.parse_args() | 627 options, args = option_parser.parse_args() |
| 690 | 628 |
| 691 if not options.merge and not options.revert: | 629 if not options.merge and not options.revert: |
| 692 option_parser.error("You need at least --merge or --revert") | 630 option_parser.error("You need at least --merge or --revert") |
| 693 return 1 | 631 return 1 |
| 694 | 632 |
| 695 if options.merge and not (options.branch or options.milestone or | 633 if options.merge and not (options.branch or options.local): |
| 696 options.local): | 634 option_parser.error("--merge requires --branch or --local") |
| 697 option_parser.error("--merge requires either --branch " | |
| 698 "or --milestone or --local") | |
| 699 return 1 | 635 return 1 |
| 700 | 636 |
| 701 if options.local and (options.revert or options.branch or options.milestone): | 637 if options.local and (options.revert or options.branch): |
| 702 option_parser.error("--local cannot be used with --revert " | 638 option_parser.error("--local cannot be used with --revert or --branch") |
| 703 "or --branch or --milestone") | |
| 704 return 1 | |
| 705 | |
| 706 if options.branch and options.milestone: | |
| 707 option_parser.error("--branch cannot be used with --milestone") | |
| 708 return 1 | 639 return 1 |
| 709 | 640 |
| 710 return drover(options, args) | 641 return drover(options, args) |
| 711 | 642 |
| 712 | 643 |
| 713 if __name__ == "__main__": | 644 if __name__ == "__main__": |
| 714 sys.exit(main()) | 645 sys.exit(main()) |
| OLD | NEW |