[PATCH 09/19] buildman: Split out Boards into its own file
Simon Glass
sjg at chromium.org
Tue Jul 12 03:04:03 CEST 2022
Use a separate file for the Boards class so that its name matches the
module name.
Fix up the function names to match the pylint style and fix some other
warnings.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
tools/buildman/board.py | 281 +---------------------------------
tools/buildman/boards.py | 290 ++++++++++++++++++++++++++++++++++++
tools/buildman/control.py | 4 +-
tools/buildman/func_test.py | 11 +-
tools/buildman/test.py | 3 +-
5 files changed, 301 insertions(+), 288 deletions(-)
create mode 100644 tools/buildman/boards.py
diff --git a/tools/buildman/board.py b/tools/buildman/board.py
index ebb9d6f67dc..3268b39e356 100644
--- a/tools/buildman/board.py
+++ b/tools/buildman/board.py
@@ -1,74 +1,8 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2012 The Chromium OS Authors.
-from collections import OrderedDict
-import re
-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
+"""A single board which can be selected and built"""
class Board:
"""A particular board that we can build"""
@@ -95,216 +29,3 @@ class Board:
self.props = [self.target, self.arch, self.cpu, self.board_name,
self.vendor, self.soc, self.options]
self.build_it = False
-
-
-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 fd:
- for line in fd:
- if line[0] == '#':
- continue
- fields = line.split()
- if not fields:
- continue
- for upto in range(len(fields)):
- if fields[upto] == '-':
- fields[upto] = ''
- while len(fields) < 8:
- fields.append('')
- if len(fields) > 8:
- fields = fields[:8]
-
- brd = 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]
-
- def _build_terms(self, 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=[], 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 = []
- for expr in exclude:
- exclude_list.append(Expr(expr))
-
- found = []
- for brd in self._boards:
- matching_term = None
- build_it = False
- if terms:
- match = False
- 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('Boards not found: %s\n' % ', '.join(remaining))
-
- return result, warnings
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
diff --git a/tools/buildman/control.py b/tools/buildman/control.py
index a5c1c2e51c6..8d3e781d51a 100644
--- a/tools/buildman/control.py
+++ b/tools/buildman/control.py
@@ -8,7 +8,7 @@ import shutil
import subprocess
import sys
-from buildman import board
+from buildman import boards
from buildman import bsettings
from buildman import cfgutil
from buildman import toolchain
@@ -197,7 +197,7 @@ def DoBuildman(options, args, toolchains=None, make_func=None, brds=None,
if status != 0:
sys.exit("Failed to generate boards.cfg")
- brds = board.Boards()
+ brds = boards.Boards()
brds.read_boards(board_file)
exclude = []
diff --git a/tools/buildman/func_test.py b/tools/buildman/func_test.py
index 6806ea7fbe6..f12e9966349 100644
--- a/tools/buildman/func_test.py
+++ b/tools/buildman/func_test.py
@@ -9,6 +9,7 @@ import tempfile
import unittest
from buildman import board
+from buildman import boards
from buildman import bsettings
from buildman import cmdline
from buildman import control
@@ -187,7 +188,7 @@ class TestFunctional(unittest.TestCase):
self.setupToolchains()
self._toolchains.Add('arm-gcc', test=False)
self._toolchains.Add('powerpc-gcc', test=False)
- self._boards = board.Boards()
+ self._boards = boards.Boards()
for brd in BOARDS:
self._boards.add_board(board.Board(*brd))
@@ -442,7 +443,7 @@ class TestFunctional(unittest.TestCase):
def testNoBoards(self):
"""Test that buildman aborts when there are no boards"""
- self._boards = board.Boards()
+ self._boards = boards.Boards()
with self.assertRaises(SystemExit):
self._RunControl()
@@ -580,7 +581,7 @@ class TestFunctional(unittest.TestCase):
def testWorkInOutput(self):
"""Test the -w option which should write directly to the output dir"""
- board_list = board.Boards()
+ board_list = boards.Boards()
board_list.add_board(board.Board(*BOARDS[0]))
self._RunControl('-o', self._output_dir, '-w', clean_dir=False,
brds=board_list)
@@ -599,14 +600,14 @@ class TestFunctional(unittest.TestCase):
self.assertFalse(
os.path.exists(os.path.join(self._output_dir, 'u-boot')))
- board_list = board.Boards()
+ board_list = boards.Boards()
board_list.add_board(board.Board(*BOARDS[0]))
with self.assertRaises(SystemExit) as e:
self._RunControl('-b', self._test_branch, '-o', self._output_dir,
'-w', clean_dir=False, brds=board_list)
self.assertIn("single commit", str(e.exception))
- board_list = board.Boards()
+ board_list = boards.Boards()
board_list.add_board(board.Board(*BOARDS[0]))
with self.assertRaises(SystemExit) as e:
self._RunControl('-w', clean_dir=False)
diff --git a/tools/buildman/test.py b/tools/buildman/test.py
index d7306fb4dfa..daf5467503e 100644
--- a/tools/buildman/test.py
+++ b/tools/buildman/test.py
@@ -10,6 +10,7 @@ import time
import unittest
from buildman import board
+from buildman import boards
from buildman import bsettings
from buildman import builder
from buildman import cfgutil
@@ -131,7 +132,7 @@ class TestBuild(unittest.TestCase):
self.commits.append(comm)
# Set up boards to build
- self.brds = board.Boards()
+ self.brds = boards.Boards()
for brd in BOARDS:
self.brds.add_board(board.Board(*brd))
self.brds.select_boards([])
--
2.37.0.144.g8ac04bfd2-goog
More information about the U-Boot
mailing list