From patchwork Sat Jan 10 20:08:17 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1442 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1768075798; bh=9HVk9sDU/aNyjNTBmuV4Yz5Ix0rUWGTCkIes9QhD6wQ=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=GrUDgKDHpqBAqD3k1mTfM2uKXq8k1bThJ9WUlS54A56872mDexi0/65V2L/jzMEMY rXZ/isJ42UWFqpYDiWp50wLRGHxx4lP5K3o+W1euej1C97cnOUbGPThVyjh2BcOVC+ fyxjsxjwAdLmw6F7sfv8N8DXl5u+fZUln8saEU/dZAsk1Nw8CTguEnh4cW2uZ/bGND t8RURCJHyIRdlnBeLdEGEE2ZhrYrAyvzuTj5E2CAPNHpoudqDnZhEGt7cn0WFUMzri cNWg2A4CLNW3whMCguICBkj1J1YcrMOewG4n5uHJnL6YoXpYJ1c3mK3pE2xK6W0S1b g4YXsHVDwsX1A== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 9B05C69281 for ; Sat, 10 Jan 2026 13:09:58 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 76nLM-z3s-HG for ; Sat, 10 Jan 2026 13:09:58 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1768075798; bh=9HVk9sDU/aNyjNTBmuV4Yz5Ix0rUWGTCkIes9QhD6wQ=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=GrUDgKDHpqBAqD3k1mTfM2uKXq8k1bThJ9WUlS54A56872mDexi0/65V2L/jzMEMY rXZ/isJ42UWFqpYDiWp50wLRGHxx4lP5K3o+W1euej1C97cnOUbGPThVyjh2BcOVC+ fyxjsxjwAdLmw6F7sfv8N8DXl5u+fZUln8saEU/dZAsk1Nw8CTguEnh4cW2uZ/bGND t8RURCJHyIRdlnBeLdEGEE2ZhrYrAyvzuTj5E2CAPNHpoudqDnZhEGt7cn0WFUMzri cNWg2A4CLNW3whMCguICBkj1J1YcrMOewG4n5uHJnL6YoXpYJ1c3mK3pE2xK6W0S1b g4YXsHVDwsX1A== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 89B4169275 for ; Sat, 10 Jan 2026 13:09:58 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1768075796; bh=1HVsIO+CyJuozCcGAb1XLHWUshLu3SsrU/AUHdg6PPM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iIVjlmKRSNlvA40yptHCPqRpxbVP0mdrwcYyNfyStD5QS/V4mJJ2hv2PNfayG7Rkw 7mno0G/sH36YyFM3RHIUNdNrMiJvUS10saD8QZg9iVP4maqipijsdR1PE70qCOaBG2 0itJg+zvpjL+xwXlLc9PAZclyHGZYkLB/OYJXXisEnkUD1xzHyjEOj6ZzxhxKmTx0j FPomGX8/WFIPaERcQJuSX65X6YQ+pJ05iOo1y6CjtNDHXpOXBK9AYeHsXxHMBETSOU GFOo+OAKeW5zrHfbiK8j2t6TfEdbMaJ3/TDKg9Ea+WZqm3TPjuD/kKRu+wI4GbTe9H fHtf6cumAIRuQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 7D0EC69275; Sat, 10 Jan 2026 13:09:56 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id PeU36_kzO8EP; Sat, 10 Jan 2026 13:09:56 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1768075791; bh=q6nmpjfHVK0kU0uNVzTjM5XX0LZqs3hqm7clEGL5q8U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ozOlsUslqOJ7ATUJhJe5y4gw+gcvI7T8sIvB+0Y9+/+7C1HOJfQxczA13W2PAl3ok 3P5AWbuPY5cLETEM7nz8UPGLfXHk3V+08EXR7DeGF2hUjaJ70oYVjx8dM0z5VydoCV DdOU8I4AkZjkWj79AeILGiB69xT1uj2NG4muKGU3yco1U5DaxK2joY3GNmn70fJDce zH7qem4LCkufpBGHy1hVVJRYVHgPIK+lW8/Qm2fc1qmL28YXBRWNIJ5MIYlaDXRmIM XzAeNOiXE3z1JS+G+mJhqJvYGBg519wN7oo317PJ5byDPm2HnDGEv4T5cf5dUFwkVW 10dcDpmCBtnxg== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id F047C69221; Sat, 10 Jan 2026 13:09:50 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Sat, 10 Jan 2026 13:08:17 -0700 Message-ID: <20260110200828.168672-15-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260110200828.168672-1-sjg@u-boot.org> References: <20260110200828.168672-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: WROJ2PTBVDJPX7LC5FGB2RTXODJZPTYB X-Message-ID-Hash: WROJ2PTBVDJPX7LC5FGB2RTXODJZPTYB X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , "Claude Opus 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 14/18] buildman: Move result summary methods to ResultHandler List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Move the print_result_summary() method and baseline state management from Builder to ResultHandler. This includes: - Baseline state attributes (_base_board_dict, _base_err_lines, etc.) - reset_result_summary() to initialise baseline state - print_result_summary() to display build result deltas - get_error_lines() to access the error line count Builder now delegates to ResultHandler for result display and baseline tracking. The OUTCOME_* constants are passed as parameters since they remain defined in builder.py. Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- tools/buildman/builder.py | 139 +++------------------------- tools/buildman/resulthandler.py | 154 ++++++++++++++++++++++++++++++-- 2 files changed, 161 insertions(+), 132 deletions(-) diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py index a2d4470b70c..412acfa9e4b 100644 --- a/tools/buildman/builder.py +++ b/tools/buildman/builder.py @@ -305,7 +305,6 @@ class Builder: self._next_delay_update = datetime.now() self._start_time = None self._step = step - self._error_lines = 0 self.no_subdirs = no_subdirs self.full_path = full_path self.verbose_build = verbose_build @@ -364,14 +363,7 @@ class Builder: self._timestamps = None self._verbose = False - # Attributes for result summaries - self._base_board_dict = {} - self._base_err_lines = [] - self._base_warn_lines = [] - self._base_err_line_boards = {} - self._base_warn_line_boards = {} - self._base_config = None - self._base_environment = None + # Note: baseline state for result summaries is now in ResultHandler self._setup_threads(mrproper, per_board_out_dir, test_thread_exceptions) @@ -580,7 +572,7 @@ class Builder: elif self._verbose: terminal.print_clear() boards_selected = {target : result.brd} - self.reset_result_summary(boards_selected) + self._result_handler.reset_result_summary(boards_selected) self.produce_result_summary(result.commit_upto, self.commits, boards_selected) else: @@ -1011,113 +1003,6 @@ class Builder: return (board_dict, err_lines_summary, err_lines_boards, warn_lines_summary, warn_lines_boards, config, environment) - def reset_result_summary(self, board_selected): - """Reset the results summary ready for use. - - Set up the base board list to be all those selected, and set the - error lines to empty. - - Following this, calls to print_result_summary() will use this - information to work out what has changed. - - Args: - board_selected (dict): Dict containing boards to summarise, keyed - by board.target - """ - self._base_board_dict = {} - for brd in board_selected: - self._base_board_dict[brd] = Outcome(0, [], [], {}, {}, {}) - self._base_err_lines = [] - self._base_warn_lines = [] - self._base_err_line_boards = {} - self._base_warn_line_boards = {} - self._base_config = None - self._base_environment = None - - 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, - show_bloat, show_config, show_environment): - """Compare results with the base results and display delta. - - Only boards mentioned in board_selected will be considered. This - function is intended to be called repeatedly with the results of - each commit. It therefore shows a 'diff' between what it saw in - the last call and what it sees now. - - Args: - board_selected (dict): Dict containing boards to summarise, keyed - by board.target - board_dict (dict): Dict containing boards for which we built this - commit, keyed by board.target. The value is an Outcome object. - err_lines (list): A list of errors for this commit, or [] if there - is none, or we don't want to print errors - err_line_boards (dict): Dict keyed by error line, containing a list - of the Board objects with that error - warn_lines (list): A list of warnings for this commit, or [] if - there is none, or we don't want to print errors - warn_line_boards (dict): Dict keyed by warning line, containing a - list of the Board objects with that warning - config (dict): Dictionary keyed by filename - e.g. '.config'. Each - value is itself a dictionary: - key: config name - value: config value - environment (dict): Dictionary keyed by environment variable, Each - value is the value of environment variable. - show_sizes (bool): Show image size deltas - show_detail (bool): Show size delta detail for each board if - show_sizes - show_bloat (bool): Show detail for each function - show_config (bool): Show config changes - show_environment (bool): Show environment changes - """ - brd_status = ResultHandler.classify_boards( - board_selected, board_dict, self._base_board_dict) - - # Get a list of errors and warnings that have appeared, and disappeared - better_err, worse_err = ResultHandler.calc_error_delta( - self._base_err_lines, self._base_err_line_boards, err_lines, - err_line_boards, '', self._opts.list_error_boards) - better_warn, worse_warn = ResultHandler.calc_error_delta( - self._base_warn_lines, self._base_warn_line_boards, warn_lines, - warn_line_boards, 'w', self._opts.list_error_boards) - - # For the IDE mode, print out all the output - if self._opts.ide: - self._result_handler.print_ide_output(board_selected, board_dict) - - # Display results by arch - 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( - board_selected, board_dict, self._base_board_dict, - show_detail, show_bloat) - - if show_environment and self._base_environment: - self._result_handler.show_environment_changes( - board_selected, board_dict, environment, self._base_environment) - - if show_config and self._base_config: - self._result_handler.show_config_changes( - board_selected, board_dict, config, self._base_config, - self.config_filenames) - - - # Save our updated information for the next call to this function - self._base_board_dict = board_dict - self._base_err_lines = err_lines - self._base_warn_lines = warn_lines - self._base_err_line_boards = err_line_boards - self._base_warn_line_boards = warn_line_boards - self._base_config = config - self._base_environment = environment - - ResultHandler.show_not_built(board_selected, board_dict) - def produce_result_summary(self, commit_upto, commits, board_selected): """Produce a summary of the results for a single commit @@ -1135,11 +1020,14 @@ class Builder: if commits: msg = f'{commit_upto + 1:02d}: {commits[commit_upto].subject}' tprint(msg, colour=self.col.BLUE) - self.print_result_summary(board_selected, board_dict, - err_lines if self._opts.show_errors else [], err_line_boards, - warn_lines if self._opts.show_errors else [], warn_line_boards, - config, environment, self._opts.show_sizes, self._opts.show_detail, - self._opts.show_bloat, self._opts.show_config, self._opts.show_environment) + self._result_handler.print_result_summary( + board_selected, board_dict, + err_lines if self._opts.show_errors else [], err_line_boards, + warn_lines if self._opts.show_errors else [], warn_line_boards, + config, environment, self._opts.show_sizes, self._opts.show_detail, + self._opts.show_bloat, self._opts.show_config, self._opts.show_environment, + self._opts.show_unknown, self._opts.ide, self._opts.list_error_boards, + self.config_filenames) def show_summary(self, commits, board_selected): """Show a build summary for U-Boot for a given board list. @@ -1153,12 +1041,11 @@ class Builder: """ self.commit_count = len(commits) if commits else 1 self.commits = commits - self.reset_result_summary(board_selected) - self._error_lines = 0 + self._result_handler.reset_result_summary(board_selected) for commit_upto in range(0, self.commit_count, self._step): self.produce_result_summary(commit_upto, commits, board_selected) - if not self._error_lines: + if not self._result_handler.get_error_lines(): tprint('(no errors to report)', colour=self.col.GREEN) @@ -1328,7 +1215,7 @@ class Builder: self.commits = commits self._verbose = verbose - self.reset_result_summary(board_selected) + self._result_handler.reset_result_summary(board_selected) builderthread.mkdir(self.base_dir, parents = True) self._prepare_working_space(min(self.num_threads, len(board_selected)), commits is not None) diff --git a/tools/buildman/resulthandler.py b/tools/buildman/resulthandler.py index a2064986729..d1d6232ff97 100644 --- a/tools/buildman/resulthandler.py +++ b/tools/buildman/resulthandler.py @@ -8,8 +8,9 @@ import sys -from buildman.outcome import (BoardStatus, ErrLine, OUTCOME_OK, - OUTCOME_WARNING, OUTCOME_ERROR, OUTCOME_UNKNOWN) +from buildman.outcome import (BoardStatus, ErrLine, Outcome, + OUTCOME_OK, OUTCOME_WARNING, OUTCOME_ERROR, + OUTCOME_UNKNOWN) from u_boot_pylib.terminal import tprint @@ -18,10 +19,19 @@ class ResultHandler: This class is responsible for displaying size information from builds, including per-architecture summaries, per-board details, and per-function - bloat analysis. + bloat analysis. It also manages baseline state for comparing results + between commits. Attributes: col: terminal.Color object for coloured output + _base_board_dict: Last-summarised Dict of boards + _base_err_lines: Last-summarised list of errors + _base_warn_lines: Last-summarised list of warnings + _base_err_line_boards: Dict of error lines to boards + _base_warn_line_boards: Dict of warning lines to boards + _base_config: Last-summarised config + _base_environment: Last-summarised environment + _error_lines: Number of error lines output """ def __init__(self, col, opts): @@ -34,6 +44,16 @@ class ResultHandler: self._col = col self._opts = opts self._builder = None + self._error_lines = 0 + + # Baseline state for result comparisons + self._base_board_dict = {} + self._base_err_lines = [] + self._base_warn_lines = [] + self._base_err_line_boards = {} + self._base_warn_line_boards = {} + self._base_config = None + self._base_environment = None def set_builder(self, builder): """Set the builder for this result handler @@ -43,6 +63,128 @@ class ResultHandler: """ self._builder = builder + def reset_result_summary(self, board_selected): + """Reset the results summary ready for use. + + Set up the base board list to be all those selected, and set the + error lines to empty. + + Following this, calls to print_result_summary() will use this + information to work out what has changed. + + Args: + board_selected (dict): Dict containing boards to summarise, keyed + by board.target + """ + outcome_init = Outcome(0, [], [], {}, {}, {}) + self._base_board_dict = {} + for brd in board_selected: + self._base_board_dict[brd] = outcome_init + self._base_err_lines = [] + self._base_warn_lines = [] + self._base_err_line_boards = {} + self._base_warn_line_boards = {} + self._base_config = None + self._base_environment = None + self._error_lines = 0 + + 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, + show_bloat, show_config, show_environment, + show_unknown, ide, list_error_boards, + config_filenames): + """Compare results with the base results and display delta. + + Only boards mentioned in board_selected will be considered. This + function is intended to be called repeatedly with the results of + each commit. It therefore shows a 'diff' between what it saw in + the last call and what it sees now. + + Args: + board_selected (dict): Dict containing boards to summarise, keyed + by board.target + board_dict (dict): Dict containing boards for which we built this + commit, keyed by board.target. The value is an Outcome object. + err_lines (list): A list of errors for this commit, or [] if there + is none, or we don't want to print errors + err_line_boards (dict): Dict keyed by error line, containing a list + of the Board objects with that error + warn_lines (list): A list of warnings for this commit, or [] if + there is none, or we don't want to print errors + warn_line_boards (dict): Dict keyed by warning line, containing a + list of the Board objects with that warning + config (dict): Dictionary keyed by filename - e.g. '.config'. Each + value is itself a dictionary: + key: config name + value: config value + environment (dict): Dictionary keyed by environment variable, Each + value is the value of environment variable. + show_sizes (bool): Show image size deltas + show_detail (bool): Show size delta detail for each board if + show_sizes + show_bloat (bool): Show detail for each function + show_config (bool): Show config changes + show_environment (bool): Show environment changes + show_unknown (bool): Show unknown boards in summary + ide (bool): IDE mode - output to stderr + list_error_boards (bool): Include board list with error lines + config_filenames (list): List of config filenames + """ + brd_status = self.classify_boards( + board_selected, board_dict, self._base_board_dict) + + # Get a list of errors and warnings that have appeared, and disappeared + better_err, worse_err = self.calc_error_delta( + self._base_err_lines, self._base_err_line_boards, err_lines, + err_line_boards, '', list_error_boards) + better_warn, worse_warn = self.calc_error_delta( + self._base_warn_lines, self._base_warn_line_boards, warn_lines, + warn_line_boards, 'w', list_error_boards) + + # For the IDE mode, print out all the output + if ide: + self.print_ide_output(board_selected, board_dict) + + # Display results by arch + if not ide: + self._error_lines += self.display_arch_results( + board_selected, brd_status, better_err, worse_err, better_warn, + worse_warn, show_unknown) + + if show_sizes: + self.print_size_summary( + board_selected, board_dict, self._base_board_dict, + show_detail, show_bloat) + + if show_environment and self._base_environment: + self.show_environment_changes( + board_selected, board_dict, environment, self._base_environment) + + if show_config and self._base_config: + self.show_config_changes( + board_selected, board_dict, config, self._base_config, + config_filenames) + + # Save our updated information for the next call to this function + self._base_board_dict = board_dict + self._base_err_lines = err_lines + self._base_warn_lines = warn_lines + self._base_err_line_boards = err_line_boards + self._base_warn_line_boards = warn_line_boards + self._base_config = config + self._base_environment = environment + + self.show_not_built(board_selected, board_dict) + + def get_error_lines(self): + """Get the number of error lines output + + Returns: + int: Number of error lines output + """ + return self._error_lines + def colour_num(self, num): """Format a number with colour depending on its value @@ -476,11 +618,11 @@ class ResultHandler: continue col = None if line[0] == '+': - col = self.col.GREEN + col = self._col.GREEN elif line[0] == '-': - col = self.col.RED + col = self._col.RED elif line[0] == 'c': - col = self.col.YELLOW + col = self._col.YELLOW tprint(' ' + line, newline=True, colour=col) def show_environment_changes(self, board_selected, board_dict,