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