xref: /openbmc/u-boot/tools/buildman/board.py (revision 78a88f79)
1# SPDX-License-Identifier: GPL-2.0+
2# Copyright (c) 2012 The Chromium OS Authors.
3
4import re
5
6class Expr:
7    """A single regular expression for matching boards to build"""
8
9    def __init__(self, expr):
10        """Set up a new Expr object.
11
12        Args:
13            expr: String cotaining regular expression to store
14        """
15        self._expr = expr
16        self._re = re.compile(expr)
17
18    def Matches(self, props):
19        """Check if any of the properties match the regular expression.
20
21        Args:
22           props: List of properties to check
23        Returns:
24           True if any of the properties match the regular expression
25        """
26        for prop in props:
27            if self._re.match(prop):
28                return True
29        return False
30
31    def __str__(self):
32        return self._expr
33
34class Term:
35    """A list of expressions each of which must match with properties.
36
37    This provides a list of 'AND' expressions, meaning that each must
38    match the board properties for that board to be built.
39    """
40    def __init__(self):
41        self._expr_list = []
42        self._board_count = 0
43
44    def AddExpr(self, expr):
45        """Add an Expr object to the list to check.
46
47        Args:
48            expr: New Expr object to add to the list of those that must
49                  match for a board to be built.
50        """
51        self._expr_list.append(Expr(expr))
52
53    def __str__(self):
54        """Return some sort of useful string describing the term"""
55        return '&'.join([str(expr) for expr in self._expr_list])
56
57    def Matches(self, props):
58        """Check if any of the properties match this term
59
60        Each of the expressions in the term is checked. All must match.
61
62        Args:
63           props: List of properties to check
64        Returns:
65           True if all of the expressions in the Term match, else False
66        """
67        for expr in self._expr_list:
68            if not expr.Matches(props):
69                return False
70        return True
71
72class Board:
73    """A particular board that we can build"""
74    def __init__(self, status, arch, cpu, soc, vendor, board_name, target, options):
75        """Create a new board type.
76
77        Args:
78            status: define whether the board is 'Active' or 'Orphaned'
79            arch: Architecture name (e.g. arm)
80            cpu: Cpu name (e.g. arm1136)
81            soc: Name of SOC, or '' if none (e.g. mx31)
82            vendor: Name of vendor (e.g. armltd)
83            board_name: Name of board (e.g. integrator)
84            target: Target name (use make <target>_defconfig to configure)
85            options: board-specific options (e.g. integratorcp:CM1136)
86        """
87        self.target = target
88        self.arch = arch
89        self.cpu = cpu
90        self.board_name = board_name
91        self.vendor = vendor
92        self.soc = soc
93        self.options = options
94        self.props = [self.target, self.arch, self.cpu, self.board_name,
95                      self.vendor, self.soc, self.options]
96        self.build_it = False
97
98
99class Boards:
100    """Manage a list of boards."""
101    def __init__(self):
102        # Use a simple list here, sinc OrderedDict requires Python 2.7
103        self._boards = []
104
105    def AddBoard(self, board):
106        """Add a new board to the list.
107
108        The board's target member must not already exist in the board list.
109
110        Args:
111            board: board to add
112        """
113        self._boards.append(board)
114
115    def ReadBoards(self, fname):
116        """Read a list of boards from a board file.
117
118        Create a board object for each and add it to our _boards list.
119
120        Args:
121            fname: Filename of boards.cfg file
122        """
123        with open(fname, 'r') as fd:
124            for line in fd:
125                if line[0] == '#':
126                    continue
127                fields = line.split()
128                if not fields:
129                    continue
130                for upto in range(len(fields)):
131                    if fields[upto] == '-':
132                        fields[upto] = ''
133                while len(fields) < 8:
134                    fields.append('')
135                if len(fields) > 8:
136                    fields = fields[:8]
137
138                board = Board(*fields)
139                self.AddBoard(board)
140
141
142    def GetList(self):
143        """Return a list of available boards.
144
145        Returns:
146            List of Board objects
147        """
148        return self._boards
149
150    def GetDict(self):
151        """Build a dictionary containing all the boards.
152
153        Returns:
154            Dictionary:
155                key is board.target
156                value is board
157        """
158        board_dict = {}
159        for board in self._boards:
160            board_dict[board.target] = board
161        return board_dict
162
163    def GetSelectedDict(self):
164        """Return a dictionary containing the selected boards
165
166        Returns:
167            List of Board objects that are marked selected
168        """
169        board_dict = {}
170        for board in self._boards:
171            if board.build_it:
172                board_dict[board.target] = board
173        return board_dict
174
175    def GetSelected(self):
176        """Return a list of selected boards
177
178        Returns:
179            List of Board objects that are marked selected
180        """
181        return [board for board in self._boards if board.build_it]
182
183    def GetSelectedNames(self):
184        """Return a list of selected boards
185
186        Returns:
187            List of board names that are marked selected
188        """
189        return [board.target for board in self._boards if board.build_it]
190
191    def _BuildTerms(self, args):
192        """Convert command line arguments to a list of terms.
193
194        This deals with parsing of the arguments. It handles the '&'
195        operator, which joins several expressions into a single Term.
196
197        For example:
198            ['arm & freescale sandbox', 'tegra']
199
200        will produce 3 Terms containing expressions as follows:
201            arm, freescale
202            sandbox
203            tegra
204
205        The first Term has two expressions, both of which must match for
206        a board to be selected.
207
208        Args:
209            args: List of command line arguments
210        Returns:
211            A list of Term objects
212        """
213        syms = []
214        for arg in args:
215            for word in arg.split():
216                sym_build = []
217                for term in word.split('&'):
218                    if term:
219                        sym_build.append(term)
220                    sym_build.append('&')
221                syms += sym_build[:-1]
222        terms = []
223        term = None
224        oper = None
225        for sym in syms:
226            if sym == '&':
227                oper = sym
228            elif oper:
229                term.AddExpr(sym)
230                oper = None
231            else:
232                if term:
233                    terms.append(term)
234                term = Term()
235                term.AddExpr(sym)
236        if term:
237            terms.append(term)
238        return terms
239
240    def SelectBoards(self, args, exclude=[]):
241        """Mark boards selected based on args
242
243        Args:
244            args: List of strings specifying boards to include, either named,
245                  or by their target, architecture, cpu, vendor or soc. If
246                  empty, all boards are selected.
247            exclude: List of boards to exclude, regardless of 'args'
248
249        Returns:
250            Dictionary which holds the list of boards which were selected
251            due to each argument, arranged by argument.
252        """
253        result = {}
254        terms = self._BuildTerms(args)
255
256        result['all'] = []
257        for term in terms:
258            result[str(term)] = []
259
260        exclude_list = []
261        for expr in exclude:
262            exclude_list.append(Expr(expr))
263
264        for board in self._boards:
265            matching_term = None
266            build_it = False
267            if terms:
268                match = False
269                for term in terms:
270                    if term.Matches(board.props):
271                        matching_term = str(term)
272                        build_it = True
273                        break
274            else:
275                build_it = True
276
277            # Check that it is not specifically excluded
278            for expr in exclude_list:
279                if expr.Matches(board.props):
280                    build_it = False
281                    break
282
283            if build_it:
284                board.build_it = True
285                if matching_term:
286                    result[matching_term].append(board.target)
287                result['all'].append(board.target)
288
289        return result
290