1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Script for dumping and/or comparing build config contents."""
10 from chromite.buildbot import cbuildbot_config
11 from chromite.lib import commandline
12 from chromite.lib import cros_build_lib
15 class _JSONEncoder(json.JSONEncoder):
16 """Json Encoder that encodes objects as their dictionaries."""
17 # pylint: disable=E0202
18 def default(self, obj):
19 return self.encode(obj.__dict__)
22 def _InjectDisplayPosition(config):
23 """Add field to help buildbot masters order builders on the waterfall.
26 config: A dict of build config items.
29 A similar config where each config item has a new 'display_position' value.
31 def _GetSortKey(items):
33 # Allow configs to override the display_position.
34 return (my_config.get('display_position', 1000000),
35 cbuildbot_config.GetDisplayPosition(my_config['name']),
36 my_config['internal'], my_config['vm_tests'])
38 source = sorted(config.iteritems(), key=_GetSortKey)
39 return dict((name, dict(value.items() + [('display_position', idx)]))
40 for idx, (name, value) in enumerate(source))
43 def _DumpConfigJson(cfg):
44 """Dump |cfg| contents in JSON format.
47 cfg: A single build config.
49 print json.dumps(cfg, cls=_JSONEncoder)
52 def _DumpConfigPrettyJson(cfg):
53 """Dump |cfg| contents in pretty JSON format.
56 cfg: A single build config.
58 print json.dumps(cfg, cls=_JSONEncoder,
59 sort_keys=True, indent=4, separators=(',', ': '))
62 def _DumpConfigPrettyPrint(cfg):
63 """Dump |cfg| contents in pretty printer format.
66 cfg: A single build config.
68 pretty_printer = pprint.PrettyPrinter(indent=2)
69 pretty_printer.pprint(cfg)
72 def _CompareConfig(old_cfg, new_cfg):
73 """Compare two build configs targets, printing results.
76 old_cfg: The 'from' build config for comparison.
77 new_cfg: The 'to' build config for comparison.
79 new_cfg = json.loads(json.dumps(new_cfg, cls=_JSONEncoder))
80 for key in sorted(set(new_cfg.keys() + old_cfg.keys())):
81 obj1, obj2 = old_cfg.get(key), new_cfg.get(key)
85 print '%s: added to config\n' % (key,)
88 print '%s: removed from config\n' % (key,)
93 for subkey in sorted(set(obj1.keys() + obj2.keys())):
94 sobj1, sobj2 = obj1.get(subkey), obj2.get(subkey)
96 print ' %s: %r, %r' % (subkey, sobj1, sobj2)
102 """Creates the argparse parser."""
103 parser = commandline.ArgumentParser(description=__doc__)
105 # Put options that control the mode of script into mutually exclusive group.
106 mode = parser.add_mutually_exclusive_group(required=True)
107 mode.add_argument('-c', '--compare', action='store',
108 type=commandline.argparse.FileType('rb'),
109 default=None, metavar='file_name',
110 help='Compare current config against a saved on disk '
111 'serialized (json) dump of a config.')
112 mode.add_argument('-d', '--dump', action='store_true', default=False,
113 help='Dump the configs in JSON format.')
115 parser.add_argument('--pretty', action='store_true', default=False,
116 help='If dumping, make json output human readable.')
117 parser.add_argument('--for-buildbot', action='store_true', default=False,
118 help='Include the display position in data.')
119 parser.add_argument('config_targets', metavar='config_target', nargs='*',
120 help='Name of a cbuildbot config target.')
127 options = parser.parse_args(argv)
129 if options.pretty and not options.dump:
130 parser.error('The --pretty option does not make sense without --dump')
132 # Possibly translate config contents first.
133 convert = lambda x: x
134 if options.for_buildbot:
135 convert = _InjectDisplayPosition
137 config = convert(cbuildbot_config.config)
139 # If config_targets specified, only dump/load those.
140 if options.config_targets:
142 for c in options.config_targets:
144 temp_config[c] = config[c]
146 cros_build_lib.Die('No such config id: %s', c)
153 _DumpConfigPrettyJson(config)
155 _DumpConfigJson(config)
156 elif options.compare:
157 # Load the previously saved build config for comparison.
158 old_cfg = convert(json.load(options.compare))
159 _CompareConfig(old_cfg, config)