| Index: tools/mb/mb.py
|
| diff --git a/tools/mb/mb.py b/tools/mb/mb.py
|
| index e54763c0370b0c2fff818d36e2fdb9550c539a91..2711bf1fc89b795f97ab0264225a5b8cb7f6772f 100755
|
| --- a/tools/mb/mb.py
|
| +++ b/tools/mb/mb.py
|
| @@ -61,7 +61,7 @@ class MetaBuildWrapper(object):
|
| self.DumpInputFiles()
|
| return ret
|
| except KeyboardInterrupt:
|
| - self.Print('interrupted, exiting', stream=sys.stderr)
|
| + self.Print('interrupted, exiting')
|
| return 130
|
| except Exception:
|
| self.DumpInputFiles()
|
| @@ -229,7 +229,7 @@ class MetaBuildWrapper(object):
|
| def DumpContentsOfFilePassedTo(arg_name, path):
|
| if path and self.Exists(path):
|
| self.Print("\n# To recreate the file passed to %s:" % arg_name)
|
| - self.Print("%% cat > %s <<EOF)" % path)
|
| + self.Print("%% cat > %s <<EOF" % path)
|
| contents = self.ReadFile(path)
|
| self.Print(contents)
|
| self.Print("EOF\n%\n")
|
| @@ -643,6 +643,10 @@ class MetaBuildWrapper(object):
|
| self.masters = contents['masters']
|
| self.mixins = contents['mixins']
|
|
|
| + def ReadIsolateMap(self):
|
| + return ast.literal_eval(self.ReadFile(self.PathJoin(
|
| + self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl')))
|
| +
|
| def ConfigFromArgs(self):
|
| if self.args.config:
|
| if self.args.master or self.args.builder:
|
| @@ -770,7 +774,7 @@ class MetaBuildWrapper(object):
|
| if getattr(self.args, 'swarming_targets_file', None):
|
| # We need GN to generate the list of runtime dependencies for
|
| # the compile targets listed (one per line) in the file so
|
| - # we can run them via swarming. We use ninja_to_gn.pyl to convert
|
| + # we can run them via swarming. We use gn_isolate_map.pyl to convert
|
| # the compile targets to the matching GN labels.
|
| path = self.args.swarming_targets_file
|
| if not self.Exists(path):
|
| @@ -778,25 +782,14 @@ class MetaBuildWrapper(object):
|
| output_path=None)
|
| contents = self.ReadFile(path)
|
| swarming_targets = set(contents.splitlines())
|
| - gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin(
|
| - self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl')))
|
| - gn_labels = []
|
| - err = ''
|
| - for target in swarming_targets:
|
| - target_name = self.GNTargetName(target)
|
| - if not target_name in gn_isolate_map:
|
| - err += ('test target "%s" not found\n' % target_name)
|
| - elif gn_isolate_map[target_name]['type'] == 'unknown':
|
| - err += ('test target "%s" type is unknown\n' % target_name)
|
| - else:
|
| - gn_labels.append(gn_isolate_map[target_name]['label'])
|
|
|
| + isolate_map = self.ReadIsolateMap()
|
| + err, labels = self.MapTargetsToLabels(isolate_map, swarming_targets)
|
| if err:
|
| - raise MBErr('Error: Failed to match swarming targets to %s:\n%s' %
|
| - ('//testing/buildbot/gn_isolate_map.pyl', err))
|
| + raise MBErr(err)
|
|
|
| gn_runtime_deps_path = self.ToAbsPath(build_dir, 'runtime_deps')
|
| - self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n')
|
| + self.WriteFile(gn_runtime_deps_path, '\n'.join(labels) + '\n')
|
| cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path)
|
|
|
| ret, _, _ = self.Run(cmd)
|
| @@ -812,22 +805,21 @@ class MetaBuildWrapper(object):
|
| # Android targets may be either android_apk or executable. The former
|
| # will result in runtime_deps associated with the stamp file, while the
|
| # latter will result in runtime_deps associated with the executable.
|
| - target_name = self.GNTargetName(target)
|
| - label = gn_isolate_map[target_name]['label']
|
| + label = isolate_map[target]['label']
|
| runtime_deps_targets = [
|
| - target_name + '.runtime_deps',
|
| + target + '.runtime_deps',
|
| 'obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
|
| - elif gn_isolate_map[target]['type'] == 'gpu_browser_test':
|
| + elif isolate_map[target]['type'] == 'gpu_browser_test':
|
| if self.platform == 'win32':
|
| runtime_deps_targets = ['browser_tests.exe.runtime_deps']
|
| else:
|
| runtime_deps_targets = ['browser_tests.runtime_deps']
|
| - elif (gn_isolate_map[target]['type'] == 'script' or
|
| - gn_isolate_map[target].get('label_type') == 'group'):
|
| + elif (isolate_map[target]['type'] == 'script' or
|
| + isolate_map[target].get('label_type') == 'group'):
|
| # For script targets, the build target is usually a group,
|
| # for which gn generates the runtime_deps next to the stamp file
|
| # for the label, which lives under the obj/ directory.
|
| - label = gn_isolate_map[target]['label']
|
| + label = isolate_map[target]['label']
|
| runtime_deps_targets = [
|
| 'obj/%s.stamp.runtime_deps' % label.replace(':', '/')]
|
| elif self.platform == 'win32':
|
| @@ -843,8 +835,7 @@ class MetaBuildWrapper(object):
|
| raise MBErr('did not generate any of %s' %
|
| ', '.join(runtime_deps_targets))
|
|
|
| - command, extra_files = self.GetIsolateCommand(target, vals,
|
| - gn_isolate_map)
|
| + command, extra_files = self.GetIsolateCommand(target, vals)
|
|
|
| runtime_deps = self.ReadFile(runtime_deps_path).splitlines()
|
|
|
| @@ -854,15 +845,16 @@ class MetaBuildWrapper(object):
|
| return 0
|
|
|
| def RunGNIsolate(self, vals):
|
| - gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin(
|
| - self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl')))
|
| + target = self.args.target[0]
|
| + isolate_map = self.ReadIsolateMap()
|
| + err, labels = self.MapTargetsToLabels(isolate_map, [target])
|
| + if err:
|
| + raise MBErr(err)
|
| + label = labels[0]
|
|
|
| build_dir = self.args.path[0]
|
| - target = self.args.target[0]
|
| - target_name = self.GNTargetName(target)
|
| - command, extra_files = self.GetIsolateCommand(target, vals, gn_isolate_map)
|
| + command, extra_files = self.GetIsolateCommand(target, vals)
|
|
|
| - label = gn_isolate_map[target_name]['label']
|
| cmd = self.GNCmd('desc', build_dir, label, 'runtime_deps')
|
| ret, out, _ = self.Call(cmd)
|
| if ret:
|
| @@ -912,6 +904,27 @@ class MetaBuildWrapper(object):
|
| isolate_path + 'd.gen.json',
|
| )
|
|
|
| + def MapTargetsToLabels(self, isolate_map, targets):
|
| + labels = []
|
| + err = ''
|
| + for target in targets:
|
| + if target == 'all':
|
| + labels.append(target)
|
| + elif not target in isolate_map:
|
| + non_run_target = target[:-4]
|
| + if target.endswith('_run') and non_run_target in isolate_map:
|
| + labels.append(isolate_map[non_run_target]['label'] + '_run')
|
| + elif target.startswith('//'):
|
| + labels.append(target)
|
| + else:
|
| + err += ('target "%s" not found in '
|
| + '//testing/buildbot/gn_isolate_map.pyl\n' % target)
|
| + elif isolate_map[target]['type'] == 'unknown':
|
| + err += ('test target "%s" type is unknown\n' % target)
|
| + else:
|
| + labels.append(isolate_map[target]['label'])
|
| + return err, labels
|
| +
|
| def GNCmd(self, subcommand, path, *args):
|
| if self.platform == 'linux2':
|
| subdir, exe = 'linux64', 'gn'
|
| @@ -921,9 +934,9 @@ class MetaBuildWrapper(object):
|
| subdir, exe = 'win', 'gn.exe'
|
|
|
| gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, exe)
|
| -
|
| return [gn_path, subcommand, path] + list(args)
|
|
|
| +
|
| def GNArgs(self, vals):
|
| if vals['cros_passthrough']:
|
| if not 'GN_ARGS' in os.environ:
|
| @@ -988,7 +1001,7 @@ class MetaBuildWrapper(object):
|
|
|
| return ret
|
|
|
| - def GetIsolateCommand(self, target, vals, gn_isolate_map):
|
| + def GetIsolateCommand(self, target, vals):
|
| android = 'target_os="android"' in vals['gn_args']
|
|
|
| # This needs to mirror the settings in //build/config/ui.gni:
|
| @@ -1001,15 +1014,19 @@ class MetaBuildWrapper(object):
|
| msan = 'is_msan=true' in vals['gn_args']
|
| tsan = 'is_tsan=true' in vals['gn_args']
|
|
|
| - target_name = self.GNTargetName(target)
|
| - test_type = gn_isolate_map[target_name]['type']
|
| + isolate_map = self.ReadIsolateMap()
|
| + test_type = isolate_map[target]['type']
|
|
|
| - executable = gn_isolate_map[target_name].get('executable', target_name)
|
| + executable = isolate_map[target].get('executable', target)
|
| executable_suffix = '.exe' if self.platform == 'win32' else ''
|
|
|
| cmdline = []
|
| extra_files = []
|
|
|
| + if test_type == 'nontest':
|
| + self.WriteFailureAndRaise('We should not be isolating %s.' % target,
|
| + output_path=None)
|
| +
|
| if android and test_type != "script":
|
| logdog_command = [
|
| '--logdog-bin-cmd', './../../bin/logdog_butler',
|
| @@ -1021,7 +1038,7 @@ class MetaBuildWrapper(object):
|
| '--name', 'unified_logcats',
|
| ]
|
| test_cmdline = [
|
| - self.PathJoin('bin', 'run_%s' % target_name),
|
| + self.PathJoin('bin', 'run_%s' % target),
|
| '--logcat-output-file', '${ISOLATED_OUTDIR}/logcats',
|
| '--target-devices-file', '${SWARMING_BOT_FILE}',
|
| '-v'
|
| @@ -1061,7 +1078,7 @@ class MetaBuildWrapper(object):
|
| extra_files = [
|
| '../../testing/test_env.py'
|
| ]
|
| - gtest_filter = gn_isolate_map[target]['gtest_filter']
|
| + gtest_filter = isolate_map[target]['gtest_filter']
|
| cmdline = [
|
| '../../testing/test_env.py',
|
| './browser_tests' + executable_suffix,
|
| @@ -1076,7 +1093,7 @@ class MetaBuildWrapper(object):
|
| ]
|
| cmdline = [
|
| '../../testing/test_env.py',
|
| - '../../' + self.ToSrcRelPath(gn_isolate_map[target]['script'])
|
| + '../../' + self.ToSrcRelPath(isolate_map[target]['script'])
|
| ]
|
| elif test_type in ('raw'):
|
| extra_files = []
|
| @@ -1088,7 +1105,7 @@ class MetaBuildWrapper(object):
|
| self.WriteFailureAndRaise('No command line for %s found (test type %s).'
|
| % (target, test_type), output_path=None)
|
|
|
| - cmdline += gn_isolate_map[target_name].get('args', [])
|
| + cmdline += isolate_map[target].get('args', [])
|
|
|
| return cmdline, extra_files
|
|
|
| @@ -1184,12 +1201,18 @@ class MetaBuildWrapper(object):
|
| return cmd, env
|
|
|
| def RunGNAnalyze(self, vals):
|
| - # analyze runs before 'gn gen' now, so we need to run gn gen
|
| + # Analyze runs before 'gn gen' now, so we need to run gn gen
|
| # in order to ensure that we have a build directory.
|
| ret = self.RunGNGen(vals)
|
| if ret:
|
| return ret
|
|
|
| + build_path = self.args.path[0]
|
| + input_path = self.args.input_path[0]
|
| + gn_input_path = input_path + '.gn'
|
| + output_path = self.args.output_path[0]
|
| + gn_output_path = output_path + '.gn'
|
| +
|
| inp = self.ReadInputJSON(['files', 'test_targets',
|
| 'additional_compile_targets'])
|
| if self.args.verbose:
|
| @@ -1198,26 +1221,6 @@ class MetaBuildWrapper(object):
|
| self.PrintJSON(inp)
|
| self.Print()
|
|
|
| - # TODO(crbug.com/555273) - currently GN treats targets and
|
| - # additional_compile_targets identically since we can't tell the
|
| - # difference between a target that is a group in GN and one that isn't.
|
| - # We should eventually fix this and treat the two types differently.
|
| - targets = (set(inp['test_targets']) |
|
| - set(inp['additional_compile_targets']))
|
| -
|
| - output_path = self.args.output_path[0]
|
| -
|
| - # Bail out early if a GN file was modified, since 'gn refs' won't know
|
| - # what to do about it. Also, bail out early if 'all' was asked for,
|
| - # since we can't deal with it yet.
|
| - if (any(f.endswith('.gn') or f.endswith('.gni') for f in inp['files']) or
|
| - 'all' in targets):
|
| - self.WriteJSON({
|
| - 'status': 'Found dependency (all)',
|
| - 'compile_targets': sorted(targets),
|
| - 'test_targets': sorted(targets & set(inp['test_targets'])),
|
| - }, output_path)
|
| - return 0
|
|
|
| # This shouldn't normally happen, but could due to unusual race conditions,
|
| # like a try job that gets scheduled before a patch lands but runs after
|
| @@ -1231,68 +1234,65 @@ class MetaBuildWrapper(object):
|
| }, output_path)
|
| return 0
|
|
|
| - ret = 0
|
| - response_file = self.TempFile()
|
| - response_file.write('\n'.join(inp['files']) + '\n')
|
| - response_file.close()
|
| + gn_inp = {}
|
| + gn_inp['files'] = ['//' + f for f in inp['files'] if not f.startswith('//')]
|
| +
|
| + isolate_map = self.ReadIsolateMap()
|
| + err, gn_inp['additional_compile_targets'] = self.MapTargetsToLabels(
|
| + isolate_map, inp['additional_compile_targets'])
|
| + if err:
|
| + raise MBErr(err)
|
| +
|
| + err, gn_inp['test_targets'] = self.MapTargetsToLabels(
|
| + isolate_map, inp['test_targets'])
|
| + if err:
|
| + raise MBErr(err)
|
| + labels_to_targets = {}
|
| + for i, label in enumerate(gn_inp['test_targets']):
|
| + labels_to_targets[label] = inp['test_targets'][i]
|
|
|
| - matching_targets = set()
|
| try:
|
| - cmd = self.GNCmd('refs',
|
| - self.args.path[0],
|
| - '@%s' % response_file.name,
|
| - '--all',
|
| - '--as=output')
|
| - ret, out, _ = self.Run(cmd, force_verbose=False)
|
| - if ret and not 'The input matches no targets' in out:
|
| - self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out),
|
| - output_path)
|
| - build_dir = self.ToSrcRelPath(self.args.path[0]) + self.sep
|
| - for output in out.splitlines():
|
| - build_output = output.replace(build_dir, '')
|
| - if build_output in targets:
|
| - matching_targets.add(build_output)
|
| -
|
| - cmd = self.GNCmd('refs',
|
| - self.args.path[0],
|
| - '@%s' % response_file.name,
|
| - '--all')
|
| - ret, out, _ = self.Run(cmd, force_verbose=False)
|
| - if ret and not 'The input matches no targets' in out:
|
| - self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out),
|
| - output_path)
|
| - for label in out.splitlines():
|
| - build_target = label[2:]
|
| - # We want to accept 'chrome/android:chrome_public_apk' and
|
| - # just 'chrome_public_apk'. This may result in too many targets
|
| - # getting built, but we can adjust that later if need be.
|
| - for input_target in targets:
|
| - if (input_target == build_target or
|
| - build_target.endswith(':' + input_target)):
|
| - matching_targets.add(input_target)
|
| - finally:
|
| - self.RemoveFile(response_file.name)
|
| + self.WriteJSON(gn_inp, gn_input_path)
|
| + cmd = self.GNCmd('analyze', build_path, gn_input_path, gn_output_path)
|
| + ret, _, _ = self.Run(cmd, force_verbose=True)
|
| + if ret:
|
| + return ret
|
|
|
| - if matching_targets:
|
| - self.WriteJSON({
|
| - 'status': 'Found dependency',
|
| - 'compile_targets': sorted(matching_targets),
|
| - 'test_targets': sorted(matching_targets &
|
| - set(inp['test_targets'])),
|
| - }, output_path)
|
| - else:
|
| - self.WriteJSON({
|
| - 'status': 'No dependency',
|
| - 'compile_targets': [],
|
| - 'test_targets': [],
|
| - }, output_path)
|
| + gn_outp_str = self.ReadFile(gn_output_path)
|
| + try:
|
| + gn_outp = json.loads(gn_outp_str)
|
| + except Exception as e:
|
| + self.Print("Failed to parse the JSON string GN returned: %s\n%s"
|
| + % (repr(gn_outp_str), str(e)))
|
| + raise
|
|
|
| - if self.args.verbose:
|
| - outp = json.loads(self.ReadFile(output_path))
|
| - self.Print()
|
| - self.Print('analyze output:')
|
| - self.PrintJSON(outp)
|
| - self.Print()
|
| + outp = {}
|
| + if 'status' in gn_outp:
|
| + outp['status'] = gn_outp['status']
|
| + if 'error' in gn_outp:
|
| + outp['error'] = gn_outp['error']
|
| + if 'invalid_targets' in gn_outp:
|
| + outp['invalid_targets'] = gn_outp['invalid_targets']
|
| + if 'compile_targets' in gn_outp:
|
| + outp['compile_targets'] = [
|
| + label.replace('//', '') for label in gn_outp['compile_targets']]
|
| + if 'test_targets' in gn_outp:
|
| + outp['test_targets'] = [
|
| + labels_to_targets[label] for label in gn_outp['test_targets']]
|
| +
|
| + if self.args.verbose:
|
| + self.Print()
|
| + self.Print('analyze output:')
|
| + self.PrintJSON(outp)
|
| + self.Print()
|
| +
|
| + self.WriteJSON(outp, output_path)
|
| +
|
| + finally:
|
| + if self.Exists(gn_input_path):
|
| + self.RemoveFile(gn_input_path)
|
| + if self.Exists(gn_output_path):
|
| + self.RemoveFile(gn_output_path)
|
|
|
| return 0
|
|
|
| @@ -1375,9 +1375,6 @@ class MetaBuildWrapper(object):
|
| def PrintJSON(self, obj):
|
| self.Print(json.dumps(obj, indent=2, sort_keys=True))
|
|
|
| - def GNTargetName(self, target):
|
| - return target
|
| -
|
| def Build(self, target):
|
| build_dir = self.ToSrcRelPath(self.args.path[0])
|
| ninja_cmd = ['ninja', '-C', build_dir]
|
|
|