Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Side by Side Diff: recipe_modules/bot_update/resources/bot_update.py

Issue 2321203003: A bunch more little cleanups in bot_update. (Closed)
Patch Set: rebase, just in case Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « recipe_modules/bot_update/example.expected/tryjob_v8_head_by_default.json ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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. 6 # TODO(hinoka): Use logging.
7 7
8 import cStringIO 8 import cStringIO
9 import codecs 9 import codecs
10 import collections 10 import collections
(...skipping 604 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 if not ok: 615 if not ok:
616 # Get off of the temporary branch since it can't be deleted otherwise. 616 # Get off of the temporary branch since it can't be deleted otherwise.
617 git('checkout', base_rev, cwd=root) 617 git('checkout', base_rev, cwd=root)
618 git('branch', '-D', temp_branch_name, cwd=root) 618 git('branch', '-D', temp_branch_name, cwd=root)
619 619
620 if gerrit_reset: 620 if gerrit_reset:
621 git('reset', '--soft', base_rev, cwd=root) 621 git('reset', '--soft', base_rev, cwd=root)
622 except SubprocessFailed as e: 622 except SubprocessFailed as e:
623 raise PatchFailed(e.message, e.code, e.output) 623 raise PatchFailed(e.message, e.code, e.output)
624 624
625 def check_flag(flag_file):
626 """Returns True if the flag file is present."""
627 return os.path.isfile(flag_file)
628
629
630 def delete_flag(flag_file):
631 """Remove bot update flag."""
632 if os.path.isfile(flag_file):
633 os.remove(flag_file)
634
635
636 def emit_flag(flag_file):
637 """Deposit a bot update flag on the system to tell gclient not to run."""
638 print 'Emitting flag file at %s' % flag_file
639 with open(flag_file, 'wb') as f:
640 f.write('Success!')
641
642 625
643 def get_commit_position(git_path, revision='HEAD'): 626 def get_commit_position(git_path, revision='HEAD'):
644 """Dumps the 'git' log for a specific revision and parses out the commit 627 """Dumps the 'git' log for a specific revision and parses out the commit
645 position. 628 position.
646 629
647 If a commit position metadata key is found, its value will be returned. 630 If a commit position metadata key is found, its value will be returned.
648 """ 631 """
649 # TODO(iannucci): Use git-footers for this. 632 # TODO(iannucci): Use git-footers for this.
650 git_log = git('log', '--format=%B', '-n1', revision, cwd=git_path) 633 git_log = git('log', '--format=%B', '-n1', revision, cwd=git_path)
651 footer_map = get_commit_message_footer_map(git_log) 634 footer_map = get_commit_message_footer_map(git_log)
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
843 default='codereview.chromium.org', 826 default='codereview.chromium.org',
844 help='Rietveld server.') 827 help='Rietveld server.')
845 parse.add_option('--gerrit_repo', 828 parse.add_option('--gerrit_repo',
846 help='Gerrit repository to pull the ref from.') 829 help='Gerrit repository to pull the ref from.')
847 parse.add_option('--gerrit_ref', help='Gerrit ref to apply.') 830 parse.add_option('--gerrit_ref', help='Gerrit ref to apply.')
848 parse.add_option('--gerrit_no_rebase_patch_ref', action='store_true', 831 parse.add_option('--gerrit_no_rebase_patch_ref', action='store_true',
849 help='Bypass rebase of Gerrit patch ref after checkout.') 832 help='Bypass rebase of Gerrit patch ref after checkout.')
850 parse.add_option('--gerrit_no_reset', action='store_true', 833 parse.add_option('--gerrit_no_reset', action='store_true',
851 help='Bypass calling reset after applying a gerrit ref.') 834 help='Bypass calling reset after applying a gerrit ref.')
852 parse.add_option('--specs', help='Gcilent spec.') 835 parse.add_option('--specs', help='Gcilent spec.')
853 parse.add_option('-f', '--force', action='store_true',
854 help='Bypass check to see if we want to be run. '
855 'Should ONLY be used locally or by smart recipes.')
856 parse.add_option('--revision_mapping',
857 help='{"path/to/repo/": "property_name"}')
858 parse.add_option('--revision_mapping_file', 836 parse.add_option('--revision_mapping_file',
859 help=('Same as revision_mapping, except its a path to a json' 837 help=('Path to a json file of the form '
860 ' file containing that format.')) 838 '{"path/to/repo/": "property_name"}'))
861 parse.add_option('--revision', action='append', default=[], 839 parse.add_option('--revision', action='append', default=[],
862 help='Revision to check out. Can be any form of git ref. ' 840 help='Revision to check out. Can be any form of git ref. '
863 'Can prepend root@<rev> to specify which repository, ' 841 'Can prepend root@<rev> to specify which repository, '
864 'where root is either a filesystem path or git https ' 842 'where root is either a filesystem path or git https '
865 'url. To specify Tip of Tree, set rev to HEAD. ') 843 'url. To specify Tip of Tree, set rev to HEAD. ')
866 parse.add_option('--output_manifest', action='store_true', 844 parse.add_option('--output_manifest', action='store_true',
867 help=('Add manifest json to the json output.')) 845 help=('Add manifest json to the json output.'))
868 parse.add_option('--slave_name', default=socket.getfqdn().split('.')[0],
869 help='Hostname of the current machine, '
870 'used for determining whether or not to activate.')
871 parse.add_option('--build_dir', default=os.getcwd())
872 parse.add_option('--flag_file', default=path.join(os.getcwd(),
873 'update.flag'))
874 parse.add_option('--shallow', action='store_true',
875 help='Use shallow clones for cache repositories.')
876 parse.add_option('--clobber', action='store_true', 846 parse.add_option('--clobber', action='store_true',
877 help='Delete checkout first, always') 847 help='Delete checkout first, always')
878 parse.add_option('--bot_update_clobber', action='store_true', dest='clobber', 848 parse.add_option('--output_json',
879 help='(synonym for --clobber)')
880 parse.add_option('-o', '--output_json',
881 help='Output JSON information into a specified file') 849 help='Output JSON information into a specified file')
882 parse.add_option('--no_shallow', action='store_true', 850 parse.add_option('--no_shallow', action='store_true',
883 help='Bypass disk detection and never shallow clone. ' 851 help='Bypass disk detection and never shallow clone. '
884 'Does not override the --shallow flag') 852 'Does not override the --shallow flag')
885 parse.add_option('--refs', action='append', 853 parse.add_option('--refs', action='append',
886 help='Also fetch this refspec for the main solution(s). ' 854 help='Also fetch this refspec for the main solution(s). '
887 'Eg. +refs/branch-heads/*') 855 'Eg. +refs/branch-heads/*')
888 parse.add_option('--with_branch_heads', action='store_true', 856 parse.add_option('--with_branch_heads', action='store_true',
889 help='Always pass --with_branch_heads to gclient. This ' 857 help='Always pass --with_branch_heads to gclient. This '
890 'does the same thing as --refs +refs/branch-heads/*') 858 'does the same thing as --refs +refs/branch-heads/*')
891 parse.add_option('--git-cache-dir', help='Path to git cache directory.') 859 parse.add_option('--git-cache-dir', help='Path to git cache directory.')
892 860
893 861
894 options, args = parse.parse_args() 862 options, args = parse.parse_args()
895 863
896 if not options.git_cache_dir: 864 if not options.git_cache_dir:
897 parse.error('--git-cache-dir is required') 865 parse.error('--git-cache-dir is required')
898 866
899 if not options.refs: 867 if not options.refs:
900 options.refs = [] 868 options.refs = []
901 869
902 if options.with_branch_heads: 870 if options.with_branch_heads:
903 options.refs.append(BRANCH_HEADS_REFSPEC) 871 options.refs.append(BRANCH_HEADS_REFSPEC)
904 del options.with_branch_heads 872 del options.with_branch_heads
905 873
906 try: 874 try:
907 if options.revision_mapping_file: 875 if not options.revision_mapping_file:
908 if options.revision_mapping: 876 parse.error('--revision_mapping_file is required')
909 print ('WARNING: Ignoring --revision_mapping: --revision_mapping_file ' 877
910 'was set at the same time as --revision_mapping?') 878 with open(options.revision_mapping_file, 'r') as f:
911 with open(options.revision_mapping_file, 'r') as f: 879 options.revision_mapping = json.load(f)
912 options.revision_mapping = json.load(f)
913 elif options.revision_mapping:
914 options.revision_mapping = json.loads(options.revision_mapping)
915 except Exception as e: 880 except Exception as e:
916 print ( 881 print (
917 'WARNING: Caught execption while parsing revision_mapping*: %s' 882 'WARNING: Caught execption while parsing revision_mapping*: %s'
918 % (str(e),) 883 % (str(e),)
919 ) 884 )
920 885
921 # Because we print CACHE_DIR out into a .gclient file, and then later run 886 # Because we print CACHE_DIR out into a .gclient file, and then later run
922 # eval() on it, backslashes need to be escaped, otherwise "E:\b\build" gets 887 # eval() on it, backslashes need to be escaped, otherwise "E:\b\build" gets
923 # parsed as "E:[\x08][\x08]uild". 888 # parsed as "E:[\x08][\x08]uild".
924 if sys.platform.startswith('win'): 889 if sys.platform.startswith('win'):
925 options.git_cache_dir = options.git_cache_dir.replace('\\', '\\\\') 890 options.git_cache_dir = options.git_cache_dir.replace('\\', '\\\\')
926 891
927 return options, args 892 return options, args
928 893
929 894
930 def prepare(options, git_slns, active): 895 def prepare(options, git_slns, active):
931 """Prepares the target folder before we checkout.""" 896 """Prepares the target folder before we checkout."""
932 dir_names = [sln.get('name') for sln in git_slns if 'name' in sln] 897 dir_names = [sln.get('name') for sln in git_slns if 'name' in sln]
933 # If we're active now, but the flag file doesn't exist (we weren't active 898 if options.clobber:
934 # last run) or vice versa, blow away all checkouts.
935 if options.clobber or (bool(active) != bool(check_flag(options.flag_file))):
936 ensure_no_checkout(dir_names) 899 ensure_no_checkout(dir_names)
937 if options.output_json: 900 # Make sure we tell recipes that we didn't run if the script exits here.
938 # Make sure we tell recipes that we didn't run if the script exits here. 901 emit_json(options.output_json, did_run=active)
939 emit_json(options.output_json, did_run=active)
940 emit_flag(options.flag_file)
941 902
942 # Do a shallow checkout if the disk is less than 100GB. 903 # Do a shallow checkout if the disk is less than 100GB.
943 total_disk_space, free_disk_space = get_total_disk_space() 904 total_disk_space, free_disk_space = get_total_disk_space()
944 total_disk_space_gb = int(total_disk_space / (1024 * 1024 * 1024)) 905 total_disk_space_gb = int(total_disk_space / (1024 * 1024 * 1024))
945 used_disk_space_gb = int((total_disk_space - free_disk_space) 906 used_disk_space_gb = int((total_disk_space - free_disk_space)
946 / (1024 * 1024 * 1024)) 907 / (1024 * 1024 * 1024))
947 percent_used = int(used_disk_space_gb * 100 / total_disk_space_gb) 908 percent_used = int(used_disk_space_gb * 100 / total_disk_space_gb)
948 step_text = '[%dGB/%dGB used (%d%%)]' % (used_disk_space_gb, 909 step_text = '[%dGB/%dGB used (%d%%)]' % (used_disk_space_gb,
949 total_disk_space_gb, 910 total_disk_space_gb,
950 percent_used) 911 percent_used)
951 if not options.output_json: 912 if not options.output_json:
952 print '@@@STEP_TEXT@%s@@@' % step_text 913 print '@@@STEP_TEXT@%s@@@' % step_text
953 if not options.shallow: 914 shallow = (total_disk_space < SHALLOW_CLONE_THRESHOLD
954 options.shallow = (total_disk_space < SHALLOW_CLONE_THRESHOLD 915 and not options.no_shallow)
955 and not options.no_shallow)
956 916
957 # The first solution is where the primary DEPS file resides. 917 # The first solution is where the primary DEPS file resides.
958 first_sln = dir_names[0] 918 first_sln = dir_names[0]
959 919
960 # Split all the revision specifications into a nice dict. 920 # Split all the revision specifications into a nice dict.
961 print 'Revisions: %s' % options.revision 921 print 'Revisions: %s' % options.revision
962 revisions = parse_revisions(options.revision, first_sln) 922 revisions = parse_revisions(options.revision, first_sln)
963 print 'Fetching Git checkout at %s@%s' % (first_sln, revisions[first_sln]) 923 print 'Fetching Git checkout at %s@%s' % (first_sln, revisions[first_sln])
964 return revisions, step_text 924 return revisions, step_text, shallow
965 925
966 926
967 def checkout(options, git_slns, specs, revisions, step_text): 927 def checkout(options, git_slns, specs, revisions, step_text, shallow):
968 first_sln = git_slns[0]['name'] 928 first_sln = git_slns[0]['name']
969 dir_names = [sln.get('name') for sln in git_slns if 'name' in sln] 929 dir_names = [sln.get('name') for sln in git_slns if 'name' in sln]
970 try: 930 try:
971 # Outer try is for catching patch failures and exiting gracefully. 931 # Outer try is for catching patch failures and exiting gracefully.
972 # Inner try is for catching gclient failures and retrying gracefully. 932 # Inner try is for catching gclient failures and retrying gracefully.
973 try: 933 try:
974 checkout_parameters = dict( 934 checkout_parameters = dict(
975 # First, pass in the base of what we want to check out. 935 # First, pass in the base of what we want to check out.
976 solutions=git_slns, 936 solutions=git_slns,
977 revisions=revisions, 937 revisions=revisions,
978 first_sln=first_sln, 938 first_sln=first_sln,
979 939
980 # Also, target os variables for gclient. 940 # Also, target os variables for gclient.
981 target_os=specs.get('target_os', []), 941 target_os=specs.get('target_os', []),
982 target_os_only=specs.get('target_os_only', False), 942 target_os_only=specs.get('target_os_only', False),
983 943
984 # Then, pass in information about how to patch. 944 # Then, pass in information about how to patch.
985 patch_root=options.patch_root, 945 patch_root=options.patch_root,
986 issue=options.issue, 946 issue=options.issue,
987 patchset=options.patchset, 947 patchset=options.patchset,
988 rietveld_server=options.rietveld_server, 948 rietveld_server=options.rietveld_server,
989 gerrit_repo=options.gerrit_repo, 949 gerrit_repo=options.gerrit_repo,
990 gerrit_ref=options.gerrit_ref, 950 gerrit_ref=options.gerrit_ref,
991 gerrit_rebase_patch_ref=not options.gerrit_no_rebase_patch_ref, 951 gerrit_rebase_patch_ref=not options.gerrit_no_rebase_patch_ref,
992 revision_mapping=options.revision_mapping, 952 revision_mapping=options.revision_mapping,
993 apply_issue_email_file=options.apply_issue_email_file, 953 apply_issue_email_file=options.apply_issue_email_file,
994 apply_issue_key_file=options.apply_issue_key_file, 954 apply_issue_key_file=options.apply_issue_key_file,
995 955
996 # Finally, extra configurations such as shallowness of the clone. 956 # Finally, extra configurations such as shallowness of the clone.
997 shallow=options.shallow, 957 shallow=shallow,
998 refs=options.refs, 958 refs=options.refs,
999 git_cache_dir=options.git_cache_dir, 959 git_cache_dir=options.git_cache_dir,
1000 gerrit_reset=not options.gerrit_no_reset) 960 gerrit_reset=not options.gerrit_no_reset)
1001 gclient_output = ensure_checkout(**checkout_parameters) 961 gclient_output = ensure_checkout(**checkout_parameters)
1002 except GclientSyncFailed: 962 except GclientSyncFailed:
1003 print 'We failed gclient sync, lets delete the checkout and retry.' 963 print 'We failed gclient sync, lets delete the checkout and retry.'
1004 ensure_no_checkout(dir_names) 964 ensure_no_checkout(dir_names)
1005 gclient_output = ensure_checkout(**checkout_parameters) 965 gclient_output = ensure_checkout(**checkout_parameters)
1006 except PatchFailed as e: 966 except PatchFailed as e:
1007 if options.output_json: 967 if options.output_json:
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1066 'DEPOT_TOOLS_DIR': DEPOT_TOOLS_DIR, 1026 'DEPOT_TOOLS_DIR': DEPOT_TOOLS_DIR,
1067 } 1027 }
1068 for k, v in sorted(debug_params.iteritems()): 1028 for k, v in sorted(debug_params.iteritems()):
1069 print "%s: %r" % (k, v) 1029 print "%s: %r" % (k, v)
1070 1030
1071 1031
1072 def main(): 1032 def main():
1073 # Get inputs. 1033 # Get inputs.
1074 options, _ = parse_args() 1034 options, _ = parse_args()
1075 1035
1076 # Always run. This option will be removed in a later CL, but for now make sure
1077 # that bot_update is ALWAYS set to run, no matter what.
1078 options.force = True
1079
1080 # Check if this script should activate or not. 1036 # Check if this script should activate or not.
1081 active = True 1037 active = True
1082 1038
1083 # Print a helpful message to tell developers whats going on with this step. 1039 # Print a helpful message to tell developers whats going on with this step.
1084 print_debug_info() 1040 print_debug_info()
1085 1041
1086 # Parse, munipulate, and print the gclient solutions. 1042 # Parse, munipulate, and print the gclient solutions.
1087 specs = {} 1043 specs = {}
1088 exec(options.specs, specs) 1044 exec(options.specs, specs)
1089 orig_solutions = specs.get('solutions', []) 1045 orig_solutions = specs.get('solutions', [])
1090 git_slns = modify_solutions(orig_solutions) 1046 git_slns = modify_solutions(orig_solutions)
1091 1047
1092 solutions_printer(git_slns) 1048 solutions_printer(git_slns)
1093 1049
1094 try: 1050 try:
1095 # Dun dun dun, the main part of bot_update. 1051 # Dun dun dun, the main part of bot_update.
1096 revisions, step_text = prepare(options, git_slns, active) 1052 revisions, step_text, shallow = prepare(options, git_slns, active)
1097 checkout(options, git_slns, specs, revisions, step_text) 1053 checkout(options, git_slns, specs, revisions, step_text, shallow)
1098 1054
1099 except PatchFailed as e: 1055 except PatchFailed as e:
1100 emit_flag(options.flag_file)
1101 # Return a specific non-zero exit code for patch failure (because it is 1056 # Return a specific non-zero exit code for patch failure (because it is
1102 # a failure), but make it different than other failures to distinguish 1057 # a failure), but make it different than other failures to distinguish
1103 # between infra failures (independent from patch author), and patch 1058 # between infra failures (independent from patch author), and patch
1104 # failures (that patch author can fix). However, PatchFailure due to 1059 # failures (that patch author can fix). However, PatchFailure due to
1105 # download patch failure is still an infra problem. 1060 # download patch failure is still an infra problem.
1106 if e.code == 3: 1061 if e.code == 3:
1107 # Patch download problem. 1062 # Patch download problem.
1108 return 87 1063 return 87
1109 # Genuine patch problem. 1064 # Genuine patch problem.
1110 return 88 1065 return 88
1111 except Exception:
1112 # Unexpected failure.
1113 emit_flag(options.flag_file)
1114 raise
1115 else:
1116 emit_flag(options.flag_file)
1117 1066
1118 1067
1119 if __name__ == '__main__': 1068 if __name__ == '__main__':
1120 sys.exit(main()) 1069 sys.exit(main())
OLDNEW
« no previous file with comments | « recipe_modules/bot_update/example.expected/tryjob_v8_head_by_default.json ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698