mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-30 19:11:37 +00:00
Various improvements to buildman summary output
-----BEGIN PGP SIGNATURE----- iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAl6e6GgRHHNqZ0BjaHJv bWl1bS5vcmcACgkQfxc6PpAIreZ5hwf9Eso9WyGKLi32j764EXnCf0XLj6WZ1HiI ybk7NABiu9XAg0zfGxX8k3AUdhmMVHSAmLQiATi2rpyXFoyTRVHM5EG6jB8xVpM4 tc9DBYSGAHSyD+zUQKkc+8aChdN/xAT/32PKe4g6boHnZOXQ0GLZyE4JMsSePC21 h8sVb5KyTCZfCY503ej+TwTWPgkI2yq5neDAt2SO8v5cXYs6ImgzJbi5hnOACkeA G3b9QBGrOWdDMQS7qBdoo5d/JQZ6CCXS3j7FddtEuAa6pebVDmxEk3cuDaxqycK3 EpZdROERyk9B7uQy6mSEtfeZHxpcaL1OMAhNnPGhRyTSQjRpuY4/XQ== =4Z39 -----END PGP SIGNATURE----- Merge tag 'dm-pull-21apr20' of git://git.denx.de/u-boot-dm Various improvements to buildman summary output
This commit is contained in:
commit
2f2031e647
9 changed files with 614 additions and 257 deletions
|
@ -51,23 +51,25 @@ Theory of Operation
|
||||||
|
|
||||||
Buildman is a builder. It is not make, although it runs make. It does not
|
Buildman is a builder. It is not make, although it runs make. It does not
|
||||||
produce any useful output on the terminal while building, except for
|
produce any useful output on the terminal while building, except for
|
||||||
progress information (except with -v, see below). All the output (errors,
|
progress information (but see -v below). All the output (errors, warnings and
|
||||||
warnings and binaries if you ask for them) is stored in output
|
binaries if you ask for them) is stored in output directories, which you can
|
||||||
directories, which you can look at while the build is progressing, or when
|
look at from a separate 'buildman -s' instance while the build is progressing,
|
||||||
it is finished.
|
or when it is finished.
|
||||||
|
|
||||||
Buildman is designed to build entire git branches, i.e. muliple commits. It
|
Buildman is designed to build entire git branches, i.e. muliple commits. It
|
||||||
can be run repeatedly on the same branch. In this case it will automatically
|
can be run repeatedly on the same branch after making changes to commits on
|
||||||
rebuild commits which have changed (and remove its old results for that
|
that branch. In this case it will automatically rebuild commits which have
|
||||||
commit). It is possible to build a branch for one board, then later build it
|
changed (and remove its old results for that commit). It is possible to build
|
||||||
for another board. If you want buildman to re-build a commit it has already
|
a branch for one board, then later build it for another board. This adds to
|
||||||
built (e.g. because of a toolchain update), use the -f flag.
|
the output, so now you have results for two boards. If you want buildman to
|
||||||
|
re-build a commit it has already built (e.g. because of a toolchain update),
|
||||||
|
use the -f flag.
|
||||||
|
|
||||||
Buildman produces a concise summary of which boards succeeded and failed.
|
Buildman produces a concise summary of which boards succeeded and failed.
|
||||||
It shows which commit introduced which board failure using a simple
|
It shows which commit introduced which board failure using a simple
|
||||||
red/green colour coding. Full error information can be requested, in which
|
red/green colour coding (with yellow/cyan for warnings). Full error
|
||||||
case it is de-duped and displayed against the commit that introduced the
|
information can be requested, in which case it is de-duped and displayed
|
||||||
error. An example workflow is below.
|
against the commit that introduced the error. An example workflow is below.
|
||||||
|
|
||||||
Buildman stores image size information and can report changes in image size
|
Buildman stores image size information and can report changes in image size
|
||||||
from commit to commit. An example of this is below.
|
from commit to commit. An example of this is below.
|
||||||
|
@ -75,16 +77,20 @@ from commit to commit. An example of this is below.
|
||||||
Buildman starts multiple threads, and each thread builds for one board at
|
Buildman starts multiple threads, and each thread builds for one board at
|
||||||
a time. A thread starts at the first commit, configures the source for your
|
a time. A thread starts at the first commit, configures the source for your
|
||||||
board and builds it. Then it checks out the next commit and does an
|
board and builds it. Then it checks out the next commit and does an
|
||||||
incremental build. Eventually the thread reaches the last commit and stops.
|
incremental build (i.e. not using 'make xxx_defconfig' unless you use -C).
|
||||||
If errors or warnings are found along the way, the thread will reconfigure
|
Eventually the thread reaches the last commit and stops. If a commit causes
|
||||||
after every commit, and your build will be very slow. This is because a
|
an error or warning, buildman will try it again after reconfiguring (but see
|
||||||
file that produces just a warning would not normally be rebuilt in an
|
-Q). Thus some commits may be built twice, with the first result silently
|
||||||
incremental build.
|
discarded. Lots of errors and warnings will causes lots of reconfigures and your
|
||||||
|
build will be very slow. This is because a file that produces just a warning
|
||||||
|
would not normally be rebuilt in an incremental build. Once a thread finishes
|
||||||
|
building all the commits for a board, it starts on the commits for another
|
||||||
|
board.
|
||||||
|
|
||||||
Buildman works in an entirely separate place from your U-Boot repository.
|
Buildman works in an entirely separate place from your U-Boot repository.
|
||||||
It creates a separate working directory for each thread, and puts the
|
It creates a separate working directory for each thread, and puts the
|
||||||
output files in the working directory, organised by commit name and board
|
output files in the working directory, organised by commit name and board
|
||||||
name, in a two-level hierarchy.
|
name, in a two-level hierarchy (but see -P).
|
||||||
|
|
||||||
Buildman is invoked in your U-Boot directory, the one with the .git
|
Buildman is invoked in your U-Boot directory, the one with the .git
|
||||||
directory. It clones this repository into a copy for each thread, and the
|
directory. It clones this repository into a copy for each thread, and the
|
||||||
|
@ -92,20 +98,23 @@ threads do not affect the state of your git repository. Any checkouts done
|
||||||
by the thread affect only the working directory for that thread.
|
by the thread affect only the working directory for that thread.
|
||||||
|
|
||||||
Buildman automatically selects the correct tool chain for each board. You
|
Buildman automatically selects the correct tool chain for each board. You
|
||||||
must supply suitable tool chains, but buildman takes care of selecting the
|
must supply suitable tool chains (see --fetch-arch), but buildman takes care
|
||||||
right one.
|
of selecting the right one.
|
||||||
|
|
||||||
Buildman generally builds a branch (with the -b flag), and in this case
|
Buildman generally builds a branch (with the -b flag), and in this case
|
||||||
builds the upstream commit as well, for comparison. It cannot build
|
builds the upstream commit as well, for comparison. So even if you have one
|
||||||
individual commits at present, unless (maybe) you point it at an empty
|
commit in your branch, two commits will be built. Put all your commits in a
|
||||||
branch. Put all your commits in a branch, set the branch's upstream to a
|
branch, set the branch's upstream to a valid value, and all will be well.
|
||||||
valid value, and all will be well. Otherwise buildman will perform random
|
Otherwise buildman will perform random actions. Use -n to check what the
|
||||||
actions. Use -n to check what the random actions might be.
|
random actions might be.
|
||||||
|
|
||||||
If you just want to build the current source tree, leave off the -b flag
|
Buildman effectively has two modes: without -s it builds, with -s it
|
||||||
and add -e. This will display results and errors as they happen. You can
|
summarises the results of previous (or active) builds.
|
||||||
still look at them later using -se. Note that buildman will assume that the
|
|
||||||
source has changed, and will build all specified boards in this case.
|
If you just want to build the current source tree, leave off the -b flag.
|
||||||
|
This will display results and errors as they happen. You can still look at
|
||||||
|
them later using -se. Note that buildman will assume that the source has
|
||||||
|
changed, and will build all specified boards in this case.
|
||||||
|
|
||||||
Buildman is optimised for building many commits at once, for many boards.
|
Buildman is optimised for building many commits at once, for many boards.
|
||||||
On multi-core machines, Buildman is fast because it uses most of the
|
On multi-core machines, Buildman is fast because it uses most of the
|
||||||
|
@ -142,9 +151,9 @@ You can also use -x to specifically exclude some boards. For example:
|
||||||
means to build all arm boards except nvidia, freescale and anything ending
|
means to build all arm boards except nvidia, freescale and anything ending
|
||||||
with 'ball'.
|
with 'ball'.
|
||||||
|
|
||||||
For building specific boards you can use the --boards option, which takes a
|
For building specific boards you can use the --boards (or --bo) option, which
|
||||||
comma-separated list of board target names and be used multiple times on
|
takes a comma-separated list of board target names and be used multiple times
|
||||||
the command line:
|
on the command line:
|
||||||
|
|
||||||
buildman --boards sandbox,snow --boards
|
buildman --boards sandbox,snow --boards
|
||||||
|
|
||||||
|
@ -492,6 +501,8 @@ If it can't detect the upstream branch, try checking out the branch, and
|
||||||
doing something like 'git branch --set-upstream-to upstream/master'
|
doing something like 'git branch --set-upstream-to upstream/master'
|
||||||
or something similar. Buildman will try to guess a suitable upstream branch
|
or something similar. Buildman will try to guess a suitable upstream branch
|
||||||
if it can't find one (you will see a message like" Guessing upstream as ...).
|
if it can't find one (you will see a message like" Guessing upstream as ...).
|
||||||
|
You can also use the -c option to manually specify the number of commits to
|
||||||
|
build.
|
||||||
|
|
||||||
As an example:
|
As an example:
|
||||||
|
|
||||||
|
@ -542,12 +553,13 @@ Buildman will set up some working directories, and get started. After a
|
||||||
minute or so it will settle down to a steady pace, with a display like this:
|
minute or so it will settle down to a steady pace, with a display like this:
|
||||||
|
|
||||||
Building 18 commits for 1059 boards (4 threads, 1 job per thread)
|
Building 18 commits for 1059 boards (4 threads, 1 job per thread)
|
||||||
528 36 124 /19062 1:13:30 : SIMPC8313_SP
|
528 36 124 /19062 -18374 1:13:30 : SIMPC8313_SP
|
||||||
|
|
||||||
This means that it is building 19062 board/commit combinations. So far it
|
This means that it is building 19062 board/commit combinations. So far it
|
||||||
has managed to successfully build 528. Another 36 have built with warnings,
|
has managed to successfully build 528. Another 36 have built with warnings,
|
||||||
and 124 more didn't build at all. Buildman expects to complete the process
|
and 124 more didn't build at all. It has 18374 builds left to complete.
|
||||||
in around an hour and a quarter. Use this time to buy a faster computer.
|
Buildman expects to complete the process in around an hour and a quarter.
|
||||||
|
Use this time to buy a faster computer.
|
||||||
|
|
||||||
|
|
||||||
To find out how the build went, ask for a summary with -s. You can do this
|
To find out how the build went, ask for a summary with -s. You can do this
|
||||||
|
@ -579,32 +591,32 @@ $ ./tools/buildman/buildman -b lcd9b -s
|
||||||
|
|
||||||
This shows which commits have succeeded and which have failed. In this case
|
This shows which commits have succeeded and which have failed. In this case
|
||||||
the build is still in progress so many boards are not built yet (use -u to
|
the build is still in progress so many boards are not built yet (use -u to
|
||||||
see which ones). But still we can see a few failures. The galaxy5200_LOWBOOT
|
see which ones). But already we can see a few failures. The galaxy5200_LOWBOOT
|
||||||
never builds correctly. This could be a problem with our toolchain, or it
|
never builds correctly. This could be a problem with our toolchain, or it
|
||||||
could be a bug in the upstream. The good news is that we probably don't need
|
could be a bug in the upstream. The good news is that we probably don't need
|
||||||
to blame our commits. The bad news is that our commits are not tested on that
|
to blame our commits. The bad news is that our commits are not tested on that
|
||||||
board.
|
board.
|
||||||
|
|
||||||
Commit 12 broke lubbock. That's what the '+ lubbock' means. The failure
|
Commit 12 broke lubbock. That's what the '+ lubbock', in red, means. The
|
||||||
is never fixed by a later commit, or you would see lubbock again, in green,
|
failure is never fixed by a later commit, or you would see lubbock again, in
|
||||||
without the +.
|
green, without the +.
|
||||||
|
|
||||||
To see the actual error:
|
To see the actual error:
|
||||||
|
|
||||||
$ ./tools/buildman/buildman -b <branch> -se lubbock
|
$ ./tools/buildman/buildman -b <branch> -se
|
||||||
...
|
...
|
||||||
12: lcd: Add support for flushing LCD fb from dcache after update
|
12: lcd: Add support for flushing LCD fb from dcache after update
|
||||||
arm: + lubbock
|
arm: + lubbock
|
||||||
+common/libcommon.o: In function `lcd_sync':
|
+common/libcommon.o: In function `lcd_sync':
|
||||||
+/u-boot/lcd9b/.bm-work/00/common/lcd.c:120: undefined reference to `flush_dcache_range'
|
+common/lcd.c:120: undefined reference to `flush_dcache_range'
|
||||||
+arm-none-linux-gnueabi-ld: BFD (Sourcery G++ Lite 2010q1-202) 2.19.51.20090709 assertion fail /scratch/julian/2010q1-release-linux-lite/obj/binutils-src-2010q1-202-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:12572
|
+arm-none-linux-gnueabi-ld: BFD (Sourcery G++ Lite 2010q1-202) 2.19.51.20090709 assertion fail /scratch/julian/2010q1-release-linux-lite/obj/binutils-src-2010q1-202-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:12572
|
||||||
+make: *** [/u-boot/lcd9b/.bm-work/00/build/u-boot] Error 139
|
+make: *** [build/u-boot] Error 139
|
||||||
13: tegra: Align LCD frame buffer to section boundary
|
13: tegra: Align LCD frame buffer to section boundary
|
||||||
14: tegra: Support control of cache settings for LCD
|
14: tegra: Support control of cache settings for LCD
|
||||||
15: tegra: fdt: Add LCD definitions for Seaboard
|
15: tegra: fdt: Add LCD definitions for Seaboard
|
||||||
16: lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console
|
16: lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console
|
||||||
-/u-boot/lcd9b/.bm-work/00/common/lcd.c:120: undefined reference to `flush_dcache_range'
|
-common/lcd.c:120: undefined reference to `flush_dcache_range'
|
||||||
+/u-boot/lcd9b/.bm-work/00/common/lcd.c:125: undefined reference to `flush_dcache_range'
|
+common/lcd.c:125: undefined reference to `flush_dcache_range'
|
||||||
17: tegra: Enable display/lcd support on Seaboard
|
17: tegra: Enable display/lcd support on Seaboard
|
||||||
18: wip
|
18: wip
|
||||||
|
|
||||||
|
@ -612,6 +624,21 @@ So the problem is in lcd.c, due to missing cache operations. This information
|
||||||
should be enough to work out what that commit is doing to break these
|
should be enough to work out what that commit is doing to break these
|
||||||
boards. (In this case pxa did not have cache operations defined).
|
boards. (In this case pxa did not have cache operations defined).
|
||||||
|
|
||||||
|
Note that if there were other boards with errors, the above command would
|
||||||
|
show their errors also. Each line is shown only once. So if lubbock and snow
|
||||||
|
produce the same error, we just see:
|
||||||
|
|
||||||
|
12: lcd: Add support for flushing LCD fb from dcache after update
|
||||||
|
arm: + lubbock snow
|
||||||
|
+common/libcommon.o: In function `lcd_sync':
|
||||||
|
+common/lcd.c:120: undefined reference to `flush_dcache_range'
|
||||||
|
+arm-none-linux-gnueabi-ld: BFD (Sourcery G++ Lite 2010q1-202) 2.19.51.20090709 assertion fail /scratch/julian/2010q1-release-linux-lite/obj/binutils-src-2010q1-202-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:12572
|
||||||
|
+make: *** [build/u-boot] Error 139
|
||||||
|
|
||||||
|
But if you did want to see just the errors for lubbock, use:
|
||||||
|
|
||||||
|
$ ./tools/buildman/buildman -b <branch> -se lubbock
|
||||||
|
|
||||||
If you see error lines marked with '-', that means that the errors were fixed
|
If you see error lines marked with '-', that means that the errors were fixed
|
||||||
by that commit. Sometimes commits can be in the wrong order, so that a
|
by that commit. Sometimes commits can be in the wrong order, so that a
|
||||||
breakage is introduced for a few commits and fixed by later commits. This
|
breakage is introduced for a few commits and fixed by later commits. This
|
||||||
|
@ -622,13 +649,14 @@ At commit 16, the error moves: you can see that the old error at line 120
|
||||||
is fixed, but there is a new one at line 126. This is probably only because
|
is fixed, but there is a new one at line 126. This is probably only because
|
||||||
we added some code and moved the broken line further down the file.
|
we added some code and moved the broken line further down the file.
|
||||||
|
|
||||||
If many boards have the same error, then -e will display the error only
|
As mentioned, if many boards have the same error, then -e will display the
|
||||||
once. This makes the output as concise as possible. To see which boards have
|
error only once. This makes the output as concise as possible. To see which
|
||||||
each error, use -l. So it is safe to omit the board name - you will not get
|
boards have each error, use -l. So it is safe to omit the board name - you
|
||||||
lots of repeated output for every board.
|
will not get lots of repeated output for every board.
|
||||||
|
|
||||||
Buildman tries to distinguish warnings from errors, and shows warning lines
|
Buildman tries to distinguish warnings from errors, and shows warning lines
|
||||||
separately with a 'w' prefix.
|
separately with a 'w' prefix. Warnings introduced show as yellow. Warnings
|
||||||
|
fixed show as cyan.
|
||||||
|
|
||||||
The full build output in this case is available in:
|
The full build output in this case is available in:
|
||||||
|
|
||||||
|
@ -930,12 +958,11 @@ will build commits in us-buildman that are not in upstream/master.
|
||||||
Building Faster
|
Building Faster
|
||||||
===============
|
===============
|
||||||
|
|
||||||
By default, buildman executes 'make mrproper' prior to building the first
|
By default, buildman doesn't execute 'make mrproper' prior to building the
|
||||||
commit for each board. This causes everything to be built from scratch. If you
|
first commit for each board. This reduces the amount of work 'make' does, and
|
||||||
trust the build system's incremental build capabilities, you can pass the -I
|
hence speeds up the build. To force use of 'make mrproper', use -the -m flag.
|
||||||
flag to skip the 'make mproper' invocation, which will reduce the amount of
|
This flag will slow down any buildman invocation, since it increases the amount
|
||||||
work 'make' does, and hence speed up the build. This flag will speed up any
|
of work done on any build.
|
||||||
buildman invocation, since it reduces the amount of work done on any build.
|
|
||||||
|
|
||||||
One possible application of buildman is as part of a continual edit, build,
|
One possible application of buildman is as part of a continual edit, build,
|
||||||
edit, build, ... cycle; repeatedly applying buildman to the same change or
|
edit, build, ... cycle; repeatedly applying buildman to the same change or
|
||||||
|
@ -966,7 +993,7 @@ Combining all of these options together yields the command-line shown below.
|
||||||
This will provide the quickest possible feedback regarding the current content
|
This will provide the quickest possible feedback regarding the current content
|
||||||
of the source tree, thus allowing rapid tested evolution of the code.
|
of the source tree, thus allowing rapid tested evolution of the code.
|
||||||
|
|
||||||
SOURCE_DATE_EPOCH=0 ./tools/buildman/buildman -I -P tegra
|
SOURCE_DATE_EPOCH=0 ./tools/buildman/buildman -P tegra
|
||||||
|
|
||||||
|
|
||||||
Checking configuration
|
Checking configuration
|
||||||
|
@ -1087,15 +1114,18 @@ with -E, e.g. the migration warnings:
|
||||||
When doing builds, Buildman's return code will reflect the overall result:
|
When doing builds, Buildman's return code will reflect the overall result:
|
||||||
|
|
||||||
0 (success) No errors or warnings found
|
0 (success) No errors or warnings found
|
||||||
128 Errors found
|
100 Errors found
|
||||||
129 Warnings found (only if no -W)
|
101 Warnings found (only if no -W)
|
||||||
|
|
||||||
You can use -W to tell Buildman to return 0 (success) instead of 129 when
|
You can use -W to tell Buildman to return 0 (success) instead of 101 when
|
||||||
warnings are found. Note that it can be useful to combine -E and -W. This means
|
warnings are found. Note that it can be useful to combine -E and -W. This means
|
||||||
that all compiler warnings will produce failures (code 128) and all other
|
that all compiler warnings will produce failures (code 100) and all other
|
||||||
warnings will produce success (since 129 is changed to 0).
|
warnings will produce success (since 101 is changed to 0).
|
||||||
|
|
||||||
If there are both warnings and errors, errors win, so buildman returns 128.
|
If there are both warnings and errors, errors win, so buildman returns 100.
|
||||||
|
|
||||||
|
The -y option is provided (for use with -s) to ignore the bountiful device-tree
|
||||||
|
warnings. Similarly, -Y tells buildman to ignore the migration warnings.
|
||||||
|
|
||||||
|
|
||||||
How to change from MAKEALL
|
How to change from MAKEALL
|
||||||
|
@ -1202,12 +1232,16 @@ Some options you might like are:
|
||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
This has mostly be written in my spare time as a response to my difficulties
|
Many improvements have been made over the years. There is still quite a bit of
|
||||||
in testing large series of patches. Apart from tidying up there is quite a
|
scope for more though, e.g.:
|
||||||
bit of scope for improvement. Things like better error diffs and easier
|
|
||||||
access to log files. Also it would be nice if buildman could 'hunt' for
|
- easier access to log files
|
||||||
problems, perhaps by building a few boards for each arch, or checking
|
- 'hunting' for problems, perhaps by building a few boards for each arch, or
|
||||||
commits for changed files and building only boards which use those files.
|
checking commits for changed files and building only boards which use those
|
||||||
|
files
|
||||||
|
- using the same git repo for all threads instead of cloning it. Currently
|
||||||
|
it uses about 500MB per thread, so on a 64-thread machine this is 32GB for
|
||||||
|
the build.
|
||||||
|
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
|
@ -1223,3 +1257,4 @@ sjg@chromium.org
|
||||||
Halloween 2012
|
Halloween 2012
|
||||||
Updated 12-12-12
|
Updated 12-12-12
|
||||||
Updated 23-02-13
|
Updated 23-02-13
|
||||||
|
Updated 09-04-20
|
||||||
|
|
|
@ -24,7 +24,6 @@ import terminal
|
||||||
from terminal import Print
|
from terminal import Print
|
||||||
import toolchain
|
import toolchain
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Theory of Operation
|
Theory of Operation
|
||||||
|
|
||||||
|
@ -91,6 +90,15 @@ u-boot/ source directory
|
||||||
.git/ repository
|
.git/ repository
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
"""Holds information about a particular error line we are outputing
|
||||||
|
|
||||||
|
char: Character representation: '+': error, '-': fixed error, 'w+': warning,
|
||||||
|
'w-' = fixed warning
|
||||||
|
boards: List of Board objects which have line in the error/warning output
|
||||||
|
errline: The text of the error line
|
||||||
|
"""
|
||||||
|
ErrLine = collections.namedtuple('ErrLine', 'char,boards,errline')
|
||||||
|
|
||||||
# Possible build outcomes
|
# Possible build outcomes
|
||||||
OUTCOME_OK, OUTCOME_WARNING, OUTCOME_ERROR, OUTCOME_UNKNOWN = list(range(4))
|
OUTCOME_OK, OUTCOME_WARNING, OUTCOME_ERROR, OUTCOME_UNKNOWN = list(range(4))
|
||||||
|
|
||||||
|
@ -154,8 +162,6 @@ class Builder:
|
||||||
force_build_failures: If a previously-built build (i.e. built on
|
force_build_failures: If a previously-built build (i.e. built on
|
||||||
a previous run of buildman) is marked as failed, rebuild it.
|
a previous run of buildman) is marked as failed, rebuild it.
|
||||||
git_dir: Git directory containing source repository
|
git_dir: Git directory containing source repository
|
||||||
last_line_len: Length of the last line we printed (used for erasing
|
|
||||||
it with new progress information)
|
|
||||||
num_jobs: Number of jobs to run at once (passed to make as -j)
|
num_jobs: Number of jobs to run at once (passed to make as -j)
|
||||||
num_threads: Number of builder threads to run
|
num_threads: Number of builder threads to run
|
||||||
out_queue: Queue of results to process
|
out_queue: Queue of results to process
|
||||||
|
@ -186,6 +192,7 @@ class Builder:
|
||||||
_next_delay_update: Next time we plan to display a progress update
|
_next_delay_update: Next time we plan to display a progress update
|
||||||
(datatime)
|
(datatime)
|
||||||
_show_unknown: Show unknown boards (those not built) in summary
|
_show_unknown: Show unknown boards (those not built) in summary
|
||||||
|
_start_time: Start time for the build
|
||||||
_timestamps: List of timestamps for the completion of the last
|
_timestamps: List of timestamps for the completion of the last
|
||||||
last _timestamp_count builds. Each is a datetime object.
|
last _timestamp_count builds. Each is a datetime object.
|
||||||
_timestamp_count: Number of timestamps to keep in our list.
|
_timestamp_count: Number of timestamps to keep in our list.
|
||||||
|
@ -224,7 +231,7 @@ class Builder:
|
||||||
def __init__(self, toolchains, base_dir, git_dir, num_threads, num_jobs,
|
def __init__(self, toolchains, base_dir, git_dir, num_threads, num_jobs,
|
||||||
gnu_make='make', checkout=True, show_unknown=True, step=1,
|
gnu_make='make', checkout=True, show_unknown=True, step=1,
|
||||||
no_subdirs=False, full_path=False, verbose_build=False,
|
no_subdirs=False, full_path=False, verbose_build=False,
|
||||||
incremental=False, per_board_out_dir=False,
|
mrproper=False, per_board_out_dir=False,
|
||||||
config_only=False, squash_config_y=False,
|
config_only=False, squash_config_y=False,
|
||||||
warnings_as_errors=False, work_in_output=False):
|
warnings_as_errors=False, work_in_output=False):
|
||||||
"""Create a new Builder object
|
"""Create a new Builder object
|
||||||
|
@ -245,8 +252,7 @@ class Builder:
|
||||||
full_path: Return the full path in CROSS_COMPILE and don't set
|
full_path: Return the full path in CROSS_COMPILE and don't set
|
||||||
PATH
|
PATH
|
||||||
verbose_build: Run build with V=1 and don't use 'make -s'
|
verbose_build: Run build with V=1 and don't use 'make -s'
|
||||||
incremental: Always perform incremental builds; don't run make
|
mrproper: Always run 'make mrproper' when configuring
|
||||||
mrproper when configuring
|
|
||||||
per_board_out_dir: Build in a separate persistent directory per
|
per_board_out_dir: Build in a separate persistent directory per
|
||||||
board rather than a thread-specific directory
|
board rather than a thread-specific directory
|
||||||
config_only: Only configure each build, don't build it
|
config_only: Only configure each build, don't build it
|
||||||
|
@ -275,6 +281,7 @@ class Builder:
|
||||||
self._build_period_us = None
|
self._build_period_us = None
|
||||||
self._complete_delay = None
|
self._complete_delay = None
|
||||||
self._next_delay_update = datetime.now()
|
self._next_delay_update = datetime.now()
|
||||||
|
self._start_time = datetime.now()
|
||||||
self.force_config_on_failure = True
|
self.force_config_on_failure = True
|
||||||
self.force_build_failures = False
|
self.force_build_failures = False
|
||||||
self.force_reconfig = False
|
self.force_reconfig = False
|
||||||
|
@ -299,17 +306,18 @@ class Builder:
|
||||||
self._re_warning = re.compile('(.*):(\d*):(\d*): warning: .*')
|
self._re_warning = re.compile('(.*):(\d*):(\d*): warning: .*')
|
||||||
self._re_dtb_warning = re.compile('(.*): Warning .*')
|
self._re_dtb_warning = re.compile('(.*): Warning .*')
|
||||||
self._re_note = re.compile('(.*):(\d*):(\d*): note: this is the location of the previous.*')
|
self._re_note = re.compile('(.*):(\d*):(\d*): note: this is the location of the previous.*')
|
||||||
|
self._re_migration_warning = re.compile(r'^={21} WARNING ={22}\n.*\n=+\n',
|
||||||
|
re.MULTILINE | re.DOTALL)
|
||||||
|
|
||||||
self.queue = queue.Queue()
|
self.queue = queue.Queue()
|
||||||
self.out_queue = queue.Queue()
|
self.out_queue = queue.Queue()
|
||||||
for i in range(self.num_threads):
|
for i in range(self.num_threads):
|
||||||
t = builderthread.BuilderThread(self, i, incremental,
|
t = builderthread.BuilderThread(self, i, mrproper,
|
||||||
per_board_out_dir)
|
per_board_out_dir)
|
||||||
t.setDaemon(True)
|
t.setDaemon(True)
|
||||||
t.start()
|
t.start()
|
||||||
self.threads.append(t)
|
self.threads.append(t)
|
||||||
|
|
||||||
self.last_line_len = 0
|
|
||||||
t = builderthread.ResultThread(self)
|
t = builderthread.ResultThread(self)
|
||||||
t.setDaemon(True)
|
t.setDaemon(True)
|
||||||
t.start()
|
t.start()
|
||||||
|
@ -332,9 +340,11 @@ class Builder:
|
||||||
def SetDisplayOptions(self, show_errors=False, show_sizes=False,
|
def SetDisplayOptions(self, show_errors=False, show_sizes=False,
|
||||||
show_detail=False, show_bloat=False,
|
show_detail=False, show_bloat=False,
|
||||||
list_error_boards=False, show_config=False,
|
list_error_boards=False, show_config=False,
|
||||||
show_environment=False):
|
show_environment=False, filter_dtb_warnings=False,
|
||||||
|
filter_migration_warnings=False):
|
||||||
"""Setup display options for the builder.
|
"""Setup display options for the builder.
|
||||||
|
|
||||||
|
Args:
|
||||||
show_errors: True to show summarised error/warning info
|
show_errors: True to show summarised error/warning info
|
||||||
show_sizes: Show size deltas
|
show_sizes: Show size deltas
|
||||||
show_detail: Show size delta detail for each board if show_sizes
|
show_detail: Show size delta detail for each board if show_sizes
|
||||||
|
@ -342,6 +352,10 @@ class Builder:
|
||||||
list_error_boards: Show the boards which caused each error/warning
|
list_error_boards: Show the boards which caused each error/warning
|
||||||
show_config: Show config deltas
|
show_config: Show config deltas
|
||||||
show_environment: Show environment deltas
|
show_environment: Show environment deltas
|
||||||
|
filter_dtb_warnings: Filter out any warnings from the device-tree
|
||||||
|
compiler
|
||||||
|
filter_migration_warnings: Filter out any warnings about migrating
|
||||||
|
a board to driver model
|
||||||
"""
|
"""
|
||||||
self._show_errors = show_errors
|
self._show_errors = show_errors
|
||||||
self._show_sizes = show_sizes
|
self._show_sizes = show_sizes
|
||||||
|
@ -350,6 +364,8 @@ class Builder:
|
||||||
self._list_error_boards = list_error_boards
|
self._list_error_boards = list_error_boards
|
||||||
self._show_config = show_config
|
self._show_config = show_config
|
||||||
self._show_environment = show_environment
|
self._show_environment = show_environment
|
||||||
|
self._filter_dtb_warnings = filter_dtb_warnings
|
||||||
|
self._filter_migration_warnings = filter_migration_warnings
|
||||||
|
|
||||||
def _AddTimestamp(self):
|
def _AddTimestamp(self):
|
||||||
"""Add a new timestamp to the list and record the build period.
|
"""Add a new timestamp to the list and record the build period.
|
||||||
|
@ -380,22 +396,6 @@ class Builder:
|
||||||
self._timestamps.popleft()
|
self._timestamps.popleft()
|
||||||
count -= 1
|
count -= 1
|
||||||
|
|
||||||
def ClearLine(self, length):
|
|
||||||
"""Clear any characters on the current line
|
|
||||||
|
|
||||||
Make way for a new line of length 'length', by outputting enough
|
|
||||||
spaces to clear out the old line. Then remember the new length for
|
|
||||||
next time.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
length: Length of new line, in characters
|
|
||||||
"""
|
|
||||||
if length < self.last_line_len:
|
|
||||||
Print(' ' * (self.last_line_len - length), newline=False)
|
|
||||||
Print('\r', newline=False)
|
|
||||||
self.last_line_len = length
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
def SelectCommit(self, commit, checkout=True):
|
def SelectCommit(self, commit, checkout=True):
|
||||||
"""Checkout the selected commit for this build
|
"""Checkout the selected commit for this build
|
||||||
"""
|
"""
|
||||||
|
@ -441,8 +441,7 @@ class Builder:
|
||||||
if result.already_done:
|
if result.already_done:
|
||||||
self.already_done += 1
|
self.already_done += 1
|
||||||
if self._verbose:
|
if self._verbose:
|
||||||
Print('\r', newline=False)
|
terminal.PrintClear()
|
||||||
self.ClearLine(0)
|
|
||||||
boards_selected = {target : result.brd}
|
boards_selected = {target : result.brd}
|
||||||
self.ResetResultSummary(boards_selected)
|
self.ResetResultSummary(boards_selected)
|
||||||
self.ProduceResultSummary(result.commit_upto, self.commits,
|
self.ProduceResultSummary(result.commit_upto, self.commits,
|
||||||
|
@ -456,22 +455,21 @@ class Builder:
|
||||||
line += self.col.Color(self.col.YELLOW, '%5d' % self.warned)
|
line += self.col.Color(self.col.YELLOW, '%5d' % self.warned)
|
||||||
line += self.col.Color(self.col.RED, '%5d' % self.fail)
|
line += self.col.Color(self.col.RED, '%5d' % self.fail)
|
||||||
|
|
||||||
name = ' /%-5d ' % self.count
|
line += ' /%-5d ' % self.count
|
||||||
|
remaining = self.count - self.upto
|
||||||
|
if remaining:
|
||||||
|
line += self.col.Color(self.col.MAGENTA, ' -%-5d ' % remaining)
|
||||||
|
else:
|
||||||
|
line += ' ' * 8
|
||||||
|
|
||||||
# Add our current completion time estimate
|
# Add our current completion time estimate
|
||||||
self._AddTimestamp()
|
self._AddTimestamp()
|
||||||
if self._complete_delay:
|
if self._complete_delay:
|
||||||
name += '%s : ' % self._complete_delay
|
line += '%s : ' % self._complete_delay
|
||||||
# When building all boards for a commit, we can print a commit
|
|
||||||
# progress message.
|
|
||||||
if result and result.commit_upto is None:
|
|
||||||
name += 'commit %2d/%-3d' % (self.commit_upto + 1,
|
|
||||||
self.commit_count)
|
|
||||||
|
|
||||||
name += target
|
line += target
|
||||||
Print(line + name, newline=False)
|
terminal.PrintClear()
|
||||||
length = 16 + len(name)
|
Print(line, newline=False, limit_to_line=True)
|
||||||
self.ClearLine(length)
|
|
||||||
|
|
||||||
def _GetOutputDir(self, commit_upto):
|
def _GetOutputDir(self, commit_upto):
|
||||||
"""Get the name of the output directory for a commit number
|
"""Get the name of the output directory for a commit number
|
||||||
|
@ -567,8 +565,15 @@ class Builder:
|
||||||
New list with only interesting lines included
|
New list with only interesting lines included
|
||||||
"""
|
"""
|
||||||
out_lines = []
|
out_lines = []
|
||||||
|
if self._filter_migration_warnings:
|
||||||
|
text = '\n'.join(lines)
|
||||||
|
text = self._re_migration_warning.sub('', text)
|
||||||
|
lines = text.splitlines()
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if not self.re_make_err.search(line):
|
if self.re_make_err.search(line):
|
||||||
|
continue
|
||||||
|
if self._filter_dtb_warnings and self._re_dtb_warning.search(line):
|
||||||
|
continue
|
||||||
out_lines.append(line)
|
out_lines.append(line)
|
||||||
return out_lines
|
return out_lines
|
||||||
|
|
||||||
|
@ -1128,32 +1133,52 @@ class Builder:
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
line: Error line to search for
|
line: Error line to search for
|
||||||
|
line_boards: boards to search, each a Board
|
||||||
Return:
|
Return:
|
||||||
String containing a list of boards with that error line, or
|
List of boards with that error line, or [] if the user has not
|
||||||
'' if the user has not requested such a list
|
requested such a list
|
||||||
"""
|
"""
|
||||||
|
boards = []
|
||||||
|
board_set = set()
|
||||||
if self._list_error_boards:
|
if self._list_error_boards:
|
||||||
names = []
|
|
||||||
for board in line_boards[line]:
|
for board in line_boards[line]:
|
||||||
if not board.target in names:
|
if not board in board_set:
|
||||||
names.append(board.target)
|
boards.append(board)
|
||||||
names_str = '(%s) ' % ','.join(names)
|
board_set.add(board)
|
||||||
else:
|
return boards
|
||||||
names_str = ''
|
|
||||||
return names_str
|
|
||||||
|
|
||||||
def _CalcErrorDelta(base_lines, base_line_boards, lines, line_boards,
|
def _CalcErrorDelta(base_lines, base_line_boards, lines, line_boards,
|
||||||
char):
|
char):
|
||||||
|
"""Calculate the required output based on changes in errors
|
||||||
|
|
||||||
|
Args:
|
||||||
|
base_lines: List of errors/warnings for previous commit
|
||||||
|
base_line_boards: Dict keyed by error line, containing a list
|
||||||
|
of the Board objects with that error in the previous commit
|
||||||
|
lines: List of errors/warning for this commit, each a str
|
||||||
|
line_boards: Dict keyed by error line, containing a list
|
||||||
|
of the Board objects with that error in this commit
|
||||||
|
char: Character representing error ('') or warning ('w'). The
|
||||||
|
broken ('+') or fixed ('-') characters are added in this
|
||||||
|
function
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple
|
||||||
|
List of ErrLine objects for 'better' lines
|
||||||
|
List of ErrLine objects for 'worse' lines
|
||||||
|
"""
|
||||||
better_lines = []
|
better_lines = []
|
||||||
worse_lines = []
|
worse_lines = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line not in base_lines:
|
if line not in base_lines:
|
||||||
worse_lines.append(char + '+' +
|
errline = ErrLine(char + '+', _BoardList(line, line_boards),
|
||||||
_BoardList(line, line_boards) + line)
|
line)
|
||||||
|
worse_lines.append(errline)
|
||||||
for line in base_lines:
|
for line in base_lines:
|
||||||
if line not in lines:
|
if line not in lines:
|
||||||
better_lines.append(char + '-' +
|
errline = ErrLine(char + '-',
|
||||||
_BoardList(line, base_line_boards) + line)
|
_BoardList(line, base_line_boards), line)
|
||||||
|
better_lines.append(errline)
|
||||||
return better_lines, worse_lines
|
return better_lines, worse_lines
|
||||||
|
|
||||||
def _CalcConfig(delta, name, config):
|
def _CalcConfig(delta, name, config):
|
||||||
|
@ -1209,6 +1234,34 @@ class Builder:
|
||||||
col = self.col.YELLOW
|
col = self.col.YELLOW
|
||||||
Print(' ' + line, newline=True, colour=col)
|
Print(' ' + line, newline=True, colour=col)
|
||||||
|
|
||||||
|
def _OutputErrLines(err_lines, colour):
|
||||||
|
"""Output the line of error/warning lines, if not empty
|
||||||
|
|
||||||
|
Also increments self._error_lines if err_lines not empty
|
||||||
|
|
||||||
|
Args:
|
||||||
|
err_lines: List of ErrLine objects, each an error or warning
|
||||||
|
line, possibly including a list of boards with that
|
||||||
|
error/warning
|
||||||
|
colour: Colour to use for output
|
||||||
|
"""
|
||||||
|
if err_lines:
|
||||||
|
out_list = []
|
||||||
|
for line in err_lines:
|
||||||
|
boards = ''
|
||||||
|
names = [board.target for board in line.boards]
|
||||||
|
board_str = ' '.join(names) if names else ''
|
||||||
|
if board_str:
|
||||||
|
out = self.col.Color(colour, line.char + '(')
|
||||||
|
out += self.col.Color(self.col.MAGENTA, board_str,
|
||||||
|
bright=False)
|
||||||
|
out += self.col.Color(colour, ') %s' % line.errline)
|
||||||
|
else:
|
||||||
|
out = self.col.Color(colour, line.char + line.errline)
|
||||||
|
out_list.append(out)
|
||||||
|
Print('\n'.join(out_list))
|
||||||
|
self._error_lines += 1
|
||||||
|
|
||||||
|
|
||||||
ok_boards = [] # List of boards fixed since last commit
|
ok_boards = [] # List of boards fixed since last commit
|
||||||
warn_boards = [] # List of boards with warnings since last commit
|
warn_boards = [] # List of boards with warnings since last commit
|
||||||
|
@ -1239,7 +1292,7 @@ class Builder:
|
||||||
else:
|
else:
|
||||||
new_boards.append(target)
|
new_boards.append(target)
|
||||||
|
|
||||||
# Get a list of errors that have appeared, and disappeared
|
# Get a list of errors and warnings that have appeared, and disappeared
|
||||||
better_err, worse_err = _CalcErrorDelta(self._base_err_lines,
|
better_err, worse_err = _CalcErrorDelta(self._base_err_lines,
|
||||||
self._base_err_line_boards, err_lines, err_line_boards, '')
|
self._base_err_line_boards, err_lines, err_line_boards, '')
|
||||||
better_warn, worse_warn = _CalcErrorDelta(self._base_warn_lines,
|
better_warn, worse_warn = _CalcErrorDelta(self._base_warn_lines,
|
||||||
|
@ -1262,18 +1315,10 @@ class Builder:
|
||||||
for arch, target_list in arch_list.items():
|
for arch, target_list in arch_list.items():
|
||||||
Print('%10s: %s' % (arch, target_list))
|
Print('%10s: %s' % (arch, target_list))
|
||||||
self._error_lines += 1
|
self._error_lines += 1
|
||||||
if better_err:
|
_OutputErrLines(better_err, colour=self.col.GREEN)
|
||||||
Print('\n'.join(better_err), colour=self.col.GREEN)
|
_OutputErrLines(worse_err, colour=self.col.RED)
|
||||||
self._error_lines += 1
|
_OutputErrLines(better_warn, colour=self.col.CYAN)
|
||||||
if worse_err:
|
_OutputErrLines(worse_warn, colour=self.col.YELLOW)
|
||||||
Print('\n'.join(worse_err), colour=self.col.RED)
|
|
||||||
self._error_lines += 1
|
|
||||||
if better_warn:
|
|
||||||
Print('\n'.join(better_warn), colour=self.col.CYAN)
|
|
||||||
self._error_lines += 1
|
|
||||||
if worse_warn:
|
|
||||||
Print('\n'.join(worse_warn), colour=self.col.MAGENTA)
|
|
||||||
self._error_lines += 1
|
|
||||||
|
|
||||||
if show_sizes:
|
if show_sizes:
|
||||||
self.PrintSizeSummary(board_selected, board_dict, show_detail,
|
self.PrintSizeSummary(board_selected, board_dict, show_detail,
|
||||||
|
@ -1506,12 +1551,15 @@ class Builder:
|
||||||
if setup_git and self.git_dir:
|
if setup_git and self.git_dir:
|
||||||
src_dir = os.path.abspath(self.git_dir)
|
src_dir = os.path.abspath(self.git_dir)
|
||||||
if os.path.exists(git_dir):
|
if os.path.exists(git_dir):
|
||||||
|
Print('\rFetching repo for thread %d' % thread_num,
|
||||||
|
newline=False)
|
||||||
gitutil.Fetch(git_dir, thread_dir)
|
gitutil.Fetch(git_dir, thread_dir)
|
||||||
|
terminal.PrintClear()
|
||||||
else:
|
else:
|
||||||
Print('\rCloning repo for thread %d' % thread_num,
|
Print('\rCloning repo for thread %d' % thread_num,
|
||||||
newline=False)
|
newline=False)
|
||||||
gitutil.Clone(src_dir, thread_dir)
|
gitutil.Clone(src_dir, thread_dir)
|
||||||
Print('\r%s\r' % (' ' * 30), newline=False)
|
terminal.PrintClear()
|
||||||
|
|
||||||
def _PrepareWorkingSpace(self, max_threads, setup_git):
|
def _PrepareWorkingSpace(self, max_threads, setup_git):
|
||||||
"""Prepare the working directory for use.
|
"""Prepare the working directory for use.
|
||||||
|
@ -1564,7 +1612,7 @@ class Builder:
|
||||||
newline=False)
|
newline=False)
|
||||||
for dirname in to_remove:
|
for dirname in to_remove:
|
||||||
shutil.rmtree(dirname)
|
shutil.rmtree(dirname)
|
||||||
Print('done')
|
terminal.PrintClear()
|
||||||
|
|
||||||
def BuildBoards(self, commits, board_selected, keep_outputs, verbose):
|
def BuildBoards(self, commits, board_selected, keep_outputs, verbose):
|
||||||
"""Build all commits for a list of boards
|
"""Build all commits for a list of boards
|
||||||
|
@ -1612,5 +1660,19 @@ class Builder:
|
||||||
# Wait until we have processed all output
|
# Wait until we have processed all output
|
||||||
self.out_queue.join()
|
self.out_queue.join()
|
||||||
Print()
|
Print()
|
||||||
self.ClearLine(0)
|
|
||||||
|
msg = 'Completed: %d total built' % self.count
|
||||||
|
if self.already_done:
|
||||||
|
msg += ' (%d previously' % self.already_done
|
||||||
|
if self.already_done != self.count:
|
||||||
|
msg += ', %d newly' % (self.count - self.already_done)
|
||||||
|
msg += ')'
|
||||||
|
duration = datetime.now() - self._start_time
|
||||||
|
if duration > timedelta(microseconds=1000000):
|
||||||
|
if duration.microseconds >= 500000:
|
||||||
|
duration = duration + timedelta(seconds=1)
|
||||||
|
duration = duration - timedelta(microseconds=duration.microseconds)
|
||||||
|
msg += ', duration %s' % duration
|
||||||
|
Print(msg)
|
||||||
|
|
||||||
return (self.fail, self.warned)
|
return (self.fail, self.warned)
|
||||||
|
|
|
@ -90,12 +90,12 @@ class BuilderThread(threading.Thread):
|
||||||
thread_num: Our thread number (0-n-1), used to decide on a
|
thread_num: Our thread number (0-n-1), used to decide on a
|
||||||
temporary directory
|
temporary directory
|
||||||
"""
|
"""
|
||||||
def __init__(self, builder, thread_num, incremental, per_board_out_dir):
|
def __init__(self, builder, thread_num, mrproper, per_board_out_dir):
|
||||||
"""Set up a new builder thread"""
|
"""Set up a new builder thread"""
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.builder = builder
|
self.builder = builder
|
||||||
self.thread_num = thread_num
|
self.thread_num = thread_num
|
||||||
self.incremental = incremental
|
self.mrproper = mrproper
|
||||||
self.per_board_out_dir = per_board_out_dir
|
self.per_board_out_dir = per_board_out_dir
|
||||||
|
|
||||||
def Make(self, commit, brd, stage, cwd, *args, **kwargs):
|
def Make(self, commit, brd, stage, cwd, *args, **kwargs):
|
||||||
|
@ -243,7 +243,7 @@ class BuilderThread(threading.Thread):
|
||||||
# If we need to reconfigure, do that now
|
# If we need to reconfigure, do that now
|
||||||
if do_config:
|
if do_config:
|
||||||
config_out = ''
|
config_out = ''
|
||||||
if not self.incremental:
|
if self.mrproper:
|
||||||
result = self.Make(commit, brd, 'mrproper', cwd,
|
result = self.Make(commit, brd, 'mrproper', cwd,
|
||||||
'mrproper', *args, env=env)
|
'mrproper', *args, env=env)
|
||||||
config_out += result.combined
|
config_out += result.combined
|
||||||
|
|
|
@ -55,8 +55,9 @@ def ParseArgs():
|
||||||
parser.add_option('-i', '--in-tree', dest='in_tree',
|
parser.add_option('-i', '--in-tree', dest='in_tree',
|
||||||
action='store_true', default=False,
|
action='store_true', default=False,
|
||||||
help='Build in the source tree instead of a separate directory')
|
help='Build in the source tree instead of a separate directory')
|
||||||
|
# -I will be removed after April 2021
|
||||||
parser.add_option('-I', '--incremental', action='store_true',
|
parser.add_option('-I', '--incremental', action='store_true',
|
||||||
default=False, help='Do not run make mrproper (when reconfiguring)')
|
default=False, help='Deprecated, does nothing. See -m')
|
||||||
parser.add_option('-j', '--jobs', dest='jobs', type='int',
|
parser.add_option('-j', '--jobs', dest='jobs', type='int',
|
||||||
default=None, help='Number of jobs to run at once (passed to make)')
|
default=None, help='Number of jobs to run at once (passed to make)')
|
||||||
parser.add_option('-k', '--keep-outputs', action='store_true',
|
parser.add_option('-k', '--keep-outputs', action='store_true',
|
||||||
|
@ -69,6 +70,8 @@ def ParseArgs():
|
||||||
default=False, help='Show a list of boards next to each error/warning')
|
default=False, help='Show a list of boards next to each error/warning')
|
||||||
parser.add_option('--list-tool-chains', action='store_true', default=False,
|
parser.add_option('--list-tool-chains', action='store_true', default=False,
|
||||||
help='List available tool chains (use -v to see probing detail)')
|
help='List available tool chains (use -v to see probing detail)')
|
||||||
|
parser.add_option('-m', '--mrproper', action='store_true',
|
||||||
|
default=False, help="Run 'make mrproper before reconfiguring")
|
||||||
parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
|
parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
|
||||||
default=False, help="Do a dry run (describe actions, but do nothing)")
|
default=False, help="Do a dry run (describe actions, but do nothing)")
|
||||||
parser.add_option('-N', '--no-subdirs', action='store_true', dest='no_subdirs',
|
parser.add_option('-N', '--no-subdirs', action='store_true', dest='no_subdirs',
|
||||||
|
@ -111,6 +114,12 @@ def ParseArgs():
|
||||||
parser.add_option('-x', '--exclude', dest='exclude',
|
parser.add_option('-x', '--exclude', dest='exclude',
|
||||||
type='string', action='append',
|
type='string', action='append',
|
||||||
help='Specify a list of boards to exclude, separated by comma')
|
help='Specify a list of boards to exclude, separated by comma')
|
||||||
|
parser.add_option('-y', '--filter-dtb-warnings', action='store_true',
|
||||||
|
default=False,
|
||||||
|
help='Filter out device-tree-compiler warnings from output')
|
||||||
|
parser.add_option('-Y', '--filter-migration-warnings', action='store_true',
|
||||||
|
default=False,
|
||||||
|
help='Filter out migration warnings from output')
|
||||||
|
|
||||||
parser.usage += """ [list of target/arch/cpu/board/vendor/soc to build]
|
parser.usage += """ [list of target/arch/cpu/board/vendor/soc to build]
|
||||||
|
|
||||||
|
|
|
@ -172,6 +172,10 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
|
||||||
print()
|
print()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
if options.incremental:
|
||||||
|
print(col.Color(col.RED,
|
||||||
|
'Warning: -I has been removed. See documentation'))
|
||||||
|
|
||||||
# Work out what subset of the boards we are building
|
# Work out what subset of the boards we are building
|
||||||
if not boards:
|
if not boards:
|
||||||
if not os.path.exists(options.output_dir):
|
if not os.path.exists(options.output_dir):
|
||||||
|
@ -309,7 +313,7 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
|
||||||
show_unknown=options.show_unknown, step=options.step,
|
show_unknown=options.show_unknown, step=options.step,
|
||||||
no_subdirs=options.no_subdirs, full_path=options.full_path,
|
no_subdirs=options.no_subdirs, full_path=options.full_path,
|
||||||
verbose_build=options.verbose_build,
|
verbose_build=options.verbose_build,
|
||||||
incremental=options.incremental,
|
mrproper=options.mrproper,
|
||||||
per_board_out_dir=options.per_board_out_dir,
|
per_board_out_dir=options.per_board_out_dir,
|
||||||
config_only=options.config_only,
|
config_only=options.config_only,
|
||||||
squash_config_y=not options.preserve_config_y,
|
squash_config_y=not options.preserve_config_y,
|
||||||
|
@ -346,18 +350,18 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
|
||||||
# We can't show function sizes without board details at present
|
# We can't show function sizes without board details at present
|
||||||
if options.show_bloat:
|
if options.show_bloat:
|
||||||
options.show_detail = True
|
options.show_detail = True
|
||||||
builder.SetDisplayOptions(options.show_errors, options.show_sizes,
|
builder.SetDisplayOptions(
|
||||||
options.show_detail, options.show_bloat,
|
options.show_errors, options.show_sizes, options.show_detail,
|
||||||
options.list_error_boards,
|
options.show_bloat, options.list_error_boards, options.show_config,
|
||||||
options.show_config,
|
options.show_environment, options.filter_dtb_warnings,
|
||||||
options.show_environment)
|
options.filter_migration_warnings)
|
||||||
if options.summary:
|
if options.summary:
|
||||||
builder.ShowSummary(commits, board_selected)
|
builder.ShowSummary(commits, board_selected)
|
||||||
else:
|
else:
|
||||||
fail, warned = builder.BuildBoards(commits, board_selected,
|
fail, warned = builder.BuildBoards(commits, board_selected,
|
||||||
options.keep_outputs, options.verbose)
|
options.keep_outputs, options.verbose)
|
||||||
if fail:
|
if fail:
|
||||||
return 128
|
return 100
|
||||||
elif warned and not options.ignore_warnings:
|
elif warned and not options.ignore_warnings:
|
||||||
return 129
|
return 101
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -454,7 +454,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
# Only sandbox should succeed, the others don't have toolchains
|
# Only sandbox should succeed, the others don't have toolchains
|
||||||
self.assertEqual(self._builder.fail,
|
self.assertEqual(self._builder.fail,
|
||||||
self._total_builds - self._commits)
|
self._total_builds - self._commits)
|
||||||
self.assertEqual(ret_code, 128)
|
self.assertEqual(ret_code, 100)
|
||||||
|
|
||||||
for commit in range(self._commits):
|
for commit in range(self._commits):
|
||||||
for board in self._boards.GetList():
|
for board in self._boards.GetList():
|
||||||
|
@ -476,15 +476,15 @@ class TestFunctional(unittest.TestCase):
|
||||||
self._RunControl('-b', TEST_BRANCH, '-c2', '-o', self._output_dir)
|
self._RunControl('-b', TEST_BRANCH, '-c2', '-o', self._output_dir)
|
||||||
self.assertEqual(self._builder.count, 2 * len(boards))
|
self.assertEqual(self._builder.count, 2 * len(boards))
|
||||||
self.assertEqual(self._builder.fail, 0)
|
self.assertEqual(self._builder.fail, 0)
|
||||||
# Each board has a mrproper, config, and then one make per commit
|
# Each board has a config, and then one make per commit
|
||||||
self.assertEqual(self._make_calls, len(boards) * (2 + 2))
|
self.assertEqual(self._make_calls, len(boards) * (1 + 2))
|
||||||
|
|
||||||
def testIncremental(self):
|
def testIncremental(self):
|
||||||
"""Test building a branch twice - the second time should do nothing"""
|
"""Test building a branch twice - the second time should do nothing"""
|
||||||
self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
|
self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
|
||||||
|
|
||||||
# Each board has a mrproper, config, and then one make per commit
|
# Each board has a mrproper, config, and then one make per commit
|
||||||
self.assertEqual(self._make_calls, len(boards) * (self._commits + 2))
|
self.assertEqual(self._make_calls, len(boards) * (self._commits + 1))
|
||||||
self._make_calls = 0
|
self._make_calls = 0
|
||||||
self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir, clean_dir=False)
|
self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir, clean_dir=False)
|
||||||
self.assertEqual(self._make_calls, 0)
|
self.assertEqual(self._make_calls, 0)
|
||||||
|
@ -496,14 +496,26 @@ class TestFunctional(unittest.TestCase):
|
||||||
self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
|
self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir)
|
||||||
self._make_calls = 0
|
self._make_calls = 0
|
||||||
self._RunControl('-b', TEST_BRANCH, '-f', '-o', self._output_dir, clean_dir=False)
|
self._RunControl('-b', TEST_BRANCH, '-f', '-o', self._output_dir, clean_dir=False)
|
||||||
# Each board has a mrproper, config, and then one make per commit
|
# Each board has a config and one make per commit
|
||||||
self.assertEqual(self._make_calls, len(boards) * (self._commits + 2))
|
self.assertEqual(self._make_calls, len(boards) * (self._commits + 1))
|
||||||
|
|
||||||
def testForceReconfigure(self):
|
def testForceReconfigure(self):
|
||||||
"""The -f flag should force a rebuild"""
|
"""The -f flag should force a rebuild"""
|
||||||
self._RunControl('-b', TEST_BRANCH, '-C', '-o', self._output_dir)
|
self._RunControl('-b', TEST_BRANCH, '-C', '-o', self._output_dir)
|
||||||
# Each commit has a mrproper, config and make
|
# Each commit has a config and make
|
||||||
self.assertEqual(self._make_calls, len(boards) * self._commits * 3)
|
self.assertEqual(self._make_calls, len(boards) * self._commits * 2)
|
||||||
|
|
||||||
|
def testForceReconfigure(self):
|
||||||
|
"""The -f flag should force a rebuild"""
|
||||||
|
self._RunControl('-b', TEST_BRANCH, '-C', '-o', self._output_dir)
|
||||||
|
# Each commit has a config and make
|
||||||
|
self.assertEqual(self._make_calls, len(boards) * self._commits * 2)
|
||||||
|
|
||||||
|
def testMrproper(self):
|
||||||
|
"""The -f flag should force a rebuild"""
|
||||||
|
self._RunControl('-b', TEST_BRANCH, '-m', '-o', self._output_dir)
|
||||||
|
# Each board has a mkproper, config and then one make per commit
|
||||||
|
self.assertEqual(self._make_calls, len(boards) * (self._commits + 2))
|
||||||
|
|
||||||
def testErrors(self):
|
def testErrors(self):
|
||||||
"""Test handling of build errors"""
|
"""Test handling of build errors"""
|
||||||
|
@ -525,7 +537,7 @@ class TestFunctional(unittest.TestCase):
|
||||||
self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir, '-F', clean_dir=False)
|
self._RunControl('-b', TEST_BRANCH, '-o', self._output_dir, '-F', clean_dir=False)
|
||||||
self.assertEqual(self._builder.count, self._total_builds)
|
self.assertEqual(self._builder.count, self._total_builds)
|
||||||
self.assertEqual(self._builder.fail, 0)
|
self.assertEqual(self._builder.fail, 0)
|
||||||
self.assertEqual(self._make_calls, 3)
|
self.assertEqual(self._make_calls, 2)
|
||||||
|
|
||||||
def testBranchWithSlash(self):
|
def testBranchWithSlash(self):
|
||||||
"""Test building a branch with a '/' in the name"""
|
"""Test building a branch with a '/' in the name"""
|
||||||
|
|
|
@ -36,6 +36,14 @@ main: /usr/sbin
|
||||||
x86: i386 x86_64
|
x86: i386 x86_64
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
migration = '''===================== WARNING ======================
|
||||||
|
This board does not use CONFIG_DM. CONFIG_DM will be
|
||||||
|
compulsory starting with the v2020.01 release.
|
||||||
|
Failure to update may result in board removal.
|
||||||
|
See doc/driver-model/migration.rst for more info.
|
||||||
|
====================================================
|
||||||
|
'''
|
||||||
|
|
||||||
errors = [
|
errors = [
|
||||||
'''main.c: In function 'main_loop':
|
'''main.c: In function 'main_loop':
|
||||||
main.c:260:6: warning: unused variable 'joe' [-Wunused-variable]
|
main.c:260:6: warning: unused variable 'joe' [-Wunused-variable]
|
||||||
|
@ -79,13 +87,14 @@ make: *** [sub-make] Error 2
|
||||||
|
|
||||||
# hash, subject, return code, list of errors/warnings
|
# hash, subject, return code, list of errors/warnings
|
||||||
commits = [
|
commits = [
|
||||||
['1234', 'upstream/master, ok', 0, []],
|
['1234', 'upstream/master, migration warning', 0, []],
|
||||||
['5678', 'Second commit, a warning', 0, errors[0:1]],
|
['5678', 'Second commit, a warning', 0, errors[0:1]],
|
||||||
['9012', 'Third commit, error', 1, errors[0:2]],
|
['9012', 'Third commit, error', 1, errors[0:2]],
|
||||||
['3456', 'Fourth commit, warning', 0, [errors[0], errors[2]]],
|
['3456', 'Fourth commit, warning', 0, [errors[0], errors[2]]],
|
||||||
['7890', 'Fifth commit, link errors', 1, [errors[0], errors[3]]],
|
['7890', 'Fifth commit, link errors', 1, [errors[0], errors[3]]],
|
||||||
['abcd', 'Sixth commit, fixes all errors', 0, []],
|
['abcd', 'Sixth commit, fixes all errors', 0, []],
|
||||||
['ef01', 'Seventh commit, check directory suppression', 1, [errors[4]]],
|
['ef01', 'Seventh commit, fix migration, check directory suppression', 1,
|
||||||
|
[errors[4]]],
|
||||||
]
|
]
|
||||||
|
|
||||||
boards = [
|
boards = [
|
||||||
|
@ -118,6 +127,8 @@ class TestBuild(unittest.TestCase):
|
||||||
comm.subject = commit_info[1]
|
comm.subject = commit_info[1]
|
||||||
comm.return_code = commit_info[2]
|
comm.return_code = commit_info[2]
|
||||||
comm.error_list = commit_info[3]
|
comm.error_list = commit_info[3]
|
||||||
|
if sequence < 6:
|
||||||
|
comm.error_list += [migration]
|
||||||
comm.sequence = sequence
|
comm.sequence = sequence
|
||||||
sequence += 1
|
sequence += 1
|
||||||
self.commits.append(comm)
|
self.commits.append(comm)
|
||||||
|
@ -143,9 +154,14 @@ class TestBuild(unittest.TestCase):
|
||||||
terminal.SetPrintTestMode()
|
terminal.SetPrintTestMode()
|
||||||
self._col = terminal.Color()
|
self._col = terminal.Color()
|
||||||
|
|
||||||
def Make(self, commit, brd, stage, *args, **kwargs):
|
self.base_dir = tempfile.mkdtemp()
|
||||||
global base_dir
|
if not os.path.isdir(self.base_dir):
|
||||||
|
os.mkdir(self.base_dir)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
shutil.rmtree(self.base_dir)
|
||||||
|
|
||||||
|
def Make(self, commit, brd, stage, *args, **kwargs):
|
||||||
result = command.CommandResult()
|
result = command.CommandResult()
|
||||||
boardnum = int(brd.target[-1])
|
boardnum = int(brd.target[-1])
|
||||||
result.return_code = 0
|
result.return_code = 0
|
||||||
|
@ -156,7 +172,9 @@ class TestBuild(unittest.TestCase):
|
||||||
boardnum == 4 and commit.sequence == 6):
|
boardnum == 4 and commit.sequence == 6):
|
||||||
result.return_code = commit.return_code
|
result.return_code = commit.return_code
|
||||||
result.stderr = (''.join(commit.error_list)
|
result.stderr = (''.join(commit.error_list)
|
||||||
% {'basedir' : base_dir + '/.bm-work/00/'})
|
% {'basedir' : self.base_dir + '/.bm-work/00/'})
|
||||||
|
elif commit.sequence < 6:
|
||||||
|
result.stderr = migration
|
||||||
|
|
||||||
result.combined = result.stdout + result.stderr
|
result.combined = result.stdout + result.stderr
|
||||||
return result
|
return result
|
||||||
|
@ -173,17 +191,19 @@ class TestBuild(unittest.TestCase):
|
||||||
expect += col.Color(expected_colour, ' %s' % board)
|
expect += col.Color(expected_colour, ' %s' % board)
|
||||||
self.assertEqual(text, expect)
|
self.assertEqual(text, expect)
|
||||||
|
|
||||||
def testOutput(self):
|
def _SetupTest(self, echo_lines=False, **kwdisplay_args):
|
||||||
"""Test basic builder operation and output
|
"""Set up the test by running a build and summary
|
||||||
|
|
||||||
This does a line-by-line verification of the summary output.
|
Args:
|
||||||
|
echo_lines: True to echo lines to the terminal to aid test
|
||||||
|
development
|
||||||
|
kwdisplay_args: Dict of arguemnts to pass to
|
||||||
|
Builder.SetDisplayOptions()
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Iterator containing the output lines, each a PrintLine() object
|
||||||
"""
|
"""
|
||||||
global base_dir
|
build = builder.Builder(self.toolchains, self.base_dir, None, 1, 2,
|
||||||
|
|
||||||
base_dir = tempfile.mkdtemp()
|
|
||||||
if not os.path.isdir(base_dir):
|
|
||||||
os.mkdir(base_dir)
|
|
||||||
build = builder.Builder(self.toolchains, base_dir, None, 1, 2,
|
|
||||||
checkout=False, show_unknown=False)
|
checkout=False, show_unknown=False)
|
||||||
build.do_make = self.Make
|
build.do_make = self.Make
|
||||||
board_selected = self.boards.GetSelectedDict()
|
board_selected = self.boards.GetSelectedDict()
|
||||||
|
@ -198,46 +218,107 @@ class TestBuild(unittest.TestCase):
|
||||||
if line.text.strip():
|
if line.text.strip():
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
# We should get two starting messages, then an update for every commit
|
# We should get two starting messages, an update for every commit built
|
||||||
# built.
|
# and a summary message
|
||||||
self.assertEqual(count, len(commits) * len(boards) + 2)
|
self.assertEqual(count, len(commits) * len(boards) + 3)
|
||||||
build.SetDisplayOptions(show_errors=True);
|
build.SetDisplayOptions(**kwdisplay_args);
|
||||||
build.ShowSummary(self.commits, board_selected)
|
build.ShowSummary(self.commits, board_selected)
|
||||||
#terminal.EchoPrintTestLines()
|
if echo_lines:
|
||||||
lines = terminal.GetPrintTestLines()
|
terminal.EchoPrintTestLines()
|
||||||
|
return iter(terminal.GetPrintTestLines())
|
||||||
|
|
||||||
# Upstream commit: no errors
|
def _CheckOutput(self, lines, list_error_boards=False,
|
||||||
self.assertEqual(lines[0].text, '01: %s' % commits[0][1])
|
filter_dtb_warnings=False,
|
||||||
|
filter_migration_warnings=False):
|
||||||
|
"""Check for expected output from the build summary
|
||||||
|
|
||||||
# Second commit: all archs should fail with warnings
|
Args:
|
||||||
self.assertEqual(lines[1].text, '02: %s' % commits[1][1])
|
lines: Iterator containing the lines returned from the summary
|
||||||
|
list_error_boards: Adjust the check for output produced with the
|
||||||
|
--list-error-boards flag
|
||||||
|
filter_dtb_warnings: Adjust the check for output produced with the
|
||||||
|
--filter-dtb-warnings flag
|
||||||
|
"""
|
||||||
|
def add_line_prefix(prefix, boards, error_str, colour):
|
||||||
|
"""Add a prefix to each line of a string
|
||||||
|
|
||||||
|
The training \n in error_str is removed before processing
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prefix: String prefix to add
|
||||||
|
error_str: Error string containing the lines
|
||||||
|
colour: Expected colour for the line. Note that the board list,
|
||||||
|
if present, always appears in magenta
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
New string where each line has the prefix added
|
||||||
|
"""
|
||||||
|
lines = error_str.strip().splitlines()
|
||||||
|
new_lines = []
|
||||||
|
for line in lines:
|
||||||
|
if boards:
|
||||||
|
expect = self._col.Color(colour, prefix + '(')
|
||||||
|
expect += self._col.Color(self._col.MAGENTA, boards,
|
||||||
|
bright=False)
|
||||||
|
expect += self._col.Color(colour, ') %s' % line)
|
||||||
|
else:
|
||||||
|
expect = self._col.Color(colour, prefix + line)
|
||||||
|
new_lines.append(expect)
|
||||||
|
return '\n'.join(new_lines)
|
||||||
|
|
||||||
col = terminal.Color()
|
col = terminal.Color()
|
||||||
self.assertSummary(lines[2].text, 'arm', 'w+', ['board1'],
|
boards01234 = ('board0 board1 board2 board3 board4'
|
||||||
|
if list_error_boards else '')
|
||||||
|
boards1234 = 'board1 board2 board3 board4' if list_error_boards else ''
|
||||||
|
boards234 = 'board2 board3 board4' if list_error_boards else ''
|
||||||
|
boards34 = 'board3 board4' if list_error_boards else ''
|
||||||
|
boards4 = 'board4' if list_error_boards else ''
|
||||||
|
|
||||||
|
# Upstream commit: migration warnings only
|
||||||
|
self.assertEqual(next(lines).text, '01: %s' % commits[0][1])
|
||||||
|
|
||||||
|
if not filter_migration_warnings:
|
||||||
|
self.assertSummary(next(lines).text, 'arm', 'w+',
|
||||||
|
['board0', 'board1'], outcome=OUTCOME_WARN)
|
||||||
|
self.assertSummary(next(lines).text, 'powerpc', 'w+',
|
||||||
|
['board2', 'board3'], outcome=OUTCOME_WARN)
|
||||||
|
self.assertSummary(next(lines).text, 'sandbox', 'w+', ['board4'],
|
||||||
outcome=OUTCOME_WARN)
|
outcome=OUTCOME_WARN)
|
||||||
self.assertSummary(lines[3].text, 'powerpc', 'w+', ['board2', 'board3'],
|
|
||||||
outcome=OUTCOME_WARN)
|
self.assertEqual(next(lines).text,
|
||||||
self.assertSummary(lines[4].text, 'sandbox', 'w+', ['board4'],
|
add_line_prefix('+', boards01234, migration, col.RED))
|
||||||
|
|
||||||
|
# Second commit: all archs should fail with warnings
|
||||||
|
self.assertEqual(next(lines).text, '02: %s' % commits[1][1])
|
||||||
|
|
||||||
|
if filter_migration_warnings:
|
||||||
|
self.assertSummary(next(lines).text, 'arm', 'w+',
|
||||||
|
['board1'], outcome=OUTCOME_WARN)
|
||||||
|
self.assertSummary(next(lines).text, 'powerpc', 'w+',
|
||||||
|
['board2', 'board3'], outcome=OUTCOME_WARN)
|
||||||
|
self.assertSummary(next(lines).text, 'sandbox', 'w+', ['board4'],
|
||||||
outcome=OUTCOME_WARN)
|
outcome=OUTCOME_WARN)
|
||||||
|
|
||||||
# Second commit: The warnings should be listed
|
# Second commit: The warnings should be listed
|
||||||
self.assertEqual(lines[5].text, 'w+%s' %
|
self.assertEqual(next(lines).text,
|
||||||
errors[0].rstrip().replace('\n', '\nw+'))
|
add_line_prefix('w+', boards1234, errors[0], col.YELLOW))
|
||||||
self.assertEqual(lines[5].colour, col.MAGENTA)
|
|
||||||
|
|
||||||
# Third commit: Still fails
|
# Third commit: Still fails
|
||||||
self.assertEqual(lines[6].text, '03: %s' % commits[2][1])
|
self.assertEqual(next(lines).text, '03: %s' % commits[2][1])
|
||||||
self.assertSummary(lines[7].text, 'arm', '', ['board1'],
|
if filter_migration_warnings:
|
||||||
outcome=OUTCOME_OK)
|
self.assertSummary(next(lines).text, 'arm', '',
|
||||||
self.assertSummary(lines[8].text, 'powerpc', '+', ['board2', 'board3'])
|
['board1'], outcome=OUTCOME_OK)
|
||||||
self.assertSummary(lines[9].text, 'sandbox', '+', ['board4'])
|
self.assertSummary(next(lines).text, 'powerpc', '+',
|
||||||
|
['board2', 'board3'])
|
||||||
|
self.assertSummary(next(lines).text, 'sandbox', '+', ['board4'])
|
||||||
|
|
||||||
# Expect a compiler error
|
# Expect a compiler error
|
||||||
self.assertEqual(lines[10].text, '+%s' %
|
self.assertEqual(next(lines).text,
|
||||||
errors[1].rstrip().replace('\n', '\n+'))
|
add_line_prefix('+', boards234, errors[1], col.RED))
|
||||||
|
|
||||||
# Fourth commit: Compile errors are fixed, just have warning for board3
|
# Fourth commit: Compile errors are fixed, just have warning for board3
|
||||||
self.assertEqual(lines[11].text, '04: %s' % commits[3][1])
|
self.assertEqual(next(lines).text, '04: %s' % commits[3][1])
|
||||||
|
if filter_migration_warnings:
|
||||||
expect = '%10s: ' % 'powerpc'
|
expect = '%10s: ' % 'powerpc'
|
||||||
expect += ' ' + col.Color(col.GREEN, '')
|
expect += ' ' + col.Color(col.GREEN, '')
|
||||||
expect += ' '
|
expect += ' '
|
||||||
|
@ -245,77 +326,130 @@ class TestBuild(unittest.TestCase):
|
||||||
expect += ' ' + col.Color(col.YELLOW, 'w+')
|
expect += ' ' + col.Color(col.YELLOW, 'w+')
|
||||||
expect += ' '
|
expect += ' '
|
||||||
expect += col.Color(col.YELLOW, ' %s' % 'board3')
|
expect += col.Color(col.YELLOW, ' %s' % 'board3')
|
||||||
self.assertEqual(lines[12].text, expect)
|
self.assertEqual(next(lines).text, expect)
|
||||||
self.assertSummary(lines[13].text, 'sandbox', 'w+', ['board4'],
|
else:
|
||||||
|
self.assertSummary(next(lines).text, 'powerpc', 'w+',
|
||||||
|
['board2', 'board3'], outcome=OUTCOME_WARN)
|
||||||
|
self.assertSummary(next(lines).text, 'sandbox', 'w+', ['board4'],
|
||||||
outcome=OUTCOME_WARN)
|
outcome=OUTCOME_WARN)
|
||||||
|
|
||||||
# Compile error fixed
|
# Compile error fixed
|
||||||
self.assertEqual(lines[14].text, '-%s' %
|
self.assertEqual(next(lines).text,
|
||||||
errors[1].rstrip().replace('\n', '\n-'))
|
add_line_prefix('-', boards234, errors[1], col.GREEN))
|
||||||
self.assertEqual(lines[14].colour, col.GREEN)
|
|
||||||
|
|
||||||
self.assertEqual(lines[15].text, 'w+%s' %
|
if not filter_dtb_warnings:
|
||||||
errors[2].rstrip().replace('\n', '\nw+'))
|
self.assertEqual(
|
||||||
self.assertEqual(lines[15].colour, col.MAGENTA)
|
next(lines).text,
|
||||||
|
add_line_prefix('w+', boards34, errors[2], col.YELLOW))
|
||||||
|
|
||||||
# Fifth commit
|
# Fifth commit
|
||||||
self.assertEqual(lines[16].text, '05: %s' % commits[4][1])
|
self.assertEqual(next(lines).text, '05: %s' % commits[4][1])
|
||||||
self.assertSummary(lines[17].text, 'powerpc', '', ['board3'],
|
if filter_migration_warnings:
|
||||||
|
self.assertSummary(next(lines).text, 'powerpc', '', ['board3'],
|
||||||
outcome=OUTCOME_OK)
|
outcome=OUTCOME_OK)
|
||||||
self.assertSummary(lines[18].text, 'sandbox', '+', ['board4'])
|
self.assertSummary(next(lines).text, 'sandbox', '+', ['board4'])
|
||||||
|
|
||||||
# The second line of errors[3] is a duplicate, so buildman will drop it
|
# The second line of errors[3] is a duplicate, so buildman will drop it
|
||||||
expect = errors[3].rstrip().split('\n')
|
expect = errors[3].rstrip().split('\n')
|
||||||
expect = [expect[0]] + expect[2:]
|
expect = [expect[0]] + expect[2:]
|
||||||
self.assertEqual(lines[19].text, '+%s' %
|
expect = '\n'.join(expect)
|
||||||
'\n'.join(expect).replace('\n', '\n+'))
|
self.assertEqual(next(lines).text,
|
||||||
|
add_line_prefix('+', boards4, expect, col.RED))
|
||||||
|
|
||||||
self.assertEqual(lines[20].text, 'w-%s' %
|
if not filter_dtb_warnings:
|
||||||
errors[2].rstrip().replace('\n', '\nw-'))
|
self.assertEqual(
|
||||||
|
next(lines).text,
|
||||||
|
add_line_prefix('w-', boards34, errors[2], col.CYAN))
|
||||||
|
|
||||||
# Sixth commit
|
# Sixth commit
|
||||||
self.assertEqual(lines[21].text, '06: %s' % commits[5][1])
|
self.assertEqual(next(lines).text, '06: %s' % commits[5][1])
|
||||||
self.assertSummary(lines[22].text, 'sandbox', '', ['board4'],
|
if filter_migration_warnings:
|
||||||
|
self.assertSummary(next(lines).text, 'sandbox', '', ['board4'],
|
||||||
outcome=OUTCOME_OK)
|
outcome=OUTCOME_OK)
|
||||||
|
else:
|
||||||
|
self.assertSummary(next(lines).text, 'sandbox', 'w+', ['board4'],
|
||||||
|
outcome=OUTCOME_WARN)
|
||||||
|
|
||||||
# The second line of errors[3] is a duplicate, so buildman will drop it
|
# The second line of errors[3] is a duplicate, so buildman will drop it
|
||||||
expect = errors[3].rstrip().split('\n')
|
expect = errors[3].rstrip().split('\n')
|
||||||
expect = [expect[0]] + expect[2:]
|
expect = [expect[0]] + expect[2:]
|
||||||
self.assertEqual(lines[23].text, '-%s' %
|
expect = '\n'.join(expect)
|
||||||
'\n'.join(expect).replace('\n', '\n-'))
|
self.assertEqual(next(lines).text,
|
||||||
|
add_line_prefix('-', boards4, expect, col.GREEN))
|
||||||
self.assertEqual(lines[24].text, 'w-%s' %
|
self.assertEqual(next(lines).text,
|
||||||
errors[0].rstrip().replace('\n', '\nw-'))
|
add_line_prefix('w-', boards4, errors[0], col.CYAN))
|
||||||
|
|
||||||
# Seventh commit
|
# Seventh commit
|
||||||
self.assertEqual(lines[25].text, '07: %s' % commits[6][1])
|
self.assertEqual(next(lines).text, '07: %s' % commits[6][1])
|
||||||
self.assertSummary(lines[26].text, 'sandbox', '+', ['board4'])
|
if filter_migration_warnings:
|
||||||
|
self.assertSummary(next(lines).text, 'sandbox', '+', ['board4'])
|
||||||
|
else:
|
||||||
|
self.assertSummary(next(lines).text, 'arm', '', ['board0', 'board1'],
|
||||||
|
outcome=OUTCOME_OK)
|
||||||
|
self.assertSummary(next(lines).text, 'powerpc', '',
|
||||||
|
['board2', 'board3'], outcome=OUTCOME_OK)
|
||||||
|
self.assertSummary(next(lines).text, 'sandbox', '+', ['board4'])
|
||||||
|
|
||||||
# Pick out the correct error lines
|
# Pick out the correct error lines
|
||||||
expect_str = errors[4].rstrip().replace('%(basedir)s', '').split('\n')
|
expect_str = errors[4].rstrip().replace('%(basedir)s', '').split('\n')
|
||||||
expect = expect_str[3:8] + [expect_str[-1]]
|
expect = expect_str[3:8] + [expect_str[-1]]
|
||||||
self.assertEqual(lines[27].text, '+%s' %
|
expect = '\n'.join(expect)
|
||||||
'\n'.join(expect).replace('\n', '\n+'))
|
if not filter_migration_warnings:
|
||||||
|
self.assertEqual(
|
||||||
|
next(lines).text,
|
||||||
|
add_line_prefix('-', boards01234, migration, col.GREEN))
|
||||||
|
|
||||||
|
self.assertEqual(next(lines).text,
|
||||||
|
add_line_prefix('+', boards4, expect, col.RED))
|
||||||
|
|
||||||
# Now the warnings lines
|
# Now the warnings lines
|
||||||
expect = [expect_str[0]] + expect_str[10:12] + [expect_str[9]]
|
expect = [expect_str[0]] + expect_str[10:12] + [expect_str[9]]
|
||||||
self.assertEqual(lines[28].text, 'w+%s' %
|
expect = '\n'.join(expect)
|
||||||
'\n'.join(expect).replace('\n', '\nw+'))
|
self.assertEqual(next(lines).text,
|
||||||
|
add_line_prefix('w+', boards4, expect, col.YELLOW))
|
||||||
|
|
||||||
self.assertEqual(len(lines), 29)
|
def testOutput(self):
|
||||||
shutil.rmtree(base_dir)
|
"""Test basic builder operation and output
|
||||||
|
|
||||||
|
This does a line-by-line verification of the summary output.
|
||||||
|
"""
|
||||||
|
lines = self._SetupTest(show_errors=True)
|
||||||
|
self._CheckOutput(lines, list_error_boards=False,
|
||||||
|
filter_dtb_warnings=False)
|
||||||
|
|
||||||
|
def testErrorBoards(self):
|
||||||
|
"""Test output with --list-error-boards
|
||||||
|
|
||||||
|
This does a line-by-line verification of the summary output.
|
||||||
|
"""
|
||||||
|
lines = self._SetupTest(show_errors=True, list_error_boards=True)
|
||||||
|
self._CheckOutput(lines, list_error_boards=True)
|
||||||
|
|
||||||
|
def testFilterDtb(self):
|
||||||
|
"""Test output with --filter-dtb-warnings
|
||||||
|
|
||||||
|
This does a line-by-line verification of the summary output.
|
||||||
|
"""
|
||||||
|
lines = self._SetupTest(show_errors=True, filter_dtb_warnings=True)
|
||||||
|
self._CheckOutput(lines, filter_dtb_warnings=True)
|
||||||
|
|
||||||
|
def testFilterMigration(self):
|
||||||
|
"""Test output with --filter-migration-warnings
|
||||||
|
|
||||||
|
This does a line-by-line verification of the summary output.
|
||||||
|
"""
|
||||||
|
lines = self._SetupTest(show_errors=True,
|
||||||
|
filter_migration_warnings=True)
|
||||||
|
self._CheckOutput(lines, filter_migration_warnings=True)
|
||||||
|
|
||||||
def _testGit(self):
|
def _testGit(self):
|
||||||
"""Test basic builder operation by building a branch"""
|
"""Test basic builder operation by building a branch"""
|
||||||
base_dir = tempfile.mkdtemp()
|
|
||||||
if not os.path.isdir(base_dir):
|
|
||||||
os.mkdir(base_dir)
|
|
||||||
options = Options()
|
options = Options()
|
||||||
options.git = os.getcwd()
|
options.git = os.getcwd()
|
||||||
options.summary = False
|
options.summary = False
|
||||||
options.jobs = None
|
options.jobs = None
|
||||||
options.dry_run = False
|
options.dry_run = False
|
||||||
#options.git = os.path.join(base_dir, 'repo')
|
#options.git = os.path.join(self.base_dir, 'repo')
|
||||||
options.branch = 'test-buildman'
|
options.branch = 'test-buildman'
|
||||||
options.force_build = False
|
options.force_build = False
|
||||||
options.list_tool_chains = False
|
options.list_tool_chains = False
|
||||||
|
@ -328,7 +462,6 @@ class TestBuild(unittest.TestCase):
|
||||||
options.keep_outputs = False
|
options.keep_outputs = False
|
||||||
args = ['tegra20']
|
args = ['tegra20']
|
||||||
control.DoBuildman(options, args)
|
control.DoBuildman(options, args)
|
||||||
shutil.rmtree(base_dir)
|
|
||||||
|
|
||||||
def testBoardSingle(self):
|
def testBoardSingle(self):
|
||||||
"""Test single board selection"""
|
"""Test single board selection"""
|
||||||
|
|
|
@ -93,7 +93,7 @@ elif options.test:
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(module)
|
suite = unittest.TestLoader().loadTestsFromTestCase(module)
|
||||||
suite.run(result)
|
suite.run(result)
|
||||||
|
|
||||||
for module in ['gitutil', 'settings']:
|
for module in ['gitutil', 'settings', 'terminal']:
|
||||||
suite = doctest.DocTestSuite(module)
|
suite = doctest.DocTestSuite(module)
|
||||||
suite.run(result)
|
suite.run(result)
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ This module handles terminal interaction including ANSI color codes.
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# Selection of when we want our output to be colored
|
# Selection of when we want our output to be colored
|
||||||
|
@ -19,6 +21,13 @@ COLOR_IF_TERMINAL, COLOR_ALWAYS, COLOR_NEVER = range(3)
|
||||||
print_test_mode = False
|
print_test_mode = False
|
||||||
print_test_list = []
|
print_test_list = []
|
||||||
|
|
||||||
|
# The length of the last line printed without a newline
|
||||||
|
last_print_len = None
|
||||||
|
|
||||||
|
# credit:
|
||||||
|
# stackoverflow.com/questions/14693701/how-can-i-remove-the-ansi-escape-sequences-from-a-string-in-python
|
||||||
|
ansi_escape = re.compile(r'\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
|
||||||
|
|
||||||
class PrintLine:
|
class PrintLine:
|
||||||
"""A line of text output
|
"""A line of text output
|
||||||
|
|
||||||
|
@ -36,7 +45,86 @@ class PrintLine:
|
||||||
return 'newline=%s, colour=%s, text=%s' % (self.newline, self.colour,
|
return 'newline=%s, colour=%s, text=%s' % (self.newline, self.colour,
|
||||||
self.text)
|
self.text)
|
||||||
|
|
||||||
def Print(text='', newline=True, colour=None):
|
def CalcAsciiLen(text):
|
||||||
|
"""Calculate the length of a string, ignoring any ANSI sequences
|
||||||
|
|
||||||
|
When displayed on a terminal, ANSI sequences don't take any space, so we
|
||||||
|
need to ignore them when calculating the length of a string.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text: Text to check
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Length of text, after skipping ANSI sequences
|
||||||
|
|
||||||
|
>>> col = Color(COLOR_ALWAYS)
|
||||||
|
>>> text = col.Color(Color.RED, 'abc')
|
||||||
|
>>> len(text)
|
||||||
|
14
|
||||||
|
>>> CalcAsciiLen(text)
|
||||||
|
3
|
||||||
|
>>>
|
||||||
|
>>> text += 'def'
|
||||||
|
>>> CalcAsciiLen(text)
|
||||||
|
6
|
||||||
|
>>> text += col.Color(Color.RED, 'abc')
|
||||||
|
>>> CalcAsciiLen(text)
|
||||||
|
9
|
||||||
|
"""
|
||||||
|
result = ansi_escape.sub('', text)
|
||||||
|
return len(result)
|
||||||
|
|
||||||
|
def TrimAsciiLen(text, size):
|
||||||
|
"""Trim a string containing ANSI sequences to the given ASCII length
|
||||||
|
|
||||||
|
The string is trimmed with ANSI sequences being ignored for the length
|
||||||
|
calculation.
|
||||||
|
|
||||||
|
>>> col = Color(COLOR_ALWAYS)
|
||||||
|
>>> text = col.Color(Color.RED, 'abc')
|
||||||
|
>>> len(text)
|
||||||
|
14
|
||||||
|
>>> CalcAsciiLen(TrimAsciiLen(text, 4))
|
||||||
|
3
|
||||||
|
>>> CalcAsciiLen(TrimAsciiLen(text, 2))
|
||||||
|
2
|
||||||
|
>>> text += 'def'
|
||||||
|
>>> CalcAsciiLen(TrimAsciiLen(text, 4))
|
||||||
|
4
|
||||||
|
>>> text += col.Color(Color.RED, 'ghi')
|
||||||
|
>>> CalcAsciiLen(TrimAsciiLen(text, 7))
|
||||||
|
7
|
||||||
|
"""
|
||||||
|
if CalcAsciiLen(text) < size:
|
||||||
|
return text
|
||||||
|
pos = 0
|
||||||
|
out = ''
|
||||||
|
left = size
|
||||||
|
|
||||||
|
# Work through each ANSI sequence in turn
|
||||||
|
for m in ansi_escape.finditer(text):
|
||||||
|
# Find the text before the sequence and add it to our string, making
|
||||||
|
# sure it doesn't overflow
|
||||||
|
before = text[pos:m.start()]
|
||||||
|
toadd = before[:left]
|
||||||
|
out += toadd
|
||||||
|
|
||||||
|
# Figure out how much non-ANSI space we have left
|
||||||
|
left -= len(toadd)
|
||||||
|
|
||||||
|
# Add the ANSI sequence and move to the position immediately after it
|
||||||
|
out += m.group()
|
||||||
|
pos = m.start() + len(m.group())
|
||||||
|
|
||||||
|
# Deal with text after the last ANSI sequence
|
||||||
|
after = text[pos:]
|
||||||
|
toadd = after[:left]
|
||||||
|
out += toadd
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def Print(text='', newline=True, colour=None, limit_to_line=False):
|
||||||
"""Handle a line of output to the terminal.
|
"""Handle a line of output to the terminal.
|
||||||
|
|
||||||
In test mode this is recorded in a list. Otherwise it is output to the
|
In test mode this is recorded in a list. Otherwise it is output to the
|
||||||
|
@ -47,17 +135,31 @@ def Print(text='', newline=True, colour=None):
|
||||||
newline: True to add a new line at the end of the text
|
newline: True to add a new line at the end of the text
|
||||||
colour: Colour to use for the text
|
colour: Colour to use for the text
|
||||||
"""
|
"""
|
||||||
|
global last_print_len
|
||||||
|
|
||||||
if print_test_mode:
|
if print_test_mode:
|
||||||
print_test_list.append(PrintLine(text, newline, colour))
|
print_test_list.append(PrintLine(text, newline, colour))
|
||||||
else:
|
else:
|
||||||
if colour:
|
if colour:
|
||||||
col = Color()
|
col = Color()
|
||||||
text = col.Color(colour, text)
|
text = col.Color(colour, text)
|
||||||
print(text, end='')
|
|
||||||
if newline:
|
if newline:
|
||||||
print()
|
print(text)
|
||||||
|
last_print_len = None
|
||||||
else:
|
else:
|
||||||
sys.stdout.flush()
|
if limit_to_line:
|
||||||
|
cols = shutil.get_terminal_size().columns
|
||||||
|
text = TrimAsciiLen(text, cols)
|
||||||
|
print(text, end='', flush=True)
|
||||||
|
last_print_len = CalcAsciiLen(text)
|
||||||
|
|
||||||
|
def PrintClear():
|
||||||
|
"""Clear a previously line that was printed with no newline"""
|
||||||
|
global last_print_len
|
||||||
|
|
||||||
|
if last_print_len:
|
||||||
|
print('\r%s\r' % (' '* last_print_len), end='', flush=True)
|
||||||
|
last_print_len = None
|
||||||
|
|
||||||
def SetPrintTestMode():
|
def SetPrintTestMode():
|
||||||
"""Go into test mode, where all printing is recorded"""
|
"""Go into test mode, where all printing is recorded"""
|
||||||
|
|
Loading…
Add table
Reference in a new issue