blob: 529a512b78b4674d2b0cc0da48a544641eed94b5 [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',
C Shapiro6830e6c2020-04-29 13:29:56 -050040 'arc_hw_features',
41 'dptf_file'])
C Shapiro5bf23a72020-04-24 11:40:17 -050042
C Shapiro6830e6c2020-04-29 13:29:56 -050043DPTF_PATH = 'sw_build_config/platform/chromeos-config/thermal/dptf.dv'
David Burger7fd1dbe2020-03-26 09:26:55 -060044
45def ParseArgs(argv):
46 """Parse the available arguments.
47
48 Invalid arguments or -h cause this function to print a message and exit.
49
50 Args:
51 argv: List of string arguments (excluding program name / argv[0])
52
53 Returns:
54 argparse.Namespace object containing the attributes.
55 """
56 parser = argparse.ArgumentParser(
57 description='Converts source proto config into platform JSON config.')
58 parser.add_argument(
59 '-c',
60 '--project_configs',
61 nargs='+',
62 type=str,
63 help='Space delimited list of source protobinary project config files.')
64 parser.add_argument(
65 '-p',
66 '--program_config',
67 type=str,
68 help='Path to the source program-level protobinary file')
69 parser.add_argument(
70 '-o',
71 '--output',
72 type=str,
73 help='Output file that will be generated')
74 return parser.parse_args(argv)
75
76
77def _Set(field, target, target_name):
78 if field:
79 target[target_name] = field
80
81
C Shapiro5bf23a72020-04-24 11:40:17 -050082def _BuildArc(config, config_files):
David Burger7fd1dbe2020-03-26 09:26:55 -060083 if config.build_target.arc:
84 build_properties = {
85 'device': config.build_target.arc.device,
86 'first-api-level': config.build_target.arc.first_api_level,
87 'marketing-name': config.device_brand.brand_name,
88 'metrics-tag': config.hw_design.name.lower(),
Andrew Lambb47b7dc2020-04-07 10:20:32 -060089 'product': config.build_target.id.value,
David Burger7fd1dbe2020-03-26 09:26:55 -060090 }
91 if config.oem:
92 build_properties['oem'] = config.oem.name
C Shapiro5bf23a72020-04-24 11:40:17 -050093 result = {
94 'build-properties': build_properties
95 }
96 feature_id = _ArcHardwareFeatureId(config.hw_design_config)
97 if feature_id in config_files.arc_hw_features:
98 result['hardware-features'] = config_files.arc_hw_features[feature_id]
99 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600100
C Shapiro90fda252020-04-17 14:34:57 -0500101def _BuildBluetooth(config, bluetooth_files):
102 bt_flags = config.sw_config.bluetooth_config.flags
103 # Convert to native map (from proto wrapper)
104 bt_flags_map = dict(bt_flags)
105 result = {}
106 if bt_flags_map:
107 result['flags'] = bt_flags_map
108 bt_comp = config.hw_design_config.hardware_features.bluetooth.component
109 if bt_comp.vendor_id:
110 bt_id = _BluetoothId(config.hw_design.name.lower(), bt_comp)
111 if bt_id in bluetooth_files:
112 result['config'] = bluetooth_files[bt_id]
113 return result
114
David Burger7fd1dbe2020-03-26 09:26:55 -0600115
116def _BuildFingerprint(hw_topology):
Andrew Lambc2c55462020-04-06 08:43:34 -0600117 if hw_topology.HasField('fingerprint'):
David Burger7fd1dbe2020-03-26 09:26:55 -0600118 fp = hw_topology.fingerprint.hardware_feature.fingerprint
David Burger92609a32020-04-23 10:38:50 -0600119 result = {}
120 if fp.location != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
121 location = fp.Location.DESCRIPTOR.values_by_number[fp.location].name
122 result['sensor-location'] = location.lower().replace('_', '-')
123 if fp.board:
124 result['board'] = fp.board
David Burger7fd1dbe2020-03-26 09:26:55 -0600125 return result
126
127
128def _FwBcsPath(payload):
129 if payload and payload.firmware_image_name:
130 return 'bcs://%s.%d.%d.0.tbz2' % (
131 payload.firmware_image_name,
132 payload.version.major,
133 payload.version.minor)
134
135
136def _FwBuildTarget(payload):
137 if payload:
138 return payload.build_target_name
139
140
141def _BuildFirmware(config):
Andrew Lamb3da156d2020-04-16 16:00:56 -0600142 fw_payload_config = config.sw_config.firmware
143 fw_build_config = config.sw_config.firmware_build_config
144 main_ro = fw_payload_config.main_ro_payload
145 main_rw = fw_payload_config.main_rw_payload
146 ec_ro = fw_payload_config.ec_ro_payload
147 pd_ro = fw_payload_config.pd_ro_payload
David Burger7fd1dbe2020-03-26 09:26:55 -0600148
149 build_targets = {}
Andrew Lamb3da156d2020-04-16 16:00:56 -0600150
Andrew Lambf8954ee2020-04-21 10:24:40 -0600151 _Set(fw_build_config.build_targets.depthcharge, build_targets, 'depthcharge')
152 _Set(fw_build_config.build_targets.coreboot, build_targets, 'coreboot')
153 _Set(fw_build_config.build_targets.ec, build_targets, 'ec')
154 _Set(
155 list(fw_build_config.build_targets.ec_extras), build_targets, 'ec_extras')
156 _Set(fw_build_config.build_targets.libpayload, build_targets, 'libpayload')
David Burger7fd1dbe2020-03-26 09:26:55 -0600157
158 result = {
159 'bcs-overlay': config.build_target.overlay_name,
160 'build-targets': build_targets,
David Burger7fd1dbe2020-03-26 09:26:55 -0600161 }
Andrew Lamb883fa042020-04-06 11:37:22 -0600162
163 _Set(main_ro.firmware_image_name.lower(), result, 'image-name')
164
Andrew Lamb883fa042020-04-06 11:37:22 -0600165 _Set(_FwBcsPath(main_ro), result, 'main-ro-image')
166 _Set(_FwBcsPath(main_rw), result, 'main-rw-image')
167 _Set(_FwBcsPath(ec_ro), result, 'ec-ro-image')
168 _Set(_FwBcsPath(pd_ro), result, 'pd-ro-image')
David Burger7fd1dbe2020-03-26 09:26:55 -0600169
Andrew Lambf39fbe82020-04-13 16:14:33 -0600170 _Set(
171 config.hw_design_config.hardware_features.fw_config.value,
172 result,
173 'firmware-config',
174 )
175
David Burger7fd1dbe2020-03-26 09:26:55 -0600176 return result
177
178
179def _BuildFwSigning(config):
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500180 if config.sw_config.firmware and config.device_signer_config:
181 return {
182 'key-id': config.device_signer_config.key_id,
183 'signature-id': config.hw_design.name.lower(),
184 }
185 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600186
187
188def _File(source, destination):
189 return {
190 'destination': destination,
191 'source': source
192 }
193
194
195def _BuildAudio(config):
196 alsa_path = '/usr/share/alsa/ucm'
197 cras_path = '/etc/cras'
198 project_name = config.hw_design.name.lower()
Andrew Lamb7d536782020-04-07 10:23:55 -0600199 if not config.sw_config.HasField('audio_config'):
David Burger7fd1dbe2020-03-26 09:26:55 -0600200 return {}
201 audio = config.sw_config.audio_config
202 card = audio.card_name
David Burger599ff7b2020-04-06 16:29:31 -0600203 card_with_suffix = audio.card_name
204 if audio.ucm_suffix:
205 card_with_suffix += '.' + audio.ucm_suffix
David Burger7fd1dbe2020-03-26 09:26:55 -0600206 files = []
207 if audio.ucm_file:
David Burger599ff7b2020-04-06 16:29:31 -0600208 files.append(_File(
209 audio.ucm_file,
210 '%s/%s/HiFi.conf' % (alsa_path, card_with_suffix)))
David Burger7fd1dbe2020-03-26 09:26:55 -0600211 if audio.ucm_master_file:
212 files.append(_File(
David Burger599ff7b2020-04-06 16:29:31 -0600213 audio.ucm_master_file,
214 '%s/%s/%s.conf' % (alsa_path, card_with_suffix, card_with_suffix)))
David Burger7fd1dbe2020-03-26 09:26:55 -0600215 if audio.card_config_file:
216 files.append(_File(
217 audio.card_config_file, '%s/%s/%s' % (cras_path, project_name, card)))
218 if audio.dsp_file:
219 files.append(
David Burger2e254902020-04-02 16:56:01 -0600220 _File(audio.dsp_file, '%s/%s/dsp.ini' % (cras_path, project_name)))
David Burger599ff7b2020-04-06 16:29:31 -0600221
222 result = {
David Burger7fd1dbe2020-03-26 09:26:55 -0600223 'main': {
224 'cras-config-dir': project_name,
225 'files': files,
226 }
227 }
David Burger599ff7b2020-04-06 16:29:31 -0600228 if audio.ucm_suffix:
David Burger03cdcbd2020-04-13 13:54:48 -0600229 result['main']['ucm-suffix'] = audio.ucm_suffix
David Burger599ff7b2020-04-06 16:29:31 -0600230
231 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600232
233
David Burger8aa8fa32020-04-14 08:30:34 -0600234def _BuildCamera(hw_topology):
235 if hw_topology.HasField('camera'):
236 camera = hw_topology.camera.hardware_feature.camera
237 result = {}
238 if camera.count.value:
239 result['count'] = camera.count.value
240 return result
241
242
Andrew Lamb7806ce92020-04-07 10:22:17 -0600243def _BuildIdentity(hw_scan_config, program, brand_scan_config=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600244 identity = {}
245 _Set(hw_scan_config.firmware_sku, identity, 'sku-id')
246 _Set(hw_scan_config.smbios_name_match, identity, 'smbios-name-match')
Andrew Lamb7806ce92020-04-07 10:22:17 -0600247 # 'platform-name' is needed to support 'mosys platform name'. Clients should
248 # longer require platform name, but set it here for backwards compatibility.
249 _Set(program.name, identity, 'platform-name')
David Burger7fd1dbe2020-03-26 09:26:55 -0600250 # ARM architecture
251 _Set(hw_scan_config.device_tree_compatible_match, identity,
252 'device-tree-compatible-match')
253
254 if brand_scan_config:
255 _Set(brand_scan_config.whitelabel_tag, identity, 'whitelabel-tag')
256
257 return identity
258
259
260def _Lookup(id_value, id_map):
261 if id_value.value:
262 key = id_value.value
263 if key in id_map:
264 return id_map[id_value.value]
265 error = 'Failed to lookup %s with value: %s' % (
266 id_value.__class__.__name__.replace('Id', ''), key)
267 print(error)
268 print('Check the config contents provided:')
269 pp = pprint.PrettyPrinter(indent=4)
270 pp.pprint(id_map)
271 raise Exception(error)
272
273
C Shapiro6830e6c2020-04-29 13:29:56 -0500274def _TransformBuildConfigs(config, config_files=ConfigFiles({}, {}, None)):
David Burger7fd1dbe2020-03-26 09:26:55 -0600275 partners = dict([(x.id.value, x) for x in config.partners.value])
276 programs = dict([(x.id.value, x) for x in config.programs.value])
David Burger7fd1dbe2020-03-26 09:26:55 -0600277 sw_configs = list(config.software_configs)
278 brand_configs = dict([(x.brand_id.value, x) for x in config.brand_configs])
279
C Shapiroa0b766c2020-03-31 08:35:28 -0500280 if len(config.build_targets) != 1:
281 # Artifact of sharing the config_bundle for analysis and transforms.
282 # Integrated analysis of multiple programs/projects it the only time
283 # having multiple build targets would be valid.
284 raise Exception('Single build_target required for transform')
285
David Burger7fd1dbe2020-03-26 09:26:55 -0600286 results = {}
287 for hw_design in config.designs.value:
288 if config.device_brands.value:
289 device_brands = [x for x in config.device_brands.value
290 if x.design_id.value == hw_design.id.value]
291 else:
292 device_brands = [device_brand_pb2.DeviceBrand()]
293
294 for device_brand in device_brands:
295 # Brand config can be empty since platform JSON config allows it
296 brand_config = brand_config_pb2.BrandConfig()
297 if device_brand.id.value in brand_configs:
298 brand_config = brand_configs[device_brand.id.value]
299
300 for hw_design_config in hw_design.configs:
301 design_id = hw_design_config.id.value
302 sw_config_matches = [x for x in sw_configs
303 if x.design_config_id.value == design_id]
304 if len(sw_config_matches) == 1:
305 sw_config = sw_config_matches[0]
306 elif len(sw_config_matches) > 1:
307 raise Exception('Multiple software configs found for: %s' % design_id)
308 else:
309 raise Exception('Software config is required for: %s' % design_id)
310
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500311 program = _Lookup(hw_design.program_id, programs)
312 signer_configs = dict(
313 [(x.brand_id.value, x) for x in program.device_signer_configs])
314 device_signer_config = None
315 if signer_configs:
316 device_signer_config = _Lookup(device_brand.id, signer_configs)
317
C Shapiro90fda252020-04-17 14:34:57 -0500318 transformed_config = _TransformBuildConfig(
319 Config(
320 program=program,
321 hw_design=hw_design,
322 odm=_Lookup(hw_design.odm_id, partners),
323 hw_design_config=hw_design_config,
324 device_brand=device_brand,
325 device_signer_config=device_signer_config,
326 oem=_Lookup(device_brand.oem_id, partners),
327 sw_config=sw_config,
328 brand_config=brand_config,
329 build_target=config.build_targets[0]),
C Shapiro5bf23a72020-04-24 11:40:17 -0500330 config_files)
David Burger7fd1dbe2020-03-26 09:26:55 -0600331
332 config_json = json.dumps(transformed_config,
333 sort_keys=True,
334 indent=2,
335 separators=(',', ': '))
336
337 if config_json not in results:
338 results[config_json] = transformed_config
339
340 return list(results.values())
341
342
C Shapiro5bf23a72020-04-24 11:40:17 -0500343def _TransformBuildConfig(config, config_files):
David Burger7fd1dbe2020-03-26 09:26:55 -0600344 """Transforms Config instance into target platform JSON schema.
345
346 Args:
347 config: Config namedtuple
C Shapiro5bf23a72020-04-24 11:40:17 -0500348 config_files: Map to look up the generated config files.
David Burger7fd1dbe2020-03-26 09:26:55 -0600349
350 Returns:
351 Unique config payload based on the platform JSON schema.
352 """
353 result = {
354 'identity': _BuildIdentity(
355 config.sw_config.id_scan_config,
Andrew Lamb7806ce92020-04-07 10:22:17 -0600356 config.program,
David Burger7fd1dbe2020-03-26 09:26:55 -0600357 config.brand_config.scan_config),
358 'name': config.hw_design.name.lower(),
359 }
360
C Shapiro5bf23a72020-04-24 11:40:17 -0500361 _Set(_BuildArc(config, config_files), result, 'arc')
David Burger7fd1dbe2020-03-26 09:26:55 -0600362 _Set(_BuildAudio(config), result, 'audio')
C Shapiro5bf23a72020-04-24 11:40:17 -0500363 _Set(_BuildBluetooth(config, config_files.bluetooth), result, 'bluetooth')
David Burger7fd1dbe2020-03-26 09:26:55 -0600364 _Set(config.device_brand.brand_code, result, 'brand-code')
David Burger8aa8fa32020-04-14 08:30:34 -0600365 _Set(_BuildCamera(
366 config.hw_design_config.hardware_topology), result, 'camera')
David Burger7fd1dbe2020-03-26 09:26:55 -0600367 _Set(_BuildFirmware(config), result, 'firmware')
368 _Set(_BuildFwSigning(config), result, 'firmware-signing')
369 _Set(_BuildFingerprint(
370 config.hw_design_config.hardware_topology), result, 'fingerprint')
371 power_prefs = config.sw_config.power_config.preferences
372 power_prefs_map = dict(
373 (x.replace('_', '-'),
374 power_prefs[x]) for x in power_prefs)
375 _Set(power_prefs_map, result, 'power')
C Shapiro6830e6c2020-04-29 13:29:56 -0500376 _Set(config_files.dptf_file, result, 'thermal')
David Burger7fd1dbe2020-03-26 09:26:55 -0600377
378 return result
379
380
381def WriteOutput(configs, output=None):
382 """Writes a list of configs to platform JSON format.
383
384 Args:
385 configs: List of config dicts defined in cros_config_schema.yaml
386 output: Target file output (if None, prints to stdout)
387 """
388 json_output = json.dumps(
389 {'chromeos': {
390 'configs': configs,
391 }},
392 sort_keys=True,
393 indent=2,
394 separators=(',', ': '))
395 if output:
396 with open(output, 'w') as output_stream:
397 # Using print function adds proper trailing newline.
398 print(json_output, file=output_stream)
399 else:
400 print(json_output)
401
402
C Shapiro90fda252020-04-17 14:34:57 -0500403def _BluetoothId(project_name, bt_comp):
404 return '_'.join([project_name,
405 bt_comp.vendor_id,
406 bt_comp.product_id,
407 bt_comp.bcd_device])
408
409
C Shapiro5bf23a72020-04-24 11:40:17 -0500410def _Feature(name, present):
411 attrib = {'name': name}
412 if present:
413 return etree.Element('feature', attrib=attrib)
414 else:
415 return etree.Element('unavailable-feature', attrib=attrib)
416
417
418def _AnyPresent(features):
419 return topology_pb2.HardwareFeatures.PRESENT in features;
420
421
422def _ArcHardwareFeatureId(design_config):
423 return design_config.id.value.lower().replace(':', '_')
424
425
C Shapiro5c877992020-04-29 12:11:28 -0500426def WriteArcHardwareFeatureFiles(config, output_dir, build_root_dir):
C Shapiro5bf23a72020-04-24 11:40:17 -0500427 """Writes ARC hardware_feature.xml files for each config
428
429 Args:
430 config: Source ConfigBundle to process.
431 output_dir: Path to the generated output.
C Shapiro5c877992020-04-29 12:11:28 -0500432 build_root_path: Path to the config file from portage's perspective.
C Shapiro5bf23a72020-04-24 11:40:17 -0500433 Returns:
434 dict that maps the design_config_id onto the correct file.
435 """
C Shapiro5bf23a72020-04-24 11:40:17 -0500436 result = {}
437 for hw_design in config.designs.value:
438 for design_config in hw_design.configs:
439 hw_features = design_config.hardware_features
440 multi_camera = hw_features.camera.count == 2
441 touchscreen = _AnyPresent([hw_features.screen.touch_support])
442 acc = hw_features.accelerometer
443 gyro = hw_features.gyroscope
444 compass = hw_features.magnetometer
445 ls = hw_features.light_sensor
446 root = etree.Element('permissions')
447 root.extend([
448 _Feature('android.hardware.camera', multi_camera),
449 _Feature('android.hardware.camera.autofocus', multi_camera),
450 _Feature('android.hardware.sensor.accelerometer',
451 _AnyPresent(
452 [acc.lid_accelerometer, acc.base_accelerometer])),
453 _Feature('android.hardware.sensor.gyroscope',
454 _AnyPresent(
455 [gyro.lid_gyroscope, gyro.base_gyroscope])),
456 _Feature('android.hardware.sensor.compass',
457 _AnyPresent(
458 [compass.lid_magnetometer, compass.base_magnetometer])),
459 _Feature('android.hardware.sensor.light',
460 _AnyPresent(
461 [ls.lid_lightsensor, ls.base_lightsensor])),
462 _Feature('android.hardware.touchscreen', touchscreen),
463 _Feature('android.hardware.touchscreen.multitouch', touchscreen),
464 _Feature(
465 'android.hardware.touchscreen.multitouch.distinct', touchscreen),
466 _Feature(
467 'android.hardware.touchscreen.multitouch.jazzhand', touchscreen),
468 ])
469
470 feature_id = _ArcHardwareFeatureId( design_config)
471
472 file_name = 'hardware_features_%s.xml' % feature_id
473 output = '%s/arc/%s' % (output_dir, file_name)
C Shapiro9a3ac8c2020-04-25 07:49:21 -0500474 file_content = minidom.parseString(
475 etree.tostring(root)).toprettyxml(indent=' ', encoding='utf-8')
476
477 with open(output, 'wb') as f:
478 f.write(file_content)
479
C Shapiro5bf23a72020-04-24 11:40:17 -0500480 result[feature_id] = {
C Shapiro5c877992020-04-29 12:11:28 -0500481 'build-path': '%s/arc/%s' % (build_root_dir, file_name),
C Shapiro5bf23a72020-04-24 11:40:17 -0500482 'system-path': '/etc/%s' % file_name,
483 }
484 return result
485
486
C Shapiro5c877992020-04-29 12:11:28 -0500487def WriteBluetoothConfigFiles(config, output_dir, build_root_path):
C Shapiro90fda252020-04-17 14:34:57 -0500488 """Writes bluetooth conf files for every unique bluetooth chip.
489
490 Args:
491 config: Source ConfigBundle to process.
492 output_dir: Path to the generated output.
C Shapiro5c877992020-04-29 12:11:28 -0500493 build_root_path: Path to the config file from portage's perspective.
C Shapiro90fda252020-04-17 14:34:57 -0500494 Returns:
495 dict that maps the bluetooth component id onto the file config.
496 """
C Shapiro90fda252020-04-17 14:34:57 -0500497 result = {}
498 for hw_design in config.designs.value:
499 project_name = hw_design.name.lower()
500 for design_config in hw_design.configs:
501 bt_comp = design_config.hardware_features.bluetooth.component
502 if bt_comp.vendor_id:
503 bt_id = _BluetoothId(project_name, bt_comp)
504 result[bt_id] = {
C Shapiro5c877992020-04-29 12:11:28 -0500505 'build-path': '%s/bluetooth/%s.conf' % (build_root_path, bt_id),
C Shapiro90fda252020-04-17 14:34:57 -0500506 'system-path': '/etc/bluetooth/%s/main.conf' % bt_id,
507 }
508 bt_content = '''[General]
509DeviceID = bluetooth:%s:%s:%s''' % (bt_comp.vendor_id,
510 bt_comp.product_id,
511 bt_comp.bcd_device)
512
513 output = '%s/bluetooth/%s.conf' % (output_dir, bt_id)
514 with open(output, 'w') as output_stream:
515 # Using print function adds proper trailing newline.
516 print(bt_content, file=output_stream)
517 return result
518
519
David Burger7fd1dbe2020-03-26 09:26:55 -0600520def _ReadConfig(path):
David Burgere6f76222020-04-27 11:08:01 -0600521 """Reads a ConfigBundle proto from a file.
522
523 Reads a ConfigBundle proto from a file first attempting to parse as json
524 pb and falling back to parsing as binary pb.
525 TODO(crbug.com/1073530): remove binary pb fallback when transition to json pb
526 is complete.
527
528 Args:
529 path: Path to the file encoding the proto.
530 """
531 try:
532 return _ReadJsonProtoConfig(path)
533 except:
534 return _ReadBinaryProtoConfig(path)
535
536
537def _ReadJsonProtoConfig(path):
538 """Reads a json proto ConfigBundle from a file.
539
540 Args:
541 path: Path to the json proto.
542 """
543 config = config_bundle_pb2.ConfigBundle()
544 with open(path, 'r') as f:
545 return json_format.Parse(f.read(), config)
546
547
548def _ReadBinaryProtoConfig(path):
549 """Reads a binary proto ConfigBundle from a file.
David Burger7fd1dbe2020-03-26 09:26:55 -0600550
551 Args:
552 path: Path to the binary proto.
553 """
David Burger7fd1dbe2020-03-26 09:26:55 -0600554 with open(path, 'rb') as f:
David Burgere6f76222020-04-27 11:08:01 -0600555 return config_bundle_pb2.ConfigBundle.FromString(f.read())
David Burger7fd1dbe2020-03-26 09:26:55 -0600556
557
558def _MergeConfigs(configs):
559 result = config_bundle_pb2.ConfigBundle()
560 for config in configs:
561 result.MergeFrom(config)
562
563 return result
564
565
566def Main(project_configs,
567 program_config,
568 output):
569 """Transforms source proto config into platform JSON.
570
571 Args:
572 project_configs: List of source project configs to transform.
573 program_config: Program config for the given set of projects.
574 output: Output file that will be generated by the transform.
575 """
C Shapiro90fda252020-04-17 14:34:57 -0500576 configs =_MergeConfigs(
577 [_ReadConfig(program_config)] +
578 [_ReadConfig(config) for config in project_configs])
C Shapiro5bf23a72020-04-24 11:40:17 -0500579 bluetooth_files = {}
580 arc_hw_feature_files = {}
C Shapiro6830e6c2020-04-29 13:29:56 -0500581 dptf_file = None
C Shapiro5bf23a72020-04-24 11:40:17 -0500582 output_dir = os.path.dirname(output)
C Shapiro5c877992020-04-29 12:11:28 -0500583 build_root_dir = output_dir
584 # TODO(shapiroc): Make standard after all projects migrated to new structure
585 if 'sw_build_config' in output_dir:
586 full_path = os.path.realpath(output)
587 project_name = re.match(r'.*project/\w*/(\w*).*', full_path).groups(1)[0]
588 # Projects don't know about each other until they are integrated into the
589 # build system. When this happens, the files need to be able to co-exist
590 # without any collisions. This prefixes the project name (which is how
591 # portage maps in the project), so project files co-exist and can be
592 # installed together.
593 # This is necessary to allow projects to share files at the program level
594 # without having portage file installation collisions.
595 build_root_dir = os.path.join(project_name, output_dir)
C Shapiro6830e6c2020-04-29 13:29:56 -0500596
597 if os.path.exists(DPTF_PATH):
598 project_dptf_path = os.path.join(project_name, 'dptf.dv')
599 dptf_file = {
600 'dptf-dv': project_dptf_path,
601 'files': [_File(os.path.join(project_name, DPTF_PATH),
602 os.path.join('/etc/dptf', project_dptf_path))]
603 }
C Shapiro5bf23a72020-04-24 11:40:17 -0500604 if os.path.exists(os.path.join(output_dir, 'bluetooth')):
C Shapiro5c877992020-04-29 12:11:28 -0500605 bluetooth_files = WriteBluetoothConfigFiles(
606 configs, output_dir, build_root_dir)
C Shapiro5bf23a72020-04-24 11:40:17 -0500607 if os.path.exists(os.path.join(output_dir, 'arc')):
608 arc_hw_feature_files = WriteArcHardwareFeatureFiles(
C Shapiro5c877992020-04-29 12:11:28 -0500609 configs, output_dir, build_root_dir)
C Shapiro5bf23a72020-04-24 11:40:17 -0500610 config_files = ConfigFiles(
611 bluetooth=bluetooth_files,
612 arc_hw_features=arc_hw_feature_files,
C Shapiro6830e6c2020-04-29 13:29:56 -0500613 dptf_file=dptf_file
C Shapiro5bf23a72020-04-24 11:40:17 -0500614 )
615 WriteOutput(_TransformBuildConfigs(configs, config_files), output)
David Burger7fd1dbe2020-03-26 09:26:55 -0600616
617
618def main(argv=None):
619 """Main program which parses args and runs
620
621 Args:
622 argv: List of command line arguments, if None uses sys.argv.
623 """
624 if argv is None:
625 argv = sys.argv[1:]
626 opts = ParseArgs(argv)
627 Main(opts.project_configs, opts.program_config, opts.output)
628
629
630if __name__ == '__main__':
631 sys.exit(main(sys.argv[1:]))