Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 1 | # Copyright (c) 2022 Nordic Semiconductor ASA |
| 2 | # |
| 3 | # SPDX-License-Identifier: Apache-2.0 |
| 4 | |
| 5 | '''Domain handling for west extension commands. |
| 6 | |
| 7 | This provides parsing of domains yaml file and creation of objects of the |
| 8 | Domain class. |
| 9 | ''' |
| 10 | |
Grzegorz Swiderski | 9bbf7e5 | 2023-09-28 09:36:36 +0200 | [diff] [blame] | 11 | from dataclasses import dataclass |
| 12 | |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 13 | import yaml |
| 14 | import pykwalify.core |
Daniel DeGrasse | c303c6f | 2022-11-01 12:16:39 -0500 | [diff] [blame] | 15 | import logging |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 16 | |
| 17 | DOMAINS_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. |
| 23 | type: map |
| 24 | mapping: |
| 25 | default: |
| 26 | required: true |
| 27 | type: str |
| 28 | build_dir: |
| 29 | required: true |
| 30 | type: str |
| 31 | domains: |
Grzegorz Swiderski | f82e2ef | 2023-09-28 09:36:01 +0200 | [diff] [blame] | 32 | required: true |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 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 |
Grzegorz Swiderski | 05d7769 | 2023-09-25 12:45:10 +0200 | [diff] [blame] | 43 | flash_order: |
| 44 | required: false |
| 45 | type: seq |
| 46 | sequence: |
| 47 | - type: str |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 48 | ''' |
| 49 | |
| 50 | schema = yaml.safe_load(DOMAINS_SCHEMA) |
Daniel DeGrasse | c303c6f | 2022-11-01 12:16:39 -0500 | [diff] [blame] | 51 | logger = logging.getLogger('build_helpers') |
| 52 | # Configure simple logging backend. |
| 53 | formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') |
| 54 | handler = logging.StreamHandler() |
| 55 | handler.setFormatter(formatter) |
| 56 | logger.addHandler(handler) |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 57 | |
| 58 | |
| 59 | class Domains: |
| 60 | |
Grzegorz Swiderski | 652b0a8 | 2023-09-28 09:36:18 +0200 | [diff] [blame] | 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 | |
Grzegorz Swiderski | f82e2ef | 2023-09-28 09:36:01 +0200 | [diff] [blame] | 70 | self._build_dir = data['build_dir'] |
Grzegorz Swiderski | 05d7769 | 2023-09-25 12:45:10 +0200 | [diff] [blame] | 71 | self._domains = { |
| 72 | d['name']: Domain(d['name'], d['build_dir']) |
Grzegorz Swiderski | f82e2ef | 2023-09-28 09:36:01 +0200 | [diff] [blame] | 73 | for d in data['domains'] |
Grzegorz Swiderski | 05d7769 | 2023-09-25 12:45:10 +0200 | [diff] [blame] | 74 | } |
Grzegorz Swiderski | 05d7769 | 2023-09-25 12:45:10 +0200 | [diff] [blame] | 75 | |
Grzegorz Swiderski | f82e2ef | 2023-09-28 09:36:01 +0200 | [diff] [blame] | 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']) |
Lukasz Mrugala | 2fcf4e3 | 2023-10-05 13:41:15 +0200 | [diff] [blame] | 81 | self._flash_order = self.get_domains(data.get('flash_order', [])) |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 82 | |
| 83 | @staticmethod |
| 84 | def from_file(domains_file): |
Grzegorz Swiderski | 652b0a8 | 2023-09-28 09:36:18 +0200 | [diff] [blame] | 85 | '''Load domains from a domains.yaml file. |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 86 | ''' |
| 87 | try: |
| 88 | with open(domains_file, 'r') as f: |
Grzegorz Swiderski | 652b0a8 | 2023-09-28 09:36:18 +0200 | [diff] [blame] | 89 | domains_yaml = f.read() |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 90 | except FileNotFoundError: |
Daniel DeGrasse | c303c6f | 2022-11-01 12:16:39 -0500 | [diff] [blame] | 91 | logger.critical(f'domains.yaml file not found: {domains_file}') |
| 92 | exit(1) |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 93 | |
Grzegorz Swiderski | 652b0a8 | 2023-09-28 09:36:18 +0200 | [diff] [blame] | 94 | return Domains(domains_yaml) |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 95 | |
| 96 | @staticmethod |
Grzegorz Swiderski | 652b0a8 | 2023-09-28 09:36:18 +0200 | [diff] [blame] | 97 | def from_yaml(domains_yaml): |
| 98 | '''Load domains from a string with YAML contents. |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 99 | ''' |
Grzegorz Swiderski | 652b0a8 | 2023-09-28 09:36:18 +0200 | [diff] [blame] | 100 | return Domains(domains_yaml) |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 101 | |
Grzegorz Swiderski | 05d7769 | 2023-09-25 12:45:10 +0200 | [diff] [blame] | 102 | def get_domains(self, names=None, default_flash_order=False): |
Grzegorz Swiderski | f82e2ef | 2023-09-28 09:36:01 +0200 | [diff] [blame] | 103 | if names is None: |
Grzegorz Swiderski | 05d7769 | 2023-09-25 12:45:10 +0200 | [diff] [blame] | 104 | if default_flash_order: |
| 105 | return self._flash_order |
| 106 | return list(self._domains.values()) |
Grzegorz Swiderski | f82e2ef | 2023-09-28 09:36:01 +0200 | [diff] [blame] | 107 | return list(map(self.get_domain, names)) |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 108 | |
Grzegorz Swiderski | f82e2ef | 2023-09-28 09:36:01 +0200 | [diff] [blame] | 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 |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 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 | |
Grzegorz Swiderski | 9bbf7e5 | 2023-09-28 09:36:36 +0200 | [diff] [blame] | 124 | @dataclass |
Torsten Rasmussen | 8408af6 | 2021-11-22 10:29:56 +0100 | [diff] [blame] | 125 | class Domain: |
| 126 | |
Grzegorz Swiderski | 9bbf7e5 | 2023-09-28 09:36:36 +0200 | [diff] [blame] | 127 | name: str |
| 128 | build_dir: str |