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
11import yaml
12import pykwalify.core
13import logging
14
15DOMAINS_SCHEMA = '''
16## A pykwalify schema for basic validation of the structure of a
17## domains YAML file.
18##
19# The domains.yaml file is a simple list of domains from a multi image build
20# along with the default domain to use.
21type: map
22mapping:
23  default:
24    required: true
25    type: str
26  build_dir:
27    required: true
28    type: str
29  domains:
30    required: false
31    type: seq
32    sequence:
33      - type: map
34        mapping:
35          name:
36            required: true
37            type: str
38          build_dir:
39            required: true
40            type: str
41'''
42
43schema = yaml.safe_load(DOMAINS_SCHEMA)
44logger = logging.getLogger('build_helpers')
45# Configure simple logging backend.
46formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
47handler = logging.StreamHandler()
48handler.setFormatter(formatter)
49logger.addHandler(handler)
50
51
52class Domains:
53
54    def __init__(self, data):
55        self._domains = []
56        self._domain_names = []
57        self._domain_default = []
58
59        self._build_dir = data.get('build_dir')
60        domain_list = data.get('domains')
61        if not domain_list:
62            logger.warning("no domains defined; this probably won't work")
63
64        for d in domain_list:
65            domain = Domain(d['name'], d['build_dir'])
66            self._domains.append(domain)
67            self._domain_names.append(domain.name)
68            if domain.name == data['default']:
69                self._default_domain = domain
70
71    @staticmethod
72    def from_file(domains_file):
73        '''Load domains from domains.yaml.
74
75        Exception raised:
76           - ``FileNotFoundError`` if the domains file is not found.
77        '''
78        try:
79            with open(domains_file, 'r') as f:
80                domains = yaml.safe_load(f.read())
81        except FileNotFoundError:
82            logger.critical(f'domains.yaml file not found: {domains_file}')
83            exit(1)
84
85        try:
86            pykwalify.core.Core(source_data=domains, schema_data=schema)\
87                .validate()
88        except pykwalify.errors.SchemaError:
89            logger.critical(f'ERROR: Malformed yaml in file: {domains_file}')
90            exit(1)
91
92        return Domains(domains)
93
94    @staticmethod
95    def from_data(domains_data):
96        '''Load domains from domains dictionary.
97        '''
98        return Domains(domains_data)
99
100    def get_domains(self, names=None):
101        ret = []
102
103        if not names:
104            return self._domains
105
106        for n in names:
107            found = False
108            for d in self._domains:
109                if n == d.name:
110                    ret.append(d)
111                    found = True
112                    break
113            # Getting here means the domain was not found.
114            # Todo: throw an error.
115            if not found:
116                logger.critical(f'domain {n} not found, '
117                        f'valid domains are:', *self._domain_names)
118                exit(1)
119        return ret
120
121    def get_default_domain(self):
122        return self._default_domain
123
124    def get_top_build_dir(self):
125        return self._build_dir
126
127
128class Domain:
129
130    def __init__(self, name, build_dir):
131        self.name = name
132        self.build_dir = build_dir
133
134    @property
135    def name(self):
136        return self._name
137
138    @name.setter
139    def name(self, value):
140        self._name = value
141
142    @property
143    def build_dir(self):
144        return self._build_dir
145
146    @build_dir.setter
147    def build_dir(self, value):
148        self._build_dir = value
149