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