[Concept,11/18] buildman: Move error/warning display methods to ResultHandler

Message ID 20260110200828.168672-12-sjg@u-boot.org
State New
Headers
Series buildman: Split up the enormous Builder class |

Commit Message

Simon Glass Jan. 10, 2026, 8:08 p.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Continue extracting display methods from builder.py to ResultHandler.
Move the error and warning display methods:

- add_outcome(): Format board status by architecture
- output_err_lines(): Display formatted error/warning lines
- display_arch_results(): Show board status by architecture
- print_ide_output(): Output errors to stderr for IDE

The methods now return an error line count instead of updating a
Builder attribute directly, making them more pure and testable.

Update print_result_summary() to use the ResultHandler methods and track
the error_lines counter locally.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 tools/buildman/builder.py       | 120 ++------------------------------
 tools/buildman/resulthandler.py | 118 +++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 114 deletions(-)
  

Patch

diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py
index 4b6106b881b..4d3b96ab1a0 100644
--- a/tools/buildman/builder.py
+++ b/tools/buildman/builder.py
@@ -1011,36 +1011,6 @@  class Builder:
         return (board_dict, err_lines_summary, err_lines_boards,
                 warn_lines_summary, warn_lines_boards, config, environment)
 
-    def add_outcome(self, board_dict, arch_list, changes, char, color):
-        """Add an output to our list of outcomes for each architecture
-
-        This simple function adds failing boards (changes) to the
-        relevant architecture string, so we can print the results out
-        sorted by architecture.
-
-        Args:
-             board_dict (dict): Dict containing all boards
-             arch_list (dict): Dict keyed by arch name. Value is a string
-                 containing a list of board names which failed for that arch.
-             changes (list): List of boards to add to arch_list
-             char (str): Character to display for this board
-             color (int): terminal.Colour object
-        """
-        done_arch = {}
-        for target in changes:
-            if target in board_dict:
-                arch = board_dict[target].arch
-            else:
-                arch = 'unknown'
-            text = self.col.build(color, ' ' + target)
-            if arch not in done_arch:
-                text = f' {self.col.build(color, char)}  {text}'
-                done_arch[arch] = True
-            if arch not in arch_list:
-                arch_list[arch] = text
-            else:
-                arch_list[arch] += text
-
     def reset_result_summary(self, board_selected):
         """Reset the results summary ready for use.
 
@@ -1347,87 +1317,6 @@  class Builder:
             tprint(f"{' '.join(sorted(targets))} :")
             self._output_config_info(lines.split('\n'))
 
-    def _output_err_lines(self, err_lines, colour):
-        """Output the line of error/warning lines, if not empty
-
-        Also increments self._error_lines if err_lines not empty
-
-        Args:
-            err_lines: List of ErrLine objects, each an error or warning
-                line, possibly including a list of boards with that
-                error/warning
-            colour: Colour to use for output
-        """
-        if err_lines:
-            out_list = []
-            for line in err_lines:
-                names = [brd.target for brd in line.brds]
-                board_str = ' '.join(names) if names else ''
-                if board_str:
-                    out = self.col.build(colour, line.char + '(')
-                    out += self.col.build(self.col.MAGENTA, board_str,
-                                          bright=False)
-                    out += self.col.build(colour, f') {line.errline}')
-                else:
-                    out = self.col.build(colour, line.char + line.errline)
-                out_list.append(out)
-            tprint('\n'.join(out_list))
-            self._error_lines += 1
-
-    def _display_arch_results(self, board_selected, brd_status, better_err,
-                              worse_err, better_warn, worse_warn):
-        """Display results by architecture
-
-        Args:
-            board_selected (dict): Dict containing boards to summarise
-            brd_status (BoardStatus): Named tuple with board classifications
-            better_err: List of ErrLine for fixed errors
-            worse_err: List of ErrLine for new errors
-            better_warn: List of ErrLine for fixed warnings
-            worse_warn: List of ErrLine for new warnings
-        """
-        if self._opts.ide:
-            return
-        if not any((brd_status.ok, brd_status.warn, brd_status.err,
-                    brd_status.unknown, brd_status.new, worse_err, better_err,
-                    worse_warn, better_warn)):
-            return
-        arch_list = {}
-        self.add_outcome(board_selected, arch_list, brd_status.ok, '',
-                         self.col.GREEN)
-        self.add_outcome(board_selected, arch_list, brd_status.warn, 'w+',
-                         self.col.YELLOW)
-        self.add_outcome(board_selected, arch_list, brd_status.err, '+',
-                         self.col.RED)
-        self.add_outcome(board_selected, arch_list, brd_status.new, '*',
-                         self.col.BLUE)
-        if self._opts.show_unknown:
-            self.add_outcome(board_selected, arch_list, brd_status.unknown,
-                             '?', self.col.MAGENTA)
-        for arch, target_list in arch_list.items():
-            tprint(f'{arch:>10s}: {target_list}')
-            self._error_lines += 1
-        self._output_err_lines(better_err, colour=self.col.GREEN)
-        self._output_err_lines(worse_err, colour=self.col.RED)
-        self._output_err_lines(better_warn, colour=self.col.CYAN)
-        self._output_err_lines(worse_warn, colour=self.col.YELLOW)
-
-    def _print_ide_output(self, board_selected, board_dict):
-        """Print output for IDE mode
-
-        Args:
-            board_selected (dict): Dict of selected boards, keyed by target
-            board_dict (dict): Dict of boards that were built, keyed by target
-        """
-        if not self._opts.ide:
-            return
-        for target in board_dict:
-            if target not in board_selected:
-                continue
-            outcome = board_dict[target]
-            for line in outcome.err_lines:
-                sys.stderr.write(line)
-
     def print_result_summary(self, board_selected, board_dict, err_lines,
                            err_line_boards, warn_lines, warn_line_boards,
                            config, environment, show_sizes, show_detail,
@@ -1527,11 +1416,14 @@  class Builder:
                 self._base_warn_line_boards, warn_lines, warn_line_boards, 'w')
 
         # For the IDE mode, print out all the output
-        self._print_ide_output(board_selected, board_dict)
+        if self._opts.ide:
+            self._result_handler.print_ide_output(board_selected, board_dict)
 
         # Display results by arch
-        self._display_arch_results(board_selected, brd_status, better_err,
-                                   worse_err, better_warn, worse_warn)
+        if not self._opts.ide:
+            self._error_lines += self._result_handler.display_arch_results(
+                board_selected, brd_status, better_err, worse_err, better_warn,
+                worse_warn, self._opts.show_unknown)
 
         if show_sizes:
             self._result_handler.print_size_summary(
diff --git a/tools/buildman/resulthandler.py b/tools/buildman/resulthandler.py
index 4c9b3c2f9cc..56973d801bb 100644
--- a/tools/buildman/resulthandler.py
+++ b/tools/buildman/resulthandler.py
@@ -6,6 +6,8 @@ 
 
 """Result writer for buildman build results"""
 
+import sys
+
 from u_boot_pylib.terminal import tprint
 
 
@@ -301,3 +303,119 @@  class ResultHandler:
             if show_detail:
                 self.print_size_detail(target_list, base_board_dict, board_dict,
                                        show_bloat)
+
+    def add_outcome(self, board_dict, arch_list, changes, char, color):
+        """Add an output to our list of outcomes for each architecture
+
+        This simple function adds failing boards (changes) to the
+        relevant architecture string, so we can print the results out
+        sorted by architecture.
+
+        Args:
+             board_dict (dict): Dict containing all boards
+             arch_list (dict): Dict keyed by arch name. Value is a string
+                 containing a list of board names which failed for that arch.
+             changes (list): List of boards to add to arch_list
+             char (str): Character to display for this board
+             color (int): terminal.Colour object
+        """
+        done_arch = {}
+        for target in changes:
+            if target in board_dict:
+                arch = board_dict[target].arch
+            else:
+                arch = 'unknown'
+            text = self._col.build(color, ' ' + target)
+            if arch not in done_arch:
+                text = f' {self._col.build(color, char)}  {text}'
+                done_arch[arch] = True
+            if arch not in arch_list:
+                arch_list[arch] = text
+            else:
+                arch_list[arch] += text
+
+    def output_err_lines(self, err_lines, colour):
+        """Output the line of error/warning lines, if not empty
+
+        Args:
+            err_lines: List of ErrLine objects, each an error or warning
+                line, possibly including a list of boards with that
+                error/warning
+            colour: Colour to use for output
+
+        Returns:
+            int: 1 if any lines were output, 0 otherwise
+        """
+        if err_lines:
+            out_list = []
+            for line in err_lines:
+                names = [brd.target for brd in line.brds]
+                board_str = ' '.join(names) if names else ''
+                if board_str:
+                    out = self._col.build(colour, line.char + '(')
+                    out += self._col.build(self._col.MAGENTA, board_str,
+                                          bright=False)
+                    out += self._col.build(colour, f') {line.errline}')
+                else:
+                    out = self._col.build(colour, line.char + line.errline)
+                out_list.append(out)
+            tprint('\n'.join(out_list))
+            return 1
+        return 0
+
+    def display_arch_results(self, board_selected, brd_status, better_err,
+                             worse_err, better_warn, worse_warn, show_unknown):
+        """Display results by architecture
+
+        Args:
+            board_selected (dict): Dict containing boards to summarise
+            brd_status (BoardStatus): Named tuple with board classifications
+            better_err: List of ErrLine for fixed errors
+            worse_err: List of ErrLine for new errors
+            better_warn: List of ErrLine for fixed warnings
+            worse_warn: List of ErrLine for new warnings
+            show_unknown (bool): Whether to show unknown boards
+
+        Returns:
+            int: Number of error lines output
+        """
+        error_lines = 0
+        if not any((brd_status.ok, brd_status.warn, brd_status.err,
+                    brd_status.unknown, brd_status.new, worse_err, better_err,
+                    worse_warn, better_warn)):
+            return error_lines
+        arch_list = {}
+        self.add_outcome(board_selected, arch_list, brd_status.ok, '',
+                         self._col.GREEN)
+        self.add_outcome(board_selected, arch_list, brd_status.warn, 'w+',
+                         self._col.YELLOW)
+        self.add_outcome(board_selected, arch_list, brd_status.err, '+',
+                         self._col.RED)
+        self.add_outcome(board_selected, arch_list, brd_status.new, '*',
+                         self._col.BLUE)
+        if show_unknown:
+            self.add_outcome(board_selected, arch_list, brd_status.unknown,
+                             '?', self._col.MAGENTA)
+        for arch, target_list in arch_list.items():
+            tprint(f'{arch:>10s}: {target_list}')
+            error_lines += 1
+        error_lines += self.output_err_lines(better_err, colour=self._col.GREEN)
+        error_lines += self.output_err_lines(worse_err, colour=self._col.RED)
+        error_lines += self.output_err_lines(better_warn, colour=self._col.CYAN)
+        error_lines += self.output_err_lines(worse_warn, colour=self._col.YELLOW)
+        return error_lines
+
+    @staticmethod
+    def print_ide_output(board_selected, board_dict):
+        """Print output for IDE mode
+
+        Args:
+            board_selected (dict): Dict of selected boards, keyed by target
+            board_dict (dict): Dict of boards that were built, keyed by target
+        """
+        for target in board_dict:
+            if target not in board_selected:
+                continue
+            outcome = board_dict[target]
+            for line in outcome.err_lines:
+                sys.stderr.write(line)