1fc3fe1c2SSimon Glass# Copyright (c) 2013 The Chromium OS Authors. 2fc3fe1c2SSimon Glass# 3fc3fe1c2SSimon Glass# See file CREDITS for list of people who contributed to this 4fc3fe1c2SSimon Glass# project. 5fc3fe1c2SSimon Glass# 6fc3fe1c2SSimon Glass# This program is free software; you can redistribute it and/or 7fc3fe1c2SSimon Glass# modify it under the terms of the GNU General Public License as 8fc3fe1c2SSimon Glass# published by the Free Software Foundation; either version 2 of 9fc3fe1c2SSimon Glass# the License, or (at your option) any later version. 10fc3fe1c2SSimon Glass# 11fc3fe1c2SSimon Glass# This program is distributed in the hope that it will be useful, 12fc3fe1c2SSimon Glass# but WITHOUT ANY WARRANTY; without even the implied warranty of 13fc3fe1c2SSimon Glass# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14fc3fe1c2SSimon Glass# GNU General Public License for more details. 15fc3fe1c2SSimon Glass# 16fc3fe1c2SSimon Glass# You should have received a copy of the GNU General Public License 17fc3fe1c2SSimon Glass# along with this program; if not, write to the Free Software 18fc3fe1c2SSimon Glass# Foundation, Inc., 59 Temple Place, Suite 330, Boston, 19fc3fe1c2SSimon Glass# MA 02111-1307 USA 20fc3fe1c2SSimon Glass# 21fc3fe1c2SSimon Glass 22fc3fe1c2SSimon Glassimport multiprocessing 23fc3fe1c2SSimon Glassimport os 24fc3fe1c2SSimon Glassimport sys 25fc3fe1c2SSimon Glass 26fc3fe1c2SSimon Glassimport board 27fc3fe1c2SSimon Glassimport bsettings 28fc3fe1c2SSimon Glassfrom builder import Builder 29fc3fe1c2SSimon Glassimport gitutil 30fc3fe1c2SSimon Glassimport patchstream 31fc3fe1c2SSimon Glassimport terminal 32fc3fe1c2SSimon Glassimport toolchain 33fc3fe1c2SSimon Glass 34fc3fe1c2SSimon Glassdef GetPlural(count): 35fc3fe1c2SSimon Glass """Returns a plural 's' if count is not 1""" 36fc3fe1c2SSimon Glass return 's' if count != 1 else '' 37fc3fe1c2SSimon Glass 38fc3fe1c2SSimon Glassdef GetActionSummary(is_summary, count, selected, options): 39fc3fe1c2SSimon Glass """Return a string summarising the intended action. 40fc3fe1c2SSimon Glass 41fc3fe1c2SSimon Glass Returns: 42fc3fe1c2SSimon Glass Summary string. 43fc3fe1c2SSimon Glass """ 44fc3fe1c2SSimon Glass count = (count + options.step - 1) / options.step 45fc3fe1c2SSimon Glass str = '%s %d commit%s for %d boards' % ( 46fc3fe1c2SSimon Glass 'Summary of' if is_summary else 'Building', count, GetPlural(count), 47fc3fe1c2SSimon Glass len(selected)) 48fc3fe1c2SSimon Glass str += ' (%d thread%s, %d job%s per thread)' % (options.threads, 49fc3fe1c2SSimon Glass GetPlural(options.threads), options.jobs, GetPlural(options.jobs)) 50fc3fe1c2SSimon Glass return str 51fc3fe1c2SSimon Glass 52fc3fe1c2SSimon Glassdef ShowActions(series, why_selected, boards_selected, builder, options): 53fc3fe1c2SSimon Glass """Display a list of actions that we would take, if not a dry run. 54fc3fe1c2SSimon Glass 55fc3fe1c2SSimon Glass Args: 56fc3fe1c2SSimon Glass series: Series object 57fc3fe1c2SSimon Glass why_selected: Dictionary where each key is a buildman argument 58fc3fe1c2SSimon Glass provided by the user, and the value is the boards brought 59fc3fe1c2SSimon Glass in by that argument. For example, 'arm' might bring in 60fc3fe1c2SSimon Glass 400 boards, so in this case the key would be 'arm' and 61fc3fe1c2SSimon Glass the value would be a list of board names. 62fc3fe1c2SSimon Glass boards_selected: Dict of selected boards, key is target name, 63fc3fe1c2SSimon Glass value is Board object 64fc3fe1c2SSimon Glass builder: The builder that will be used to build the commits 65fc3fe1c2SSimon Glass options: Command line options object 66fc3fe1c2SSimon Glass """ 67fc3fe1c2SSimon Glass col = terminal.Color() 68fc3fe1c2SSimon Glass print 'Dry run, so not doing much. But I would do this:' 69fc3fe1c2SSimon Glass print 70fc3fe1c2SSimon Glass print GetActionSummary(False, len(series.commits), boards_selected, 71fc3fe1c2SSimon Glass options) 72fc3fe1c2SSimon Glass print 'Build directory: %s' % builder.base_dir 73fc3fe1c2SSimon Glass for upto in range(0, len(series.commits), options.step): 74fc3fe1c2SSimon Glass commit = series.commits[upto] 75fc3fe1c2SSimon Glass print ' ', col.Color(col.YELLOW, commit.hash, bright=False), 76fc3fe1c2SSimon Glass print commit.subject 77fc3fe1c2SSimon Glass print 78fc3fe1c2SSimon Glass for arg in why_selected: 79fc3fe1c2SSimon Glass if arg != 'all': 80fc3fe1c2SSimon Glass print arg, ': %d boards' % why_selected[arg] 81fc3fe1c2SSimon Glass print ('Total boards to build for each commit: %d\n' % 82fc3fe1c2SSimon Glass why_selected['all']) 83fc3fe1c2SSimon Glass 84fc3fe1c2SSimon Glassdef DoBuildman(options, args): 85fc3fe1c2SSimon Glass """The main control code for buildman 86fc3fe1c2SSimon Glass 87fc3fe1c2SSimon Glass Args: 88fc3fe1c2SSimon Glass options: Command line options object 89fc3fe1c2SSimon Glass args: Command line arguments (list of strings) 90fc3fe1c2SSimon Glass """ 91fc3fe1c2SSimon Glass gitutil.Setup() 92fc3fe1c2SSimon Glass 93fc3fe1c2SSimon Glass bsettings.Setup() 94fc3fe1c2SSimon Glass options.git_dir = os.path.join(options.git, '.git') 95fc3fe1c2SSimon Glass 96fc3fe1c2SSimon Glass toolchains = toolchain.Toolchains() 97fc3fe1c2SSimon Glass toolchains.Scan(options.list_tool_chains) 98fc3fe1c2SSimon Glass if options.list_tool_chains: 99fc3fe1c2SSimon Glass toolchains.List() 100fc3fe1c2SSimon Glass print 101fc3fe1c2SSimon Glass return 102fc3fe1c2SSimon Glass 103fc3fe1c2SSimon Glass # Work out how many commits to build. We want to build everything on the 104fc3fe1c2SSimon Glass # branch. We also build the upstream commit as a control so we can see 105fc3fe1c2SSimon Glass # problems introduced by the first commit on the branch. 106fc3fe1c2SSimon Glass col = terminal.Color() 107fc3fe1c2SSimon Glass count = options.count 108fc3fe1c2SSimon Glass if count == -1: 109fc3fe1c2SSimon Glass if not options.branch: 110fc3fe1c2SSimon Glass str = 'Please use -b to specify a branch to build' 111fc3fe1c2SSimon Glass print col.Color(col.RED, str) 112fc3fe1c2SSimon Glass sys.exit(1) 113fc3fe1c2SSimon Glass count = gitutil.CountCommitsInBranch(options.git_dir, options.branch) 114*cce717a9SSimon Glass if count is None: 115*cce717a9SSimon Glass str = "Branch '%s' not found or has no upstream" % options.branch 116*cce717a9SSimon Glass print col.Color(col.RED, str) 117*cce717a9SSimon Glass sys.exit(1) 118fc3fe1c2SSimon Glass count += 1 # Build upstream commit also 119fc3fe1c2SSimon Glass 120fc3fe1c2SSimon Glass if not count: 121fc3fe1c2SSimon Glass str = ("No commits found to process in branch '%s': " 122fc3fe1c2SSimon Glass "set branch's upstream or use -c flag" % options.branch) 123fc3fe1c2SSimon Glass print col.Color(col.RED, str) 124fc3fe1c2SSimon Glass sys.exit(1) 125fc3fe1c2SSimon Glass 126fc3fe1c2SSimon Glass # Work out what subset of the boards we are building 127fc3fe1c2SSimon Glass boards = board.Boards() 128fc3fe1c2SSimon Glass boards.ReadBoards(os.path.join(options.git, 'boards.cfg')) 129fc3fe1c2SSimon Glass why_selected = boards.SelectBoards(args) 130fc3fe1c2SSimon Glass selected = boards.GetSelected() 131fc3fe1c2SSimon Glass if not len(selected): 132fc3fe1c2SSimon Glass print col.Color(col.RED, 'No matching boards found') 133fc3fe1c2SSimon Glass sys.exit(1) 134fc3fe1c2SSimon Glass 135fc3fe1c2SSimon Glass # Read the metadata from the commits. First look at the upstream commit, 136fc3fe1c2SSimon Glass # then the ones in the branch. We would like to do something like 137fc3fe1c2SSimon Glass # upstream/master~..branch but that isn't possible if upstream/master is 138fc3fe1c2SSimon Glass # a merge commit (it will list all the commits that form part of the 139fc3fe1c2SSimon Glass # merge) 140fc3fe1c2SSimon Glass range_expr = gitutil.GetRangeInBranch(options.git_dir, options.branch) 141fc3fe1c2SSimon Glass upstream_commit = gitutil.GetUpstream(options.git_dir, options.branch) 142fc3fe1c2SSimon Glass series = patchstream.GetMetaDataForList(upstream_commit, options.git_dir, 143fc3fe1c2SSimon Glass 1) 144f0b739f1SSimon Glass # Conflicting tags are not a problem for buildman, since it does not use 145f0b739f1SSimon Glass # them. For example, Series-version is not useful for buildman. On the 146f0b739f1SSimon Glass # other hand conflicting tags will cause an error. So allow later tags 147f0b739f1SSimon Glass # to overwrite earlier ones. 148f0b739f1SSimon Glass series.allow_overwrite = True 149fc3fe1c2SSimon Glass series = patchstream.GetMetaDataForList(range_expr, options.git_dir, None, 150fc3fe1c2SSimon Glass series) 151fc3fe1c2SSimon Glass 152fc3fe1c2SSimon Glass # By default we have one thread per CPU. But if there are not enough jobs 153fc3fe1c2SSimon Glass # we can have fewer threads and use a high '-j' value for make. 154fc3fe1c2SSimon Glass if not options.threads: 155fc3fe1c2SSimon Glass options.threads = min(multiprocessing.cpu_count(), len(selected)) 156fc3fe1c2SSimon Glass if not options.jobs: 157fc3fe1c2SSimon Glass options.jobs = max(1, (multiprocessing.cpu_count() + 158fc3fe1c2SSimon Glass len(selected) - 1) / len(selected)) 159fc3fe1c2SSimon Glass 160fc3fe1c2SSimon Glass if not options.step: 161fc3fe1c2SSimon Glass options.step = len(series.commits) - 1 162fc3fe1c2SSimon Glass 163fc3fe1c2SSimon Glass # Create a new builder with the selected options 164fc3fe1c2SSimon Glass output_dir = os.path.join('..', options.branch) 165fc3fe1c2SSimon Glass builder = Builder(toolchains, output_dir, options.git_dir, 166fc3fe1c2SSimon Glass options.threads, options.jobs, checkout=True, 167fc3fe1c2SSimon Glass show_unknown=options.show_unknown, step=options.step) 168fc3fe1c2SSimon Glass builder.force_config_on_failure = not options.quick 169fc3fe1c2SSimon Glass 170fc3fe1c2SSimon Glass # For a dry run, just show our actions as a sanity check 171fc3fe1c2SSimon Glass if options.dry_run: 172fc3fe1c2SSimon Glass ShowActions(series, why_selected, selected, builder, options) 173fc3fe1c2SSimon Glass else: 174fc3fe1c2SSimon Glass builder.force_build = options.force_build 175fc3fe1c2SSimon Glass 176fc3fe1c2SSimon Glass # Work out which boards to build 177fc3fe1c2SSimon Glass board_selected = boards.GetSelectedDict() 178fc3fe1c2SSimon Glass 179fc3fe1c2SSimon Glass print GetActionSummary(options.summary, count, board_selected, options) 180fc3fe1c2SSimon Glass 181fc3fe1c2SSimon Glass if options.summary: 182fc3fe1c2SSimon Glass # We can't show function sizes without board details at present 183fc3fe1c2SSimon Glass if options.show_bloat: 184fc3fe1c2SSimon Glass options.show_detail = True 185fc3fe1c2SSimon Glass builder.ShowSummary(series.commits, board_selected, 186fc3fe1c2SSimon Glass options.show_errors, options.show_sizes, 187fc3fe1c2SSimon Glass options.show_detail, options.show_bloat) 188fc3fe1c2SSimon Glass else: 189fc3fe1c2SSimon Glass builder.BuildBoards(series.commits, board_selected, 190fc3fe1c2SSimon Glass options.show_errors, options.keep_outputs) 191