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