diff options
Diffstat (limited to 'tools/buildman/boards.py')
-rw-r--r-- | tools/buildman/boards.py | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/tools/buildman/boards.py b/tools/buildman/boards.py new file mode 100644 index 00000000000..ec143f9e0f5 --- /dev/null +++ b/tools/buildman/boards.py @@ -0,0 +1,290 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2012 The Chromium OS Authors. + +"""Maintains a list of boards and allows them to be selected""" + +from collections import OrderedDict +import re + +from buildman import board + + +class Expr: + """A single regular expression for matching boards to build""" + + def __init__(self, expr): + """Set up a new Expr object. + + Args: + expr: String cotaining regular expression to store + """ + self._expr = expr + self._re = re.compile(expr) + + def matches(self, props): + """Check if any of the properties match the regular expression. + + Args: + props: List of properties to check + Returns: + True if any of the properties match the regular expression + """ + for prop in props: + if self._re.match(prop): + return True + return False + + def __str__(self): + return self._expr + +class Term: + """A list of expressions each of which must match with properties. + + This provides a list of 'AND' expressions, meaning that each must + match the board properties for that board to be built. + """ + def __init__(self): + self._expr_list = [] + self._board_count = 0 + + def add_expr(self, expr): + """Add an Expr object to the list to check. + + Args: + expr: New Expr object to add to the list of those that must + match for a board to be built. + """ + self._expr_list.append(Expr(expr)) + + def __str__(self): + """Return some sort of useful string describing the term""" + return '&'.join([str(expr) for expr in self._expr_list]) + + def matches(self, props): + """Check if any of the properties match this term + + Each of the expressions in the term is checked. All must match. + + Args: + props: List of properties to check + Returns: + True if all of the expressions in the Term match, else False + """ + for expr in self._expr_list: + if not expr.matches(props): + return False + return True + + +class Boards: + """Manage a list of boards.""" + def __init__(self): + # Use a simple list here, sinc OrderedDict requires Python 2.7 + self._boards = [] + + def add_board(self, brd): + """Add a new board to the list. + + The board's target member must not already exist in the board list. + + Args: + brd: board to add + """ + self._boards.append(brd) + + def read_boards(self, fname): + """Read a list of boards from a board file. + + Create a Board object for each and add it to our _boards list. + + Args: + fname: Filename of boards.cfg file + """ + with open(fname, 'r', encoding='utf-8') as inf: + for line in inf: + if line[0] == '#': + continue + fields = line.split() + if not fields: + continue + for upto, field in enumerate(fields): + if field == '-': + fields[upto] = '' + while len(fields) < 8: + fields.append('') + if len(fields) > 8: + fields = fields[:8] + + brd = board.Board(*fields) + self.add_board(brd) + + + def get_list(self): + """Return a list of available boards. + + Returns: + List of Board objects + """ + return self._boards + + def get_dict(self): + """Build a dictionary containing all the boards. + + Returns: + Dictionary: + key is board.target + value is board + """ + board_dict = OrderedDict() + for brd in self._boards: + board_dict[brd.target] = brd + return board_dict + + def get_selected_dict(self): + """Return a dictionary containing the selected boards + + Returns: + List of Board objects that are marked selected + """ + board_dict = OrderedDict() + for brd in self._boards: + if brd.build_it: + board_dict[brd.target] = brd + return board_dict + + def get_selected(self): + """Return a list of selected boards + + Returns: + List of Board objects that are marked selected + """ + return [brd for brd in self._boards if brd.build_it] + + def get_selected_names(self): + """Return a list of selected boards + + Returns: + List of board names that are marked selected + """ + return [brd.target for brd in self._boards if brd.build_it] + + @classmethod + def _build_terms(cls, args): + """Convert command line arguments to a list of terms. + + This deals with parsing of the arguments. It handles the '&' + operator, which joins several expressions into a single Term. + + For example: + ['arm & freescale sandbox', 'tegra'] + + will produce 3 Terms containing expressions as follows: + arm, freescale + sandbox + tegra + + The first Term has two expressions, both of which must match for + a board to be selected. + + Args: + args: List of command line arguments + Returns: + A list of Term objects + """ + syms = [] + for arg in args: + for word in arg.split(): + sym_build = [] + for term in word.split('&'): + if term: + sym_build.append(term) + sym_build.append('&') + syms += sym_build[:-1] + terms = [] + term = None + oper = None + for sym in syms: + if sym == '&': + oper = sym + elif oper: + term.add_expr(sym) + oper = None + else: + if term: + terms.append(term) + term = Term() + term.add_expr(sym) + if term: + terms.append(term) + return terms + + def select_boards(self, args, exclude=None, brds=None): + """Mark boards selected based on args + + Normally either boards (an explicit list of boards) or args (a list of + terms to match against) is used. It is possible to specify both, in + which case they are additive. + + If brds and args are both empty, all boards are selected. + + Args: + args: List of strings specifying boards to include, either named, + or by their target, architecture, cpu, vendor or soc. If + empty, all boards are selected. + exclude: List of boards to exclude, regardless of 'args' + brds: List of boards to build + + Returns: + Tuple + Dictionary which holds the list of boards which were selected + due to each argument, arranged by argument. + List of errors found + """ + result = OrderedDict() + warnings = [] + terms = self._build_terms(args) + + result['all'] = [] + for term in terms: + result[str(term)] = [] + + exclude_list = [] + if exclude: + for expr in exclude: + exclude_list.append(Expr(expr)) + + found = [] + for brd in self._boards: + matching_term = None + build_it = False + if terms: + for term in terms: + if term.matches(brd.props): + matching_term = str(term) + build_it = True + break + elif brds: + if brd.target in brds: + build_it = True + found.append(brd.target) + else: + build_it = True + + # Check that it is not specifically excluded + for expr in exclude_list: + if expr.matches(brd.props): + build_it = False + break + + if build_it: + brd.build_it = True + if matching_term: + result[matching_term].append(brd.target) + result['all'].append(brd.target) + + if brds: + remaining = set(brds) - set(found) + if remaining: + warnings.append(f"Boards not found: {', '.join(remaining)}\n") + + return result, warnings |