blob: 954e2be7845ddaaf10f99b697ddac01dff99a019 [file] [log] [blame]
David Burger7fd1dbe2020-03-26 09:26:55 -06001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# Copyright 2020 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6"""Transforms config from /config/proto/api proto format to platform JSON."""
7
8import argparse
9import json
10import pprint
C Shapiro90fda252020-04-17 14:34:57 -050011import os
David Burger7fd1dbe2020-03-26 09:26:55 -060012import sys
C Shapiro90fda252020-04-17 14:34:57 -050013import re
C Shapiro5bf23a72020-04-24 11:40:17 -050014import xml.etree.ElementTree as etree
C Shapiro9a3ac8c2020-04-25 07:49:21 -050015import xml.dom.minidom as minidom
David Burger7fd1dbe2020-03-26 09:26:55 -060016
17from collections import namedtuple
18
Prathmesh Prabhu72f8a002020-04-10 09:57:53 -070019from chromiumos.config.api import device_brand_pb2
David Burger92609a32020-04-23 10:38:50 -060020from chromiumos.config.api import topology_pb2
C Shapiro5bf23a72020-04-24 11:40:17 -050021from chromiumos.config.payload import config_bundle_pb2
Prathmesh Prabhu72f8a002020-04-10 09:57:53 -070022from chromiumos.config.api.software import brand_config_pb2
David Burger7fd1dbe2020-03-26 09:26:55 -060023
David Burgere6f76222020-04-27 11:08:01 -060024from google.protobuf import json_format
25
David Burger7fd1dbe2020-03-26 09:26:55 -060026Config = namedtuple('Config',
27 ['program',
28 'hw_design',
29 'odm',
30 'hw_design_config',
31 'device_brand',
C Shapiro2f0bb5d2020-04-14 10:07:47 -050032 'device_signer_config',
David Burger7fd1dbe2020-03-26 09:26:55 -060033 'oem',
34 'sw_config',
35 'brand_config',
36 'build_target'])
37
C Shapiro5bf23a72020-04-24 11:40:17 -050038ConfigFiles = namedtuple('ConfigFiles',
39 ['bluetooth',
40 'arc_hw_features'])
41
David Burger7fd1dbe2020-03-26 09:26:55 -060042
43def ParseArgs(argv):
44 """Parse the available arguments.
45
46 Invalid arguments or -h cause this function to print a message and exit.
47
48 Args:
49 argv: List of string arguments (excluding program name / argv[0])
50
51 Returns:
52 argparse.Namespace object containing the attributes.
53 """
54 parser = argparse.ArgumentParser(
55 description='Converts source proto config into platform JSON config.')
56 parser.add_argument(
57 '-c',
58 '--project_configs',
59 nargs='+',
60 type=str,
61 help='Space delimited list of source protobinary project config files.')
62 parser.add_argument(
63 '-p',
64 '--program_config',
65 type=str,
66 help='Path to the source program-level protobinary file')
67 parser.add_argument(
68 '-o',
69 '--output',
70 type=str,
71 help='Output file that will be generated')
72 return parser.parse_args(argv)
73
74
75def _Set(field, target, target_name):
76 if field:
77 target[target_name] = field
78
79
C Shapiro5bf23a72020-04-24 11:40:17 -050080def _BuildArc(config, config_files):
David Burger7fd1dbe2020-03-26 09:26:55 -060081 if config.build_target.arc:
82 build_properties = {
83 'device': config.build_target.arc.device,
84 'first-api-level': config.build_target.arc.first_api_level,
85 'marketing-name': config.device_brand.brand_name,
86 'metrics-tag': config.hw_design.name.lower(),
Andrew Lambb47b7dc2020-04-07 10:20:32 -060087 'product': config.build_target.id.value,
David Burger7fd1dbe2020-03-26 09:26:55 -060088 }
89 if config.oem:
90 build_properties['oem'] = config.oem.name
C Shapiro5bf23a72020-04-24 11:40:17 -050091 result = {
92 'build-properties': build_properties
93 }
94 feature_id = _ArcHardwareFeatureId(config.hw_design_config)
95 if feature_id in config_files.arc_hw_features:
96 result['hardware-features'] = config_files.arc_hw_features[feature_id]
97 return result
David Burger7fd1dbe2020-03-26 09:26:55 -060098
C Shapiro90fda252020-04-17 14:34:57 -050099def _BuildBluetooth(config, bluetooth_files):
100 bt_flags = config.sw_config.bluetooth_config.flags
101 # Convert to native map (from proto wrapper)
102 bt_flags_map = dict(bt_flags)
103 result = {}
104 if bt_flags_map:
105 result['flags'] = bt_flags_map
106 bt_comp = config.hw_design_config.hardware_features.bluetooth.component
107 if bt_comp.vendor_id:
108 bt_id = _BluetoothId(config.hw_design.name.lower(), bt_comp)
109 if bt_id in bluetooth_files:
110 result['config'] = bluetooth_files[bt_id]
111 return result
112
David Burger7fd1dbe2020-03-26 09:26:55 -0600113
114def _BuildFingerprint(hw_topology):
Andrew Lambc2c55462020-04-06 08:43:34 -0600115 if hw_topology.HasField('fingerprint'):
David Burger7fd1dbe2020-03-26 09:26:55 -0600116 fp = hw_topology.fingerprint.hardware_feature.fingerprint
David Burger92609a32020-04-23 10:38:50 -0600117 result = {}
118 if fp.location != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
119 location = fp.Location.DESCRIPTOR.values_by_number[fp.location].name
120 result['sensor-location'] = location.lower().replace('_', '-')
121 if fp.board:
122 result['board'] = fp.board
David Burger7fd1dbe2020-03-26 09:26:55 -0600123 return result
124
125
126def _FwBcsPath(payload):
127 if payload and payload.firmware_image_name:
128 return 'bcs://%s.%d.%d.0.tbz2' % (
129 payload.firmware_image_name,
130 payload.version.major,
131 payload.version.minor)
132
133
134def _FwBuildTarget(payload):
135 if payload:
136 return payload.build_target_name
137
138
139def _BuildFirmware(config):
Andrew Lamb3da156d2020-04-16 16:00:56 -0600140 fw_payload_config = config.sw_config.firmware
141 fw_build_config = config.sw_config.firmware_build_config
142 main_ro = fw_payload_config.main_ro_payload
143 main_rw = fw_payload_config.main_rw_payload
144 ec_ro = fw_payload_config.ec_ro_payload
145 pd_ro = fw_payload_config.pd_ro_payload
David Burger7fd1dbe2020-03-26 09:26:55 -0600146
147 build_targets = {}
Andrew Lamb3da156d2020-04-16 16:00:56 -0600148
Andrew Lambf8954ee2020-04-21 10:24:40 -0600149 _Set(fw_build_config.build_targets.depthcharge, build_targets, 'depthcharge')
150 _Set(fw_build_config.build_targets.coreboot, build_targets, 'coreboot')
151 _Set(fw_build_config.build_targets.ec, build_targets, 'ec')
152 _Set(
153 list(fw_build_config.build_targets.ec_extras), build_targets, 'ec_extras')
154 _Set(fw_build_config.build_targets.libpayload, build_targets, 'libpayload')
David Burger7fd1dbe2020-03-26 09:26:55 -0600155
156 result = {
157 'bcs-overlay': config.build_target.overlay_name,
158 'build-targets': build_targets,
David Burger7fd1dbe2020-03-26 09:26:55 -0600159 }
Andrew Lamb883fa042020-04-06 11:37:22 -0600160
161 _Set(main_ro.firmware_image_name.lower(), result, 'image-name')
162
163 if not any((
164 main_ro.firmware_image_name,
165 main_rw.firmware_image_name,
166 ec_ro.firmware_image_name,
167 pd_ro.firmware_image_name,
168 )):
Andrew Lambb9e660f2020-04-06 11:37:22 -0600169 result['no-firmware'] = True
Andrew Lamb883fa042020-04-06 11:37:22 -0600170
171 _Set(_FwBcsPath(main_ro), result, 'main-ro-image')
172 _Set(_FwBcsPath(main_rw), result, 'main-rw-image')
173 _Set(_FwBcsPath(ec_ro), result, 'ec-ro-image')
174 _Set(_FwBcsPath(pd_ro), result, 'pd-ro-image')
David Burger7fd1dbe2020-03-26 09:26:55 -0600175
Andrew Lambf39fbe82020-04-13 16:14:33 -0600176 _Set(
177 config.hw_design_config.hardware_features.fw_config.value,
178 result,
179 'firmware-config',
180 )
181
David Burger7fd1dbe2020-03-26 09:26:55 -0600182 return result
183
184
185def _BuildFwSigning(config):
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500186 if config.sw_config.firmware and config.device_signer_config:
187 return {
188 'key-id': config.device_signer_config.key_id,
189 'signature-id': config.hw_design.name.lower(),
190 }
191 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600192
193
194def _File(source, destination):
195 return {
196 'destination': destination,
197 'source': source
198 }
199
200
201def _BuildAudio(config):
202 alsa_path = '/usr/share/alsa/ucm'
203 cras_path = '/etc/cras'
204 project_name = config.hw_design.name.lower()
Andrew Lamb7d536782020-04-07 10:23:55 -0600205 if not config.sw_config.HasField('audio_config'):
David Burger7fd1dbe2020-03-26 09:26:55 -0600206 return {}
207 audio = config.sw_config.audio_config
208 card = audio.card_name
David Burger599ff7b2020-04-06 16:29:31 -0600209 card_with_suffix = audio.card_name
210 if audio.ucm_suffix:
211 card_with_suffix += '.' + audio.ucm_suffix
David Burger7fd1dbe2020-03-26 09:26:55 -0600212 files = []
213 if audio.ucm_file:
David Burger599ff7b2020-04-06 16:29:31 -0600214 files.append(_File(
215 audio.ucm_file,
216 '%s/%s/HiFi.conf' % (alsa_path, card_with_suffix)))
David Burger7fd1dbe2020-03-26 09:26:55 -0600217 if audio.ucm_master_file:
218 files.append(_File(
David Burger599ff7b2020-04-06 16:29:31 -0600219 audio.ucm_master_file,
220 '%s/%s/%s.conf' % (alsa_path, card_with_suffix, card_with_suffix)))
David Burger7fd1dbe2020-03-26 09:26:55 -0600221 if audio.card_config_file:
222 files.append(_File(
223 audio.card_config_file, '%s/%s/%s' % (cras_path, project_name, card)))
224 if audio.dsp_file:
225 files.append(
David Burger2e254902020-04-02 16:56:01 -0600226 _File(audio.dsp_file, '%s/%s/dsp.ini' % (cras_path, project_name)))
David Burger599ff7b2020-04-06 16:29:31 -0600227
228 result = {
David Burger7fd1dbe2020-03-26 09:26:55 -0600229 'main': {
230 'cras-config-dir': project_name,
231 'files': files,
232 }
233 }
David Burger599ff7b2020-04-06 16:29:31 -0600234 if audio.ucm_suffix:
David Burger03cdcbd2020-04-13 13:54:48 -0600235 result['main']['ucm-suffix'] = audio.ucm_suffix
David Burger599ff7b2020-04-06 16:29:31 -0600236
237 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600238
239
David Burger8aa8fa32020-04-14 08:30:34 -0600240def _BuildCamera(hw_topology):
241 if hw_topology.HasField('camera'):
242 camera = hw_topology.camera.hardware_feature.camera
243 result = {}
244 if camera.count.value:
245 result['count'] = camera.count.value
246 return result
247
248
Andrew Lamb7806ce92020-04-07 10:22:17 -0600249def _BuildIdentity(hw_scan_config, program, brand_scan_config=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600250 identity = {}
251 _Set(hw_scan_config.firmware_sku, identity, 'sku-id')
252 _Set(hw_scan_config.smbios_name_match, identity, 'smbios-name-match')
Andrew Lamb7806ce92020-04-07 10:22:17 -0600253 # 'platform-name' is needed to support 'mosys platform name'. Clients should
254 # longer require platform name, but set it here for backwards compatibility.
255 _Set(program.name, identity, 'platform-name')
David Burger7fd1dbe2020-03-26 09:26:55 -0600256 # ARM architecture
257 _Set(hw_scan_config.device_tree_compatible_match, identity,
258 'device-tree-compatible-match')
259
260 if brand_scan_config:
261 _Set(brand_scan_config.whitelabel_tag, identity, 'whitelabel-tag')
262
263 return identity
264
265
266def _Lookup(id_value, id_map):
267 if id_value.value:
268 key = id_value.value
269 if key in id_map:
270 return id_map[id_value.value]
271 error = 'Failed to lookup %s with value: %s' % (
272 id_value.__class__.__name__.replace('Id', ''), key)
273 print(error)
274 print('Check the config contents provided:')
275 pp = pprint.PrettyPrinter(indent=4)
276 pp.pprint(id_map)
277 raise Exception(error)
278
279
C Shapiro5bf23a72020-04-24 11:40:17 -0500280def _TransformBuildConfigs(config, config_files=ConfigFiles({}, {})):
David Burger7fd1dbe2020-03-26 09:26:55 -0600281 partners = dict([(x.id.value, x) for x in config.partners.value])
282 programs = dict([(x.id.value, x) for x in config.programs.value])
David Burger7fd1dbe2020-03-26 09:26:55 -0600283 sw_configs = list(config.software_configs)
284 brand_configs = dict([(x.brand_id.value, x) for x in config.brand_configs])
285
C Shapiroa0b766c2020-03-31 08:35:28 -0500286 if len(config.build_targets) != 1:
287 # Artifact of sharing the config_bundle for analysis and transforms.
288 # Integrated analysis of multiple programs/projects it the only time
289 # having multiple build targets would be valid.
290 raise Exception('Single build_target required for transform')
291
David Burger7fd1dbe2020-03-26 09:26:55 -0600292 results = {}
293 for hw_design in config.designs.value:
294 if config.device_brands.value:
295 device_brands = [x for x in config.device_brands.value
296 if x.design_id.value == hw_design.id.value]
297 else:
298 device_brands = [device_brand_pb2.DeviceBrand()]
299
300 for device_brand in device_brands:
301 # Brand config can be empty since platform JSON config allows it
302 brand_config = brand_config_pb2.BrandConfig()
303 if device_brand.id.value in brand_configs:
304 brand_config = brand_configs[device_brand.id.value]
305
306 for hw_design_config in hw_design.configs:
307 design_id = hw_design_config.id.value
308 sw_config_matches = [x for x in sw_configs
309 if x.design_config_id.value == design_id]
310 if len(sw_config_matches) == 1:
311 sw_config = sw_config_matches[0]
312 elif len(sw_config_matches) > 1:
313 raise Exception('Multiple software configs found for: %s' % design_id)
314 else:
315 raise Exception('Software config is required for: %s' % design_id)
316
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500317 program = _Lookup(hw_design.program_id, programs)
318 signer_configs = dict(
319 [(x.brand_id.value, x) for x in program.device_signer_configs])
320 device_signer_config = None
321 if signer_configs:
322 device_signer_config = _Lookup(device_brand.id, signer_configs)
323
C Shapiro90fda252020-04-17 14:34:57 -0500324 transformed_config = _TransformBuildConfig(
325 Config(
326 program=program,
327 hw_design=hw_design,
328 odm=_Lookup(hw_design.odm_id, partners),
329 hw_design_config=hw_design_config,
330 device_brand=device_brand,
331 device_signer_config=device_signer_config,
332 oem=_Lookup(device_brand.oem_id, partners),
333 sw_config=sw_config,
334 brand_config=brand_config,
335 build_target=config.build_targets[0]),
C Shapiro5bf23a72020-04-24 11:40:17 -0500336 config_files)
David Burger7fd1dbe2020-03-26 09:26:55 -0600337
338 config_json = json.dumps(transformed_config,
339 sort_keys=True,
340 indent=2,
341 separators=(',', ': '))
342
343 if config_json not in results:
344 results[config_json] = transformed_config
345
346 return list(results.values())
347
348
C Shapiro5bf23a72020-04-24 11:40:17 -0500349def _TransformBuildConfig(config, config_files):
David Burger7fd1dbe2020-03-26 09:26:55 -0600350 """Transforms Config instance into target platform JSON schema.
351
352 Args:
353 config: Config namedtuple
C Shapiro5bf23a72020-04-24 11:40:17 -0500354 config_files: Map to look up the generated config files.
David Burger7fd1dbe2020-03-26 09:26:55 -0600355
356 Returns:
357 Unique config payload based on the platform JSON schema.
358 """
359 result = {
360 'identity': _BuildIdentity(
361 config.sw_config.id_scan_config,
Andrew Lamb7806ce92020-04-07 10:22:17 -0600362 config.program,
David Burger7fd1dbe2020-03-26 09:26:55 -0600363 config.brand_config.scan_config),
364 'name': config.hw_design.name.lower(),
365 }
366
C Shapiro5bf23a72020-04-24 11:40:17 -0500367 _Set(_BuildArc(config, config_files), result, 'arc')
David Burger7fd1dbe2020-03-26 09:26:55 -0600368 _Set(_BuildAudio(config), result, 'audio')
C Shapiro5bf23a72020-04-24 11:40:17 -0500369 _Set(_BuildBluetooth(config, config_files.bluetooth), result, 'bluetooth')
David Burger7fd1dbe2020-03-26 09:26:55 -0600370 _Set(config.device_brand.brand_code, result, 'brand-code')
David Burger8aa8fa32020-04-14 08:30:34 -0600371 _Set(_BuildCamera(
372 config.hw_design_config.hardware_topology), result, 'camera')
David Burger7fd1dbe2020-03-26 09:26:55 -0600373 _Set(_BuildFirmware(config), result, 'firmware')
374 _Set(_BuildFwSigning(config), result, 'firmware-signing')
375 _Set(_BuildFingerprint(
376 config.hw_design_config.hardware_topology), result, 'fingerprint')
377 power_prefs = config.sw_config.power_config.preferences
378 power_prefs_map = dict(
379 (x.replace('_', '-'),
380 power_prefs[x]) for x in power_prefs)
381 _Set(power_prefs_map, result, 'power')
382
383 return result
384
385
386def WriteOutput(configs, output=None):
387 """Writes a list of configs to platform JSON format.
388
389 Args:
390 configs: List of config dicts defined in cros_config_schema.yaml
391 output: Target file output (if None, prints to stdout)
392 """
393 json_output = json.dumps(
394 {'chromeos': {
395 'configs': configs,
396 }},
397 sort_keys=True,
398 indent=2,
399 separators=(',', ': '))
400 if output:
401 with open(output, 'w') as output_stream:
402 # Using print function adds proper trailing newline.
403 print(json_output, file=output_stream)
404 else:
405 print(json_output)
406
407
C Shapiro90fda252020-04-17 14:34:57 -0500408def _BluetoothId(project_name, bt_comp):
409 return '_'.join([project_name,
410 bt_comp.vendor_id,
411 bt_comp.product_id,
412 bt_comp.bcd_device])
413
414
C Shapiro5bf23a72020-04-24 11:40:17 -0500415def _Feature(name, present):
416 attrib = {'name': name}
417 if present:
418 return etree.Element('feature', attrib=attrib)
419 else:
420 return etree.Element('unavailable-feature', attrib=attrib)
421
422
423def _AnyPresent(features):
424 return topology_pb2.HardwareFeatures.PRESENT in features;
425
426
427def _ArcHardwareFeatureId(design_config):
428 return design_config.id.value.lower().replace(':', '_')
429
430
431def WriteArcHardwareFeatureFiles(config, output_dir):
432 """Writes ARC hardware_feature.xml files for each config
433
434 Args:
435 config: Source ConfigBundle to process.
436 output_dir: Path to the generated output.
437 Returns:
438 dict that maps the design_config_id onto the correct file.
439 """
440 project_gen_path = re.match(r'.*(generated.*)', output_dir).groups(1)[0]
441 result = {}
442 for hw_design in config.designs.value:
443 for design_config in hw_design.configs:
444 hw_features = design_config.hardware_features
445 multi_camera = hw_features.camera.count == 2
446 touchscreen = _AnyPresent([hw_features.screen.touch_support])
447 acc = hw_features.accelerometer
448 gyro = hw_features.gyroscope
449 compass = hw_features.magnetometer
450 ls = hw_features.light_sensor
451 root = etree.Element('permissions')
452 root.extend([
453 _Feature('android.hardware.camera', multi_camera),
454 _Feature('android.hardware.camera.autofocus', multi_camera),
455 _Feature('android.hardware.sensor.accelerometer',
456 _AnyPresent(
457 [acc.lid_accelerometer, acc.base_accelerometer])),
458 _Feature('android.hardware.sensor.gyroscope',
459 _AnyPresent(
460 [gyro.lid_gyroscope, gyro.base_gyroscope])),
461 _Feature('android.hardware.sensor.compass',
462 _AnyPresent(
463 [compass.lid_magnetometer, compass.base_magnetometer])),
464 _Feature('android.hardware.sensor.light',
465 _AnyPresent(
466 [ls.lid_lightsensor, ls.base_lightsensor])),
467 _Feature('android.hardware.touchscreen', touchscreen),
468 _Feature('android.hardware.touchscreen.multitouch', touchscreen),
469 _Feature(
470 'android.hardware.touchscreen.multitouch.distinct', touchscreen),
471 _Feature(
472 'android.hardware.touchscreen.multitouch.jazzhand', touchscreen),
473 ])
474
475 feature_id = _ArcHardwareFeatureId( design_config)
476
477 file_name = 'hardware_features_%s.xml' % feature_id
478 output = '%s/arc/%s' % (output_dir, file_name)
C Shapiro9a3ac8c2020-04-25 07:49:21 -0500479 file_content = minidom.parseString(
480 etree.tostring(root)).toprettyxml(indent=' ', encoding='utf-8')
481
482 with open(output, 'wb') as f:
483 f.write(file_content)
484
C Shapiro5bf23a72020-04-24 11:40:17 -0500485 result[feature_id] = {
486 'build-path': '%s/arc/%s' % (project_gen_path, file_name),
487 'system-path': '/etc/%s' % file_name,
488 }
489 return result
490
491
C Shapiro90fda252020-04-17 14:34:57 -0500492def WriteBluetoothConfigFiles(config, output_dir):
493 """Writes bluetooth conf files for every unique bluetooth chip.
494
495 Args:
496 config: Source ConfigBundle to process.
497 output_dir: Path to the generated output.
498 Returns:
499 dict that maps the bluetooth component id onto the file config.
500 """
501 project_gen_path = re.match(r'.*(generated.*)', output_dir).groups(1)[0]
502 result = {}
503 for hw_design in config.designs.value:
504 project_name = hw_design.name.lower()
505 for design_config in hw_design.configs:
506 bt_comp = design_config.hardware_features.bluetooth.component
507 if bt_comp.vendor_id:
508 bt_id = _BluetoothId(project_name, bt_comp)
509 result[bt_id] = {
C Shapiro8556b2d2020-04-22 11:04:14 -0500510 'build-path': '%s/bluetooth/%s.conf' % (project_gen_path, bt_id),
C Shapiro90fda252020-04-17 14:34:57 -0500511 'system-path': '/etc/bluetooth/%s/main.conf' % bt_id,
512 }
513 bt_content = '''[General]
514DeviceID = bluetooth:%s:%s:%s''' % (bt_comp.vendor_id,
515 bt_comp.product_id,
516 bt_comp.bcd_device)
517
518 output = '%s/bluetooth/%s.conf' % (output_dir, bt_id)
519 with open(output, 'w') as output_stream:
520 # Using print function adds proper trailing newline.
521 print(bt_content, file=output_stream)
522 return result
523
524
David Burger7fd1dbe2020-03-26 09:26:55 -0600525def _ReadConfig(path):
David Burgere6f76222020-04-27 11:08:01 -0600526 """Reads a ConfigBundle proto from a file.
527
528 Reads a ConfigBundle proto from a file first attempting to parse as json
529 pb and falling back to parsing as binary pb.
530 TODO(crbug.com/1073530): remove binary pb fallback when transition to json pb
531 is complete.
532
533 Args:
534 path: Path to the file encoding the proto.
535 """
536 try:
537 return _ReadJsonProtoConfig(path)
538 except:
539 return _ReadBinaryProtoConfig(path)
540
541
542def _ReadJsonProtoConfig(path):
543 """Reads a json proto ConfigBundle from a file.
544
545 Args:
546 path: Path to the json proto.
547 """
548 config = config_bundle_pb2.ConfigBundle()
549 with open(path, 'r') as f:
550 return json_format.Parse(f.read(), config)
551
552
553def _ReadBinaryProtoConfig(path):
554 """Reads a binary proto ConfigBundle from a file.
David Burger7fd1dbe2020-03-26 09:26:55 -0600555
556 Args:
557 path: Path to the binary proto.
558 """
David Burger7fd1dbe2020-03-26 09:26:55 -0600559 with open(path, 'rb') as f:
David Burgere6f76222020-04-27 11:08:01 -0600560 return config_bundle_pb2.ConfigBundle.FromString(f.read())
David Burger7fd1dbe2020-03-26 09:26:55 -0600561
562
563def _MergeConfigs(configs):
564 result = config_bundle_pb2.ConfigBundle()
565 for config in configs:
566 result.MergeFrom(config)
567
568 return result
569
570
571def Main(project_configs,
572 program_config,
573 output):
574 """Transforms source proto config into platform JSON.
575
576 Args:
577 project_configs: List of source project configs to transform.
578 program_config: Program config for the given set of projects.
579 output: Output file that will be generated by the transform.
580 """
C Shapiro90fda252020-04-17 14:34:57 -0500581 configs =_MergeConfigs(
582 [_ReadConfig(program_config)] +
583 [_ReadConfig(config) for config in project_configs])
C Shapiro5bf23a72020-04-24 11:40:17 -0500584 bluetooth_files = {}
585 arc_hw_feature_files = {}
586 output_dir = os.path.dirname(output)
587 if os.path.exists(os.path.join(output_dir, 'bluetooth')):
588 bluetooth_files = WriteBluetoothConfigFiles(configs, output_dir)
589 if os.path.exists(os.path.join(output_dir, 'arc')):
590 arc_hw_feature_files = WriteArcHardwareFeatureFiles(
591 configs, output_dir)
592 config_files = ConfigFiles(
593 bluetooth=bluetooth_files,
594 arc_hw_features=arc_hw_feature_files,
595 )
596 WriteOutput(_TransformBuildConfigs(configs, config_files), output)
David Burger7fd1dbe2020-03-26 09:26:55 -0600597
598
599def main(argv=None):
600 """Main program which parses args and runs
601
602 Args:
603 argv: List of command line arguments, if None uses sys.argv.
604 """
605 if argv is None:
606 argv = sys.argv[1:]
607 opts = ParseArgs(argv)
608 Main(opts.project_configs, opts.program_config, opts.output)
609
610
611if __name__ == '__main__':
612 sys.exit(main(sys.argv[1:]))