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