mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 12:08:19 +00:00 
			
		
		
		
	This can take a while, so show a message when starting. Signed-off-by: Simon Glass <sjg@chromium.org> Reported-by Tom Rini <trini@konsulko.com>
		
			
				
	
	
		
			681 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			681 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # SPDX-License-Identifier: GPL-2.0+
 | |
| # Copyright (c) 2013 The Chromium OS Authors.
 | |
| #
 | |
| 
 | |
| """Control module for buildman
 | |
| 
 | |
| This holds the main control logic for buildman, when not running tests.
 | |
| """
 | |
| 
 | |
| import multiprocessing
 | |
| import os
 | |
| import shutil
 | |
| import sys
 | |
| 
 | |
| from buildman import boards
 | |
| from buildman import bsettings
 | |
| from buildman import cfgutil
 | |
| from buildman import toolchain
 | |
| from buildman.builder import Builder
 | |
| from patman import gitutil
 | |
| from patman import patchstream
 | |
| from u_boot_pylib import command
 | |
| from u_boot_pylib import terminal
 | |
| from u_boot_pylib.terminal import tprint
 | |
| 
 | |
| TEST_BUILDER = None
 | |
| 
 | |
| def get_plural(count):
 | |
|     """Returns a plural 's' if count is not 1"""
 | |
|     return 's' if count != 1 else ''
 | |
| 
 | |
| 
 | |
| def count_build_commits(commits, step):
 | |
|     """Calculate the number of commits to be built
 | |
| 
 | |
|     Args:
 | |
|         commits (list of Commit): Commits to build or None
 | |
|         step (int): Step value for commits, typically 1
 | |
| 
 | |
|     Returns:
 | |
|         Number of commits that will be built
 | |
|     """
 | |
|     if commits:
 | |
|         count = len(commits)
 | |
|         return (count + step - 1) // step
 | |
|     return 0
 | |
| 
 | |
| 
 | |
| def get_action_summary(is_summary, commit_count, selected, threads, jobs):
 | |
|     """Return a string summarising the intended action.
 | |
| 
 | |
|     Args:
 | |
|         is_summary (bool): True if this is a summary (otherwise it is building)
 | |
|         commits (list): List of commits being built
 | |
|         selected (list of Board): List of Board objects that are marked
 | |
|         step (int): Step increment through commits
 | |
|         threads (int): Number of processor threads being used
 | |
|         jobs (int): Number of jobs to build at once
 | |
| 
 | |
|     Returns:
 | |
|         Summary string.
 | |
|     """
 | |
|     if commit_count:
 | |
|         commit_str = f'{commit_count} commit{get_plural(commit_count)}'
 | |
|     else:
 | |
|         commit_str = 'current source'
 | |
|     msg = (f"{'Summary of' if is_summary else 'Building'} "
 | |
|            f'{commit_str} for {len(selected)} boards')
 | |
|     msg += (f' ({threads} thread{get_plural(threads)}, '
 | |
|             f'{jobs} job{get_plural(jobs)} per thread)')
 | |
|     return msg
 | |
| 
 | |
| # pylint: disable=R0913
 | |
| def show_actions(series, why_selected, boards_selected, output_dir,
 | |
|                  board_warnings, step, threads, jobs, verbose):
 | |
|     """Display a list of actions that we would take, if not a dry run.
 | |
| 
 | |
|     Args:
 | |
|         series: Series object
 | |
|         why_selected: Dictionary where each key is a buildman argument
 | |
|                 provided by the user, and the value is the list of boards
 | |
|                 brought in by that argument. For example, 'arm' might bring
 | |
|                 in 400 boards, so in this case the key would be 'arm' and
 | |
|                 the value would be a list of board names.
 | |
|         boards_selected: Dict of selected boards, key is target name,
 | |
|                 value is Board object
 | |
|         output_dir (str): Output directory for builder
 | |
|         board_warnings: List of warnings obtained from board selected
 | |
|         step (int): Step increment through commits
 | |
|         threads (int): Number of processor threads being used
 | |
|         jobs (int): Number of jobs to build at once
 | |
|         verbose (bool): True to indicate why each board was selected
 | |
|     """
 | |
|     col = terminal.Color()
 | |
|     print('Dry run, so not doing much. But I would do this:')
 | |
|     print()
 | |
|     if series:
 | |
|         commits = series.commits
 | |
|     else:
 | |
|         commits = None
 | |
|     print(get_action_summary(False, count_build_commits(commits, step),
 | |
|                              boards_selected, threads, jobs))
 | |
|     print(f'Build directory: {output_dir}')
 | |
|     if commits:
 | |
|         for upto in range(0, len(series.commits), step):
 | |
|             commit = series.commits[upto]
 | |
|             print('   ', col.build(col.YELLOW, commit.hash[:8], bright=False), end=' ')
 | |
|             print(commit.subject)
 | |
|     print()
 | |
|     for arg in why_selected:
 | |
|         if arg != 'all':
 | |
|             print(arg, f': {len(why_selected[arg])} boards')
 | |
|             if verbose:
 | |
|                 print(f"   {' '.join(why_selected[arg])}")
 | |
|     print('Total boards to build for each '
 | |
|           f"commit: {len(why_selected['all'])}\n")
 | |
|     if board_warnings:
 | |
|         for warning in board_warnings:
 | |
|             print(col.build(col.YELLOW, warning))
 | |
| 
 | |
| def show_toolchain_prefix(brds, toolchains):
 | |
|     """Show information about a the tool chain used by one or more boards
 | |
| 
 | |
|     The function checks that all boards use the same toolchain, then prints
 | |
|     the correct value for CROSS_COMPILE.
 | |
| 
 | |
|     Args:
 | |
|         boards: Boards object containing selected boards
 | |
|         toolchains: Toolchains object containing available toolchains
 | |
| 
 | |
|     Return:
 | |
|         None on success, string error message otherwise
 | |
|     """
 | |
|     board_selected = brds.get_selected_dict()
 | |
|     tc_set = set()
 | |
|     for brd in board_selected.values():
 | |
|         tc_set.add(toolchains.Select(brd.arch))
 | |
|     if len(tc_set) != 1:
 | |
|         sys.exit('Supplied boards must share one toolchain')
 | |
|     tchain = tc_set.pop()
 | |
|     print(tchain.GetEnvArgs(toolchain.VAR_CROSS_COMPILE))
 | |
| 
 | |
| def show_arch(brds):
 | |
|     """Show information about a the architecture used by one or more boards
 | |
| 
 | |
|     The function checks that all boards use the same architecture, then prints
 | |
|     the correct value for ARCH.
 | |
| 
 | |
|     Args:
 | |
|         boards: Boards object containing selected boards
 | |
| 
 | |
|     Return:
 | |
|         None on success, string error message otherwise
 | |
|     """
 | |
|     board_selected = brds.get_selected_dict()
 | |
|     arch_set = set()
 | |
|     for brd in board_selected.values():
 | |
|         arch_set.add(brd.arch)
 | |
|     if len(arch_set) != 1:
 | |
|         sys.exit('Supplied boards must share one arch')
 | |
|     print(arch_set.pop())
 | |
| 
 | |
| def get_allow_missing(opt_allow, opt_no_allow, num_selected, has_branch):
 | |
|     """Figure out whether to allow external blobs
 | |
| 
 | |
|     Uses the allow-missing setting and the provided arguments to decide whether
 | |
|     missing external blobs should be allowed
 | |
| 
 | |
|     Args:
 | |
|         opt_allow (bool): True if --allow-missing flag is set
 | |
|         opt_no_allow (bool): True if --no-allow-missing flag is set
 | |
|         num_selected (int): Number of selected board
 | |
|         has_branch (bool): True if a git branch (to build) has been provided
 | |
| 
 | |
|     Returns:
 | |
|         bool: True to allow missing external blobs, False to produce an error if
 | |
|             external blobs are used
 | |
|     """
 | |
|     allow_missing = False
 | |
|     am_setting = bsettings.get_global_item_value('allow-missing')
 | |
|     if am_setting:
 | |
|         if am_setting == 'always':
 | |
|             allow_missing = True
 | |
|         if 'multiple' in am_setting and num_selected > 1:
 | |
|             allow_missing = True
 | |
|         if 'branch' in am_setting and has_branch:
 | |
|             allow_missing = True
 | |
| 
 | |
|     if opt_allow:
 | |
|         allow_missing = True
 | |
|     if opt_no_allow:
 | |
|         allow_missing = False
 | |
|     return allow_missing
 | |
| 
 | |
| 
 | |
| def count_commits(branch, count, col, git_dir):
 | |
|     """Could the number of commits in the branch/ranch being built
 | |
| 
 | |
|     Args:
 | |
|         branch (str): Name of branch to build, or None if none
 | |
|         count (int): Number of commits to build, or -1 for all
 | |
|         col (Terminal.Color): Color object to use
 | |
|         git_dir (str): Git directory to use, e.g. './.git'
 | |
| 
 | |
|     Returns:
 | |
|         tuple:
 | |
|             Number of commits being built
 | |
|             True if the 'branch' string contains a range rather than a simple
 | |
|                 name
 | |
|     """
 | |
|     has_range = branch and '..' in branch
 | |
|     if count == -1:
 | |
|         if not branch:
 | |
|             count = 1
 | |
|         else:
 | |
|             if has_range:
 | |
|                 count, msg = gitutil.count_commits_in_range(git_dir, branch)
 | |
|             else:
 | |
|                 count, msg = gitutil.count_commits_in_branch(git_dir, branch)
 | |
|             if count is None:
 | |
|                 sys.exit(col.build(col.RED, msg))
 | |
|             elif count == 0:
 | |
|                 sys.exit(col.build(col.RED,
 | |
|                                    f"Range '{branch}' has no commits"))
 | |
|             if msg:
 | |
|                 print(col.build(col.YELLOW, msg))
 | |
|             count += 1   # Build upstream commit also
 | |
| 
 | |
|     if not count:
 | |
|         msg = (f"No commits found to process in branch '{branch}': "
 | |
|                "set branch's upstream or use -c flag")
 | |
|         sys.exit(col.build(col.RED, msg))
 | |
|     return count, has_range
 | |
| 
 | |
| 
 | |
| def determine_series(selected, col, git_dir, count, branch, work_in_output):
 | |
|     """Determine the series which is to be built, if any
 | |
| 
 | |
|     If there is a series, the commits in that series are numbered by setting
 | |
|     their sequence value (starting from 0). This is used by tests.
 | |
| 
 | |
|     Args:
 | |
|         selected (list of Board): List of Board objects that are marked
 | |
|             selected
 | |
|         col (Terminal.Color): Color object to use
 | |
|         git_dir (str): Git directory to use, e.g. './.git'
 | |
|         count (int): Number of commits in branch
 | |
|         branch (str): Name of branch to build, or None if none
 | |
|         work_in_output (bool): True to work in the output directory
 | |
| 
 | |
|     Returns:
 | |
|         Series: Series to build, or None for none
 | |
| 
 | |
|     Read the metadata from the commits. First look at the upstream commit,
 | |
|     then the ones in the branch. We would like to do something like
 | |
|     upstream/master~..branch but that isn't possible if upstream/master is
 | |
|     a merge commit (it will list all the commits that form part of the
 | |
|     merge)
 | |
| 
 | |
|     Conflicting tags are not a problem for buildman, since it does not use
 | |
|     them. For example, Series-version is not useful for buildman. On the
 | |
|     other hand conflicting tags will cause an error. So allow later tags
 | |
|     to overwrite earlier ones by setting allow_overwrite=True
 | |
|     """
 | |
| 
 | |
|     # Work out how many commits to build. We want to build everything on the
 | |
|     # branch. We also build the upstream commit as a control so we can see
 | |
|     # problems introduced by the first commit on the branch.
 | |
|     count, has_range = count_commits(branch, count, col, git_dir)
 | |
|     if work_in_output:
 | |
|         if len(selected) != 1:
 | |
|             sys.exit(col.build(col.RED,
 | |
|                                '-w can only be used with a single board'))
 | |
|         if count != 1:
 | |
|             sys.exit(col.build(col.RED,
 | |
|                                '-w can only be used with a single commit'))
 | |
| 
 | |
|     if branch:
 | |
|         if count == -1:
 | |
|             if has_range:
 | |
|                 range_expr = branch
 | |
|             else:
 | |
|                 range_expr = gitutil.get_range_in_branch(git_dir, branch)
 | |
|             upstream_commit = gitutil.get_upstream(git_dir, branch)
 | |
|             series = patchstream.get_metadata_for_list(upstream_commit,
 | |
|                 git_dir, 1, series=None, allow_overwrite=True)
 | |
| 
 | |
|             series = patchstream.get_metadata_for_list(range_expr,
 | |
|                     git_dir, None, series, allow_overwrite=True)
 | |
|         else:
 | |
|             # Honour the count
 | |
|             series = patchstream.get_metadata_for_list(branch,
 | |
|                     git_dir, count, series=None, allow_overwrite=True)
 | |
| 
 | |
|         # Number the commits for test purposes
 | |
|         for i, commit in enumerate(series.commits):
 | |
|             commit.sequence = i
 | |
|     else:
 | |
|         series = None
 | |
|     return series
 | |
| 
 | |
| 
 | |
| def do_fetch_arch(toolchains, col, fetch_arch):
 | |
|     """Handle the --fetch-arch option
 | |
| 
 | |
|     Args:
 | |
|         toolchains (Toolchains): Tool chains to use
 | |
|         col (terminal.Color): Color object to build
 | |
|         fetch_arch (str): Argument passed to the --fetch-arch option
 | |
| 
 | |
|     Returns:
 | |
|         int: Return code for buildman
 | |
|     """
 | |
|     if fetch_arch == 'list':
 | |
|         sorted_list = toolchains.ListArchs()
 | |
|         print(col.build(
 | |
|             col.BLUE,
 | |
|             f"Available architectures: {' '.join(sorted_list)}\n"))
 | |
|         return 0
 | |
| 
 | |
|     if fetch_arch == 'all':
 | |
|         fetch_arch = ','.join(toolchains.ListArchs())
 | |
|         print(col.build(col.CYAN,
 | |
|                         f'\nDownloading toolchains: {fetch_arch}'))
 | |
|     for arch in fetch_arch.split(','):
 | |
|         print()
 | |
|         ret = toolchains.FetchAndInstall(arch)
 | |
|         if ret:
 | |
|             return ret
 | |
|     return 0
 | |
| 
 | |
| 
 | |
| def get_toolchains(toolchains, col, override_toolchain, fetch_arch,
 | |
|                    list_tool_chains, verbose):
 | |
|     """Get toolchains object to use
 | |
| 
 | |
|     Args:
 | |
|         toolchains (Toolchains or None): Toolchains to use. If None, then a
 | |
|             Toolchains object will be created and scanned
 | |
|         col (Terminal.Color): Color object
 | |
|         override_toolchain (str or None): Override value for toolchain, or None
 | |
|         fetch_arch (bool): True to fetch the toolchain for the architectures
 | |
|         list_tool_chains (bool): True to list all tool chains
 | |
|         verbose (bool): True for verbose output when listing toolchains
 | |
| 
 | |
|     Returns:
 | |
|         Either:
 | |
|             int: Operation completed and buildman should exit with exit code
 | |
|             Toolchains: Toolchains object to use
 | |
|     """
 | |
|     no_toolchains = toolchains is None
 | |
|     if no_toolchains:
 | |
|         toolchains = toolchain.Toolchains(override_toolchain)
 | |
| 
 | |
|     if fetch_arch:
 | |
|         return do_fetch_arch(toolchains, col, fetch_arch)
 | |
| 
 | |
|     if no_toolchains:
 | |
|         toolchains.GetSettings()
 | |
|         toolchains.Scan(list_tool_chains and verbose)
 | |
|     if list_tool_chains:
 | |
|         toolchains.List()
 | |
|         print()
 | |
|         return 0
 | |
|     return toolchains
 | |
| 
 | |
| 
 | |
| def get_boards_obj(output_dir, regen_board_list, maintainer_check, full_check,
 | |
|                    threads, verbose):
 | |
|     """Object the Boards object to use
 | |
| 
 | |
|     Creates the output directory and ensures there is a boards.cfg file, then
 | |
|     read it in.
 | |
| 
 | |
|     Args:
 | |
|         output_dir (str): Output directory to use
 | |
|         regen_board_list (bool): True to just regenerate the board list
 | |
|         maintainer_check (bool): True to just run a maintainer check
 | |
|         full_check (bool): True to just run a full check of Kconfig and
 | |
|             maintainers
 | |
|         threads (int or None): Number of threads to use to create boards file
 | |
|         verbose (bool): False to suppress output from boards-file generation
 | |
| 
 | |
|     Returns:
 | |
|         Either:
 | |
|             int: Operation completed and buildman should exit with exit code
 | |
|             Boards: Boards object to use
 | |
|     """
 | |
|     brds = boards.Boards()
 | |
|     nr_cpus = threads or multiprocessing.cpu_count()
 | |
|     if maintainer_check or full_check:
 | |
|         warnings = brds.build_board_list(jobs=nr_cpus,
 | |
|                                          warn_targets=full_check)[1]
 | |
|         if warnings:
 | |
|             for warn in warnings:
 | |
|                 print(warn, file=sys.stderr)
 | |
|             return 2
 | |
|         return 0
 | |
| 
 | |
|     if not os.path.exists(output_dir):
 | |
|         os.makedirs(output_dir)
 | |
|     board_file = os.path.join(output_dir, 'boards.cfg')
 | |
|     if regen_board_list and regen_board_list != '-':
 | |
|         board_file = regen_board_list
 | |
| 
 | |
|     okay = brds.ensure_board_list(board_file, nr_cpus, force=regen_board_list,
 | |
|                                   quiet=not verbose)
 | |
|     if regen_board_list:
 | |
|         return 0 if okay else 2
 | |
|     brds.read_boards(board_file)
 | |
|     return brds
 | |
| 
 | |
| 
 | |
| def determine_boards(brds, args, col, opt_boards, exclude_list):
 | |
|     """Determine which boards to build
 | |
| 
 | |
|     Each element of args and exclude can refer to a board name, arch or SoC
 | |
| 
 | |
|     Args:
 | |
|         brds (Boards): Boards object
 | |
|         args (list of str): Arguments describing boards to build
 | |
|         col (Terminal.Color): Color object
 | |
|         opt_boards (list of str): Specific boards to build, or None for all
 | |
|         exclude_list (list of str): Arguments describing boards to exclude
 | |
| 
 | |
|     Returns:
 | |
|         tuple:
 | |
|             list of Board: List of Board objects that are marked selected
 | |
|             why_selected: Dictionary where each key is a buildman argument
 | |
|                     provided by the user, and the value is the list of boards
 | |
|                     brought in by that argument. For example, 'arm' might bring
 | |
|                     in 400 boards, so in this case the key would be 'arm' and
 | |
|                     the value would be a list of board names.
 | |
|             board_warnings: List of warnings obtained from board selected
 | |
|     """
 | |
|     exclude = []
 | |
|     if exclude_list:
 | |
|         for arg in exclude_list:
 | |
|             exclude += arg.split(',')
 | |
| 
 | |
|     if opt_boards:
 | |
|         requested_boards = []
 | |
|         for brd in opt_boards:
 | |
|             requested_boards += brd.split(',')
 | |
|     else:
 | |
|         requested_boards = None
 | |
|     why_selected, board_warnings = brds.select_boards(args, exclude,
 | |
|                                                       requested_boards)
 | |
|     selected = brds.get_selected()
 | |
|     if not selected:
 | |
|         sys.exit(col.build(col.RED, 'No matching boards found'))
 | |
|     return selected, why_selected, board_warnings
 | |
| 
 | |
| 
 | |
| def adjust_args(args, series, selected):
 | |
|     """Adjust arguments according to various constraints
 | |
| 
 | |
|     Updates verbose, show_errors, threads, jobs and step
 | |
| 
 | |
|     Args:
 | |
|         args (Namespace): Namespace object to adjust
 | |
|         series (Series): Series being built / summarised
 | |
|         selected (list of Board): List of Board objects that are marked
 | |
|     """
 | |
|     if not series and not args.dry_run:
 | |
|         args.verbose = True
 | |
|         if not args.summary:
 | |
|             args.show_errors = True
 | |
| 
 | |
|     # By default we have one thread per CPU. But if there are not enough jobs
 | |
|     # we can have fewer threads and use a high '-j' value for make.
 | |
|     if args.threads is None:
 | |
|         args.threads = min(multiprocessing.cpu_count(), len(selected))
 | |
|     if not args.jobs:
 | |
|         args.jobs = max(1, (multiprocessing.cpu_count() +
 | |
|                 len(selected) - 1) // len(selected))
 | |
| 
 | |
|     if not args.step:
 | |
|         args.step = len(series.commits) - 1
 | |
| 
 | |
|     # We can't show function sizes without board details at present
 | |
|     if args.show_bloat:
 | |
|         args.show_detail = True
 | |
| 
 | |
| 
 | |
| def setup_output_dir(output_dir, work_in_output, branch, no_subdirs, col,
 | |
|                      clean_dir):
 | |
|     """Set up the output directory
 | |
| 
 | |
|     Args:
 | |
|         output_dir (str): Output directory provided by the user, or None if none
 | |
|         work_in_output (bool): True to work in the output directory
 | |
|         branch (str): Name of branch to build, or None if none
 | |
|         no_subdirs (bool): True to put the output in the top-level output dir
 | |
|         clean_dir: Used for tests only, indicates that the existing output_dir
 | |
|             should be removed before starting the build
 | |
| 
 | |
|     Returns:
 | |
|         str: Updated output directory pathname
 | |
|     """
 | |
|     if not output_dir:
 | |
|         if work_in_output:
 | |
|             sys.exit(col.build(col.RED, '-w requires that you specify -o'))
 | |
|         output_dir = '..'
 | |
|     if branch and not no_subdirs:
 | |
|         # As a special case allow the board directory to be placed in the
 | |
|         # output directory itself rather than any subdirectory.
 | |
|         dirname = branch.replace('/', '_')
 | |
|         output_dir = os.path.join(output_dir, dirname)
 | |
|         if clean_dir and os.path.exists(output_dir):
 | |
|             shutil.rmtree(output_dir)
 | |
|     return output_dir
 | |
| 
 | |
| 
 | |
| def run_builder(builder, commits, board_selected, args):
 | |
|     """Run the builder or show the summary
 | |
| 
 | |
|     Args:
 | |
|         commits (list of Commit): List of commits being built, None if no branch
 | |
|         boards_selected (dict): Dict of selected boards:
 | |
|             key: target name
 | |
|             value: Board object
 | |
|         args (Namespace): Namespace to use
 | |
| 
 | |
|     Returns:
 | |
|         int: Return code for buildman
 | |
|     """
 | |
|     gnu_make = command.output(os.path.join(args.git,
 | |
|             'scripts/show-gnu-make'), raise_on_error=False).rstrip()
 | |
|     if not gnu_make:
 | |
|         sys.exit('GNU Make not found')
 | |
|     builder.gnu_make = gnu_make
 | |
| 
 | |
|     if not args.ide:
 | |
|         commit_count = count_build_commits(commits, args.step)
 | |
|         tprint(get_action_summary(args.summary, commit_count, board_selected,
 | |
|                                   args.threads, args.jobs))
 | |
| 
 | |
|     builder.set_display_options(
 | |
|         args.show_errors, args.show_sizes, args.show_detail, args.show_bloat,
 | |
|         args.list_error_boards, args.show_config, args.show_environment,
 | |
|         args.filter_dtb_warnings, args.filter_migration_warnings, args.ide)
 | |
|     if args.summary:
 | |
|         builder.show_summary(commits, board_selected)
 | |
|     else:
 | |
|         fail, warned, excs = builder.build_boards(
 | |
|             commits, board_selected, args.keep_outputs, args.verbose)
 | |
|         if excs:
 | |
|             return 102
 | |
|         if fail:
 | |
|             return 100
 | |
|         if warned and not args.ignore_warnings:
 | |
|             return 101
 | |
|     return 0
 | |
| 
 | |
| 
 | |
| def calc_adjust_cfg(adjust_cfg, reproducible_builds):
 | |
|     """Calculate the value to use for adjust_cfg
 | |
| 
 | |
|     Args:
 | |
|         adjust_cfg (list of str): List of configuration changes. See cfgutil for
 | |
|             details
 | |
|         reproducible_builds (bool): True to adjust the configuration to get
 | |
|             reproduceable builds
 | |
| 
 | |
|     Returns:
 | |
|         adjust_cfg (list of str): List of configuration changes
 | |
|     """
 | |
|     adjust_cfg = cfgutil.convert_list_to_dict(adjust_cfg)
 | |
| 
 | |
|     # Drop LOCALVERSION_AUTO since it changes the version string on every commit
 | |
|     if reproducible_builds:
 | |
|         # If these are mentioned, leave the local version alone
 | |
|         if 'LOCALVERSION' in adjust_cfg or 'LOCALVERSION_AUTO' in adjust_cfg:
 | |
|             print('Not dropping LOCALVERSION_AUTO for reproducible build')
 | |
|         else:
 | |
|             adjust_cfg['LOCALVERSION_AUTO'] = '~'
 | |
|     return adjust_cfg
 | |
| 
 | |
| 
 | |
| def do_buildman(args, toolchains=None, make_func=None, brds=None,
 | |
|                 clean_dir=False, test_thread_exceptions=False):
 | |
|     """The main control code for buildman
 | |
| 
 | |
|     Args:
 | |
|         args: ArgumentParser object
 | |
|         args: Command line arguments (list of strings)
 | |
|         toolchains: Toolchains to use - this should be a Toolchains()
 | |
|                 object. If None, then it will be created and scanned
 | |
|         make_func: Make function to use for the builder. This is called
 | |
|                 to execute 'make'. If this is None, the normal function
 | |
|                 will be used, which calls the 'make' tool with suitable
 | |
|                 arguments. This setting is useful for tests.
 | |
|         brds: Boards() object to use, containing a list of available
 | |
|                 boards. If this is None it will be created and scanned.
 | |
|         clean_dir: Used for tests only, indicates that the existing output_dir
 | |
|             should be removed before starting the build
 | |
|         test_thread_exceptions: Uses for tests only, True to make the threads
 | |
|             raise an exception instead of reporting their result. This simulates
 | |
|             a failure in the code somewhere
 | |
|     """
 | |
|     # Used so testing can obtain the builder: pylint: disable=W0603
 | |
|     global TEST_BUILDER
 | |
| 
 | |
|     gitutil.setup()
 | |
|     col = terminal.Color()
 | |
| 
 | |
|     git_dir = os.path.join(args.git, '.git')
 | |
| 
 | |
|     toolchains = get_toolchains(toolchains, col, args.override_toolchain,
 | |
|                                 args.fetch_arch, args.list_tool_chains,
 | |
|                                 args.verbose)
 | |
|     if isinstance(toolchains, int):
 | |
|         return toolchains
 | |
| 
 | |
|     output_dir = setup_output_dir(
 | |
|         args.output_dir, args.work_in_output, args.branch,
 | |
|         args.no_subdirs, col, clean_dir)
 | |
| 
 | |
|     # Work out what subset of the boards we are building
 | |
|     if not brds:
 | |
|         brds = get_boards_obj(output_dir, args.regen_board_list,
 | |
|                               args.maintainer_check, args.full_check,
 | |
|                               args.threads, args.verbose and
 | |
|                               not args.print_arch and not args.print_prefix)
 | |
|         if isinstance(brds, int):
 | |
|             return brds
 | |
| 
 | |
|     selected, why_selected, board_warnings = determine_boards(
 | |
|         brds, args.terms, col, args.boards, args.exclude)
 | |
| 
 | |
|     if args.print_prefix:
 | |
|         show_toolchain_prefix(brds, toolchains)
 | |
|         return 0
 | |
| 
 | |
|     if args.print_arch:
 | |
|         show_arch(brds)
 | |
|         return 0
 | |
| 
 | |
|     series = determine_series(selected, col, git_dir, args.count,
 | |
|                               args.branch, args.work_in_output)
 | |
| 
 | |
|     adjust_args(args, series, selected)
 | |
| 
 | |
|     # For a dry run, just show our actions as a sanity check
 | |
|     if args.dry_run:
 | |
|         show_actions(series, why_selected, selected, output_dir, board_warnings,
 | |
|                      args.step, args.threads, args.jobs,
 | |
|                      args.verbose)
 | |
|         return 0
 | |
| 
 | |
|     # Create a new builder with the selected args
 | |
|     builder = Builder(toolchains, output_dir, git_dir,
 | |
|             args.threads, args.jobs, checkout=True,
 | |
|             show_unknown=args.show_unknown, step=args.step,
 | |
|             no_subdirs=args.no_subdirs, full_path=args.full_path,
 | |
|             verbose_build=args.verbose_build,
 | |
|             mrproper=args.mrproper,
 | |
|             per_board_out_dir=args.per_board_out_dir,
 | |
|             config_only=args.config_only,
 | |
|             squash_config_y=not args.preserve_config_y,
 | |
|             warnings_as_errors=args.warnings_as_errors,
 | |
|             work_in_output=args.work_in_output,
 | |
|             test_thread_exceptions=test_thread_exceptions,
 | |
|             adjust_cfg=calc_adjust_cfg(args.adjust_cfg,
 | |
|                                        args.reproducible_builds),
 | |
|             allow_missing=get_allow_missing(args.allow_missing,
 | |
|                                             args.no_allow_missing,
 | |
|                                             len(selected), args.branch),
 | |
|             no_lto=args.no_lto,
 | |
|             reproducible_builds=args.reproducible_builds,
 | |
|             force_build = args.force_build,
 | |
|             force_build_failures = args.force_build_failures,
 | |
|             force_reconfig = args.force_reconfig, in_tree = args.in_tree,
 | |
|             force_config_on_failure=not args.quick, make_func=make_func)
 | |
| 
 | |
|     TEST_BUILDER = builder
 | |
| 
 | |
|     return run_builder(builder, series.commits if series else None,
 | |
|                        brds.get_selected_dict(), args)
 |