Home | History | Annotate | Download | only in buildman
      1 # SPDX-License-Identifier: GPL-2.0+
      2 # Copyright (c) 2012 The Chromium OS Authors.
      3 
      4 import re
      5 
      6 class 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 
     34 class 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 
     72 class 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 
     99 class 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