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

Unified Diff: tools/mb/mb.py

Issue 1370373005: Add MB commands for generating isolates and running them. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge mb_isolates forward, clean up a bit Created 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/mb/mb.py
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 347fc8cd5d558d2e26bfd0f288b022e7e9629cf4..e40d2cecf18cfcc19f27413aef1a853a7b21b99c 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -98,12 +98,37 @@ class MetaBuildWrapper(object):
help='path to generate build into')
subp.set_defaults(func=self.CmdGen)
+ subp = subps.add_parser('isolate',
+ help='generate the .isolate files for a given'
+ 'binary')
+ AddCommonOptions(subp)
+ subp.add_argument('path', nargs=1,
+ help='path build was generated into')
+ subp.add_argument('target', nargs=1,
+ help='ninja target to generate the isolate for')
+ subp.set_defaults(func=self.CmdIsolate)
+
subp = subps.add_parser('lookup',
help='look up the command for a given config or '
'builder')
AddCommonOptions(subp)
subp.set_defaults(func=self.CmdLookup)
+ subp = subps.add_parser('run',
+ help='build and run the isolated version of a '
+ 'binary')
+ AddCommonOptions(subp)
+ subp.add_argument('-j', '--jobs', dest='jobs', type=int,
+ help='Number of jobs to pass to ninja')
+ subp.add_argument('--no-build', dest='build', default=True,
+ action='store_false',
+ help='Do not build, just isolate and run')
+ subp.add_argument('path', nargs=1,
+ help='path to generate build into')
+ subp.add_argument('target', nargs=1,
+ help='ninja target to build and run')
+ subp.set_defaults(func=self.CmdRun)
+
subp = subps.add_parser('validate',
help='validate the config file')
subp.add_argument('-f', '--config-file', metavar='PATH',
@@ -121,44 +146,79 @@ class MetaBuildWrapper(object):
self.args = parser.parse_args(argv)
def CmdAnalyze(self):
- vals = self.GetConfig()
+ vals = self.Lookup()
if vals['type'] == 'gn':
return self.RunGNAnalyze(vals)
- elif vals['type'] == 'gyp':
- return self.RunGYPAnalyze(vals)
else:
- raise MBErr('Unknown meta-build type "%s"' % vals['type'])
+ return self.RunGYPAnalyze(vals)
def CmdGen(self):
- vals = self.GetConfig()
-
+ vals = self.Lookup()
self.ClobberIfNeeded(vals)
if vals['type'] == 'gn':
return self.RunGNGen(vals)
- if vals['type'] == 'gyp':
+ else:
return self.RunGYPGen(vals)
- raise MBErr('Unknown meta-build type "%s"' % vals['type'])
+ def CmdHelp(self):
+ if self.args.subcommand:
+ self.ParseArgs([self.args.subcommand, '--help'])
+ else:
+ self.ParseArgs(['--help'])
+
+ def CmdIsolate(self):
+ vals = self.GetConfig()
+ if vals['type'] == 'gn':
+ return self.RunGNIsolate(vals)
+ else:
+ return self.Build('%s_run' % self.args.target[0])
def CmdLookup(self):
- vals = self.GetConfig()
+ vals = self.Lookup()
if vals['type'] == 'gn':
cmd = self.GNCmd('gen', '_path_', vals['gn_args'])
env = None
- elif vals['type'] == 'gyp':
- cmd, env = self.GYPCmd('_path_', vals)
else:
- raise MBErr('Unknown meta-build type "%s"' % vals['type'])
+ cmd, env = self.GYPCmd('_path_', vals)
self.PrintCmd(cmd, env)
return 0
- def CmdHelp(self):
- if self.args.subcommand:
- self.ParseArgs([self.args.subcommand, '--help'])
+ def CmdRun(self):
+ vals = self.GetConfig()
+ build_dir = self.args.path[0]
+ target = self.args.target[0]
+
+ if vals['type'] == 'gn':
+ ret = self.RunGNIsolate(vals)
+ if ret:
+ return ret
+ if self.args.build:
+ ret = self.Build(target)
+ if ret:
+ return ret
else:
- self.ParseArgs(['--help'])
+ ret = self.Build('%s_run' % target)
+ if ret:
+ return ret
+
+ ret, out, err = self.Run([
+ self.executable,
+ self.PathJoin('tools', 'swarming_client', 'isolate.py'),
+ 'run',
+ '-s',
+ self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target))])
Ken Russell (switch to Gerrit) 2015/10/02 18:08:19 Will this '/' cause problems on Windows? I'm guess
+
+ # Always log the output of the test run, but we only log the
+ # commend when self.args.verbose=True.
+ if not self.args.verbose:
+ if out:
+ self.Print(out)
+ if err:
+ self.Print(err, file=sys.stderr)
+
+ return ret
def CmdValidate(self):
errs = []
@@ -234,13 +294,70 @@ class MetaBuildWrapper(object):
return 0
def GetConfig(self):
+ build_dir = self.args.path[0]
+
+ vals = {}
+ if self.args.builder or self.args.master or self.args.config:
+ vals = self.Lookup()
+ if vals['type'] == 'gn':
+ # Re-run gn gen in order to ensure the config is consistent with the
+ # build dir.
+ self.RunGNGen(vals)
+ return vals
+
+ # TODO: We can only get the config for GN build dirs, not GYP build dirs.
+ # GN stores the args that were used in args.gn in the build dir,
+ # but GYP doesn't store them anywhere. We should consider modifying
+ # gyp_chromium to record the arguments it runs with in a similar
+ # manner.
+
+ mb_type_path = self.PathJoin(self.ToAbsPath(build_dir), 'mb_type')
+ if not self.Exists(mb_type_path):
+ self.Print('Must either specify a path to an existing GN build dir '
+ 'or pass in a -m/-b pair or a -c flag to specify the '
+ 'configuration')
+ return 1
+
+ mb_type = self.ReadFile(mb_type_path).strip()
+ if mb_type == 'gn':
+ vals = self.GNValsFromDir(build_dir)
+ else:
+ vals = {}
+ vals['type'] = mb_type
+
+ return vals
+
+ def GNValsFromDir(self, build_dir):
+ args_contents = self.ReadFile(
+ self.PathJoin(self.ToAbsPath(build_dir), 'args.gn'))
+ gn_args = []
+ for l in args_contents.splitlines():
+ fields = l.split(' ')
+ name = fields[0]
+ val = ' '.join(fields[2:])
+ gn_args.append('%s=%s' % (name, val))
+
+ return {
+ 'gn_args': ' '.join(gn_args),
+ 'type': 'gn',
+ }
+
+ def Lookup(self):
self.ReadConfigFile()
config = self.ConfigFromArgs()
if not config in self.configs:
raise MBErr('Config "%s" not found in %s' %
(config, self.args.config_file))
- return self.FlattenConfig(config)
+ vals = self.FlattenConfig(config)
+
+ # Do some basic sanity checking on the config so that we
+ # don't have to do this in every caller.
+ assert 'type' in vals, 'No meta-build type specified in the config'
+ assert vals['type'] in ('gn', 'gyp'), (
+ 'Unknown meta-build type "%s"' % vals['gn_args'])
+
+ return vals
def ReadConfigFile(self):
if not self.Exists(self.args.config_file):
@@ -353,9 +470,9 @@ class MetaBuildWrapper(object):
self.WriteFile(mb_type_path, new_mb_type)
def RunGNGen(self, vals):
- path = self.args.path[0]
+ build_dir = self.args.path[0]
- cmd = self.GNCmd('gen', path, vals['gn_args'], extra_args=['--check'])
+ cmd = self.GNCmd('gen', build_dir, vals['gn_args'], extra_args=['--check'])
swarming_targets = []
if self.args.swarming_targets_file:
@@ -374,10 +491,10 @@ class MetaBuildWrapper(object):
(target, '//testing/buildbot/gn_isolate_map.pyl'))
gn_labels.append(gn_isolate_map[target]['label'])
- gn_runtime_deps_path = self.ToAbsPath(path, 'runtime_deps')
+ gn_runtime_deps_path = self.ToAbsPath(build_dir, 'runtime_deps')
# Since GN hasn't run yet, the build directory may not even exist.
- self.MaybeMakeDirectory(self.ToAbsPath(path))
+ self.MaybeMakeDirectory(self.ToAbsPath(build_dir))
self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n')
cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path)
@@ -401,10 +518,10 @@ class MetaBuildWrapper(object):
else:
runtime_deps_target = target
if self.platform == 'win32':
- deps_path = self.ToAbsPath(path,
+ deps_path = self.ToAbsPath(build_dir,
runtime_deps_target + '.exe.runtime_deps')
else:
- deps_path = self.ToAbsPath(path,
+ deps_path = self.ToAbsPath(build_dir,
runtime_deps_target + '.runtime_deps')
if not self.Exists(deps_path):
raise MBErr('did not generate %s' % deps_path)
@@ -414,31 +531,65 @@ class MetaBuildWrapper(object):
runtime_deps = self.ReadFile(deps_path).splitlines()
- isolate_path = self.ToAbsPath(path, target + '.isolate')
- self.WriteFile(isolate_path,
- pprint.pformat({
- 'variables': {
- 'command': command,
- 'files': sorted(runtime_deps + extra_files),
- }
- }) + '\n')
-
- self.WriteJSON(
- {
- 'args': [
- '--isolated',
- self.ToSrcRelPath('%s%s%s.isolated' % (path, self.sep, target)),
- '--isolate',
- self.ToSrcRelPath('%s%s%s.isolate' % (path, self.sep, target)),
- ],
- 'dir': self.chromium_src_dir,
- 'version': 1,
- },
- isolate_path + 'd.gen.json',
- )
+ self.WriteIsolateFiles(build_dir, command, target, runtime_deps,
+ extra_files)
+
+ 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')))
+
+ build_dir = self.args.path[0]
+ target = self.args.target[0]
+ command, extra_files = self.GetIsolateCommand(target, vals, gn_isolate_map)
+
+ label = gn_isolate_map[target]['label']
+ ret, out, _ = self.Call(['gn', 'desc', build_dir, label, 'runtime_deps'])
+ if ret:
+ return ret
+
+ runtime_deps = out.splitlines()
+
+ self.WriteIsolateFiles(build_dir, command, target, runtime_deps,
+ extra_files)
+
+ ret, _, _ = self.Run([
+ self.executable,
+ self.PathJoin('tools', 'swarming_client', 'isolate.py'),
+ 'check',
+ '-i',
+ self.ToSrcRelPath('%s/%s.isolate' % (build_dir, target)),
+ '-s',
+ self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target))])
return ret
+ def WriteIsolateFiles(self, build_dir, command, target, runtime_deps,
+ extra_files):
+ isolate_path = self.ToAbsPath(build_dir, target + '.isolate')
+ self.WriteFile(isolate_path,
+ pprint.pformat({
+ 'variables': {
+ 'command': command,
+ 'files': sorted(runtime_deps + extra_files),
+ }
+ }) + '\n')
+
+ self.WriteJSON(
+ {
+ 'args': [
+ '--isolated',
+ self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target)),
+ '--isolate',
+ self.ToSrcRelPath('%s/%s.isolate' % (build_dir, target)),
+ ],
+ 'dir': self.chromium_src_dir,
+ 'version': 1,
+ },
+ isolate_path + 'd.gen.json',
+ )
+
def GNCmd(self, subcommand, path, gn_args='', extra_args=None):
if self.platform == 'linux2':
subdir = 'linux64'
@@ -769,6 +920,14 @@ class MetaBuildWrapper(object):
# This function largely exists so it can be overridden for testing.
print(*args, **kwargs)
+ def Build(self, target):
+ build_dir = self.ToSrcRelPath(self.args.path[0])
+ ninja_cmd = ['ninja', '-C', build_dir]
+ if self.args.jobs:
+ ninja_cmd.extend(['-j', '%d' % self.args.jobs])
+ ninja_cmd.append(target)
+ return self.Run(ninja_cmd)
+
def Run(self, cmd, env=None, force_verbose=True):
# This function largely exists so it can be overridden for testing.
if self.args.dryrun or self.args.verbose or force_verbose:
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698