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

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

Issue 2357483002: Clean up mb_config.pyl now that we're off GYP. (Closed)
Patch Set: patch for landing (no .export file) Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/mb/PRESUBMIT.py ('k') | tools/mb/mb_config.pyl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2015 The Chromium Authors. All rights reserved. 2 # Copyright 2015 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """MB - the Meta-Build wrapper around GYP and GN 6 """MB - the Meta-Build wrapper around GYP and GN
7 7
8 MB is a wrapper script for GYP and GN that can be used to generate build files 8 MB is a wrapper script for GYP and GN that can be used to generate build files
9 for sets of canned configurations and analyze them. 9 for sets of canned configurations and analyze them.
10 """ 10 """
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 subp.add_argument('path', nargs=1, 113 subp.add_argument('path', nargs=1,
114 help='path build was generated into.') 114 help='path build was generated into.')
115 subp.add_argument('input_path', nargs=1, 115 subp.add_argument('input_path', nargs=1,
116 help='path to a file containing the input arguments ' 116 help='path to a file containing the input arguments '
117 'as a JSON object.') 117 'as a JSON object.')
118 subp.add_argument('output_path', nargs=1, 118 subp.add_argument('output_path', nargs=1,
119 help='path to a file containing the output arguments ' 119 help='path to a file containing the output arguments '
120 'as a JSON object.') 120 'as a JSON object.')
121 subp.set_defaults(func=self.CmdAnalyze) 121 subp.set_defaults(func=self.CmdAnalyze)
122 122
123 subp = subps.add_parser('export',
124 help='print out the expanded configuration for'
125 'each builder as a JSON object')
126 subp.add_argument('-f', '--config-file', metavar='PATH',
127 default=self.default_config,
128 help='path to config file '
129 '(default is //tools/mb/mb_config.pyl)')
130 subp.add_argument('-g', '--goma-dir',
131 help='path to goma directory')
132 subp.set_defaults(func=self.CmdExport)
133
123 subp = subps.add_parser('gen', 134 subp = subps.add_parser('gen',
124 help='generate a new set of build files') 135 help='generate a new set of build files')
125 AddCommonOptions(subp) 136 AddCommonOptions(subp)
126 subp.add_argument('--swarming-targets-file', 137 subp.add_argument('--swarming-targets-file',
127 help='save runtime dependencies for targets listed ' 138 help='save runtime dependencies for targets listed '
128 'in file.') 139 'in file.')
129 subp.add_argument('path', nargs=1, 140 subp.add_argument('path', nargs=1,
130 help='path to generate build into') 141 help='path to generate build into')
131 subp.set_defaults(func=self.CmdGen) 142 subp.set_defaults(func=self.CmdGen)
132 143
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 '--swarming-targets-file', self.args.swarming_targets_file) 253 '--swarming-targets-file', self.args.swarming_targets_file)
243 254
244 def CmdAnalyze(self): 255 def CmdAnalyze(self):
245 vals = self.Lookup() 256 vals = self.Lookup()
246 self.ClobberIfNeeded(vals) 257 self.ClobberIfNeeded(vals)
247 if vals['type'] == 'gn': 258 if vals['type'] == 'gn':
248 return self.RunGNAnalyze(vals) 259 return self.RunGNAnalyze(vals)
249 else: 260 else:
250 return self.RunGYPAnalyze(vals) 261 return self.RunGYPAnalyze(vals)
251 262
263 def CmdExport(self):
264 self.ReadConfigFile()
265 obj = {}
266 for master, builders in self.masters.items():
267 obj[master] = {}
268 for builder in builders:
269 config = self.masters[master][builder]
270 if not config:
271 continue
272
273 if isinstance(config, list):
274 args = [self.FlattenConfig(c)['gn_args'] for c in config]
275 elif config.startswith('//'):
276 args = config
277 else:
278 args = self.FlattenConfig(config)['gn_args']
279 if 'error' in args:
280 continue
281
282 obj[master][builder] = args
283
284 # Dump object and trim trailing whitespace.
285 s = '\n'.join(l.rstrip() for l in
286 json.dumps(obj, sort_keys=True, indent=2).splitlines())
287 self.Print(s)
288 return 0
289
252 def CmdGen(self): 290 def CmdGen(self):
253 vals = self.Lookup() 291 vals = self.Lookup()
254 self.ClobberIfNeeded(vals) 292 self.ClobberIfNeeded(vals)
255 if vals['type'] == 'gn': 293 if vals['type'] == 'gn':
256 return self.RunGNGen(vals) 294 return self.RunGNGen(vals)
257 else: 295 else:
258 return self.RunGYPGen(vals) 296 return self.RunGYPGen(vals)
259 297
260 def CmdHelp(self): 298 def CmdHelp(self):
261 if self.args.subcommand: 299 if self.args.subcommand:
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 self.Print(fmt.format('Totals', str(sum(int(v) for v in stats.values())))) 557 self.Print(fmt.format('Totals', str(sum(int(v) for v in stats.values()))))
520 self.Print(fmt.format('-' * 27, '----')) 558 self.Print(fmt.format('-' * 27, '----'))
521 for stat, count in stats.items(): 559 for stat, count in stats.items():
522 self.Print(fmt.format(stat, str(count))) 560 self.Print(fmt.format(stat, str(count)))
523 561
524 return 0 562 return 0
525 563
526 def GetConfig(self): 564 def GetConfig(self):
527 build_dir = self.args.path[0] 565 build_dir = self.args.path[0]
528 566
529 vals = {} 567 vals = self.DefaultVals()
530 if self.args.builder or self.args.master or self.args.config: 568 if self.args.builder or self.args.master or self.args.config:
531 vals = self.Lookup() 569 vals = self.Lookup()
532 if vals['type'] == 'gn': 570 if vals['type'] == 'gn':
533 # Re-run gn gen in order to ensure the config is consistent with the 571 # Re-run gn gen in order to ensure the config is consistent with the
534 # build dir. 572 # build dir.
535 self.RunGNGen(vals) 573 self.RunGNGen(vals)
536 return vals 574 return vals
537 575
538 mb_type_path = self.PathJoin(self.ToAbsPath(build_dir), 'mb_type') 576 mb_type_path = self.PathJoin(self.ToAbsPath(build_dir), 'mb_type')
539 if not self.Exists(mb_type_path): 577 if not self.Exists(mb_type_path):
540 toolchain_path = self.PathJoin(self.ToAbsPath(build_dir), 578 toolchain_path = self.PathJoin(self.ToAbsPath(build_dir),
541 'toolchain.ninja') 579 'toolchain.ninja')
542 if not self.Exists(toolchain_path): 580 if not self.Exists(toolchain_path):
543 self.Print('Must either specify a path to an existing GN build dir ' 581 self.Print('Must either specify a path to an existing GN build dir '
544 'or pass in a -m/-b pair or a -c flag to specify the ' 582 'or pass in a -m/-b pair or a -c flag to specify the '
545 'configuration') 583 'configuration')
546 return {} 584 return {}
547 else: 585 else:
548 mb_type = 'gn' 586 mb_type = 'gn'
549 else: 587 else:
550 mb_type = self.ReadFile(mb_type_path).strip() 588 mb_type = self.ReadFile(mb_type_path).strip()
551 589
552 if mb_type == 'gn': 590 if mb_type == 'gn':
553 vals = self.GNValsFromDir(build_dir) 591 vals['gn_args'] = self.GNArgsFromDir(build_dir)
554 else:
555 vals = {}
556 vals['type'] = mb_type 592 vals['type'] = mb_type
557 593
558 return vals 594 return vals
559 595
560 def GNValsFromDir(self, build_dir): 596 def GNArgsFromDir(self, build_dir):
561 args_contents = "" 597 args_contents = ""
562 gn_args_path = self.PathJoin(self.ToAbsPath(build_dir), 'args.gn') 598 gn_args_path = self.PathJoin(self.ToAbsPath(build_dir), 'args.gn')
563 if self.Exists(gn_args_path): 599 if self.Exists(gn_args_path):
564 args_contents = self.ReadFile(gn_args_path) 600 args_contents = self.ReadFile(gn_args_path)
565 gn_args = [] 601 gn_args = []
566 for l in args_contents.splitlines(): 602 for l in args_contents.splitlines():
567 fields = l.split(' ') 603 fields = l.split(' ')
568 name = fields[0] 604 name = fields[0]
569 val = ' '.join(fields[2:]) 605 val = ' '.join(fields[2:])
570 gn_args.append('%s=%s' % (name, val)) 606 gn_args.append('%s=%s' % (name, val))
571 607
572 return { 608 return ' '.join(gn_args)
573 'gn_args': ' '.join(gn_args),
574 'type': 'gn',
575 }
576 609
577 def Lookup(self): 610 def Lookup(self):
578 vals = self.ReadBotConfig() 611 vals = self.ReadIOSBotConfig()
579 if not vals: 612 if not vals:
580 self.ReadConfigFile() 613 self.ReadConfigFile()
581 config = self.ConfigFromArgs() 614 config = self.ConfigFromArgs()
582 if config.startswith('//'): 615 if config.startswith('//'):
583 if not self.Exists(self.ToAbsPath(config)): 616 if not self.Exists(self.ToAbsPath(config)):
584 raise MBErr('args file "%s" not found' % config) 617 raise MBErr('args file "%s" not found' % config)
585 vals = { 618 vals = self.DefaultVals()
586 'args_file': config, 619 vals['args_file'] = config
587 'cros_passthrough': False,
588 'gn_args': '',
589 'gyp_crosscompile': False,
590 'gyp_defines': '',
591 'type': 'gn',
592 }
593 else: 620 else:
594 if not config in self.configs: 621 if not config in self.configs:
595 raise MBErr('Config "%s" not found in %s' % 622 raise MBErr('Config "%s" not found in %s' %
596 (config, self.args.config_file)) 623 (config, self.args.config_file))
597 vals = self.FlattenConfig(config) 624 vals = self.FlattenConfig(config)
598 625
599 # Do some basic sanity checking on the config so that we 626 # Do some basic sanity checking on the config so that we
600 # don't have to do this in every caller. 627 # don't have to do this in every caller.
601 assert 'type' in vals, 'No meta-build type specified in the config' 628 if 'type' not in vals:
629 vals['type'] = 'gn'
602 assert vals['type'] in ('gn', 'gyp'), ( 630 assert vals['type'] in ('gn', 'gyp'), (
603 'Unknown meta-build type "%s"' % vals['gn_args']) 631 'Unknown meta-build type "%s"' % vals['gn_args'])
604 632
605 return vals 633 return vals
606 634
607 def ReadBotConfig(self): 635 def ReadIOSBotConfig(self):
608 if not self.args.master or not self.args.builder: 636 if not self.args.master or not self.args.builder:
609 return {} 637 return {}
610 path = self.PathJoin(self.chromium_src_dir, 'ios', 'build', 'bots', 638 path = self.PathJoin(self.chromium_src_dir, 'ios', 'build', 'bots',
611 self.args.master, self.args.builder + '.json') 639 self.args.master, self.args.builder + '.json')
612 if not self.Exists(path): 640 if not self.Exists(path):
613 return {} 641 return {}
614 642
615 contents = json.loads(self.ReadFile(path)) 643 contents = json.loads(self.ReadFile(path))
616 gyp_vals = contents.get('GYP_DEFINES', {}) 644 gyp_vals = contents.get('GYP_DEFINES', {})
617 if isinstance(gyp_vals, dict): 645 if isinstance(gyp_vals, dict):
618 gyp_defines = ' '.join('%s=%s' % (k, v) for k, v in gyp_vals.items()) 646 gyp_defines = ' '.join('%s=%s' % (k, v) for k, v in gyp_vals.items())
619 else: 647 else:
620 gyp_defines = ' '.join(gyp_vals) 648 gyp_defines = ' '.join(gyp_vals)
621 gn_args = ' '.join(contents.get('gn_args', [])) 649 gn_args = ' '.join(contents.get('gn_args', []))
622 650
623 return { 651 vals = self.DefaultVals()
624 'args_file': '', 652 vals['gn_args'] = gn_args
625 'cros_passthrough': False, 653 vals['gyp_defines'] = gyp_defines
626 'gn_args': gn_args, 654 vals['type'] = contents.get('mb_type', 'gn')
627 'gyp_crosscompile': False, 655 return vals
628 'gyp_defines': gyp_defines,
629 'type': contents.get('mb_type', ''),
630 }
631 656
632 def ReadConfigFile(self): 657 def ReadConfigFile(self):
633 if not self.Exists(self.args.config_file): 658 if not self.Exists(self.args.config_file):
634 raise MBErr('config file not found at %s' % self.args.config_file) 659 raise MBErr('config file not found at %s' % self.args.config_file)
635 660
636 try: 661 try:
637 contents = ast.literal_eval(self.ReadFile(self.args.config_file)) 662 contents = ast.literal_eval(self.ReadFile(self.args.config_file))
638 except SyntaxError as e: 663 except SyntaxError as e:
639 raise MBErr('Failed to parse config file "%s": %s' % 664 raise MBErr('Failed to parse config file "%s": %s' %
640 (self.args.config_file, e)) 665 (self.args.config_file, e))
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 (phase, self.args.builder, self.args.master)) 703 (phase, self.args.builder, self.args.master))
679 return config[phase-1] 704 return config[phase-1]
680 705
681 if self.args.phase is not None: 706 if self.args.phase is not None:
682 raise MBErr('Must not specify a build --phase for %s on %s' % 707 raise MBErr('Must not specify a build --phase for %s on %s' %
683 (self.args.builder, self.args.master)) 708 (self.args.builder, self.args.master))
684 return config 709 return config
685 710
686 def FlattenConfig(self, config): 711 def FlattenConfig(self, config):
687 mixins = self.configs[config] 712 mixins = self.configs[config]
688 vals = { 713 vals = self.DefaultVals()
689 'args_file': '',
690 'cros_passthrough': False,
691 'gn_args': [],
692 'gyp_defines': '',
693 'gyp_crosscompile': False,
694 'type': None,
695 }
696 714
697 visited = [] 715 visited = []
698 self.FlattenMixins(mixins, vals, visited) 716 self.FlattenMixins(mixins, vals, visited)
699 return vals 717 return vals
700 718
719 def DefaultVals(self):
720 return {
721 'args_file': '',
722 'cros_passthrough': False,
723 'gn_args': '',
724 'gyp_defines': '',
725 'gyp_crosscompile': False,
726 'type': 'gn',
727 }
728
701 def FlattenMixins(self, mixins, vals, visited): 729 def FlattenMixins(self, mixins, vals, visited):
702 for m in mixins: 730 for m in mixins:
703 if m not in self.mixins: 731 if m not in self.mixins:
704 raise MBErr('Unknown mixin "%s"' % m) 732 raise MBErr('Unknown mixin "%s"' % m)
705 733
706 visited.append(m) 734 visited.append(m)
707 735
708 mixin_vals = self.mixins[m] 736 mixin_vals = self.mixins[m]
709 737
710 if 'cros_passthrough' in mixin_vals: 738 if 'cros_passthrough' in mixin_vals:
(...skipping 812 matching lines...) Expand 10 before | Expand all | Expand 10 after
1523 # Then check to see if the arg contains any metacharacters other than 1551 # Then check to see if the arg contains any metacharacters other than
1524 # double quotes; if it does, quote everything (including the double 1552 # double quotes; if it does, quote everything (including the double
1525 # quotes) for safety. 1553 # quotes) for safety.
1526 if any(a in UNSAFE_FOR_CMD for a in arg): 1554 if any(a in UNSAFE_FOR_CMD for a in arg):
1527 arg = ''.join('^' + a if a in ALL_META_CHARS else a for a in arg) 1555 arg = ''.join('^' + a if a in ALL_META_CHARS else a for a in arg)
1528 return arg 1556 return arg
1529 1557
1530 1558
1531 if __name__ == '__main__': 1559 if __name__ == '__main__':
1532 sys.exit(main(sys.argv[1:])) 1560 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « tools/mb/PRESUBMIT.py ('k') | tools/mb/mb_config.pyl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698