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

Side by Side Diff: tools/mb/mb.py

Issue 2352473002: Re-land "Update MB to use `gn analyze`." (Closed)
Patch Set: remove testing changes 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 | « testing/buildbot/manage.py ('k') | tools/mb/mb_unittest.py » ('j') | 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 2015 The Chromium Authors. All rights reserved. 2 # Copyright 2015 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 """MB - the Meta-Build wrapper around GYP and GN 6 """MB - the Meta-Build wrapper around GYP and GN
7 7
8 MB is a wrapper script for GYP and GN that can be used to generate build files 8 MB is a wrapper script for GYP and GN that can be used to generate build files
9 for sets of canned configurations and analyze them. 9 for sets of canned configurations and analyze them.
10 """ 10 """
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 self.mixins = {} 54 self.mixins = {}
55 55
56 def Main(self, args): 56 def Main(self, args):
57 self.ParseArgs(args) 57 self.ParseArgs(args)
58 try: 58 try:
59 ret = self.args.func() 59 ret = self.args.func()
60 if ret: 60 if ret:
61 self.DumpInputFiles() 61 self.DumpInputFiles()
62 return ret 62 return ret
63 except KeyboardInterrupt: 63 except KeyboardInterrupt:
64 self.Print('interrupted, exiting', stream=sys.stderr) 64 self.Print('interrupted, exiting')
65 return 130 65 return 130
66 except Exception: 66 except Exception:
67 self.DumpInputFiles() 67 self.DumpInputFiles()
68 s = traceback.format_exc() 68 s = traceback.format_exc()
69 for l in s.splitlines(): 69 for l in s.splitlines():
70 self.Print(l) 70 self.Print(l)
71 return 1 71 return 1
72 72
73 def ParseArgs(self, argv): 73 def ParseArgs(self, argv):
74 def AddCommonOptions(subp): 74 def AddCommonOptions(subp):
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 help='The command to get help for.') 222 help='The command to get help for.')
223 subp.set_defaults(func=self.CmdHelp) 223 subp.set_defaults(func=self.CmdHelp)
224 224
225 self.args = parser.parse_args(argv) 225 self.args = parser.parse_args(argv)
226 226
227 def DumpInputFiles(self): 227 def DumpInputFiles(self):
228 228
229 def DumpContentsOfFilePassedTo(arg_name, path): 229 def DumpContentsOfFilePassedTo(arg_name, path):
230 if path and self.Exists(path): 230 if path and self.Exists(path):
231 self.Print("\n# To recreate the file passed to %s:" % arg_name) 231 self.Print("\n# To recreate the file passed to %s:" % arg_name)
232 self.Print("%% cat > %s <<EOF)" % path) 232 self.Print("%% cat > %s <<EOF" % path)
233 contents = self.ReadFile(path) 233 contents = self.ReadFile(path)
234 self.Print(contents) 234 self.Print(contents)
235 self.Print("EOF\n%\n") 235 self.Print("EOF\n%\n")
236 236
237 if getattr(self.args, 'input_path', None): 237 if getattr(self.args, 'input_path', None):
238 DumpContentsOfFilePassedTo( 238 DumpContentsOfFilePassedTo(
239 'argv[0] (input_path)', self.args.input_path[0]) 239 'argv[0] (input_path)', self.args.input_path[0])
240 if getattr(self.args, 'swarming_targets_file', None): 240 if getattr(self.args, 'swarming_targets_file', None):
241 DumpContentsOfFilePassedTo( 241 DumpContentsOfFilePassedTo(
242 '--swarming-targets-file', self.args.swarming_targets_file) 242 '--swarming-targets-file', self.args.swarming_targets_file)
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 try: 636 try:
637 contents = ast.literal_eval(self.ReadFile(self.args.config_file)) 637 contents = ast.literal_eval(self.ReadFile(self.args.config_file))
638 except SyntaxError as e: 638 except SyntaxError as e:
639 raise MBErr('Failed to parse config file "%s": %s' % 639 raise MBErr('Failed to parse config file "%s": %s' %
640 (self.args.config_file, e)) 640 (self.args.config_file, e))
641 641
642 self.configs = contents['configs'] 642 self.configs = contents['configs']
643 self.masters = contents['masters'] 643 self.masters = contents['masters']
644 self.mixins = contents['mixins'] 644 self.mixins = contents['mixins']
645 645
646 def ReadIsolateMap(self):
647 return ast.literal_eval(self.ReadFile(self.PathJoin(
648 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl')))
649
646 def ConfigFromArgs(self): 650 def ConfigFromArgs(self):
647 if self.args.config: 651 if self.args.config:
648 if self.args.master or self.args.builder: 652 if self.args.master or self.args.builder:
649 raise MBErr('Can not specific both -c/--config and -m/--master or ' 653 raise MBErr('Can not specific both -c/--config and -m/--master or '
650 '-b/--builder') 654 '-b/--builder')
651 655
652 return self.args.config 656 return self.args.config
653 657
654 if not self.args.master or not self.args.builder: 658 if not self.args.master or not self.args.builder:
655 raise MBErr('Must specify either -c/--config or ' 659 raise MBErr('Must specify either -c/--config or '
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 # Since GN hasn't run yet, the build directory may not even exist. 767 # Since GN hasn't run yet, the build directory may not even exist.
764 self.MaybeMakeDirectory(self.ToAbsPath(build_dir)) 768 self.MaybeMakeDirectory(self.ToAbsPath(build_dir))
765 769
766 gn_args_path = self.ToAbsPath(build_dir, 'args.gn') 770 gn_args_path = self.ToAbsPath(build_dir, 'args.gn')
767 self.WriteFile(gn_args_path, gn_args, force_verbose=True) 771 self.WriteFile(gn_args_path, gn_args, force_verbose=True)
768 772
769 swarming_targets = [] 773 swarming_targets = []
770 if getattr(self.args, 'swarming_targets_file', None): 774 if getattr(self.args, 'swarming_targets_file', None):
771 # We need GN to generate the list of runtime dependencies for 775 # We need GN to generate the list of runtime dependencies for
772 # the compile targets listed (one per line) in the file so 776 # the compile targets listed (one per line) in the file so
773 # we can run them via swarming. We use ninja_to_gn.pyl to convert 777 # we can run them via swarming. We use gn_isolate_map.pyl to convert
774 # the compile targets to the matching GN labels. 778 # the compile targets to the matching GN labels.
775 path = self.args.swarming_targets_file 779 path = self.args.swarming_targets_file
776 if not self.Exists(path): 780 if not self.Exists(path):
777 self.WriteFailureAndRaise('"%s" does not exist' % path, 781 self.WriteFailureAndRaise('"%s" does not exist' % path,
778 output_path=None) 782 output_path=None)
779 contents = self.ReadFile(path) 783 contents = self.ReadFile(path)
780 swarming_targets = set(contents.splitlines()) 784 swarming_targets = set(contents.splitlines())
781 gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin(
782 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl')))
783 gn_labels = []
784 err = ''
785 for target in swarming_targets:
786 target_name = self.GNTargetName(target)
787 if not target_name in gn_isolate_map:
788 err += ('test target "%s" not found\n' % target_name)
789 elif gn_isolate_map[target_name]['type'] == 'unknown':
790 err += ('test target "%s" type is unknown\n' % target_name)
791 else:
792 gn_labels.append(gn_isolate_map[target_name]['label'])
793 785
786 isolate_map = self.ReadIsolateMap()
787 err, labels = self.MapTargetsToLabels(isolate_map, swarming_targets)
794 if err: 788 if err:
795 raise MBErr('Error: Failed to match swarming targets to %s:\n%s' % 789 raise MBErr(err)
796 ('//testing/buildbot/gn_isolate_map.pyl', err))
797 790
798 gn_runtime_deps_path = self.ToAbsPath(build_dir, 'runtime_deps') 791 gn_runtime_deps_path = self.ToAbsPath(build_dir, 'runtime_deps')
799 self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n') 792 self.WriteFile(gn_runtime_deps_path, '\n'.join(labels) + '\n')
800 cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path) 793 cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path)
801 794
802 ret, _, _ = self.Run(cmd) 795 ret, _, _ = self.Run(cmd)
803 if ret: 796 if ret:
804 # If `gn gen` failed, we should exit early rather than trying to 797 # If `gn gen` failed, we should exit early rather than trying to
805 # generate isolates. Run() will have already logged any error output. 798 # generate isolates. Run() will have already logged any error output.
806 self.Print('GN gen failed: %d' % ret) 799 self.Print('GN gen failed: %d' % ret)
807 return ret 800 return ret
808 801
809 android = 'target_os="android"' in vals['gn_args'] 802 android = 'target_os="android"' in vals['gn_args']
810 for target in swarming_targets: 803 for target in swarming_targets:
811 if android: 804 if android:
812 # Android targets may be either android_apk or executable. The former 805 # Android targets may be either android_apk or executable. The former
813 # will result in runtime_deps associated with the stamp file, while the 806 # will result in runtime_deps associated with the stamp file, while the
814 # latter will result in runtime_deps associated with the executable. 807 # latter will result in runtime_deps associated with the executable.
815 target_name = self.GNTargetName(target) 808 label = isolate_map[target]['label']
816 label = gn_isolate_map[target_name]['label']
817 runtime_deps_targets = [ 809 runtime_deps_targets = [
818 target_name + '.runtime_deps', 810 target + '.runtime_deps',
819 'obj/%s.stamp.runtime_deps' % label.replace(':', '/')] 811 'obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
820 elif gn_isolate_map[target]['type'] == 'gpu_browser_test': 812 elif isolate_map[target]['type'] == 'gpu_browser_test':
821 if self.platform == 'win32': 813 if self.platform == 'win32':
822 runtime_deps_targets = ['browser_tests.exe.runtime_deps'] 814 runtime_deps_targets = ['browser_tests.exe.runtime_deps']
823 else: 815 else:
824 runtime_deps_targets = ['browser_tests.runtime_deps'] 816 runtime_deps_targets = ['browser_tests.runtime_deps']
825 elif (gn_isolate_map[target]['type'] == 'script' or 817 elif (isolate_map[target]['type'] == 'script' or
826 gn_isolate_map[target].get('label_type') == 'group'): 818 isolate_map[target].get('label_type') == 'group'):
827 # For script targets, the build target is usually a group, 819 # For script targets, the build target is usually a group,
828 # for which gn generates the runtime_deps next to the stamp file 820 # for which gn generates the runtime_deps next to the stamp file
829 # for the label, which lives under the obj/ directory. 821 # for the label, which lives under the obj/ directory.
830 label = gn_isolate_map[target]['label'] 822 label = isolate_map[target]['label']
831 runtime_deps_targets = [ 823 runtime_deps_targets = [
832 'obj/%s.stamp.runtime_deps' % label.replace(':', '/')] 824 'obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
833 elif self.platform == 'win32': 825 elif self.platform == 'win32':
834 runtime_deps_targets = [target + '.exe.runtime_deps'] 826 runtime_deps_targets = [target + '.exe.runtime_deps']
835 else: 827 else:
836 runtime_deps_targets = [target + '.runtime_deps'] 828 runtime_deps_targets = [target + '.runtime_deps']
837 829
838 for r in runtime_deps_targets: 830 for r in runtime_deps_targets:
839 runtime_deps_path = self.ToAbsPath(build_dir, r) 831 runtime_deps_path = self.ToAbsPath(build_dir, r)
840 if self.Exists(runtime_deps_path): 832 if self.Exists(runtime_deps_path):
841 break 833 break
842 else: 834 else:
843 raise MBErr('did not generate any of %s' % 835 raise MBErr('did not generate any of %s' %
844 ', '.join(runtime_deps_targets)) 836 ', '.join(runtime_deps_targets))
845 837
846 command, extra_files = self.GetIsolateCommand(target, vals, 838 command, extra_files = self.GetIsolateCommand(target, vals)
847 gn_isolate_map)
848 839
849 runtime_deps = self.ReadFile(runtime_deps_path).splitlines() 840 runtime_deps = self.ReadFile(runtime_deps_path).splitlines()
850 841
851 self.WriteIsolateFiles(build_dir, command, target, runtime_deps, 842 self.WriteIsolateFiles(build_dir, command, target, runtime_deps,
852 extra_files) 843 extra_files)
853 844
854 return 0 845 return 0
855 846
856 def RunGNIsolate(self, vals): 847 def RunGNIsolate(self, vals):
857 gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin( 848 target = self.args.target[0]
858 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl'))) 849 isolate_map = self.ReadIsolateMap()
850 err, labels = self.MapTargetsToLabels(isolate_map, [target])
851 if err:
852 raise MBErr(err)
853 label = labels[0]
859 854
860 build_dir = self.args.path[0] 855 build_dir = self.args.path[0]
861 target = self.args.target[0] 856 command, extra_files = self.GetIsolateCommand(target, vals)
862 target_name = self.GNTargetName(target)
863 command, extra_files = self.GetIsolateCommand(target, vals, gn_isolate_map)
864 857
865 label = gn_isolate_map[target_name]['label']
866 cmd = self.GNCmd('desc', build_dir, label, 'runtime_deps') 858 cmd = self.GNCmd('desc', build_dir, label, 'runtime_deps')
867 ret, out, _ = self.Call(cmd) 859 ret, out, _ = self.Call(cmd)
868 if ret: 860 if ret:
869 if out: 861 if out:
870 self.Print(out) 862 self.Print(out)
871 return ret 863 return ret
872 864
873 runtime_deps = out.splitlines() 865 runtime_deps = out.splitlines()
874 866
875 self.WriteIsolateFiles(build_dir, command, target, runtime_deps, 867 self.WriteIsolateFiles(build_dir, command, target, runtime_deps,
(...skipping 29 matching lines...) Expand all
905 self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target)), 897 self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target)),
906 '--isolate', 898 '--isolate',
907 self.ToSrcRelPath('%s/%s.isolate' % (build_dir, target)), 899 self.ToSrcRelPath('%s/%s.isolate' % (build_dir, target)),
908 ], 900 ],
909 'dir': self.chromium_src_dir, 901 'dir': self.chromium_src_dir,
910 'version': 1, 902 'version': 1,
911 }, 903 },
912 isolate_path + 'd.gen.json', 904 isolate_path + 'd.gen.json',
913 ) 905 )
914 906
907 def MapTargetsToLabels(self, isolate_map, targets):
908 labels = []
909 err = ''
910
911 def StripTestSuffixes(target):
912 for suffix in ('_apk_run', '_apk', '_run'):
913 if target.endswith(suffix):
914 return target[:-len(suffix)], suffix
915 return None, None
916
917 for target in targets:
918 if target == 'all':
919 labels.append(target)
920 elif target.startswith('//'):
921 labels.append(target)
922 else:
923 if target in isolate_map:
924 stripped_target, suffix = target, ''
925 else:
926 stripped_target, suffix = StripTestSuffixes(target)
927 if stripped_target in isolate_map:
928 if isolate_map[stripped_target]['type'] == 'unknown':
929 err += ('test target "%s" type is unknown\n' % target)
930 else:
931 labels.append(isolate_map[stripped_target]['label'] + suffix)
932 else:
933 err += ('target "%s" not found in '
934 '//testing/buildbot/gn_isolate_map.pyl\n' % target)
935
936 return err, labels
937
915 def GNCmd(self, subcommand, path, *args): 938 def GNCmd(self, subcommand, path, *args):
916 if self.platform == 'linux2': 939 if self.platform == 'linux2':
917 subdir, exe = 'linux64', 'gn' 940 subdir, exe = 'linux64', 'gn'
918 elif self.platform == 'darwin': 941 elif self.platform == 'darwin':
919 subdir, exe = 'mac', 'gn' 942 subdir, exe = 'mac', 'gn'
920 else: 943 else:
921 subdir, exe = 'win', 'gn.exe' 944 subdir, exe = 'win', 'gn.exe'
922 945
923 gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, exe) 946 gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, exe)
947 return [gn_path, subcommand, path] + list(args)
924 948
925 return [gn_path, subcommand, path] + list(args)
926 949
927 def GNArgs(self, vals): 950 def GNArgs(self, vals):
928 if vals['cros_passthrough']: 951 if vals['cros_passthrough']:
929 if not 'GN_ARGS' in os.environ: 952 if not 'GN_ARGS' in os.environ:
930 raise MBErr('MB is expecting GN_ARGS to be in the environment') 953 raise MBErr('MB is expecting GN_ARGS to be in the environment')
931 gn_args = os.environ['GN_ARGS'] 954 gn_args = os.environ['GN_ARGS']
932 if not re.search('target_os.*=.*"chromeos"', gn_args): 955 if not re.search('target_os.*=.*"chromeos"', gn_args):
933 raise MBErr('GN_ARGS is missing target_os = "chromeos": (GN_ARGS=%s)' % 956 raise MBErr('GN_ARGS is missing target_os = "chromeos": (GN_ARGS=%s)' %
934 gn_args) 957 gn_args)
935 else: 958 else:
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
981 ret, _, _ = self.Run(cmd, env=env) 1004 ret, _, _ = self.Run(cmd, env=env)
982 if not ret and self.args.verbose: 1005 if not ret and self.args.verbose:
983 outp = json.loads(self.ReadFile(self.args.output_path[0])) 1006 outp = json.loads(self.ReadFile(self.args.output_path[0]))
984 self.Print() 1007 self.Print()
985 self.Print('analyze output:') 1008 self.Print('analyze output:')
986 self.PrintJSON(outp) 1009 self.PrintJSON(outp)
987 self.Print() 1010 self.Print()
988 1011
989 return ret 1012 return ret
990 1013
991 def GetIsolateCommand(self, target, vals, gn_isolate_map): 1014 def GetIsolateCommand(self, target, vals):
992 android = 'target_os="android"' in vals['gn_args'] 1015 android = 'target_os="android"' in vals['gn_args']
993 1016
994 # This needs to mirror the settings in //build/config/ui.gni: 1017 # This needs to mirror the settings in //build/config/ui.gni:
995 # use_x11 = is_linux && !use_ozone. 1018 # use_x11 = is_linux && !use_ozone.
996 use_x11 = (self.platform == 'linux2' and 1019 use_x11 = (self.platform == 'linux2' and
997 not android and 1020 not android and
998 not 'use_ozone=true' in vals['gn_args']) 1021 not 'use_ozone=true' in vals['gn_args'])
999 1022
1000 asan = 'is_asan=true' in vals['gn_args'] 1023 asan = 'is_asan=true' in vals['gn_args']
1001 msan = 'is_msan=true' in vals['gn_args'] 1024 msan = 'is_msan=true' in vals['gn_args']
1002 tsan = 'is_tsan=true' in vals['gn_args'] 1025 tsan = 'is_tsan=true' in vals['gn_args']
1003 1026
1004 target_name = self.GNTargetName(target) 1027 isolate_map = self.ReadIsolateMap()
1005 test_type = gn_isolate_map[target_name]['type'] 1028 test_type = isolate_map[target]['type']
1006 1029
1007 executable = gn_isolate_map[target_name].get('executable', target_name) 1030 executable = isolate_map[target].get('executable', target)
1008 executable_suffix = '.exe' if self.platform == 'win32' else '' 1031 executable_suffix = '.exe' if self.platform == 'win32' else ''
1009 1032
1010 cmdline = [] 1033 cmdline = []
1011 extra_files = [] 1034 extra_files = []
1012 1035
1036 if test_type == 'nontest':
1037 self.WriteFailureAndRaise('We should not be isolating %s.' % target,
1038 output_path=None)
1039
1013 if android and test_type != "script": 1040 if android and test_type != "script":
1014 logdog_command = [ 1041 logdog_command = [
1015 '--logdog-bin-cmd', './../../bin/logdog_butler', 1042 '--logdog-bin-cmd', './../../bin/logdog_butler',
1016 '--project', 'chromium', 1043 '--project', 'chromium',
1017 '--service-account-json', 1044 '--service-account-json',
1018 '/creds/service_accounts/service-account-luci-logdog-publisher.json', 1045 '/creds/service_accounts/service-account-luci-logdog-publisher.json',
1019 '--prefix', 'android/swarming/logcats/${SWARMING_TASK_ID}', 1046 '--prefix', 'android/swarming/logcats/${SWARMING_TASK_ID}',
1020 '--source', '${ISOLATED_OUTDIR}/logcats', 1047 '--source', '${ISOLATED_OUTDIR}/logcats',
1021 '--name', 'unified_logcats', 1048 '--name', 'unified_logcats',
1022 ] 1049 ]
1023 test_cmdline = [ 1050 test_cmdline = [
1024 self.PathJoin('bin', 'run_%s' % target_name), 1051 self.PathJoin('bin', 'run_%s' % target),
1025 '--logcat-output-file', '${ISOLATED_OUTDIR}/logcats', 1052 '--logcat-output-file', '${ISOLATED_OUTDIR}/logcats',
1026 '--target-devices-file', '${SWARMING_BOT_FILE}', 1053 '--target-devices-file', '${SWARMING_BOT_FILE}',
1027 '-v' 1054 '-v'
1028 ] 1055 ]
1029 cmdline = (['./../../build/android/test_wrapper/logdog_wrapper.py'] 1056 cmdline = (['./../../build/android/test_wrapper/logdog_wrapper.py']
1030 + logdog_command + test_cmdline) 1057 + logdog_command + test_cmdline)
1031 elif use_x11 and test_type == 'windowed_test_launcher': 1058 elif use_x11 and test_type == 'windowed_test_launcher':
1032 extra_files = [ 1059 extra_files = [
1033 'xdisplaycheck', 1060 'xdisplaycheck',
1034 '../../testing/test_env.py', 1061 '../../testing/test_env.py',
(...skipping 19 matching lines...) Expand all
1054 '--brave-new-test-launcher', 1081 '--brave-new-test-launcher',
1055 '--test-launcher-bot-mode', 1082 '--test-launcher-bot-mode',
1056 '--asan=%d' % asan, 1083 '--asan=%d' % asan,
1057 '--msan=%d' % msan, 1084 '--msan=%d' % msan,
1058 '--tsan=%d' % tsan, 1085 '--tsan=%d' % tsan,
1059 ] 1086 ]
1060 elif test_type == 'gpu_browser_test': 1087 elif test_type == 'gpu_browser_test':
1061 extra_files = [ 1088 extra_files = [
1062 '../../testing/test_env.py' 1089 '../../testing/test_env.py'
1063 ] 1090 ]
1064 gtest_filter = gn_isolate_map[target]['gtest_filter'] 1091 gtest_filter = isolate_map[target]['gtest_filter']
1065 cmdline = [ 1092 cmdline = [
1066 '../../testing/test_env.py', 1093 '../../testing/test_env.py',
1067 './browser_tests' + executable_suffix, 1094 './browser_tests' + executable_suffix,
1068 '--test-launcher-bot-mode', 1095 '--test-launcher-bot-mode',
1069 '--enable-gpu', 1096 '--enable-gpu',
1070 '--test-launcher-jobs=1', 1097 '--test-launcher-jobs=1',
1071 '--gtest_filter=%s' % gtest_filter, 1098 '--gtest_filter=%s' % gtest_filter,
1072 ] 1099 ]
1073 elif test_type == 'script': 1100 elif test_type == 'script':
1074 extra_files = [ 1101 extra_files = [
1075 '../../testing/test_env.py' 1102 '../../testing/test_env.py'
1076 ] 1103 ]
1077 cmdline = [ 1104 cmdline = [
1078 '../../testing/test_env.py', 1105 '../../testing/test_env.py',
1079 '../../' + self.ToSrcRelPath(gn_isolate_map[target]['script']) 1106 '../../' + self.ToSrcRelPath(isolate_map[target]['script'])
1080 ] 1107 ]
1081 elif test_type in ('raw'): 1108 elif test_type in ('raw'):
1082 extra_files = [] 1109 extra_files = []
1083 cmdline = [ 1110 cmdline = [
1084 './' + str(target) + executable_suffix, 1111 './' + str(target) + executable_suffix,
1085 ] 1112 ]
1086 1113
1087 else: 1114 else:
1088 self.WriteFailureAndRaise('No command line for %s found (test type %s).' 1115 self.WriteFailureAndRaise('No command line for %s found (test type %s).'
1089 % (target, test_type), output_path=None) 1116 % (target, test_type), output_path=None)
1090 1117
1091 cmdline += gn_isolate_map[target_name].get('args', []) 1118 cmdline += isolate_map[target].get('args', [])
1092 1119
1093 return cmdline, extra_files 1120 return cmdline, extra_files
1094 1121
1095 def ToAbsPath(self, build_path, *comps): 1122 def ToAbsPath(self, build_path, *comps):
1096 return self.PathJoin(self.chromium_src_dir, 1123 return self.PathJoin(self.chromium_src_dir,
1097 self.ToSrcRelPath(build_path), 1124 self.ToSrcRelPath(build_path),
1098 *comps) 1125 *comps)
1099 1126
1100 def ToSrcRelPath(self, path): 1127 def ToSrcRelPath(self, path):
1101 """Returns a relative path from the top of the repo.""" 1128 """Returns a relative path from the top of the repo."""
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1177 if 'GYP_CHROMIUM_NO_ACTION' in env: 1204 if 'GYP_CHROMIUM_NO_ACTION' in env:
1178 del env['GYP_CHROMIUM_NO_ACTION'] 1205 del env['GYP_CHROMIUM_NO_ACTION']
1179 if 'GYP_CROSSCOMPILE' in env: 1206 if 'GYP_CROSSCOMPILE' in env:
1180 del env['GYP_CROSSCOMPILE'] 1207 del env['GYP_CROSSCOMPILE']
1181 env['GYP_DEFINES'] = gyp_defines 1208 env['GYP_DEFINES'] = gyp_defines
1182 if vals['gyp_crosscompile']: 1209 if vals['gyp_crosscompile']:
1183 env['GYP_CROSSCOMPILE'] = '1' 1210 env['GYP_CROSSCOMPILE'] = '1'
1184 return cmd, env 1211 return cmd, env
1185 1212
1186 def RunGNAnalyze(self, vals): 1213 def RunGNAnalyze(self, vals):
1187 # analyze runs before 'gn gen' now, so we need to run gn gen 1214 # Analyze runs before 'gn gen' now, so we need to run gn gen
1188 # in order to ensure that we have a build directory. 1215 # in order to ensure that we have a build directory.
1189 ret = self.RunGNGen(vals) 1216 ret = self.RunGNGen(vals)
1190 if ret: 1217 if ret:
1191 return ret 1218 return ret
1192 1219
1220 build_path = self.args.path[0]
1221 input_path = self.args.input_path[0]
1222 gn_input_path = input_path + '.gn'
1223 output_path = self.args.output_path[0]
1224 gn_output_path = output_path + '.gn'
1225
1193 inp = self.ReadInputJSON(['files', 'test_targets', 1226 inp = self.ReadInputJSON(['files', 'test_targets',
1194 'additional_compile_targets']) 1227 'additional_compile_targets'])
1195 if self.args.verbose: 1228 if self.args.verbose:
1196 self.Print() 1229 self.Print()
1197 self.Print('analyze input:') 1230 self.Print('analyze input:')
1198 self.PrintJSON(inp) 1231 self.PrintJSON(inp)
1199 self.Print() 1232 self.Print()
1200 1233
1201 # TODO(crbug.com/555273) - currently GN treats targets and
1202 # additional_compile_targets identically since we can't tell the
1203 # difference between a target that is a group in GN and one that isn't.
1204 # We should eventually fix this and treat the two types differently.
1205 targets = (set(inp['test_targets']) |
1206 set(inp['additional_compile_targets']))
1207
1208 output_path = self.args.output_path[0]
1209
1210 # Bail out early if a GN file was modified, since 'gn refs' won't know
1211 # what to do about it. Also, bail out early if 'all' was asked for,
1212 # since we can't deal with it yet.
1213 if (any(f.endswith('.gn') or f.endswith('.gni') for f in inp['files']) or
1214 'all' in targets):
1215 self.WriteJSON({
1216 'status': 'Found dependency (all)',
1217 'compile_targets': sorted(targets),
1218 'test_targets': sorted(targets & set(inp['test_targets'])),
1219 }, output_path)
1220 return 0
1221 1234
1222 # This shouldn't normally happen, but could due to unusual race conditions, 1235 # This shouldn't normally happen, but could due to unusual race conditions,
1223 # like a try job that gets scheduled before a patch lands but runs after 1236 # like a try job that gets scheduled before a patch lands but runs after
1224 # the patch has landed. 1237 # the patch has landed.
1225 if not inp['files']: 1238 if not inp['files']:
1226 self.Print('Warning: No files modified in patch, bailing out early.') 1239 self.Print('Warning: No files modified in patch, bailing out early.')
1227 self.WriteJSON({ 1240 self.WriteJSON({
1228 'status': 'No dependency', 1241 'status': 'No dependency',
1229 'compile_targets': [], 1242 'compile_targets': [],
1230 'test_targets': [], 1243 'test_targets': [],
1231 }, output_path) 1244 }, output_path)
1232 return 0 1245 return 0
1233 1246
1234 ret = 0 1247 gn_inp = {}
1235 response_file = self.TempFile() 1248 gn_inp['files'] = ['//' + f for f in inp['files'] if not f.startswith('//')]
1236 response_file.write('\n'.join(inp['files']) + '\n')
1237 response_file.close()
1238 1249
1239 matching_targets = set() 1250 isolate_map = self.ReadIsolateMap()
1251 err, gn_inp['additional_compile_targets'] = self.MapTargetsToLabels(
1252 isolate_map, inp['additional_compile_targets'])
1253 if err:
1254 raise MBErr(err)
1255
1256 err, gn_inp['test_targets'] = self.MapTargetsToLabels(
1257 isolate_map, inp['test_targets'])
1258 if err:
1259 raise MBErr(err)
1260 labels_to_targets = {}
1261 for i, label in enumerate(gn_inp['test_targets']):
1262 labels_to_targets[label] = inp['test_targets'][i]
1263
1240 try: 1264 try:
1241 cmd = self.GNCmd('refs', 1265 self.WriteJSON(gn_inp, gn_input_path)
1242 self.args.path[0], 1266 cmd = self.GNCmd('analyze', build_path, gn_input_path, gn_output_path)
1243 '@%s' % response_file.name, 1267 ret, _, _ = self.Run(cmd, force_verbose=True)
1244 '--all', 1268 if ret:
1245 '--as=output') 1269 return ret
1246 ret, out, _ = self.Run(cmd, force_verbose=False)
1247 if ret and not 'The input matches no targets' in out:
1248 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out),
1249 output_path)
1250 build_dir = self.ToSrcRelPath(self.args.path[0]) + self.sep
1251 for output in out.splitlines():
1252 build_output = output.replace(build_dir, '')
1253 if build_output in targets:
1254 matching_targets.add(build_output)
1255 1270
1256 cmd = self.GNCmd('refs', 1271 gn_outp_str = self.ReadFile(gn_output_path)
1257 self.args.path[0], 1272 try:
1258 '@%s' % response_file.name, 1273 gn_outp = json.loads(gn_outp_str)
1259 '--all') 1274 except Exception as e:
1260 ret, out, _ = self.Run(cmd, force_verbose=False) 1275 self.Print("Failed to parse the JSON string GN returned: %s\n%s"
1261 if ret and not 'The input matches no targets' in out: 1276 % (repr(gn_outp_str), str(e)))
1262 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), 1277 raise
1263 output_path) 1278
1264 for label in out.splitlines(): 1279 outp = {}
1265 build_target = label[2:] 1280 if 'status' in gn_outp:
1266 # We want to accept 'chrome/android:chrome_public_apk' and 1281 outp['status'] = gn_outp['status']
1267 # just 'chrome_public_apk'. This may result in too many targets 1282 if 'error' in gn_outp:
1268 # getting built, but we can adjust that later if need be. 1283 outp['error'] = gn_outp['error']
1269 for input_target in targets: 1284 if 'invalid_targets' in gn_outp:
1270 if (input_target == build_target or 1285 outp['invalid_targets'] = gn_outp['invalid_targets']
1271 build_target.endswith(':' + input_target)): 1286 if 'compile_targets' in gn_outp:
1272 matching_targets.add(input_target) 1287 outp['compile_targets'] = [
1288 label.replace('//', '') for label in gn_outp['compile_targets']]
1289 if 'test_targets' in gn_outp:
1290 outp['test_targets'] = [
1291 labels_to_targets[label] for label in gn_outp['test_targets']]
1292
1293 if self.args.verbose:
1294 self.Print()
1295 self.Print('analyze output:')
1296 self.PrintJSON(outp)
1297 self.Print()
1298
1299 self.WriteJSON(outp, output_path)
1300
1273 finally: 1301 finally:
1274 self.RemoveFile(response_file.name) 1302 if self.Exists(gn_input_path):
1275 1303 self.RemoveFile(gn_input_path)
1276 if matching_targets: 1304 if self.Exists(gn_output_path):
1277 self.WriteJSON({ 1305 self.RemoveFile(gn_output_path)
1278 'status': 'Found dependency',
1279 'compile_targets': sorted(matching_targets),
1280 'test_targets': sorted(matching_targets &
1281 set(inp['test_targets'])),
1282 }, output_path)
1283 else:
1284 self.WriteJSON({
1285 'status': 'No dependency',
1286 'compile_targets': [],
1287 'test_targets': [],
1288 }, output_path)
1289
1290 if self.args.verbose:
1291 outp = json.loads(self.ReadFile(output_path))
1292 self.Print()
1293 self.Print('analyze output:')
1294 self.PrintJSON(outp)
1295 self.Print()
1296 1306
1297 return 0 1307 return 0
1298 1308
1299 def ReadInputJSON(self, required_keys): 1309 def ReadInputJSON(self, required_keys):
1300 path = self.args.input_path[0] 1310 path = self.args.input_path[0]
1301 output_path = self.args.output_path[0] 1311 output_path = self.args.output_path[0]
1302 if not self.Exists(path): 1312 if not self.Exists(path):
1303 self.WriteFailureAndRaise('"%s" does not exist' % path, output_path) 1313 self.WriteFailureAndRaise('"%s" does not exist' % path, output_path)
1304 1314
1305 try: 1315 try:
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1368 print_env('GYP_LINK_CONCURRENCY') 1378 print_env('GYP_LINK_CONCURRENCY')
1369 print_env('LLVM_FORCE_HEAD_REVISION') 1379 print_env('LLVM_FORCE_HEAD_REVISION')
1370 1380
1371 if cmd[0] == self.executable: 1381 if cmd[0] == self.executable:
1372 cmd = ['python'] + cmd[1:] 1382 cmd = ['python'] + cmd[1:]
1373 self.Print(*[shell_quoter(arg) for arg in cmd]) 1383 self.Print(*[shell_quoter(arg) for arg in cmd])
1374 1384
1375 def PrintJSON(self, obj): 1385 def PrintJSON(self, obj):
1376 self.Print(json.dumps(obj, indent=2, sort_keys=True)) 1386 self.Print(json.dumps(obj, indent=2, sort_keys=True))
1377 1387
1378 def GNTargetName(self, target):
1379 return target
1380
1381 def Build(self, target): 1388 def Build(self, target):
1382 build_dir = self.ToSrcRelPath(self.args.path[0]) 1389 build_dir = self.ToSrcRelPath(self.args.path[0])
1383 ninja_cmd = ['ninja', '-C', build_dir] 1390 ninja_cmd = ['ninja', '-C', build_dir]
1384 if self.args.jobs: 1391 if self.args.jobs:
1385 ninja_cmd.extend(['-j', '%d' % self.args.jobs]) 1392 ninja_cmd.extend(['-j', '%d' % self.args.jobs])
1386 ninja_cmd.append(target) 1393 ninja_cmd.append(target)
1387 ret, _, _ = self.Run(ninja_cmd, force_verbose=False, buffer_output=False) 1394 ret, _, _ = self.Run(ninja_cmd, force_verbose=False, buffer_output=False)
1388 return ret 1395 return ret
1389 1396
1390 def Run(self, cmd, env=None, force_verbose=True, buffer_output=True): 1397 def Run(self, cmd, env=None, force_verbose=True, buffer_output=True):
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
1513 # Then check to see if the arg contains any metacharacters other than 1520 # Then check to see if the arg contains any metacharacters other than
1514 # double quotes; if it does, quote everything (including the double 1521 # double quotes; if it does, quote everything (including the double
1515 # quotes) for safety. 1522 # quotes) for safety.
1516 if any(a in UNSAFE_FOR_CMD for a in arg): 1523 if any(a in UNSAFE_FOR_CMD for a in arg):
1517 arg = ''.join('^' + a if a in ALL_META_CHARS else a for a in arg) 1524 arg = ''.join('^' + a if a in ALL_META_CHARS else a for a in arg)
1518 return arg 1525 return arg
1519 1526
1520 1527
1521 if __name__ == '__main__': 1528 if __name__ == '__main__':
1522 sys.exit(main(sys.argv[1:])) 1529 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « testing/buildbot/manage.py ('k') | tools/mb/mb_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698