Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 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 # TODO(hinoka): Use logging. | |
| 7 | |
| 6 import codecs | 8 import codecs |
| 7 import copy | 9 import copy |
| 8 import cStringIO | 10 import cStringIO |
| 9 import ctypes | 11 import ctypes |
| 10 import json | 12 import json |
| 11 import optparse | 13 import optparse |
| 12 import os | 14 import os |
| 13 import pprint | 15 import pprint |
| 14 import re | 16 import re |
| 15 import shutil | 17 import shutil |
| (...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 finally: | 501 finally: |
| 500 os.remove(gclient_output_file) | 502 os.remove(gclient_output_file) |
| 501 | 503 |
| 502 | 504 |
| 503 def gclient_runhooks(gyp_envs): | 505 def gclient_runhooks(gyp_envs): |
| 504 gclient_bin = 'gclient.bat' if sys.platform.startswith('win') else 'gclient' | 506 gclient_bin = 'gclient.bat' if sys.platform.startswith('win') else 'gclient' |
| 505 env = dict([env_var.split('=', 1) for env_var in gyp_envs]) | 507 env = dict([env_var.split('=', 1) for env_var in gyp_envs]) |
| 506 call(gclient_bin, 'runhooks', env=env) | 508 call(gclient_bin, 'runhooks', env=env) |
| 507 | 509 |
| 508 | 510 |
| 509 def create_less_than_or_equal_regex(number): | |
| 510 """ Return a regular expression to test whether an integer less than or equal | |
| 511 to 'number' is present in a given string. | |
| 512 """ | |
| 513 | |
| 514 # In three parts, build a regular expression that match any numbers smaller | |
| 515 # than 'number'. | |
| 516 # For example, 78656 would give a regular expression that looks like: | |
| 517 # Part 1 | |
| 518 # (78356| # 78356 | |
| 519 # Part 2 | |
| 520 # 7835[0-5]| # 78350-78355 | |
| 521 # 783[0-4][0-9]| # 78300-78349 | |
| 522 # 78[0-2][0-9]{2}| # 78000-78299 | |
| 523 # 7[0-7][0-9]{3}| # 70000-77999 | |
| 524 # [0-6][0-9]{4}| # 10000-69999 | |
| 525 # Part 3 | |
| 526 # [0-9]{1,4} # 0-9999 | |
| 527 | |
| 528 # Part 1: Create an array with all the regexes, as described above. | |
| 529 # Prepopulate it with the number itself. | |
| 530 number = str(number) | |
| 531 expressions = [number] | |
| 532 | |
| 533 # Convert the number to a list, so we can translate digits in it to | |
| 534 # expressions. | |
| 535 num_list = list(number) | |
| 536 num_len = len(num_list) | |
| 537 | |
| 538 # Part 2: Go through all the digits in the number, starting from the end. | |
| 539 # Each iteration appends a line to 'expressions'. | |
| 540 for index in range (num_len - 1, -1, -1): | |
| 541 # Convert this digit back to an integer. | |
| 542 digit = int(num_list[index]) | |
| 543 | |
| 544 # Part 2.1: No processing if this digit is a zero. | |
| 545 if digit == 0: | |
| 546 continue | |
| 547 | |
| 548 # Part 2.2: We switch the current digit X by a range "[0-(X-1)]". | |
| 549 if digit == 1: | |
| 550 num_list[index] = '0' | |
| 551 else: | |
| 552 num_list[index] = '[0-%d]' % (digit - 1) | |
| 553 | |
| 554 # Part 2.3: We set all following digits to be "[0-9]". | |
| 555 # Since we just decrementented a digit in a most important position, all | |
| 556 # following digits don't matter. The possible numbers will always be smaller | |
| 557 # than before we decremented. | |
| 558 if (index + 1) < num_len: | |
| 559 if (num_len - (index + 1)) == 1: | |
| 560 num_list[index + 1] = '[0-9]' | |
| 561 else: | |
| 562 num_list[index + 1] = '[0-9]{%s}' % (num_len - (index + 1)) | |
| 563 | |
| 564 # Part 2.4: Add this new sub-expression to the list. | |
| 565 expressions.append(''.join(num_list[:min(index+2, num_len)])) | |
| 566 | |
| 567 # Part 3: We add all the full ranges to match all numbers that are at least | |
| 568 # one order of magnitude smaller than the original numbers. | |
| 569 if num_len == 2: | |
| 570 expressions.append('[0-9]') | |
| 571 elif num_len > 2: | |
| 572 expressions.append('[0-9]{1,%s}' % (num_len - 1)) | |
| 573 | |
| 574 # All done. We now have our final regular expression. | |
| 575 regex = '(%s)' % ('|'.join(expressions)) | |
| 576 return regex | |
| 577 | |
| 578 | |
| 579 def get_svn_rev(git_hash, dir_name): | 511 def get_svn_rev(git_hash, dir_name): |
| 580 pattern = r'^\s*git-svn-id: [^ ]*@(\d+) ' | 512 pattern = r'^\s*git-svn-id: [^ ]*@(\d+) ' |
| 581 lkcr_pattern = r'^\s*LK[CG]R w/ DEPS up to revision (\d+)' | |
| 582 log = git('log', '-1', git_hash, cwd=dir_name) | 513 log = git('log', '-1', git_hash, cwd=dir_name) |
| 583 match = re.search(pattern, log, re.M) | 514 match = re.search(pattern, log, re.M) |
| 584 if not match: | 515 if not match: |
| 585 # This might be a patched checkout, try the parent commit. | 516 return None |
| 586 log = git('log', '-1', '%s^' % git_hash, cwd=dir_name) | |
| 587 match = re.search(pattern, log, re.M) | |
| 588 if not match: | |
| 589 # Might be patched on top of LKCR, which has a special message. | |
| 590 match = re.search(lkcr_pattern, log, re.M) | |
| 591 if not match: | |
| 592 return None | |
| 593 return int(match.group(1)) | 517 return int(match.group(1)) |
| 594 | 518 |
| 595 | 519 |
| 596 def get_git_hash(revision, dir_name): | 520 def get_git_hash(revision, sln_dir): |
| 597 match = "^git-svn-id: [^ ]*@%s " % create_less_than_or_equal_regex(revision) | 521 """We want to search for the SVN revision on the git-svn branch. |
| 598 cmd = ['log', '-E', '--grep', match, '--format=%H', '--max-count=1'] | 522 |
| 599 results = git(*cmd, cwd=dir_name).strip().splitlines() | 523 Note that git will search backwards from origin/master. |
| 600 if results: | 524 """ |
| 601 return results[0] | 525 match = "^git-svn-id: [^ ]*@%s " % revision |
| 602 raise Exception('We can\'t resolve svn revision %s into a git hash' % | 526 cmd = ['log', '-E', '--grep', match, '--format=%H', '--max-count=1', |
| 603 revision) | 527 'origin/master'] |
| 528 result = git(*cmd, cwd=sln_dir).strip() | |
| 529 if result: | |
| 530 return result | |
| 531 raise SVNRevisionNotFound('We can\'t resolve svn r%s into a git hash in %s' % | |
| 532 (revision, sln_dir)) | |
| 604 | 533 |
| 605 | 534 |
| 606 def get_revision_mapping(root, addl_rev_map): | 535 def get_revision_mapping(root, addl_rev_map): |
| 607 result = {} | 536 result = {} |
| 608 if root in GOT_REVISION_MAPPINGS: | 537 if root in GOT_REVISION_MAPPINGS: |
| 609 result.update(GOT_REVISION_MAPPINGS[root]) | 538 result.update(GOT_REVISION_MAPPINGS[root]) |
| 610 if addl_rev_map: | 539 if addl_rev_map: |
| 611 result.update(json.loads(addl_rev_map)) | 540 result.update(json.loads(addl_rev_map)) |
| 612 return result | 541 return result |
| 613 | 542 |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 743 raise ctypes.WinError() | 672 raise ctypes.WinError() |
| 744 return (total.value, free.value) | 673 return (total.value, free.value) |
| 745 | 674 |
| 746 else: | 675 else: |
| 747 st = os.statvfs(cwd) | 676 st = os.statvfs(cwd) |
| 748 free = st.f_bavail * st.f_frsize | 677 free = st.f_bavail * st.f_frsize |
| 749 total = st.f_blocks * st.f_frsize | 678 total = st.f_blocks * st.f_frsize |
| 750 return (total, free) | 679 return (total, free) |
| 751 | 680 |
| 752 | 681 |
| 753 def git_checkout(solutions, revision, shallow): | 682 def get_revision(folder_name, git_url, revisions): |
| 683 normalized_name = folder_name.strip('/') | |
| 684 if normalized_name in revisions: | |
| 685 return revisions[normalized_name] | |
| 686 if git_url in revisions: | |
| 687 return revisions[git_url] | |
| 688 return None | |
| 689 | |
| 690 | |
| 691 def force_revision(folder_name, revision): | |
| 692 if revision and revision.lower() != 'head': | |
|
iannucci
2014/05/10 01:07:18
nit, I would upper() since 'HEAD' is more greppabl
Ryan Tseng
2014/05/10 01:11:36
Done.
| |
| 693 if revision and revision.isdigit() and len(revision) < 40: | |
| 694 # rev_num is really a svn revision number, convert it into a git hash. | |
| 695 git_ref = get_git_hash(int(revision), folder_name) | |
| 696 else: | |
| 697 # rev_num is actually a git hash or ref, we can just use it. | |
| 698 git_ref = revision | |
| 699 git('checkout', git_ref, cwd=folder_name) | |
| 700 else: | |
| 701 # Revision is None or 'HEAD', we want ToT. | |
| 702 git('checkout', 'origin/master', cwd=folder_name) | |
| 703 | |
| 704 | |
| 705 def git_checkout(solutions, revisions, shallow): | |
| 754 build_dir = os.getcwd() | 706 build_dir = os.getcwd() |
| 755 # Before we do anything, break all git_cache locks. | 707 # Before we do anything, break all git_cache locks. |
| 756 if path.isdir(CACHE_DIR): | 708 if path.isdir(CACHE_DIR): |
| 757 git('cache', 'unlock', '-vv', '--force', '--all', '--cache-dir', CACHE_DIR) | 709 git('cache', 'unlock', '-vv', '--force', '--all', '--cache-dir', CACHE_DIR) |
| 758 for item in os.listdir(CACHE_DIR): | 710 for item in os.listdir(CACHE_DIR): |
| 759 filename = os.path.join(CACHE_DIR, item) | 711 filename = os.path.join(CACHE_DIR, item) |
| 760 if item.endswith('.lock'): | 712 if item.endswith('.lock'): |
| 761 raise Exception('%s exists after cache unlock' % filename) | 713 raise Exception('%s exists after cache unlock' % filename) |
| 762 # Revision only applies to the first solution. | |
| 763 first_solution = True | 714 first_solution = True |
| 764 for sln in solutions: | 715 for sln in solutions: |
| 765 # This is so we can loop back and try again if we need to wait for the | 716 # This is so we can loop back and try again if we need to wait for the |
| 766 # git mirrors to update from SVN. | 717 # git mirrors to update from SVN. |
| 767 done = False | 718 done = False |
| 768 tries_left = 60 | 719 tries_left = 60 |
| 769 while not done: | 720 while not done: |
| 770 done = True | 721 done = True |
| 771 name = sln['name'] | 722 name = sln['name'] |
| 772 url = sln['url'] | 723 url = sln['url'] |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 794 # Lets wipe the checkout and try again. | 745 # Lets wipe the checkout and try again. |
| 795 chromium_utils.RemoveDirectory(sln_dir) | 746 chromium_utils.RemoveDirectory(sln_dir) |
| 796 git(*clone_cmd) | 747 git(*clone_cmd) |
| 797 git('checkout', '--force', 'origin/master', cwd=sln_dir) | 748 git('checkout', '--force', 'origin/master', cwd=sln_dir) |
| 798 git('reset', '--hard', cwd=sln_dir) | 749 git('reset', '--hard', cwd=sln_dir) |
| 799 else: | 750 else: |
| 800 raise | 751 raise |
| 801 | 752 |
| 802 git('clean', '-df', cwd=sln_dir) | 753 git('clean', '-df', cwd=sln_dir) |
| 803 git('fetch', 'origin', cwd=sln_dir) | 754 git('fetch', 'origin', cwd=sln_dir) |
| 804 # TODO(hinoka): We probably have to make use of revision mapping. | |
| 805 if first_solution and revision and revision.lower() != 'head': | |
| 806 if revision and revision.isdigit() and len(revision) < 40: | |
| 807 # rev_num is really a svn revision number, convert it into a git hash. | |
| 808 git_ref = get_git_hash(int(revision), name) | |
| 809 # Lets make sure our checkout has the correct revision number. | |
| 810 got_revision = get_svn_rev(git_ref, sln_dir) | |
| 811 if not got_revision or int(got_revision) != int(revision): | |
| 812 tries_left -= 1 | |
| 813 if tries_left > 0: | |
| 814 # If we don't have the correct revision, wait and try again. | |
| 815 print 'We want revision %s, but got revision %s.' % ( | |
| 816 revision, got_revision) | |
| 817 print 'The svn to git replicator is probably falling behind.' | |
| 818 print 'waiting 5 seconds and trying again...' | |
| 819 time.sleep(5) | |
| 820 done = False | |
| 821 continue | |
| 822 raise SVNRevisionNotFound | |
| 823 else: | |
| 824 # rev_num is actually a git hash or ref, we can just use it. | |
| 825 git_ref = revision | |
| 826 git('checkout', git_ref, cwd=sln_dir) | |
| 827 else: | |
| 828 git('checkout', 'origin/master', cwd=sln_dir) | |
| 829 if first_solution: | |
| 830 git_ref = git('log', '--format=%H', '--max-count=1', | |
| 831 cwd=sln_dir).strip() | |
| 832 | 755 |
| 756 revision = get_revision(name, url, revisions) or 'HEAD' | |
| 757 try: | |
| 758 force_revision(sln_dir, revision) | |
| 759 except SVNRevisionNotFound: | |
| 760 tries_left -= 1 | |
| 761 if tries_left > 0: | |
| 762 # If we don't have the correct revision, wait and try again. | |
| 763 print 'We can\'t find revision %s.' % revision | |
| 764 print 'The svn to git replicator is probably falling behind.' | |
| 765 print 'waiting 5 seconds and trying again...' | |
| 766 time.sleep(5) | |
| 767 done = False | |
| 768 continue | |
| 769 raise | |
| 770 | |
| 771 if first_solution: | |
| 772 git_ref = git('log', '--format=%H', '--max-count=1', | |
| 773 cwd=sln_dir).strip() | |
| 833 first_solution = False | 774 first_solution = False |
| 834 return git_ref | 775 return git_ref |
| 835 | 776 |
| 836 | 777 |
| 837 def _download(url): | 778 def _download(url): |
| 838 """Fetch url and return content, with retries for flake.""" | 779 """Fetch url and return content, with retries for flake.""" |
| 839 for attempt in xrange(RETRIES): | 780 for attempt in xrange(RETRIES): |
| 840 try: | 781 try: |
| 841 return urllib2.urlopen(url).read() | 782 return urllib2.urlopen(url).read() |
| 842 except Exception: | 783 except Exception: |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 901 for dir_name, property_name in got_revision_mapping.iteritems(): | 842 for dir_name, property_name in got_revision_mapping.iteritems(): |
| 902 if dir_name not in solutions_output: | 843 if dir_name not in solutions_output: |
| 903 continue | 844 continue |
| 904 solution_output = solutions_output[dir_name] | 845 solution_output = solutions_output[dir_name] |
| 905 if solution_output.get('scm') is None: | 846 if solution_output.get('scm') is None: |
| 906 # This is an ignored DEPS, so the output got_revision should be 'None'. | 847 # This is an ignored DEPS, so the output got_revision should be 'None'. |
| 907 git_revision = revision = None | 848 git_revision = revision = None |
| 908 else: | 849 else: |
| 909 # Since we are using .DEPS.git, everything had better be git. | 850 # Since we are using .DEPS.git, everything had better be git. |
| 910 assert solution_output.get('scm') == 'git' | 851 assert solution_output.get('scm') == 'git' |
| 911 git_revision = get_real_git_hash(solution_output['revision'], dir_name) | 852 git_revision = git('rev-parse', 'HEAD', cwd=dir_name).strip() |
| 912 if use_svn_revs: | 853 if use_svn_revs: |
| 913 revision = get_svn_rev(git_revision, dir_name) | 854 revision = get_svn_rev(git_revision, dir_name) |
| 914 if not revision: | 855 if not revision: |
| 915 revision = git_revision | 856 revision = git_revision |
| 916 else: | 857 else: |
| 917 revision = git_revision | 858 revision = git_revision |
| 918 | 859 |
| 919 properties[property_name] = revision | 860 properties[property_name] = revision |
| 920 if revision != git_revision: | 861 if revision != git_revision: |
| 921 properties['%s_git' % property_name] = git_revision | 862 properties['%s_git' % property_name] = git_revision |
| 922 | 863 |
| 923 return properties | 864 return properties |
| 924 | 865 |
| 925 | 866 |
| 926 def emit_json(out_file, did_run, gclient_output=None, **kwargs): | 867 def emit_json(out_file, did_run, gclient_output=None, **kwargs): |
| 927 """Write run information into a JSON file.""" | 868 """Write run information into a JSON file.""" |
| 928 output = {} | 869 output = {} |
| 929 output.update(gclient_output if gclient_output else {}) | 870 output.update(gclient_output if gclient_output else {}) |
| 930 output.update({'did_run': did_run}) | 871 output.update({'did_run': did_run}) |
| 931 output.update(kwargs) | 872 output.update(kwargs) |
| 932 with open(out_file, 'wb') as f: | 873 with open(out_file, 'wb') as f: |
| 933 f.write(json.dumps(output)) | 874 f.write(json.dumps(output)) |
| 934 | 875 |
| 935 | 876 |
| 936 def ensure_checkout(solutions, revision, first_sln, target_os, target_os_only, | 877 def ensure_deps_revisions(deps_url_mapping, solutions, revisions): |
| 878 """Ensure correct DEPS revisions, ignores solutions.""" | |
| 879 for deps_name, deps_data in sorted(deps_url_mapping.items()): | |
| 880 if deps_name.strip('/') in solutions: | |
| 881 # This has already been forced to the correct solution by git_checkout(). | |
| 882 continue | |
| 883 revision = get_revision(deps_name, deps_data.get('url', None), revisions) | |
| 884 if not revision: | |
| 885 continue | |
| 886 # TODO(hinoka): Catch SVNRevisionNotFound error maybe? | |
| 887 force_revision(deps_name, revision) | |
| 888 | |
| 889 | |
| 890 def ensure_checkout(solutions, revisions, first_sln, target_os, target_os_only, | |
| 937 root, issue, patchset, patch_url, rietveld_server, | 891 root, issue, patchset, patch_url, rietveld_server, |
| 938 revision_mapping, buildspec_name, gyp_env, shallow): | 892 revision_mapping, buildspec_name, gyp_env, shallow): |
| 939 # Get a checkout of each solution, without DEPS or hooks. | 893 # Get a checkout of each solution, without DEPS or hooks. |
| 940 # Calling git directly because there is no way to run Gclient without | 894 # Calling git directly because there is no way to run Gclient without |
| 941 # invoking DEPS. | 895 # invoking DEPS. |
| 942 print 'Fetching Git checkout' | 896 print 'Fetching Git checkout' |
| 943 git_ref = git_checkout(solutions, revision, shallow) | 897 git_ref = git_checkout(solutions, revisions, shallow) |
| 944 | 898 |
| 945 # If either patch_url or issue is passed in, then we need to apply a patch. | 899 # If either patch_url or issue is passed in, then we need to apply a patch. |
| 946 if patch_url: | 900 if patch_url: |
| 947 # patch_url takes precidence since its only passed in on gcl try/git try. | 901 # patch_url takes precidence since its only passed in on gcl try/git try. |
| 948 apply_issue_svn(root, patch_url) | 902 apply_issue_svn(root, patch_url) |
| 949 elif issue: | 903 elif issue: |
| 950 apply_issue_rietveld(issue, patchset, root, rietveld_server, | 904 apply_issue_rietveld(issue, patchset, root, rietveld_server, |
| 951 revision_mapping, git_ref) | 905 revision_mapping, git_ref) |
| 952 | 906 |
| 953 if buildspec_name: | 907 if buildspec_name: |
| 954 buildspecs2git(root, buildspec_name) | 908 buildspecs2git(root, buildspec_name) |
| 955 elif first_sln == root: | 909 elif first_sln == root: |
| 956 # Run deps2git if there is a DEPS commit after the last .DEPS.git commit. | 910 # Run deps2git if there is a DEPS commit after the last .DEPS.git commit. |
| 957 # We only need to ensure deps2git if the root is not overridden, since | 911 # We only need to ensure deps2git if the root is not overridden, since |
| 958 # if the root is overridden, it means we are working with a sub repository | 912 # if the root is overridden, it means we are working with a sub repository |
| 959 # patch, which means its impossible for it to touch DEPS. | 913 # patch, which means its impossible for it to touch DEPS. |
| 960 ensure_deps2git(root, shallow) | 914 ensure_deps2git(root, shallow) |
| 961 | 915 |
| 962 # Ensure our build/ directory is set up with the correct .gclient file. | 916 # Ensure our build/ directory is set up with the correct .gclient file. |
| 963 gclient_configure(solutions, target_os, target_os_only) | 917 gclient_configure(solutions, target_os, target_os_only) |
| 964 | 918 |
| 965 # Let gclient do the DEPS syncing. | 919 # Let gclient do the DEPS syncing. |
| 966 gclient_output = gclient_sync(buildspec_name) | 920 gclient_output = gclient_sync(buildspec_name) |
| 967 if buildspec_name: | 921 if buildspec_name: |
| 968 # Run gclient runhooks if we're on an official builder. | 922 # Run gclient runhooks if we're on an official builder. |
| 969 # TODO(hinoka): Remove this when the official builders run their own | 923 # TODO(hinoka): Remove this when the official builders run their own |
| 970 # runhooks step. | 924 # runhooks step. |
| 971 gclient_runhooks(gyp_env) | 925 gclient_runhooks(gyp_env) |
| 926 | |
| 927 # Finally, ensure that all DEPS are pinned to the correct revision. | |
| 928 dir_names = [sln['name'] for sln in solutions] | |
| 929 ensure_deps_revisions(gclient_output.get('solutions', {}), | |
| 930 dir_names, revisions) | |
| 972 return gclient_output | 931 return gclient_output |
| 973 | 932 |
| 974 | 933 |
| 975 class UploadTelemetryThread(threading.Thread): | 934 class UploadTelemetryThread(threading.Thread): |
| 976 def __init__(self, prefix, master, builder, slave, kwargs): | 935 def __init__(self, prefix, master, builder, slave, kwargs): |
| 977 super(UploadTelemetryThread, self).__init__() | 936 super(UploadTelemetryThread, self).__init__() |
| 978 self.master = master | 937 self.master = master |
| 979 self.builder = builder | 938 self.builder = builder |
| 980 self.slave = slave | 939 self.slave = slave |
| 981 self.prefix = prefix | 940 self.prefix = prefix |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1015 stdin_data=json.dumps(data)) | 974 stdin_data=json.dumps(data)) |
| 1016 | 975 |
| 1017 | 976 |
| 1018 def upload_telemetry(prefix, master, builder, slave, **kwargs): | 977 def upload_telemetry(prefix, master, builder, slave, **kwargs): |
| 1019 thr = UploadTelemetryThread(prefix, master, builder, slave, kwargs) | 978 thr = UploadTelemetryThread(prefix, master, builder, slave, kwargs) |
| 1020 thr.daemon = True | 979 thr.daemon = True |
| 1021 thr.start() | 980 thr.start() |
| 1022 return thr | 981 return thr |
| 1023 | 982 |
| 1024 | 983 |
| 984 def parse_revisions(revisions, root): | |
| 985 """Turn a list of revision specs into a nice dictionary. | |
| 986 | |
| 987 We will always return a dict with {root: something}. By default if root | |
| 988 is unspecified, or if revisions is [], then revision will be assigned 'HEAD' | |
| 989 """ | |
| 990 results = {root.strip('/'): 'HEAD'} | |
| 991 for revision in revisions: | |
| 992 split_revision = revision.split('@') | |
| 993 if len(split_revision) == 1: | |
| 994 # This is just a plain revision, set it as the revision for root. | |
| 995 results[root] = split_revision[0] | |
| 996 elif len(split_revision) == 2: | |
| 997 # This is an alt_root@revision argument. | |
| 998 current_root, current_rev = split_revision | |
| 999 | |
| 1000 # We want to normalize svn/git urls into .git urls. | |
| 1001 parsed_root = urlparse.urlparse(current_root) | |
| 1002 if parsed_root.scheme == 'svn': | |
| 1003 if parsed_root.path in RECOGNIZED_PATHS: | |
| 1004 normalized_root = RECOGNIZED_PATHS[parsed_root.path] | |
| 1005 else: | |
| 1006 print 'WARNING: SVN path %s not recognized, ignoring' % current_root | |
| 1007 continue | |
| 1008 elif parsed_root.scheme in ['http', 'https']: | |
| 1009 normalized_root = 'https://%s/%s' % (parsed_root.netloc, | |
| 1010 parsed_root.path) | |
| 1011 if not normalized_root.endswith('.git'): | |
| 1012 normalized_root = '%s.git' % normalized_root | |
| 1013 elif parsed_root.scheme: | |
| 1014 print 'WARNING: Unrecognized scheme %s, ignoring' % parsed_root.scheme | |
| 1015 continue | |
| 1016 else: | |
| 1017 # This is probably a local path. | |
| 1018 normalized_root = current_root.strip('/') | |
| 1019 | |
| 1020 results[normalized_root] = current_rev | |
| 1021 else: | |
| 1022 print ('WARNING: %r is not recognized as a valid revision specification,' | |
| 1023 'skipping' % revision) | |
| 1024 return results | |
| 1025 | |
| 1026 | |
| 1025 def parse_args(): | 1027 def parse_args(): |
| 1026 parse = optparse.OptionParser() | 1028 parse = optparse.OptionParser() |
| 1027 | 1029 |
| 1028 parse.add_option('--issue', help='Issue number to patch from.') | 1030 parse.add_option('--issue', help='Issue number to patch from.') |
| 1029 parse.add_option('--patchset', | 1031 parse.add_option('--patchset', |
| 1030 help='Patchset from issue to patch from, if applicable.') | 1032 help='Patchset from issue to patch from, if applicable.') |
| 1031 parse.add_option('--patch_url', help='Optional URL to SVN patch.') | 1033 parse.add_option('--patch_url', help='Optional URL to SVN patch.') |
| 1032 parse.add_option('--root', help='Repository root.') | 1034 parse.add_option('--root', help='Repository root.') |
| 1033 parse.add_option('--rietveld_server', | 1035 parse.add_option('--rietveld_server', |
| 1034 default='codereview.chromium.org', | 1036 default='codereview.chromium.org', |
| 1035 help='Rietveld server.') | 1037 help='Rietveld server.') |
| 1036 parse.add_option('--specs', help='Gcilent spec.') | 1038 parse.add_option('--specs', help='Gcilent spec.') |
| 1037 parse.add_option('--master', help='Master name.') | 1039 parse.add_option('--master', help='Master name.') |
| 1038 parse.add_option('-f', '--force', action='store_true', | 1040 parse.add_option('-f', '--force', action='store_true', |
| 1039 help='Bypass check to see if we want to be run. ' | 1041 help='Bypass check to see if we want to be run. ' |
| 1040 'Should ONLY be used locally.') | 1042 'Should ONLY be used locally.') |
| 1041 parse.add_option('--revision_mapping') | 1043 parse.add_option('--revision_mapping') |
| 1042 parse.add_option('--revision-mapping') # Backwards compatability. | 1044 parse.add_option('--revision-mapping') # Backwards compatability. |
| 1043 # TODO(hinoka): Support root@revision format. | 1045 parse.add_option('--revision', action='append', default=[], |
| 1044 parse.add_option('--revision', | |
| 1045 help='Revision to check out. Can be an SVN revision number, ' | 1046 help='Revision to check out. Can be an SVN revision number, ' |
| 1046 'git hash, or any form of git ref.') | 1047 'git hash, or any form of git ref. Can prepend ' |
| 1048 'root@<rev> to specify which repository, where root ' | |
| 1049 'is either a filesystem path, git https url, or ' | |
| 1050 'svn url. To specify Tip of Tree, set rev to HEAD.') | |
| 1047 parse.add_option('--slave_name', default=socket.getfqdn().split('.')[0], | 1051 parse.add_option('--slave_name', default=socket.getfqdn().split('.')[0], |
| 1048 help='Hostname of the current machine, ' | 1052 help='Hostname of the current machine, ' |
| 1049 'used for determining whether or not to activate.') | 1053 'used for determining whether or not to activate.') |
| 1050 parse.add_option('--builder_name', help='Name of the builder, ' | 1054 parse.add_option('--builder_name', help='Name of the builder, ' |
| 1051 'used for determining whether or not to activate.') | 1055 'used for determining whether or not to activate.') |
| 1052 parse.add_option('--build_dir', default=os.getcwd()) | 1056 parse.add_option('--build_dir', default=os.getcwd()) |
| 1053 parse.add_option('--flag_file', default=path.join(os.getcwd(), | 1057 parse.add_option('--flag_file', default=path.join(os.getcwd(), |
| 1054 'update.flag')) | 1058 'update.flag')) |
| 1055 parse.add_option('--shallow', action='store_true', | 1059 parse.add_option('--shallow', action='store_true', |
| 1056 help='Use shallow clones for cache repositories.') | 1060 help='Use shallow clones for cache repositories.') |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1142 print '@@@STEP_TEXT@%s@@@' % step_text | 1146 print '@@@STEP_TEXT@%s@@@' % step_text |
| 1143 if not options.shallow: | 1147 if not options.shallow: |
| 1144 options.shallow = total_disk_space < SHALLOW_CLONE_THRESHOLD | 1148 options.shallow = total_disk_space < SHALLOW_CLONE_THRESHOLD |
| 1145 | 1149 |
| 1146 # By default, the root should be the name of the first solution, but | 1150 # By default, the root should be the name of the first solution, but |
| 1147 # also make it overridable. The root is where patches are applied on top of. | 1151 # also make it overridable. The root is where patches are applied on top of. |
| 1148 options.root = options.root or dir_names[0] | 1152 options.root = options.root or dir_names[0] |
| 1149 # The first solution is where the primary DEPS file resides. | 1153 # The first solution is where the primary DEPS file resides. |
| 1150 first_sln = dir_names[0] | 1154 first_sln = dir_names[0] |
| 1151 | 1155 |
| 1156 # Split all the revision specifications into a nice dict. | |
| 1157 print 'Revisions: %s' % options.revision | |
| 1158 revisions = parse_revisions(options.revision, options.root) | |
| 1159 # This is meant to be just an alias to the revision of the main solution. | |
| 1160 root_revision = revisions[options.root] | |
| 1161 print 'Fetching Git checkout at %s@%s' % (options.root, root_revision) | |
| 1162 | |
| 1152 try: | 1163 try: |
| 1153 checkout_parameters = dict( | 1164 checkout_parameters = dict( |
| 1154 # First, pass in the base of what we want to check out. | 1165 # First, pass in the base of what we want to check out. |
| 1155 solutions=git_solutions, | 1166 solutions=git_solutions, |
| 1156 revision=options.revision, | 1167 revisions=revisions, |
| 1157 first_sln=first_sln, | 1168 first_sln=first_sln, |
| 1158 | 1169 |
| 1159 # Also, target os variables for gclient. | 1170 # Also, target os variables for gclient. |
| 1160 target_os=specs.get('target_os', []), | 1171 target_os=specs.get('target_os', []), |
| 1161 target_os_only=specs.get('target_os_only', False), | 1172 target_os_only=specs.get('target_os_only', False), |
| 1162 | 1173 |
| 1163 # Then, pass in information about how to patch on top of the checkout. | 1174 # Then, pass in information about how to patch on top of the checkout. |
| 1164 root=options.root, | 1175 root=options.root, |
| 1165 issue=options.issue, | 1176 issue=options.issue, |
| 1166 patchset=options.patchset, | 1177 patchset=options.patchset, |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1212 specs=options.specs) | 1223 specs=options.specs) |
| 1213 all_threads.append(thr) | 1224 all_threads.append(thr) |
| 1214 | 1225 |
| 1215 # Sort of wait for all telemetry threads to finish. | 1226 # Sort of wait for all telemetry threads to finish. |
| 1216 for thr in all_threads: | 1227 for thr in all_threads: |
| 1217 thr.join(5) | 1228 thr.join(5) |
| 1218 | 1229 |
| 1219 | 1230 |
| 1220 if __name__ == '__main__': | 1231 if __name__ == '__main__': |
| 1221 sys.exit(main()) | 1232 sys.exit(main()) |
| OLD | NEW |