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)
88 pager = os.getenv('PAGER')
91 fname = os.path.join(os.path.dirname(sys.argv[0]), 'README')
92 command.Run(pager, fname)
97 bsettings.Setup(options.config_file)
98 options.git_dir = os.path.join(options.git, '.git')
100 toolchains = toolchain.Toolchains()
101 toolchains.Scan(options.list_tool_chains)
102 if options.list_tool_chains:
107 # Work out how many commits to build. We want to build everything on the
108 # branch. We also build the upstream commit as a control so we can see
109 # problems introduced by the first commit on the branch.
110 col = terminal.Color()
111 count = options.count
113 if not options.branch:
116 count = gitutil.CountCommitsInBranch(options.git_dir,
119 str = ("Branch '%s' not found or has no upstream" %
121 sys.exit(col.Color(col.RED, str))
122 count += 1 # Build upstream commit also
125 str = ("No commits found to process in branch '%s': "
126 "set branch's upstream or use -c flag" % options.branch)
127 sys.exit(col.Color(col.RED, str))
129 # Work out what subset of the boards we are building
130 board_file = os.path.join(options.git, 'boards.cfg')
131 status = subprocess.call([os.path.join(options.git,
132 'tools/genboardscfg.py')])
134 sys.exit("Failed to generate boards.cfg")
136 boards = board.Boards()
137 boards.ReadBoards(os.path.join(options.git, 'boards.cfg'))
141 for arg in options.exclude:
142 exclude += arg.split(',')
144 why_selected = boards.SelectBoards(args, exclude)
145 selected = boards.GetSelected()
146 if not len(selected):
147 sys.exit(col.Color(col.RED, 'No matching boards found'))
149 # Read the metadata from the commits. First look at the upstream commit,
150 # then the ones in the branch. We would like to do something like
151 # upstream/master~..branch but that isn't possible if upstream/master is
152 # a merge commit (it will list all the commits that form part of the
156 range_expr = gitutil.GetRangeInBranch(options.git_dir,
158 upstream_commit = gitutil.GetUpstream(options.git_dir,
160 series = patchstream.GetMetaDataForList(upstream_commit,
163 # Conflicting tags are not a problem for buildman, since it does
164 # not use them. For example, Series-version is not useful for
165 # buildman. On the other hand conflicting tags will cause an
166 # error. So allow later tags to overwrite earlier ones.
167 series.allow_overwrite = True
168 series = patchstream.GetMetaDataForList(range_expr,
169 options.git_dir, None, series)
172 series = patchstream.GetMetaDataForList(options.branch,
173 options.git_dir, count)
176 options.verbose = True
177 options.show_errors = True
179 # By default we have one thread per CPU. But if there are not enough jobs
180 # we can have fewer threads and use a high '-j' value for make.
181 if not options.threads:
182 options.threads = min(multiprocessing.cpu_count(), len(selected))
184 options.jobs = max(1, (multiprocessing.cpu_count() +
185 len(selected) - 1) / len(selected))
188 options.step = len(series.commits) - 1
190 gnu_make = command.Output(os.path.join(options.git,
191 'scripts/show-gnu-make')).rstrip()
193 sys.exit('GNU Make not found')
195 # Create a new builder with the selected options
197 dirname = options.branch
200 output_dir = os.path.join(options.output_dir, dirname)
201 builder = Builder(toolchains, output_dir, options.git_dir,
202 options.threads, options.jobs, gnu_make=gnu_make, checkout=True,
203 show_unknown=options.show_unknown, step=options.step)
204 builder.force_config_on_failure = not options.quick
206 # For a dry run, just show our actions as a sanity check
208 ShowActions(series, why_selected, selected, builder, options)
210 builder.force_build = options.force_build
211 builder.force_build_failures = options.force_build_failures
212 builder.force_reconfig = options.force_reconfig
213 builder.in_tree = options.in_tree
215 # Work out which boards to build
216 board_selected = boards.GetSelectedDict()
219 commits = series.commits
223 print GetActionSummary(options.summary, commits, board_selected,
226 builder.SetDisplayOptions(options.show_errors, options.show_sizes,
227 options.show_detail, options.show_bloat,
228 options.list_error_boards)
230 # We can't show function sizes without board details at present
231 if options.show_bloat:
232 options.show_detail = True
233 builder.ShowSummary(commits, board_selected)
235 fail, warned = builder.BuildBoards(commits, board_selected,
236 options.keep_outputs, options.verbose)