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