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

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

Issue 2298403002: Update MB to use `gn analyze`. (Closed)
Patch Set: add mapping for remaining targets 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
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 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
915 def GNCmd(self, subcommand, path, *args): 928 def GNCmd(self, subcommand, path, *args):
916 if self.platform == 'linux2': 929 if self.platform == 'linux2':
917 subdir, exe = 'linux64', 'gn' 930 subdir, exe = 'linux64', 'gn'
918 elif self.platform == 'darwin': 931 elif self.platform == 'darwin':
919 subdir, exe = 'mac', 'gn' 932 subdir, exe = 'mac', 'gn'
920 else: 933 else:
921 subdir, exe = 'win', 'gn.exe' 934 subdir, exe = 'win', 'gn.exe'
922 935
923 gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, exe) 936 gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, exe)
937 return [gn_path, subcommand, path] + list(args)
924 938
925 return [gn_path, subcommand, path] + list(args)
926 939
927 def GNArgs(self, vals): 940 def GNArgs(self, vals):
928 if vals['cros_passthrough']: 941 if vals['cros_passthrough']:
929 if not 'GN_ARGS' in os.environ: 942 if not 'GN_ARGS' in os.environ:
930 raise MBErr('MB is expecting GN_ARGS to be in the environment') 943 raise MBErr('MB is expecting GN_ARGS to be in the environment')
931 gn_args = os.environ['GN_ARGS'] 944 gn_args = os.environ['GN_ARGS']
932 if not re.search('target_os.*=.*"chromeos"', gn_args): 945 if not re.search('target_os.*=.*"chromeos"', gn_args):
933 raise MBErr('GN_ARGS is missing target_os = "chromeos": (GN_ARGS=%s)' % 946 raise MBErr('GN_ARGS is missing target_os = "chromeos": (GN_ARGS=%s)' %
934 gn_args) 947 gn_args)
935 else: 948 else:
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
981 ret, _, _ = self.Run(cmd, env=env) 994 ret, _, _ = self.Run(cmd, env=env)
982 if not ret and self.args.verbose: 995 if not ret and self.args.verbose:
983 outp = json.loads(self.ReadFile(self.args.output_path[0])) 996 outp = json.loads(self.ReadFile(self.args.output_path[0]))
984 self.Print() 997 self.Print()
985 self.Print('analyze output:') 998 self.Print('analyze output:')
986 self.PrintJSON(outp) 999 self.PrintJSON(outp)
987 self.Print() 1000 self.Print()
988 1001
989 return ret 1002 return ret
990 1003
991 def GetIsolateCommand(self, target, vals, gn_isolate_map): 1004 def GetIsolateCommand(self, target, vals):
992 android = 'target_os="android"' in vals['gn_args'] 1005 android = 'target_os="android"' in vals['gn_args']
993 1006
994 # This needs to mirror the settings in //build/config/ui.gni: 1007 # This needs to mirror the settings in //build/config/ui.gni:
995 # use_x11 = is_linux && !use_ozone. 1008 # use_x11 = is_linux && !use_ozone.
996 use_x11 = (self.platform == 'linux2' and 1009 use_x11 = (self.platform == 'linux2' and
997 not android and 1010 not android and
998 not 'use_ozone=true' in vals['gn_args']) 1011 not 'use_ozone=true' in vals['gn_args'])
999 1012
1000 asan = 'is_asan=true' in vals['gn_args'] 1013 asan = 'is_asan=true' in vals['gn_args']
1001 msan = 'is_msan=true' in vals['gn_args'] 1014 msan = 'is_msan=true' in vals['gn_args']
1002 tsan = 'is_tsan=true' in vals['gn_args'] 1015 tsan = 'is_tsan=true' in vals['gn_args']
1003 1016
1004 target_name = self.GNTargetName(target) 1017 isolate_map = self.ReadIsolateMap()
1005 test_type = gn_isolate_map[target_name]['type'] 1018 test_type = isolate_map[target]['type']
1006 1019
1007 executable = gn_isolate_map[target_name].get('executable', target_name) 1020 executable = isolate_map[target].get('executable', target)
1008 executable_suffix = '.exe' if self.platform == 'win32' else '' 1021 executable_suffix = '.exe' if self.platform == 'win32' else ''
1009 1022
1010 cmdline = [] 1023 cmdline = []
1011 extra_files = [] 1024 extra_files = []
1012 1025
1026 if test_type == 'nontest':
1027 self.WriteFailureAndRaise('We should not be isolating %s.' % target,
1028 output_path=None)
1029
1013 if android and test_type != "script": 1030 if android and test_type != "script":
1014 logdog_command = [ 1031 logdog_command = [
1015 '--logdog-bin-cmd', './../../bin/logdog_butler', 1032 '--logdog-bin-cmd', './../../bin/logdog_butler',
1016 '--project', 'chromium', 1033 '--project', 'chromium',
1017 '--service-account-json', 1034 '--service-account-json',
1018 '/creds/service_accounts/service-account-luci-logdog-publisher.json', 1035 '/creds/service_accounts/service-account-luci-logdog-publisher.json',
1019 '--prefix', 'android/swarming/logcats/${SWARMING_TASK_ID}', 1036 '--prefix', 'android/swarming/logcats/${SWARMING_TASK_ID}',
1020 '--source', '${ISOLATED_OUTDIR}/logcats', 1037 '--source', '${ISOLATED_OUTDIR}/logcats',
1021 '--name', 'unified_logcats', 1038 '--name', 'unified_logcats',
1022 ] 1039 ]
1023 test_cmdline = [ 1040 test_cmdline = [
1024 self.PathJoin('bin', 'run_%s' % target_name), 1041 self.PathJoin('bin', 'run_%s' % target),
1025 '--logcat-output-file', '${ISOLATED_OUTDIR}/logcats', 1042 '--logcat-output-file', '${ISOLATED_OUTDIR}/logcats',
1026 '--target-devices-file', '${SWARMING_BOT_FILE}', 1043 '--target-devices-file', '${SWARMING_BOT_FILE}',
1027 '-v' 1044 '-v'
1028 ] 1045 ]
1029 cmdline = (['./../../build/android/test_wrapper/logdog_wrapper.py'] 1046 cmdline = (['./../../build/android/test_wrapper/logdog_wrapper.py']
1030 + logdog_command + test_cmdline) 1047 + logdog_command + test_cmdline)
1031 elif use_x11 and test_type == 'windowed_test_launcher': 1048 elif use_x11 and test_type == 'windowed_test_launcher':
1032 extra_files = [ 1049 extra_files = [
1033 'xdisplaycheck', 1050 'xdisplaycheck',
1034 '../../testing/test_env.py', 1051 '../../testing/test_env.py',
(...skipping 19 matching lines...) Expand all
1054 '--brave-new-test-launcher', 1071 '--brave-new-test-launcher',
1055 '--test-launcher-bot-mode', 1072 '--test-launcher-bot-mode',
1056 '--asan=%d' % asan, 1073 '--asan=%d' % asan,
1057 '--msan=%d' % msan, 1074 '--msan=%d' % msan,
1058 '--tsan=%d' % tsan, 1075 '--tsan=%d' % tsan,
1059 ] 1076 ]
1060 elif test_type == 'gpu_browser_test': 1077 elif test_type == 'gpu_browser_test':
1061 extra_files = [ 1078 extra_files = [
1062 '../../testing/test_env.py' 1079 '../../testing/test_env.py'
1063 ] 1080 ]
1064 gtest_filter = gn_isolate_map[target]['gtest_filter'] 1081 gtest_filter = isolate_map[target]['gtest_filter']
1065 cmdline = [ 1082 cmdline = [
1066 '../../testing/test_env.py', 1083 '../../testing/test_env.py',
1067 './browser_tests' + executable_suffix, 1084 './browser_tests' + executable_suffix,
1068 '--test-launcher-bot-mode', 1085 '--test-launcher-bot-mode',
1069 '--enable-gpu', 1086 '--enable-gpu',
1070 '--test-launcher-jobs=1', 1087 '--test-launcher-jobs=1',
1071 '--gtest_filter=%s' % gtest_filter, 1088 '--gtest_filter=%s' % gtest_filter,
1072 ] 1089 ]
1073 elif test_type == 'script': 1090 elif test_type == 'script':
1074 extra_files = [ 1091 extra_files = [
1075 '../../testing/test_env.py' 1092 '../../testing/test_env.py'
1076 ] 1093 ]
1077 cmdline = [ 1094 cmdline = [
1078 '../../testing/test_env.py', 1095 '../../testing/test_env.py',
1079 '../../' + self.ToSrcRelPath(gn_isolate_map[target]['script']) 1096 '../../' + self.ToSrcRelPath(isolate_map[target]['script'])
1080 ] 1097 ]
1081 elif test_type in ('raw'): 1098 elif test_type in ('raw'):
1082 extra_files = [] 1099 extra_files = []
1083 cmdline = [ 1100 cmdline = [
1084 './' + str(target) + executable_suffix, 1101 './' + str(target) + executable_suffix,
1085 ] 1102 ]
1086 1103
1087 else: 1104 else:
1088 self.WriteFailureAndRaise('No command line for %s found (test type %s).' 1105 self.WriteFailureAndRaise('No command line for %s found (test type %s).'
1089 % (target, test_type), output_path=None) 1106 % (target, test_type), output_path=None)
1090 1107
1091 cmdline += gn_isolate_map[target_name].get('args', []) 1108 cmdline += isolate_map[target].get('args', [])
1092 1109
1093 return cmdline, extra_files 1110 return cmdline, extra_files
1094 1111
1095 def ToAbsPath(self, build_path, *comps): 1112 def ToAbsPath(self, build_path, *comps):
1096 return self.PathJoin(self.chromium_src_dir, 1113 return self.PathJoin(self.chromium_src_dir,
1097 self.ToSrcRelPath(build_path), 1114 self.ToSrcRelPath(build_path),
1098 *comps) 1115 *comps)
1099 1116
1100 def ToSrcRelPath(self, path): 1117 def ToSrcRelPath(self, path):
1101 """Returns a relative path from the top of the repo.""" 1118 """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: 1194 if 'GYP_CHROMIUM_NO_ACTION' in env:
1178 del env['GYP_CHROMIUM_NO_ACTION'] 1195 del env['GYP_CHROMIUM_NO_ACTION']
1179 if 'GYP_CROSSCOMPILE' in env: 1196 if 'GYP_CROSSCOMPILE' in env:
1180 del env['GYP_CROSSCOMPILE'] 1197 del env['GYP_CROSSCOMPILE']
1181 env['GYP_DEFINES'] = gyp_defines 1198 env['GYP_DEFINES'] = gyp_defines
1182 if vals['gyp_crosscompile']: 1199 if vals['gyp_crosscompile']:
1183 env['GYP_CROSSCOMPILE'] = '1' 1200 env['GYP_CROSSCOMPILE'] = '1'
1184 return cmd, env 1201 return cmd, env
1185 1202
1186 def RunGNAnalyze(self, vals): 1203 def RunGNAnalyze(self, vals):
1187 # analyze runs before 'gn gen' now, so we need to run gn gen 1204 # Analyze runs before 'gn gen' now, so we need to run gn gen
1188 # in order to ensure that we have a build directory. 1205 # in order to ensure that we have a build directory.
1189 ret = self.RunGNGen(vals) 1206 ret = self.RunGNGen(vals)
1190 if ret: 1207 if ret:
1191 return ret 1208 return ret
1192 1209
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
1193 inp = self.ReadInputJSON(['files', 'test_targets', 1216 inp = self.ReadInputJSON(['files', 'test_targets',
1194 'additional_compile_targets']) 1217 'additional_compile_targets'])
1195 if self.args.verbose: 1218 if self.args.verbose:
1196 self.Print() 1219 self.Print()
1197 self.Print('analyze input:') 1220 self.Print('analyze input:')
1198 self.PrintJSON(inp) 1221 self.PrintJSON(inp)
1199 self.Print() 1222 self.Print()
1200 1223
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 1224
1222 # This shouldn't normally happen, but could due to unusual race conditions, 1225 # 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 1226 # like a try job that gets scheduled before a patch lands but runs after
1224 # the patch has landed. 1227 # the patch has landed.
1225 if not inp['files']: 1228 if not inp['files']:
1226 self.Print('Warning: No files modified in patch, bailing out early.') 1229 self.Print('Warning: No files modified in patch, bailing out early.')
1227 self.WriteJSON({ 1230 self.WriteJSON({
1228 'status': 'No dependency', 1231 'status': 'No dependency',
1229 'compile_targets': [], 1232 'compile_targets': [],
1230 'test_targets': [], 1233 'test_targets': [],
1231 }, output_path) 1234 }, output_path)
1232 return 0 1235 return 0
1233 1236
1234 ret = 0 1237 gn_inp = {}
1235 response_file = self.TempFile() 1238 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 1239
1239 matching_targets = set() 1240 isolate_map = self.ReadIsolateMap()
1241 err, gn_inp['additional_compile_targets'] = self.MapTargetsToLabels(
1242 isolate_map, inp['additional_compile_targets'])
1243 if err:
1244 raise MBErr(err)
1245
1246 err, gn_inp['test_targets'] = self.MapTargetsToLabels(
1247 isolate_map, inp['test_targets'])
1248 if err:
1249 raise MBErr(err)
1250 labels_to_targets = {}
1251 for i, label in enumerate(gn_inp['test_targets']):
1252 labels_to_targets[label] = inp['test_targets'][i]
1253
1240 try: 1254 try:
1241 cmd = self.GNCmd('refs', 1255 self.WriteJSON(gn_inp, gn_input_path)
1242 self.args.path[0], 1256 cmd = self.GNCmd('analyze', build_path, gn_input_path, gn_output_path)
1243 '@%s' % response_file.name, 1257 ret, _, _ = self.Run(cmd, force_verbose=True)
1244 '--all', 1258 if ret:
1245 '--as=output') 1259 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 1260
1256 cmd = self.GNCmd('refs', 1261 gn_outp_str = self.ReadFile(gn_output_path)
1257 self.args.path[0], 1262 try:
1258 '@%s' % response_file.name, 1263 gn_outp = json.loads(gn_outp_str)
1259 '--all') 1264 except Exception as e:
1260 ret, out, _ = self.Run(cmd, force_verbose=False) 1265 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: 1266 % (repr(gn_outp_str), str(e)))
1262 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), 1267 raise
1263 output_path) 1268
1264 for label in out.splitlines(): 1269 outp = {}
1265 build_target = label[2:] 1270 if 'status' in gn_outp:
1266 # We want to accept 'chrome/android:chrome_public_apk' and 1271 outp['status'] = gn_outp['status']
1267 # just 'chrome_public_apk'. This may result in too many targets 1272 if 'error' in gn_outp:
1268 # getting built, but we can adjust that later if need be. 1273 outp['error'] = gn_outp['error']
1269 for input_target in targets: 1274 if 'invalid_targets' in gn_outp:
1270 if (input_target == build_target or 1275 outp['invalid_targets'] = gn_outp['invalid_targets']
1271 build_target.endswith(':' + input_target)): 1276 if 'compile_targets' in gn_outp:
1272 matching_targets.add(input_target) 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
1273 finally: 1291 finally:
1274 self.RemoveFile(response_file.name) 1292 if self.Exists(gn_input_path):
1275 1293 self.RemoveFile(gn_input_path)
1276 if matching_targets: 1294 if self.Exists(gn_output_path):
1277 self.WriteJSON({ 1295 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 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
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
1381 def Build(self, target): 1378 def Build(self, target):
1382 build_dir = self.ToSrcRelPath(self.args.path[0]) 1379 build_dir = self.ToSrcRelPath(self.args.path[0])
1383 ninja_cmd = ['ninja', '-C', build_dir] 1380 ninja_cmd = ['ninja', '-C', build_dir]
1384 if self.args.jobs: 1381 if self.args.jobs:
1385 ninja_cmd.extend(['-j', '%d' % self.args.jobs]) 1382 ninja_cmd.extend(['-j', '%d' % self.args.jobs])
1386 ninja_cmd.append(target) 1383 ninja_cmd.append(target)
1387 ret, _, _ = self.Run(ninja_cmd, force_verbose=False, buffer_output=False) 1384 ret, _, _ = self.Run(ninja_cmd, force_verbose=False, buffer_output=False)
1388 return ret 1385 return ret
1389 1386
1390 def Run(self, cmd, env=None, force_verbose=True, buffer_output=True): 1387 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 1510 # Then check to see if the arg contains any metacharacters other than
1514 # double quotes; if it does, quote everything (including the double 1511 # double quotes; if it does, quote everything (including the double
1515 # quotes) for safety. 1512 # quotes) for safety.
1516 if any(a in UNSAFE_FOR_CMD for a in arg): 1513 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) 1514 arg = ''.join('^' + a if a in ALL_META_CHARS else a for a in arg)
1518 return arg 1515 return arg
1519 1516
1520 1517
1521 if __name__ == '__main__': 1518 if __name__ == '__main__':
1522 sys.exit(main(sys.argv[1:])) 1519 sys.exit(main(sys.argv[1:]))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698