blob: f842d3a1fa1e927cc3cb8a1754f557cee87e90b6 [file] [log] [blame]
Simon Glassc05694f2013-04-03 11:07:16 +00001# Copyright (c) 2012 The Chromium OS Authors.
2#
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02003# SPDX-License-Identifier: GPL-2.0+
Simon Glassc05694f2013-04-03 11:07:16 +00004#
5
Stephen Warren08447632013-10-10 10:00:20 -06006import re
7
Simon Glassaa40f9a2014-08-09 15:33:08 -06008class 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
Simon Glassc05694f2013-04-03 11:07:16 +000074class Board:
75 """A particular board that we can build"""
Andreas Bießmannb66a1292013-09-19 10:08:45 +020076 def __init__(self, status, arch, cpu, soc, vendor, board_name, target, options):
Simon Glassc05694f2013-04-03 11:07:16 +000077 """Create a new board type.
78
79 Args:
Andreas Bießmannb66a1292013-09-19 10:08:45 +020080 status: define whether the board is 'Active' or 'Orphaned'
Simon Glassc05694f2013-04-03 11:07:16 +000081 arch: Architecture name (e.g. arm)
82 cpu: Cpu name (e.g. arm1136)
Simon Glassc05694f2013-04-03 11:07:16 +000083 soc: Name of SOC, or '' if none (e.g. mx31)
Andreas Bießmannb66a1292013-09-19 10:08:45 +020084 vendor: Name of vendor (e.g. armltd)
85 board_name: Name of board (e.g. integrator)
Masahiro Yamadae9bc8d22014-07-30 14:08:22 +090086 target: Target name (use make <target>_defconfig to configure)
Simon Glassc05694f2013-04-03 11:07:16 +000087 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
Simon Glassc05694f2013-04-03 11:07:16 +000095 self.options = options
Tom Rinib7876c82016-11-04 22:59:45 -040096 self.props = [self.target, self.arch, self.cpu, self.board_name,
97 self.vendor, self.soc, self.options]
Simon Glassc05694f2013-04-03 11:07:16 +000098 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] = ''
Andreas Bießmannb66a1292013-09-19 10:08:45 +0200135 while len(fields) < 8:
Simon Glassc05694f2013-04-03 11:07:16 +0000136 fields.append('')
Andreas Bießmannb66a1292013-09-19 10:08:45 +0200137 if len(fields) > 8:
138 fields = fields[:8]
Simon Glassc05694f2013-04-03 11:07:16 +0000139
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
Simon Glassaa40f9a2014-08-09 15:33:08 -0600193 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
Simon Glass924c73a2014-08-28 09:43:41 -0600242 def SelectBoards(self, args, exclude=[]):
Simon Glassc05694f2013-04-03 11:07:16 +0000243 """Mark boards selected based on args
244
245 Args:
Simon Glass924c73a2014-08-28 09:43:41 -0600246 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'
Simon Glassc05694f2013-04-03 11:07:16 +0000250
251 Returns:
Simon Glass6af145f2017-01-23 05:38:56 -0700252 Dictionary which holds the list of boards which were selected
Simon Glassc05694f2013-04-03 11:07:16 +0000253 due to each argument, arranged by argument.
254 """
255 result = {}
Simon Glassaa40f9a2014-08-09 15:33:08 -0600256 terms = self._BuildTerms(args)
257
Simon Glass6af145f2017-01-23 05:38:56 -0700258 result['all'] = []
Simon Glassaa40f9a2014-08-09 15:33:08 -0600259 for term in terms:
Simon Glass6af145f2017-01-23 05:38:56 -0700260 result[str(term)] = []
Simon Glassc05694f2013-04-03 11:07:16 +0000261
Simon Glass924c73a2014-08-28 09:43:41 -0600262 exclude_list = []
263 for expr in exclude:
264 exclude_list.append(Expr(expr))
265
Simon Glassc05694f2013-04-03 11:07:16 +0000266 for board in self._boards:
Simon Glass924c73a2014-08-28 09:43:41 -0600267 matching_term = None
268 build_it = False
Simon Glassaa40f9a2014-08-09 15:33:08 -0600269 if terms:
270 match = False
271 for term in terms:
272 if term.Matches(board.props):
Simon Glass924c73a2014-08-28 09:43:41 -0600273 matching_term = str(term)
274 build_it = True
Simon Glassaa40f9a2014-08-09 15:33:08 -0600275 break
Simon Glassc05694f2013-04-03 11:07:16 +0000276 else:
Simon Glass924c73a2014-08-28 09:43:41 -0600277 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:
Simon Glassc05694f2013-04-03 11:07:16 +0000286 board.build_it = True
Simon Glass924c73a2014-08-28 09:43:41 -0600287 if matching_term:
Simon Glass6af145f2017-01-23 05:38:56 -0700288 result[matching_term].append(board.target)
289 result['all'].append(board.target)
Simon Glassc05694f2013-04-03 11:07:16 +0000290
291 return result