blob: 272bac0c21c47a5678240cc980006ae118f22228 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glassfc3fe1c2013-04-03 11:07:16 +00002# Copyright (c) 2012 The Chromium OS Authors.
Simon Glassfc3fe1c2013-04-03 11:07:16 +00003
Stephen Warren8426d8b2013-10-10 10:00:20 -06004import re
5
Simon Glass6131bea2014-08-09 15:33:08 -06006class 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
Simon Glassfc3fe1c2013-04-03 11:07:16 +000072class Board:
73 """A particular board that we can build"""
Andreas Bießmann03c1bb22013-09-19 10:08:45 +020074 def __init__(self, status, arch, cpu, soc, vendor, board_name, target, options):
Simon Glassfc3fe1c2013-04-03 11:07:16 +000075 """Create a new board type.
76
77 Args:
Andreas Bießmann03c1bb22013-09-19 10:08:45 +020078 status: define whether the board is 'Active' or 'Orphaned'
Simon Glassfc3fe1c2013-04-03 11:07:16 +000079 arch: Architecture name (e.g. arm)
80 cpu: Cpu name (e.g. arm1136)
Simon Glassfc3fe1c2013-04-03 11:07:16 +000081 soc: Name of SOC, or '' if none (e.g. mx31)
Andreas Bießmann03c1bb22013-09-19 10:08:45 +020082 vendor: Name of vendor (e.g. armltd)
83 board_name: Name of board (e.g. integrator)
Masahiro Yamada73f30b92014-07-30 14:08:22 +090084 target: Target name (use make <target>_defconfig to configure)
Simon Glassfc3fe1c2013-04-03 11:07:16 +000085 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
Simon Glassfc3fe1c2013-04-03 11:07:16 +000093 self.options = options
Tom Rinie0f24062016-11-04 22:59:45 -040094 self.props = [self.target, self.arch, self.cpu, self.board_name,
95 self.vendor, self.soc, self.options]
Simon Glassfc3fe1c2013-04-03 11:07:16 +000096 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] = ''
Andreas Bießmann03c1bb22013-09-19 10:08:45 +0200133 while len(fields) < 8:
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000134 fields.append('')
Andreas Bießmann03c1bb22013-09-19 10:08:45 +0200135 if len(fields) > 8:
136 fields = fields[:8]
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000137
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
Simon Glass6131bea2014-08-09 15:33:08 -0600191 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
Simon Glass3cf4ae62014-08-28 09:43:41 -0600240 def SelectBoards(self, args, exclude=[]):
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000241 """Mark boards selected based on args
242
243 Args:
Simon Glass3cf4ae62014-08-28 09:43:41 -0600244 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'
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000248
249 Returns:
Simon Glass8d7523c2017-01-23 05:38:56 -0700250 Dictionary which holds the list of boards which were selected
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000251 due to each argument, arranged by argument.
252 """
253 result = {}
Simon Glass6131bea2014-08-09 15:33:08 -0600254 terms = self._BuildTerms(args)
255
Simon Glass8d7523c2017-01-23 05:38:56 -0700256 result['all'] = []
Simon Glass6131bea2014-08-09 15:33:08 -0600257 for term in terms:
Simon Glass8d7523c2017-01-23 05:38:56 -0700258 result[str(term)] = []
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000259
Simon Glass3cf4ae62014-08-28 09:43:41 -0600260 exclude_list = []
261 for expr in exclude:
262 exclude_list.append(Expr(expr))
263
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000264 for board in self._boards:
Simon Glass3cf4ae62014-08-28 09:43:41 -0600265 matching_term = None
266 build_it = False
Simon Glass6131bea2014-08-09 15:33:08 -0600267 if terms:
268 match = False
269 for term in terms:
270 if term.Matches(board.props):
Simon Glass3cf4ae62014-08-28 09:43:41 -0600271 matching_term = str(term)
272 build_it = True
Simon Glass6131bea2014-08-09 15:33:08 -0600273 break
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000274 else:
Simon Glass3cf4ae62014-08-28 09:43:41 -0600275 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:
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000284 board.build_it = True
Simon Glass3cf4ae62014-08-28 09:43:41 -0600285 if matching_term:
Simon Glass8d7523c2017-01-23 05:38:56 -0700286 result[matching_term].append(board.target)
287 result['all'].append(board.target)
Simon Glassfc3fe1c2013-04-03 11:07:16 +0000288
289 return result