xref: /rk3399_rockchip-uboot/tools/buildman/builderthread.py (revision 40f11fce7c686f2b51ae109c4085fb5988c5631c)
1190064b4SSimon Glass# Copyright (c) 2014 Google, Inc
2190064b4SSimon Glass#
3190064b4SSimon Glass# SPDX-License-Identifier:      GPL-2.0+
4190064b4SSimon Glass#
5190064b4SSimon Glass
6190064b4SSimon Glassimport errno
7190064b4SSimon Glassimport glob
8190064b4SSimon Glassimport os
9190064b4SSimon Glassimport shutil
10190064b4SSimon Glassimport threading
11190064b4SSimon Glass
12190064b4SSimon Glassimport command
13190064b4SSimon Glassimport gitutil
14190064b4SSimon Glass
15f3d015cbSThierry Redingdef Mkdir(dirname, parents = False):
16190064b4SSimon Glass    """Make a directory if it doesn't already exist.
17190064b4SSimon Glass
18190064b4SSimon Glass    Args:
19190064b4SSimon Glass        dirname: Directory to create
20190064b4SSimon Glass    """
21190064b4SSimon Glass    try:
22f3d015cbSThierry Reding        if parents:
23f3d015cbSThierry Reding            os.makedirs(dirname)
24f3d015cbSThierry Reding        else:
25190064b4SSimon Glass            os.mkdir(dirname)
26190064b4SSimon Glass    except OSError as err:
27190064b4SSimon Glass        if err.errno == errno.EEXIST:
28190064b4SSimon Glass            pass
29190064b4SSimon Glass        else:
30190064b4SSimon Glass            raise
31190064b4SSimon Glass
32190064b4SSimon Glassclass BuilderJob:
33190064b4SSimon Glass    """Holds information about a job to be performed by a thread
34190064b4SSimon Glass
35190064b4SSimon Glass    Members:
36190064b4SSimon Glass        board: Board object to build
37190064b4SSimon Glass        commits: List of commit options to build.
38190064b4SSimon Glass    """
39190064b4SSimon Glass    def __init__(self):
40190064b4SSimon Glass        self.board = None
41190064b4SSimon Glass        self.commits = []
42190064b4SSimon Glass
43190064b4SSimon Glass
44190064b4SSimon Glassclass ResultThread(threading.Thread):
45190064b4SSimon Glass    """This thread processes results from builder threads.
46190064b4SSimon Glass
47190064b4SSimon Glass    It simply passes the results on to the builder. There is only one
48190064b4SSimon Glass    result thread, and this helps to serialise the build output.
49190064b4SSimon Glass    """
50190064b4SSimon Glass    def __init__(self, builder):
51190064b4SSimon Glass        """Set up a new result thread
52190064b4SSimon Glass
53190064b4SSimon Glass        Args:
54190064b4SSimon Glass            builder: Builder which will be sent each result
55190064b4SSimon Glass        """
56190064b4SSimon Glass        threading.Thread.__init__(self)
57190064b4SSimon Glass        self.builder = builder
58190064b4SSimon Glass
59190064b4SSimon Glass    def run(self):
60190064b4SSimon Glass        """Called to start up the result thread.
61190064b4SSimon Glass
62190064b4SSimon Glass        We collect the next result job and pass it on to the build.
63190064b4SSimon Glass        """
64190064b4SSimon Glass        while True:
65190064b4SSimon Glass            result = self.builder.out_queue.get()
66190064b4SSimon Glass            self.builder.ProcessResult(result)
67190064b4SSimon Glass            self.builder.out_queue.task_done()
68190064b4SSimon Glass
69190064b4SSimon Glass
70190064b4SSimon Glassclass BuilderThread(threading.Thread):
71190064b4SSimon Glass    """This thread builds U-Boot for a particular board.
72190064b4SSimon Glass
73190064b4SSimon Glass    An input queue provides each new job. We run 'make' to build U-Boot
74190064b4SSimon Glass    and then pass the results on to the output queue.
75190064b4SSimon Glass
76190064b4SSimon Glass    Members:
77190064b4SSimon Glass        builder: The builder which contains information we might need
78190064b4SSimon Glass        thread_num: Our thread number (0-n-1), used to decide on a
79190064b4SSimon Glass                temporary directory
80190064b4SSimon Glass    """
81190064b4SSimon Glass    def __init__(self, builder, thread_num):
82190064b4SSimon Glass        """Set up a new builder thread"""
83190064b4SSimon Glass        threading.Thread.__init__(self)
84190064b4SSimon Glass        self.builder = builder
85190064b4SSimon Glass        self.thread_num = thread_num
86190064b4SSimon Glass
87190064b4SSimon Glass    def Make(self, commit, brd, stage, cwd, *args, **kwargs):
88190064b4SSimon Glass        """Run 'make' on a particular commit and board.
89190064b4SSimon Glass
90190064b4SSimon Glass        The source code will already be checked out, so the 'commit'
91190064b4SSimon Glass        argument is only for information.
92190064b4SSimon Glass
93190064b4SSimon Glass        Args:
94190064b4SSimon Glass            commit: Commit object that is being built
95190064b4SSimon Glass            brd: Board object that is being built
96190064b4SSimon Glass            stage: Stage of the build. Valid stages are:
97fd18a89eSRoger Meier                        mrproper - can be called to clean source
98190064b4SSimon Glass                        config - called to configure for a board
99190064b4SSimon Glass                        build - the main make invocation - it does the build
100190064b4SSimon Glass            args: A list of arguments to pass to 'make'
101190064b4SSimon Glass            kwargs: A list of keyword arguments to pass to command.RunPipe()
102190064b4SSimon Glass
103190064b4SSimon Glass        Returns:
104190064b4SSimon Glass            CommandResult object
105190064b4SSimon Glass        """
106190064b4SSimon Glass        return self.builder.do_make(commit, brd, stage, cwd, *args,
107190064b4SSimon Glass                **kwargs)
108190064b4SSimon Glass
109190064b4SSimon Glass    def RunCommit(self, commit_upto, brd, work_dir, do_config, force_build,
110190064b4SSimon Glass                  force_build_failures):
111190064b4SSimon Glass        """Build a particular commit.
112190064b4SSimon Glass
113190064b4SSimon Glass        If the build is already done, and we are not forcing a build, we skip
114190064b4SSimon Glass        the build and just return the previously-saved results.
115190064b4SSimon Glass
116190064b4SSimon Glass        Args:
117190064b4SSimon Glass            commit_upto: Commit number to build (0...n-1)
118190064b4SSimon Glass            brd: Board object to build
119190064b4SSimon Glass            work_dir: Directory to which the source will be checked out
120190064b4SSimon Glass            do_config: True to run a make <board>_defconfig on the source
121190064b4SSimon Glass            force_build: Force a build even if one was previously done
122190064b4SSimon Glass            force_build_failures: Force a bulid if the previous result showed
123190064b4SSimon Glass                failure
124190064b4SSimon Glass
125190064b4SSimon Glass        Returns:
126190064b4SSimon Glass            tuple containing:
127190064b4SSimon Glass                - CommandResult object containing the results of the build
128190064b4SSimon Glass                - boolean indicating whether 'make config' is still needed
129190064b4SSimon Glass        """
130190064b4SSimon Glass        # Create a default result - it will be overwritte by the call to
131190064b4SSimon Glass        # self.Make() below, in the event that we do a build.
132190064b4SSimon Glass        result = command.CommandResult()
133190064b4SSimon Glass        result.return_code = 0
134190064b4SSimon Glass        if self.builder.in_tree:
135190064b4SSimon Glass            out_dir = work_dir
136190064b4SSimon Glass        else:
137190064b4SSimon Glass            out_dir = os.path.join(work_dir, 'build')
138190064b4SSimon Glass
139190064b4SSimon Glass        # Check if the job was already completed last time
140190064b4SSimon Glass        done_file = self.builder.GetDoneFile(commit_upto, brd.target)
141190064b4SSimon Glass        result.already_done = os.path.exists(done_file)
142190064b4SSimon Glass        will_build = (force_build or force_build_failures or
143190064b4SSimon Glass            not result.already_done)
144fb3954f9SSimon Glass        if result.already_done:
145190064b4SSimon Glass            # Get the return code from that build and use it
146190064b4SSimon Glass            with open(done_file, 'r') as fd:
147190064b4SSimon Glass                result.return_code = int(fd.readline())
148fb3954f9SSimon Glass            if will_build:
149190064b4SSimon Glass                err_file = self.builder.GetErrFile(commit_upto, brd.target)
150190064b4SSimon Glass                if os.path.exists(err_file) and os.stat(err_file).st_size:
151190064b4SSimon Glass                    result.stderr = 'bad'
152190064b4SSimon Glass                elif not force_build:
153190064b4SSimon Glass                    # The build passed, so no need to build it again
154190064b4SSimon Glass                    will_build = False
155190064b4SSimon Glass
156190064b4SSimon Glass        if will_build:
157190064b4SSimon Glass            # We are going to have to build it. First, get a toolchain
158190064b4SSimon Glass            if not self.toolchain:
159190064b4SSimon Glass                try:
160190064b4SSimon Glass                    self.toolchain = self.builder.toolchains.Select(brd.arch)
161190064b4SSimon Glass                except ValueError as err:
162190064b4SSimon Glass                    result.return_code = 10
163190064b4SSimon Glass                    result.stdout = ''
164190064b4SSimon Glass                    result.stderr = str(err)
165190064b4SSimon Glass                    # TODO(sjg@chromium.org): This gets swallowed, but needs
166190064b4SSimon Glass                    # to be reported.
167190064b4SSimon Glass
168190064b4SSimon Glass            if self.toolchain:
169190064b4SSimon Glass                # Checkout the right commit
170190064b4SSimon Glass                if self.builder.commits:
171190064b4SSimon Glass                    commit = self.builder.commits[commit_upto]
172190064b4SSimon Glass                    if self.builder.checkout:
173190064b4SSimon Glass                        git_dir = os.path.join(work_dir, '.git')
174190064b4SSimon Glass                        gitutil.Checkout(commit.hash, git_dir, work_dir,
175190064b4SSimon Glass                                         force=True)
176190064b4SSimon Glass                else:
177190064b4SSimon Glass                    commit = 'current'
178190064b4SSimon Glass
179190064b4SSimon Glass                # Set up the environment and command line
180bb1501f2SSimon Glass                env = self.toolchain.MakeEnvironment(self.builder.full_path)
181190064b4SSimon Glass                Mkdir(out_dir)
182190064b4SSimon Glass                args = []
183190064b4SSimon Glass                cwd = work_dir
18448c1b6a8SSimon Glass                src_dir = os.path.realpath(work_dir)
185190064b4SSimon Glass                if not self.builder.in_tree:
186190064b4SSimon Glass                    if commit_upto is None:
187190064b4SSimon Glass                        # In this case we are building in the original source
188190064b4SSimon Glass                        # directory (i.e. the current directory where buildman
189190064b4SSimon Glass                        # is invoked. The output directory is set to this
190190064b4SSimon Glass                        # thread's selected work directory.
191190064b4SSimon Glass                        #
192190064b4SSimon Glass                        # Symlinks can confuse U-Boot's Makefile since
193190064b4SSimon Glass                        # we may use '..' in our path, so remove them.
194190064b4SSimon Glass                        work_dir = os.path.realpath(work_dir)
195190064b4SSimon Glass                        args.append('O=%s/build' % work_dir)
196190064b4SSimon Glass                        cwd = None
19748c1b6a8SSimon Glass                        src_dir = os.getcwd()
198190064b4SSimon Glass                    else:
199190064b4SSimon Glass                        args.append('O=build')
200d2ce658dSSimon Glass                if not self.builder.verbose_build:
201190064b4SSimon Glass                    args.append('-s')
202190064b4SSimon Glass                if self.builder.num_jobs is not None:
203190064b4SSimon Glass                    args.extend(['-j', str(self.builder.num_jobs)])
204190064b4SSimon Glass                config_args = ['%s_defconfig' % brd.target]
205190064b4SSimon Glass                config_out = ''
206190064b4SSimon Glass                args.extend(self.builder.toolchains.GetMakeArguments(brd))
207190064b4SSimon Glass
208190064b4SSimon Glass                # If we need to reconfigure, do that now
209190064b4SSimon Glass                if do_config:
210fd18a89eSRoger Meier                    result = self.Make(commit, brd, 'mrproper', cwd,
211fd18a89eSRoger Meier                            'mrproper', *args, env=env)
212*40f11fceSSimon Glass                    config_out = result.combined
213190064b4SSimon Glass                    result = self.Make(commit, brd, 'config', cwd,
214190064b4SSimon Glass                            *(args + config_args), env=env)
215*40f11fceSSimon Glass                    config_out += result.combined
216190064b4SSimon Glass                    do_config = False   # No need to configure next time
217190064b4SSimon Glass                if result.return_code == 0:
218190064b4SSimon Glass                    result = self.Make(commit, brd, 'build', cwd, *args,
219190064b4SSimon Glass                            env=env)
22048c1b6a8SSimon Glass                result.stderr = result.stderr.replace(src_dir + '/', '')
221*40f11fceSSimon Glass                if self.builder.verbose_build:
222*40f11fceSSimon Glass                    result.stdout = config_out + result.stdout
223190064b4SSimon Glass            else:
224190064b4SSimon Glass                result.return_code = 1
225190064b4SSimon Glass                result.stderr = 'No tool chain for %s\n' % brd.arch
226190064b4SSimon Glass            result.already_done = False
227190064b4SSimon Glass
228190064b4SSimon Glass        result.toolchain = self.toolchain
229190064b4SSimon Glass        result.brd = brd
230190064b4SSimon Glass        result.commit_upto = commit_upto
231190064b4SSimon Glass        result.out_dir = out_dir
232190064b4SSimon Glass        return result, do_config
233190064b4SSimon Glass
234190064b4SSimon Glass    def _WriteResult(self, result, keep_outputs):
235190064b4SSimon Glass        """Write a built result to the output directory.
236190064b4SSimon Glass
237190064b4SSimon Glass        Args:
238190064b4SSimon Glass            result: CommandResult object containing result to write
239190064b4SSimon Glass            keep_outputs: True to store the output binaries, False
240190064b4SSimon Glass                to delete them
241190064b4SSimon Glass        """
242190064b4SSimon Glass        # Fatal error
243190064b4SSimon Glass        if result.return_code < 0:
244190064b4SSimon Glass            return
245190064b4SSimon Glass
246190064b4SSimon Glass        # Aborted?
247190064b4SSimon Glass        if result.stderr and 'No child processes' in result.stderr:
248190064b4SSimon Glass            return
249190064b4SSimon Glass
250190064b4SSimon Glass        if result.already_done:
251190064b4SSimon Glass            return
252190064b4SSimon Glass
253190064b4SSimon Glass        # Write the output and stderr
254190064b4SSimon Glass        output_dir = self.builder._GetOutputDir(result.commit_upto)
255190064b4SSimon Glass        Mkdir(output_dir)
256190064b4SSimon Glass        build_dir = self.builder.GetBuildDir(result.commit_upto,
257190064b4SSimon Glass                result.brd.target)
258190064b4SSimon Glass        Mkdir(build_dir)
259190064b4SSimon Glass
260190064b4SSimon Glass        outfile = os.path.join(build_dir, 'log')
261190064b4SSimon Glass        with open(outfile, 'w') as fd:
262190064b4SSimon Glass            if result.stdout:
263190064b4SSimon Glass                fd.write(result.stdout)
264190064b4SSimon Glass
265190064b4SSimon Glass        errfile = self.builder.GetErrFile(result.commit_upto,
266190064b4SSimon Glass                result.brd.target)
267190064b4SSimon Glass        if result.stderr:
268190064b4SSimon Glass            with open(errfile, 'w') as fd:
269190064b4SSimon Glass                fd.write(result.stderr)
270190064b4SSimon Glass        elif os.path.exists(errfile):
271190064b4SSimon Glass            os.remove(errfile)
272190064b4SSimon Glass
273190064b4SSimon Glass        if result.toolchain:
274190064b4SSimon Glass            # Write the build result and toolchain information.
275190064b4SSimon Glass            done_file = self.builder.GetDoneFile(result.commit_upto,
276190064b4SSimon Glass                    result.brd.target)
277190064b4SSimon Glass            with open(done_file, 'w') as fd:
278190064b4SSimon Glass                fd.write('%s' % result.return_code)
279190064b4SSimon Glass            with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
280190064b4SSimon Glass                print >>fd, 'gcc', result.toolchain.gcc
281190064b4SSimon Glass                print >>fd, 'path', result.toolchain.path
282190064b4SSimon Glass                print >>fd, 'cross', result.toolchain.cross
283190064b4SSimon Glass                print >>fd, 'arch', result.toolchain.arch
284190064b4SSimon Glass                fd.write('%s' % result.return_code)
285190064b4SSimon Glass
286190064b4SSimon Glass            with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
287190064b4SSimon Glass                print >>fd, 'gcc', result.toolchain.gcc
288190064b4SSimon Glass                print >>fd, 'path', result.toolchain.path
289190064b4SSimon Glass
290190064b4SSimon Glass            # Write out the image and function size information and an objdump
291bb1501f2SSimon Glass            env = result.toolchain.MakeEnvironment(self.builder.full_path)
292190064b4SSimon Glass            lines = []
293190064b4SSimon Glass            for fname in ['u-boot', 'spl/u-boot-spl']:
294190064b4SSimon Glass                cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
295190064b4SSimon Glass                nm_result = command.RunPipe([cmd], capture=True,
296190064b4SSimon Glass                        capture_stderr=True, cwd=result.out_dir,
297190064b4SSimon Glass                        raise_on_error=False, env=env)
298190064b4SSimon Glass                if nm_result.stdout:
299190064b4SSimon Glass                    nm = self.builder.GetFuncSizesFile(result.commit_upto,
300190064b4SSimon Glass                                    result.brd.target, fname)
301190064b4SSimon Glass                    with open(nm, 'w') as fd:
302190064b4SSimon Glass                        print >>fd, nm_result.stdout,
303190064b4SSimon Glass
304190064b4SSimon Glass                cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname]
305190064b4SSimon Glass                dump_result = command.RunPipe([cmd], capture=True,
306190064b4SSimon Glass                        capture_stderr=True, cwd=result.out_dir,
307190064b4SSimon Glass                        raise_on_error=False, env=env)
308190064b4SSimon Glass                rodata_size = ''
309190064b4SSimon Glass                if dump_result.stdout:
310190064b4SSimon Glass                    objdump = self.builder.GetObjdumpFile(result.commit_upto,
311190064b4SSimon Glass                                    result.brd.target, fname)
312190064b4SSimon Glass                    with open(objdump, 'w') as fd:
313190064b4SSimon Glass                        print >>fd, dump_result.stdout,
314190064b4SSimon Glass                    for line in dump_result.stdout.splitlines():
315190064b4SSimon Glass                        fields = line.split()
316190064b4SSimon Glass                        if len(fields) > 5 and fields[1] == '.rodata':
317190064b4SSimon Glass                            rodata_size = fields[2]
318190064b4SSimon Glass
319190064b4SSimon Glass                cmd = ['%ssize' % self.toolchain.cross, fname]
320190064b4SSimon Glass                size_result = command.RunPipe([cmd], capture=True,
321190064b4SSimon Glass                        capture_stderr=True, cwd=result.out_dir,
322190064b4SSimon Glass                        raise_on_error=False, env=env)
323190064b4SSimon Glass                if size_result.stdout:
324190064b4SSimon Glass                    lines.append(size_result.stdout.splitlines()[1] + ' ' +
325190064b4SSimon Glass                                 rodata_size)
326190064b4SSimon Glass
327190064b4SSimon Glass            # Write out the image sizes file. This is similar to the output
328190064b4SSimon Glass            # of binutil's 'size' utility, but it omits the header line and
329190064b4SSimon Glass            # adds an additional hex value at the end of each line for the
330190064b4SSimon Glass            # rodata size
331190064b4SSimon Glass            if len(lines):
332190064b4SSimon Glass                sizes = self.builder.GetSizesFile(result.commit_upto,
333190064b4SSimon Glass                                result.brd.target)
334190064b4SSimon Glass                with open(sizes, 'w') as fd:
335190064b4SSimon Glass                    print >>fd, '\n'.join(lines)
336190064b4SSimon Glass
337190064b4SSimon Glass        # Now write the actual build output
338190064b4SSimon Glass        if keep_outputs:
339ce267335STom Rini            patterns = ['u-boot', '*.bin', 'u-boot.dtb', '*.map', '*.img',
340190064b4SSimon Glass                        'include/autoconf.mk', 'spl/u-boot-spl',
341190064b4SSimon Glass                        'spl/u-boot-spl.bin']
342190064b4SSimon Glass            for pattern in patterns:
343190064b4SSimon Glass                file_list = glob.glob(os.path.join(result.out_dir, pattern))
344190064b4SSimon Glass                for fname in file_list:
345190064b4SSimon Glass                    shutil.copy(fname, build_dir)
346190064b4SSimon Glass
347190064b4SSimon Glass
348190064b4SSimon Glass    def RunJob(self, job):
349190064b4SSimon Glass        """Run a single job
350190064b4SSimon Glass
351190064b4SSimon Glass        A job consists of a building a list of commits for a particular board.
352190064b4SSimon Glass
353190064b4SSimon Glass        Args:
354190064b4SSimon Glass            job: Job to build
355190064b4SSimon Glass        """
356190064b4SSimon Glass        brd = job.board
357190064b4SSimon Glass        work_dir = self.builder.GetThreadDir(self.thread_num)
358190064b4SSimon Glass        self.toolchain = None
359190064b4SSimon Glass        if job.commits:
360190064b4SSimon Glass            # Run 'make board_defconfig' on the first commit
361190064b4SSimon Glass            do_config = True
362190064b4SSimon Glass            commit_upto  = 0
363190064b4SSimon Glass            force_build = False
364190064b4SSimon Glass            for commit_upto in range(0, len(job.commits), job.step):
365190064b4SSimon Glass                result, request_config = self.RunCommit(commit_upto, brd,
366190064b4SSimon Glass                        work_dir, do_config,
367190064b4SSimon Glass                        force_build or self.builder.force_build,
368190064b4SSimon Glass                        self.builder.force_build_failures)
369190064b4SSimon Glass                failed = result.return_code or result.stderr
370190064b4SSimon Glass                did_config = do_config
371190064b4SSimon Glass                if failed and not do_config:
372190064b4SSimon Glass                    # If our incremental build failed, try building again
373190064b4SSimon Glass                    # with a reconfig.
374190064b4SSimon Glass                    if self.builder.force_config_on_failure:
375190064b4SSimon Glass                        result, request_config = self.RunCommit(commit_upto,
376190064b4SSimon Glass                            brd, work_dir, True, True, False)
377190064b4SSimon Glass                        did_config = True
378190064b4SSimon Glass                if not self.builder.force_reconfig:
379190064b4SSimon Glass                    do_config = request_config
380190064b4SSimon Glass
381190064b4SSimon Glass                # If we built that commit, then config is done. But if we got
382190064b4SSimon Glass                # an warning, reconfig next time to force it to build the same
383190064b4SSimon Glass                # files that created warnings this time. Otherwise an
384190064b4SSimon Glass                # incremental build may not build the same file, and we will
385190064b4SSimon Glass                # think that the warning has gone away.
386190064b4SSimon Glass                # We could avoid this by using -Werror everywhere...
387190064b4SSimon Glass                # For errors, the problem doesn't happen, since presumably
388190064b4SSimon Glass                # the build stopped and didn't generate output, so will retry
389190064b4SSimon Glass                # that file next time. So we could detect warnings and deal
390190064b4SSimon Glass                # with them specially here. For now, we just reconfigure if
391190064b4SSimon Glass                # anything goes work.
392190064b4SSimon Glass                # Of course this is substantially slower if there are build
393190064b4SSimon Glass                # errors/warnings (e.g. 2-3x slower even if only 10% of builds
394190064b4SSimon Glass                # have problems).
395190064b4SSimon Glass                if (failed and not result.already_done and not did_config and
396190064b4SSimon Glass                        self.builder.force_config_on_failure):
397190064b4SSimon Glass                    # If this build failed, try the next one with a
398190064b4SSimon Glass                    # reconfigure.
399190064b4SSimon Glass                    # Sometimes if the board_config.h file changes it can mess
400190064b4SSimon Glass                    # with dependencies, and we get:
401190064b4SSimon Glass                    # make: *** No rule to make target `include/autoconf.mk',
402190064b4SSimon Glass                    #     needed by `depend'.
403190064b4SSimon Glass                    do_config = True
404190064b4SSimon Glass                    force_build = True
405190064b4SSimon Glass                else:
406190064b4SSimon Glass                    force_build = False
407190064b4SSimon Glass                    if self.builder.force_config_on_failure:
408190064b4SSimon Glass                        if failed:
409190064b4SSimon Glass                            do_config = True
410190064b4SSimon Glass                    result.commit_upto = commit_upto
411190064b4SSimon Glass                    if result.return_code < 0:
412190064b4SSimon Glass                        raise ValueError('Interrupt')
413190064b4SSimon Glass
414190064b4SSimon Glass                # We have the build results, so output the result
415190064b4SSimon Glass                self._WriteResult(result, job.keep_outputs)
416190064b4SSimon Glass                self.builder.out_queue.put(result)
417190064b4SSimon Glass        else:
418190064b4SSimon Glass            # Just build the currently checked-out build
419190064b4SSimon Glass            result, request_config = self.RunCommit(None, brd, work_dir, True,
420190064b4SSimon Glass                        True, self.builder.force_build_failures)
421190064b4SSimon Glass            result.commit_upto = 0
422190064b4SSimon Glass            self._WriteResult(result, job.keep_outputs)
423190064b4SSimon Glass            self.builder.out_queue.put(result)
424190064b4SSimon Glass
425190064b4SSimon Glass    def run(self):
426190064b4SSimon Glass        """Our thread's run function
427190064b4SSimon Glass
428190064b4SSimon Glass        This thread picks a job from the queue, runs it, and then goes to the
429190064b4SSimon Glass        next job.
430190064b4SSimon Glass        """
431190064b4SSimon Glass        alive = True
432190064b4SSimon Glass        while True:
433190064b4SSimon Glass            job = self.builder.queue.get()
434190064b4SSimon Glass            if self.builder.active and alive:
435190064b4SSimon Glass                self.RunJob(job)
436190064b4SSimon Glass            '''
437190064b4SSimon Glass            try:
438190064b4SSimon Glass                if self.builder.active and alive:
439190064b4SSimon Glass                    self.RunJob(job)
440190064b4SSimon Glass            except Exception as err:
441190064b4SSimon Glass                alive = False
442190064b4SSimon Glass                print err
443190064b4SSimon Glass            '''
444190064b4SSimon Glass            self.builder.queue.task_done()
445