1
# Copyright (c) 2013 The Chromium OS Authors.
3
# SPDX-License-Identifier: GPL-2.0+
12
from builder import Builder
19
"""Returns a plural 's' if count is not 1"""
20
return 's' if count != 1 else ''
22
def GetActionSummary(is_summary, count, selected, options):
23
"""Return a string summarising the intended action.
28
count = (count + options.step - 1) / options.step
29
str = '%s %d commit%s for %d boards' % (
30
'Summary of' if is_summary else 'Building', count, GetPlural(count),
32
str += ' (%d thread%s, %d job%s per thread)' % (options.threads,
33
GetPlural(options.threads), options.jobs, GetPlural(options.jobs))
36
def ShowActions(series, why_selected, boards_selected, builder, options):
37
"""Display a list of actions that we would take, if not a dry run.
41
why_selected: Dictionary where each key is a buildman argument
42
provided by the user, and the value is the boards brought
43
in by that argument. For example, 'arm' might bring in
44
400 boards, so in this case the key would be 'arm' and
45
the value would be a list of board names.
46
boards_selected: Dict of selected boards, key is target name,
48
builder: The builder that will be used to build the commits
49
options: Command line options object
51
col = terminal.Color()
52
print 'Dry run, so not doing much. But I would do this:'
54
print GetActionSummary(False, len(series.commits), boards_selected,
56
print 'Build directory: %s' % builder.base_dir
57
for upto in range(0, len(series.commits), options.step):
58
commit = series.commits[upto]
59
print ' ', col.Color(col.YELLOW, commit.hash, bright=False),
62
for arg in why_selected:
64
print arg, ': %d boards' % why_selected[arg]
65
print ('Total boards to build for each commit: %d\n' %
68
def DoBuildman(options, args):
69
"""The main control code for buildman
72
options: Command line options object
73
args: Command line arguments (list of strings)
78
options.git_dir = os.path.join(options.git, '.git')
80
toolchains = toolchain.Toolchains()
81
toolchains.Scan(options.list_tool_chains)
82
if options.list_tool_chains:
87
# Work out how many commits to build. We want to build everything on the
88
# branch. We also build the upstream commit as a control so we can see
89
# problems introduced by the first commit on the branch.
90
col = terminal.Color()
93
if not options.branch:
94
str = 'Please use -b to specify a branch to build'
95
print col.Color(col.RED, str)
97
count = gitutil.CountCommitsInBranch(options.git_dir, options.branch)
99
str = "Branch '%s' not found or has no upstream" % options.branch
100
print col.Color(col.RED, str)
102
count += 1 # Build upstream commit also
105
str = ("No commits found to process in branch '%s': "
106
"set branch's upstream or use -c flag" % options.branch)
107
print col.Color(col.RED, str)
110
# Work out what subset of the boards we are building
111
boards = board.Boards()
112
boards.ReadBoards(os.path.join(options.git, 'boards.cfg'))
113
why_selected = boards.SelectBoards(args)
114
selected = boards.GetSelected()
115
if not len(selected):
116
print col.Color(col.RED, 'No matching boards found')
119
# Read the metadata from the commits. First look at the upstream commit,
120
# then the ones in the branch. We would like to do something like
121
# upstream/master~..branch but that isn't possible if upstream/master is
122
# a merge commit (it will list all the commits that form part of the
124
range_expr = gitutil.GetRangeInBranch(options.git_dir, options.branch)
125
upstream_commit = gitutil.GetUpstream(options.git_dir, options.branch)
126
series = patchstream.GetMetaDataForList(upstream_commit, options.git_dir,
128
# Conflicting tags are not a problem for buildman, since it does not use
129
# them. For example, Series-version is not useful for buildman. On the
130
# other hand conflicting tags will cause an error. So allow later tags
131
# to overwrite earlier ones.
132
series.allow_overwrite = True
133
series = patchstream.GetMetaDataForList(range_expr, options.git_dir, None,
136
# By default we have one thread per CPU. But if there are not enough jobs
137
# we can have fewer threads and use a high '-j' value for make.
138
if not options.threads:
139
options.threads = min(multiprocessing.cpu_count(), len(selected))
141
options.jobs = max(1, (multiprocessing.cpu_count() +
142
len(selected) - 1) / len(selected))
145
options.step = len(series.commits) - 1
147
# Create a new builder with the selected options
148
output_dir = os.path.join(options.output_dir, options.branch)
149
builder = Builder(toolchains, output_dir, options.git_dir,
150
options.threads, options.jobs, checkout=True,
151
show_unknown=options.show_unknown, step=options.step)
152
builder.force_config_on_failure = not options.quick
154
# For a dry run, just show our actions as a sanity check
156
ShowActions(series, why_selected, selected, builder, options)
158
builder.force_build = options.force_build
160
# Work out which boards to build
161
board_selected = boards.GetSelectedDict()
163
print GetActionSummary(options.summary, count, board_selected, options)
166
# We can't show function sizes without board details at present
167
if options.show_bloat:
168
options.show_detail = True
169
builder.ShowSummary(series.commits, board_selected,
170
options.show_errors, options.show_sizes,
171
options.show_detail, options.show_bloat)
173
builder.BuildBoards(series.commits, board_selected,
174
options.show_errors, options.keep_outputs)