diff options
Diffstat (limited to 'tools/buildman/control.py')
| -rw-r--r-- | tools/buildman/control.py | 181 | 
1 files changed, 181 insertions, 0 deletions
| diff --git a/tools/buildman/control.py b/tools/buildman/control.py new file mode 100644 index 000000000..8d7b9b547 --- /dev/null +++ b/tools/buildman/control.py @@ -0,0 +1,181 @@ +# Copyright (c) 2013 The Chromium OS Authors. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +import multiprocessing +import os +import sys + +import board +import bsettings +from builder import Builder +import gitutil +import patchstream +import terminal +import toolchain + +def GetPlural(count): +    """Returns a plural 's' if count is not 1""" +    return 's' if count != 1 else '' + +def GetActionSummary(is_summary, count, selected, options): +    """Return a string summarising the intended action. + +    Returns: +        Summary string. +    """ +    count = (count + options.step - 1) / options.step +    str = '%s %d commit%s for %d boards' % ( +        'Summary of' if is_summary else 'Building', count, GetPlural(count), +        len(selected)) +    str += ' (%d thread%s, %d job%s per thread)' % (options.threads, +            GetPlural(options.threads), options.jobs, GetPlural(options.jobs)) +    return str + +def ShowActions(series, why_selected, boards_selected, builder, options): +    """Display a list of actions that we would take, if not a dry run. + +    Args: +        series: Series object +        why_selected: Dictionary where each key is a buildman argument +                provided by the user, and the value is the boards brought +                in by that argument. For example, 'arm' might bring in +                400 boards, so in this case the key would be 'arm' and +                the value would be a list of board names. +        boards_selected: Dict of selected boards, key is target name, +                value is Board object +        builder: The builder that will be used to build the commits +        options: Command line options object +    """ +    col = terminal.Color() +    print 'Dry run, so not doing much. But I would do this:' +    print +    print GetActionSummary(False, len(series.commits), boards_selected, +            options) +    print 'Build directory: %s' % builder.base_dir +    for upto in range(0, len(series.commits), options.step): +        commit = series.commits[upto] +        print '   ', col.Color(col.YELLOW, commit.hash, bright=False), +        print commit.subject +    print +    for arg in why_selected: +        if arg != 'all': +            print arg, ': %d boards' % why_selected[arg] +    print ('Total boards to build for each commit: %d\n' % +            why_selected['all']) + +def DoBuildman(options, args): +    """The main control code for buildman + +    Args: +        options: Command line options object +        args: Command line arguments (list of strings) +    """ +    gitutil.Setup() + +    bsettings.Setup() +    options.git_dir = os.path.join(options.git, '.git') + +    toolchains = toolchain.Toolchains() +    toolchains.Scan(options.list_tool_chains) +    if options.list_tool_chains: +        toolchains.List() +        print +        return + +    # Work out how many commits to build. We want to build everything on the +    # branch. We also build the upstream commit as a control so we can see +    # problems introduced by the first commit on the branch. +    col = terminal.Color() +    count = options.count +    if count == -1: +        if not options.branch: +            str = 'Please use -b to specify a branch to build' +            print col.Color(col.RED, str) +            sys.exit(1) +        count = gitutil.CountCommitsInBranch(options.git_dir, options.branch) +        count += 1   # Build upstream commit also + +    if not count: +        str = ("No commits found to process in branch '%s': " +               "set branch's upstream or use -c flag" % options.branch) +        print col.Color(col.RED, str) +        sys.exit(1) + +    # Work out what subset of the boards we are building +    boards = board.Boards() +    boards.ReadBoards(os.path.join(options.git, 'boards.cfg')) +    why_selected = boards.SelectBoards(args) +    selected = boards.GetSelected() +    if not len(selected): +        print col.Color(col.RED, 'No matching boards found') +        sys.exit(1) + +    # Read the metadata from the commits. First look at the upstream commit, +    # then the ones in the branch. We would like to do something like +    # upstream/master~..branch but that isn't possible if upstream/master is +    # a merge commit (it will list all the commits that form part of the +    # merge) +    range_expr = gitutil.GetRangeInBranch(options.git_dir, options.branch) +    upstream_commit = gitutil.GetUpstream(options.git_dir, options.branch) +    series = patchstream.GetMetaDataForList(upstream_commit, options.git_dir, +            1) +    series = patchstream.GetMetaDataForList(range_expr, options.git_dir, None, +            series) + +    # By default we have one thread per CPU. But if there are not enough jobs +    # we can have fewer threads and use a high '-j' value for make. +    if not options.threads: +        options.threads = min(multiprocessing.cpu_count(), len(selected)) +    if not options.jobs: +        options.jobs = max(1, (multiprocessing.cpu_count() + +                len(selected) - 1) / len(selected)) + +    if not options.step: +        options.step = len(series.commits) - 1 + +    # Create a new builder with the selected options +    output_dir = os.path.join('..', options.branch) +    builder = Builder(toolchains, output_dir, options.git_dir, +            options.threads, options.jobs, checkout=True, +            show_unknown=options.show_unknown, step=options.step) +    builder.force_config_on_failure = not options.quick + +    # For a dry run, just show our actions as a sanity check +    if options.dry_run: +        ShowActions(series, why_selected, selected, builder, options) +    else: +        builder.force_build = options.force_build + +        # Work out which boards to build +        board_selected = boards.GetSelectedDict() + +        print GetActionSummary(options.summary, count, board_selected, options) + +        if options.summary: +            # We can't show function sizes without board details at present +            if options.show_bloat: +                options.show_detail = True +            builder.ShowSummary(series.commits, board_selected, +                    options.show_errors, options.show_sizes, +                    options.show_detail, options.show_bloat) +        else: +            builder.BuildBoards(series.commits, board_selected, +                    options.show_errors, options.keep_outputs) |