1 # Copyright (c) 2013 The Chromium OS Authors.
3 # SPDX-License-Identifier: GPL-2.0+
12 from builder import Builder
21 """Returns a plural 's' if count is not 1"""
22 return 's' if count != 1 else ''
24 def GetActionSummary(is_summary, commits, selected, options):
25 """Return a string summarising the intended action.
32 count = (count + options.step - 1) / options.step
33 commit_str = '%d commit%s' % (count, GetPlural(count))
35 commit_str = 'current source'
36 str = '%s %s for %d boards' % (
37 'Summary of' if is_summary else 'Building', commit_str,
39 str += ' (%d thread%s, %d job%s per thread)' % (options.threads,
40 GetPlural(options.threads), options.jobs, GetPlural(options.jobs))
43 def ShowActions(series, why_selected, boards_selected, builder, options):
44 """Display a list of actions that we would take, if not a dry run.
48 why_selected: Dictionary where each key is a buildman argument
49 provided by the user, and the value is the boards brought
50 in by that argument. For example, 'arm' might bring in
51 400 boards, so in this case the key would be 'arm' and
52 the value would be a list of board names.
53 boards_selected: Dict of selected boards, key is target name,
55 builder: The builder that will be used to build the commits
56 options: Command line options object
58 col = terminal.Color()
59 print 'Dry run, so not doing much. But I would do this:'
62 commits = series.commits
65 print GetActionSummary(False, commits, boards_selected,
67 print 'Build directory: %s' % builder.base_dir
69 for upto in range(0, len(series.commits), options.step):
70 commit = series.commits[upto]
71 print ' ', col.Color(col.YELLOW, commit.hash, bright=False),
74 for arg in why_selected:
76 print arg, ': %d boards' % why_selected[arg]
77 print ('Total boards to build for each commit: %d\n' %
80 def DoBuildman(options, args):
81 """The main control code for buildman
84 options: Command line options object
85 args: Command line arguments (list of strings)
89 bsettings.Setup(options.config_file)
90 options.git_dir = os.path.join(options.git, '.git')
92 toolchains = toolchain.Toolchains()
93 toolchains.Scan(options.list_tool_chains)
94 if options.list_tool_chains:
99 # Work out how many commits to build. We want to build everything on the
100 # branch. We also build the upstream commit as a control so we can see
101 # problems introduced by the first commit on the branch.
102 col = terminal.Color()
103 count = options.count
105 if not options.branch:
108 count = gitutil.CountCommitsInBranch(options.git_dir,
111 str = ("Branch '%s' not found or has no upstream" %
113 sys.exit(col.Color(col.RED, str))
114 count += 1 # Build upstream commit also
117 str = ("No commits found to process in branch '%s': "
118 "set branch's upstream or use -c flag" % options.branch)
119 sys.exit(col.Color(col.RED, str))
121 # Work out what subset of the boards we are building
122 board_file = os.path.join(options.git, 'boards.cfg')
123 status = subprocess.call([os.path.join(options.git,
124 'tools/genboardscfg.py')])
126 sys.exit("Failed to generate boards.cfg")
128 boards = board.Boards()
129 boards.ReadBoards(os.path.join(options.git, 'boards.cfg'))
133 for arg in options.exclude:
134 exclude += arg.split(',')
136 why_selected = boards.SelectBoards(args, exclude)
137 selected = boards.GetSelected()
138 if not len(selected):
139 sys.exit(col.Color(col.RED, 'No matching boards found'))
141 # Read the metadata from the commits. First look at the upstream commit,
142 # then the ones in the branch. We would like to do something like
143 # upstream/master~..branch but that isn't possible if upstream/master is
144 # a merge commit (it will list all the commits that form part of the
148 range_expr = gitutil.GetRangeInBranch(options.git_dir,
150 upstream_commit = gitutil.GetUpstream(options.git_dir,
152 series = patchstream.GetMetaDataForList(upstream_commit,
155 # Conflicting tags are not a problem for buildman, since it does
156 # not use them. For example, Series-version is not useful for
157 # buildman. On the other hand conflicting tags will cause an
158 # error. So allow later tags to overwrite earlier ones.
159 series.allow_overwrite = True
160 series = patchstream.GetMetaDataForList(range_expr,
161 options.git_dir, None, series)
164 series = patchstream.GetMetaDataForList(options.branch,
165 options.git_dir, count)
168 options.verbose = True
169 options.show_errors = True
171 # By default we have one thread per CPU. But if there are not enough jobs
172 # we can have fewer threads and use a high '-j' value for make.
173 if not options.threads:
174 options.threads = min(multiprocessing.cpu_count(), len(selected))
176 options.jobs = max(1, (multiprocessing.cpu_count() +
177 len(selected) - 1) / len(selected))
180 options.step = len(series.commits) - 1
182 gnu_make = command.Output(os.path.join(options.git,
183 'scripts/show-gnu-make')).rstrip()
185 sys.exit('GNU Make not found')
187 # Create a new builder with the selected options
189 dirname = options.branch
192 output_dir = os.path.join(options.output_dir, dirname)
193 builder = Builder(toolchains, output_dir, options.git_dir,
194 options.threads, options.jobs, gnu_make=gnu_make, checkout=True,
195 show_unknown=options.show_unknown, step=options.step)
196 builder.force_config_on_failure = not options.quick
198 # For a dry run, just show our actions as a sanity check
200 ShowActions(series, why_selected, selected, builder, options)
202 builder.force_build = options.force_build
203 builder.force_build_failures = options.force_build_failures
204 builder.force_reconfig = options.force_reconfig
205 builder.in_tree = options.in_tree
207 # Work out which boards to build
208 board_selected = boards.GetSelectedDict()
211 commits = series.commits
215 print GetActionSummary(options.summary, commits, board_selected,
218 builder.SetDisplayOptions(options.show_errors, options.show_sizes,
219 options.show_detail, options.show_bloat,
220 options.list_error_boards)
222 # We can't show function sizes without board details at present
223 if options.show_bloat:
224 options.show_detail = True
225 builder.ShowSummary(commits, board_selected)
227 fail, warned = builder.BuildBoards(commits, board_selected,
228 options.keep_outputs, options.verbose)