1# Copyright (c) 2022 Nordic Semiconductor ASA 2# 3# SPDX-License-Identifier: Apache-2.0 4 5'''Domain handling for west extension commands. 6 7This provides parsing of domains yaml file and creation of objects of the 8Domain class. 9''' 10 11from dataclasses import dataclass 12 13import yaml 14import pykwalify.core 15import logging 16 17DOMAINS_SCHEMA = ''' 18## A pykwalify schema for basic validation of the structure of a 19## domains YAML file. 20## 21# The domains.yaml file is a simple list of domains from a multi image build 22# along with the default domain to use. 23type: map 24mapping: 25 default: 26 required: true 27 type: str 28 build_dir: 29 required: true 30 type: str 31 domains: 32 required: true 33 type: seq 34 sequence: 35 - type: map 36 mapping: 37 name: 38 required: true 39 type: str 40 build_dir: 41 required: true 42 type: str 43 flash_order: 44 required: false 45 type: seq 46 sequence: 47 - type: str 48''' 49 50schema = yaml.safe_load(DOMAINS_SCHEMA) 51logger = logging.getLogger('build_helpers') 52# Configure simple logging backend. 53formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') 54handler = logging.StreamHandler() 55handler.setFormatter(formatter) 56logger.addHandler(handler) 57 58 59class Domains: 60 61 def __init__(self, domains_yaml): 62 try: 63 data = yaml.safe_load(domains_yaml) 64 pykwalify.core.Core(source_data=data, 65 schema_data=schema).validate() 66 except (yaml.YAMLError, pykwalify.errors.SchemaError): 67 logger.critical(f'malformed domains.yaml') 68 exit(1) 69 70 self._build_dir = data['build_dir'] 71 self._domains = { 72 d['name']: Domain(d['name'], d['build_dir']) 73 for d in data['domains'] 74 } 75 76 # In the YAML data, the values for "default" and "flash_order" 77 # must not name any domains that aren't listed under "domains". 78 # Now that self._domains has been initialized, we can leverage 79 # the common checks in self.get_domain to verify this. 80 self._default_domain = self.get_domain(data['default']) 81 self._flash_order = self.get_domains(data.get('flash_order', [])) 82 83 @staticmethod 84 def from_file(domains_file): 85 '''Load domains from a domains.yaml file. 86 ''' 87 try: 88 with open(domains_file, 'r') as f: 89 domains_yaml = f.read() 90 except FileNotFoundError: 91 logger.critical(f'domains.yaml file not found: {domains_file}') 92 exit(1) 93 94 return Domains(domains_yaml) 95 96 @staticmethod 97 def from_yaml(domains_yaml): 98 '''Load domains from a string with YAML contents. 99 ''' 100 return Domains(domains_yaml) 101 102 def get_domains(self, names=None, default_flash_order=False): 103 if names is None: 104 if default_flash_order: 105 return self._flash_order 106 return list(self._domains.values()) 107 return list(map(self.get_domain, names)) 108 109 def get_domain(self, name): 110 found = self._domains.get(name) 111 if not found: 112 logger.critical(f'domain "{name}" not found, ' 113 f'valid domains are: {", ".join(self._domains)}') 114 exit(1) 115 return found 116 117 def get_default_domain(self): 118 return self._default_domain 119 120 def get_top_build_dir(self): 121 return self._build_dir 122 123 124@dataclass 125class Domain: 126 127 name: str 128 build_dir: str 129