Merge branch 'buildman' of git://git.denx.de/u-boot-x86
This commit is contained in:
commit
d1c3310d40
|
|
@ -141,8 +141,8 @@ $ git clone git://git.denx.de/u-boot.git .
|
||||||
$ git checkout -b my-branch origin/master
|
$ git checkout -b my-branch origin/master
|
||||||
$ # Add some commits to the branch, reading for testing
|
$ # Add some commits to the branch, reading for testing
|
||||||
|
|
||||||
2. Create ~/.buildman to tell buildman where to find tool chains. As an
|
2. Create ~/.buildman to tell buildman where to find tool chains (see 'The
|
||||||
example:
|
.buildman file' later for details). As an example:
|
||||||
|
|
||||||
# Buildman settings file
|
# Buildman settings file
|
||||||
|
|
||||||
|
|
@ -171,7 +171,16 @@ The toolchain-alias section indicates that the i386 toolchain should be used
|
||||||
to build x86 commits.
|
to build x86 commits.
|
||||||
|
|
||||||
|
|
||||||
2. Check the available toolchains
|
3. Make sure you have the require Python pre-requisites
|
||||||
|
|
||||||
|
Buildman uses multiprocessing, Queue, shutil, StringIO, ConfigParser and
|
||||||
|
urllib2. These should normally be available, but if you get an error like
|
||||||
|
this then you will need to obtain those modules:
|
||||||
|
|
||||||
|
ImportError: No module named multiprocessing
|
||||||
|
|
||||||
|
|
||||||
|
4. Check the available toolchains
|
||||||
|
|
||||||
Run this check to make sure that you have a toolchain for every architecture.
|
Run this check to make sure that you have a toolchain for every architecture.
|
||||||
|
|
||||||
|
|
@ -301,6 +310,47 @@ You can see that everything is covered, even some strange ones that won't
|
||||||
be used (c88 and c99). This is a feature.
|
be used (c88 and c99). This is a feature.
|
||||||
|
|
||||||
|
|
||||||
|
5. Install new toolchains if needed
|
||||||
|
|
||||||
|
You can download toolchains and update the [toolchain] section of the
|
||||||
|
settings file to find them.
|
||||||
|
|
||||||
|
To make this easier, buildman can automatically download and install
|
||||||
|
toolchains from kernel.org. First list the available architectures:
|
||||||
|
|
||||||
|
$ ./tools/buildman/buildman sandbox --fetch-arch list
|
||||||
|
Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.3/
|
||||||
|
Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.2/
|
||||||
|
Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.5.1/
|
||||||
|
Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.2.4/
|
||||||
|
Available architectures: alpha am33_2.0 arm avr32 bfin cris crisv32 frv h8300
|
||||||
|
hppa hppa64 i386 ia64 m32r m68k mips mips64 or32 powerpc powerpc64 s390x sh4
|
||||||
|
sparc sparc64 tilegx x86_64 xtensa
|
||||||
|
|
||||||
|
Then pick one and download it:
|
||||||
|
|
||||||
|
$ ./tools/buildman/buildman sandbox --fetch-arch or32
|
||||||
|
Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.3/
|
||||||
|
Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.2/
|
||||||
|
Checking: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.5.1/
|
||||||
|
Downloading: https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.5.1//x86_64-gcc-4.5.1-nolibc_or32-linux.tar.xz
|
||||||
|
Unpacking to: /home/sjg/.buildman-toolchains
|
||||||
|
Testing
|
||||||
|
- looking in '/home/sjg/.buildman-toolchains/gcc-4.5.1-nolibc/or32-linux/.'
|
||||||
|
- looking in '/home/sjg/.buildman-toolchains/gcc-4.5.1-nolibc/or32-linux/bin'
|
||||||
|
- found '/home/sjg/.buildman-toolchains/gcc-4.5.1-nolibc/or32-linux/bin/or32-linux-gcc'
|
||||||
|
Tool chain test: OK
|
||||||
|
|
||||||
|
Buildman should now be set up to use your new toolchain.
|
||||||
|
|
||||||
|
At the time of writing, U-Boot has these architectures:
|
||||||
|
|
||||||
|
arc, arm, avr32, blackfin, m68k, microblaze, mips, nds32, nios2, openrisc
|
||||||
|
powerpc, sandbox, sh, sparc, x86
|
||||||
|
|
||||||
|
Of these, only arc, microblaze and nds32 are not available at kernel.org..
|
||||||
|
|
||||||
|
|
||||||
How to run it
|
How to run it
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
@ -310,8 +360,9 @@ branch with a valid upstream)
|
||||||
$ ./tools/buildman/buildman -b <branch> -n
|
$ ./tools/buildman/buildman -b <branch> -n
|
||||||
|
|
||||||
If it can't detect the upstream branch, try checking out the branch, and
|
If it can't detect the upstream branch, try checking out the branch, and
|
||||||
doing something like 'git branch --set-upstream <branch> upstream/master'
|
doing something like 'git branch --set-upstream-to upstream/master'
|
||||||
or something similar.
|
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 ...).
|
||||||
|
|
||||||
As an example:
|
As an example:
|
||||||
|
|
||||||
|
|
@ -665,28 +716,62 @@ It is common when refactoring code for the rodata to decrease as the text size
|
||||||
increases, and vice versa.
|
increases, and vice versa.
|
||||||
|
|
||||||
|
|
||||||
Providing 'make' flags
|
The .buildman file
|
||||||
======================
|
==================
|
||||||
|
|
||||||
U-Boot's build system supports a few flags (such as BUILD_TAG) which affect
|
The .buildman file provides information about the available toolchains and
|
||||||
the build product. These flags can be specified in the buildman settings
|
also allows build flags to be passed to 'make'. It consists of several
|
||||||
file. They can also be useful when building U-Boot against other open source
|
sections, with the section name in square brackets. Within each section are
|
||||||
software.
|
a set of (tag, value) pairs.
|
||||||
|
|
||||||
[make-flags]
|
'[toolchain]' section
|
||||||
at91-boards=ENABLE_AT91_TEST=1
|
|
||||||
snapper9260=${at91-boards} BUILD_TAG=442
|
|
||||||
snapper9g45=${at91-boards} BUILD_TAG=443
|
|
||||||
|
|
||||||
This will use 'make ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
|
This lists the available toolchains. The tag here doesn't matter, but
|
||||||
and 'make ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. A special
|
make sure it is unique. The value is the path to the toolchain. Buildman
|
||||||
variable ${target} is available to access the target name (snapper9260 and
|
will look in that path for a file ending in 'gcc'. It will then execute
|
||||||
snapper9g20 in this case). Variables are resolved recursively. Note that
|
it to check that it is a C compiler, passing only the --version flag to
|
||||||
variables can only contain the characters A-Z, a-z, 0-9, hyphen (-) and
|
it. If the return code is 0, buildman assumes that it is a valid C
|
||||||
underscore (_).
|
compiler. It uses the first part of the name as the architecture and
|
||||||
|
strips off the last part when setting the CROSS_COMPILE environment
|
||||||
|
variable (parts are delimited with a hyphen).
|
||||||
|
|
||||||
It is expected that any variables added are dealt with in U-Boot's
|
For example powerpc-linux-gcc will be noted as a toolchain for 'powerpc'
|
||||||
config.mk file and documented in the README.
|
and CROSS_COMPILE will be set to powerpc-linux- when using it.
|
||||||
|
|
||||||
|
'[toolchain-alias]' section
|
||||||
|
|
||||||
|
This converts toolchain architecture names to U-Boot names. For example,
|
||||||
|
if an x86 toolchains is called i386-linux-gcc it will not normally be
|
||||||
|
used for architecture 'x86'. Adding 'x86: i386 x86_64' to this section
|
||||||
|
will tell buildman that the i386 and x86_64 toolchains can be used for
|
||||||
|
the x86 architecture.
|
||||||
|
|
||||||
|
'[make-flags]' section
|
||||||
|
|
||||||
|
U-Boot's build system supports a few flags (such as BUILD_TAG) which
|
||||||
|
affect the build product. These flags can be specified in the buildman
|
||||||
|
settings file. They can also be useful when building U-Boot against other
|
||||||
|
open source software.
|
||||||
|
|
||||||
|
[make-flags]
|
||||||
|
at91-boards=ENABLE_AT91_TEST=1
|
||||||
|
snapper9260=${at91-boards} BUILD_TAG=442
|
||||||
|
snapper9g45=${at91-boards} BUILD_TAG=443
|
||||||
|
|
||||||
|
This will use 'make ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260
|
||||||
|
and 'make ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. A special
|
||||||
|
variable ${target} is available to access the target name (snapper9260
|
||||||
|
and snapper9g20 in this case). Variables are resolved recursively. Note
|
||||||
|
that variables can only contain the characters A-Z, a-z, 0-9, hyphen (-)
|
||||||
|
and underscore (_).
|
||||||
|
|
||||||
|
It is expected that any variables added are dealt with in U-Boot's
|
||||||
|
config.mk file and documented in the README.
|
||||||
|
|
||||||
|
Note that you can pass ad-hoc options to the build using environment
|
||||||
|
variables, for example:
|
||||||
|
|
||||||
|
SOME_OPTION=1234 ./tools/buildman/buildman my_board
|
||||||
|
|
||||||
|
|
||||||
Quick Sanity Check
|
Quick Sanity Check
|
||||||
|
|
@ -698,6 +783,17 @@ build the selected boards and display build status as it runs (i.e. -v is
|
||||||
enabled automatically). Use -e to see errors/warnings as well.
|
enabled automatically). Use -e to see errors/warnings as well.
|
||||||
|
|
||||||
|
|
||||||
|
Building Ranges
|
||||||
|
===============
|
||||||
|
|
||||||
|
You can build a range of commits by specifying a range instead of a branch
|
||||||
|
when using the -b flag. For example:
|
||||||
|
|
||||||
|
upstream/master..us-buildman
|
||||||
|
|
||||||
|
will build commits in us-buildman that are not in upstream/master.
|
||||||
|
|
||||||
|
|
||||||
Other options
|
Other options
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,16 @@ def GetItems(section):
|
||||||
try:
|
try:
|
||||||
return settings.items(section)
|
return settings.items(section)
|
||||||
except ConfigParser.NoSectionError as e:
|
except ConfigParser.NoSectionError as e:
|
||||||
print e
|
|
||||||
return []
|
return []
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def SetItem(section, tag, value):
|
||||||
|
"""Set an item and write it back to the settings file"""
|
||||||
|
global settings
|
||||||
|
global config_fname
|
||||||
|
|
||||||
|
settings.set(section, tag, value)
|
||||||
|
if config_fname is not None:
|
||||||
|
with open(config_fname, 'w') as fd:
|
||||||
|
settings.write(fd)
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,8 @@ class Builder:
|
||||||
self.func_sizes = func_sizes
|
self.func_sizes = func_sizes
|
||||||
|
|
||||||
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):
|
||||||
"""Create a new Builder object
|
"""Create a new Builder object
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -188,6 +189,11 @@ class Builder:
|
||||||
This is used for testing.
|
This is used for testing.
|
||||||
show_unknown: Show unknown boards (those not built) in summary
|
show_unknown: Show unknown boards (those not built) in summary
|
||||||
step: 1 to process every commit, n to process every nth commit
|
step: 1 to process every commit, n to process every nth commit
|
||||||
|
no_subdirs: Don't create subdirectories when building current
|
||||||
|
source for a single board
|
||||||
|
full_path: Return the full path in CROSS_COMPILE and don't set
|
||||||
|
PATH
|
||||||
|
verbose_build: Run build with V=1 and don't use 'make -s'
|
||||||
"""
|
"""
|
||||||
self.toolchains = toolchains
|
self.toolchains = toolchains
|
||||||
self.base_dir = base_dir
|
self.base_dir = base_dir
|
||||||
|
|
@ -213,6 +219,9 @@ class Builder:
|
||||||
self._step = step
|
self._step = step
|
||||||
self.in_tree = False
|
self.in_tree = False
|
||||||
self._error_lines = 0
|
self._error_lines = 0
|
||||||
|
self.no_subdirs = no_subdirs
|
||||||
|
self.full_path = full_path
|
||||||
|
self.verbose_build = verbose_build
|
||||||
|
|
||||||
self.col = terminal.Color()
|
self.col = terminal.Color()
|
||||||
|
|
||||||
|
|
@ -392,15 +401,17 @@ class Builder:
|
||||||
Args:
|
Args:
|
||||||
commit_upto: Commit number to use (0..self.count-1)
|
commit_upto: Commit number to use (0..self.count-1)
|
||||||
"""
|
"""
|
||||||
|
commit_dir = None
|
||||||
if self.commits:
|
if self.commits:
|
||||||
commit = self.commits[commit_upto]
|
commit = self.commits[commit_upto]
|
||||||
subject = commit.subject.translate(trans_valid_chars)
|
subject = commit.subject.translate(trans_valid_chars)
|
||||||
commit_dir = ('%02d_of_%02d_g%s_%s' % (commit_upto + 1,
|
commit_dir = ('%02d_of_%02d_g%s_%s' % (commit_upto + 1,
|
||||||
self.commit_count, commit.hash, subject[:20]))
|
self.commit_count, commit.hash, subject[:20]))
|
||||||
else:
|
elif not self.no_subdirs:
|
||||||
commit_dir = 'current'
|
commit_dir = 'current'
|
||||||
output_dir = os.path.join(self.base_dir, commit_dir)
|
if not commit_dir:
|
||||||
return output_dir
|
return self.base_dir
|
||||||
|
return os.path.join(self.base_dir, commit_dir)
|
||||||
|
|
||||||
def GetBuildDir(self, commit_upto, target):
|
def GetBuildDir(self, commit_upto, target):
|
||||||
"""Get the name of the build directory for a commit number
|
"""Get the name of the build directory for a commit number
|
||||||
|
|
@ -1115,6 +1126,8 @@ class Builder:
|
||||||
create. Having left over directories is confusing when the user wants
|
create. Having left over directories is confusing when the user wants
|
||||||
to check the output manually.
|
to check the output manually.
|
||||||
"""
|
"""
|
||||||
|
if not self.commits:
|
||||||
|
return
|
||||||
dir_list = []
|
dir_list = []
|
||||||
for commit_upto in range(self.commit_count):
|
for commit_upto in range(self.commit_count):
|
||||||
dir_list.append(self._GetOutputDir(commit_upto))
|
dir_list.append(self._GetOutputDir(commit_upto))
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ class BuilderThread(threading.Thread):
|
||||||
commit = 'current'
|
commit = 'current'
|
||||||
|
|
||||||
# Set up the environment and command line
|
# Set up the environment and command line
|
||||||
env = self.toolchain.MakeEnvironment()
|
env = self.toolchain.MakeEnvironment(self.builder.full_path)
|
||||||
Mkdir(out_dir)
|
Mkdir(out_dir)
|
||||||
args = []
|
args = []
|
||||||
cwd = work_dir
|
cwd = work_dir
|
||||||
|
|
@ -197,7 +197,8 @@ class BuilderThread(threading.Thread):
|
||||||
src_dir = os.getcwd()
|
src_dir = os.getcwd()
|
||||||
else:
|
else:
|
||||||
args.append('O=build')
|
args.append('O=build')
|
||||||
args.append('-s')
|
if not self.builder.verbose_build:
|
||||||
|
args.append('-s')
|
||||||
if self.builder.num_jobs is not None:
|
if self.builder.num_jobs is not None:
|
||||||
args.extend(['-j', str(self.builder.num_jobs)])
|
args.extend(['-j', str(self.builder.num_jobs)])
|
||||||
config_args = ['%s_defconfig' % brd.target]
|
config_args = ['%s_defconfig' % brd.target]
|
||||||
|
|
@ -284,7 +285,7 @@ class BuilderThread(threading.Thread):
|
||||||
print >>fd, 'path', result.toolchain.path
|
print >>fd, 'path', result.toolchain.path
|
||||||
|
|
||||||
# Write out the image and function size information and an objdump
|
# Write out the image and function size information and an objdump
|
||||||
env = result.toolchain.MakeEnvironment()
|
env = result.toolchain.MakeEnvironment(self.builder.full_path)
|
||||||
lines = []
|
lines = []
|
||||||
for fname in ['u-boot', 'spl/u-boot-spl']:
|
for fname in ['u-boot', 'spl/u-boot-spl']:
|
||||||
cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
|
cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,10 @@ def ParseArgs():
|
||||||
parser.add_option('-F', '--force-build-failures', dest='force_build_failures',
|
parser.add_option('-F', '--force-build-failures', dest='force_build_failures',
|
||||||
action='store_true', default=False,
|
action='store_true', default=False,
|
||||||
help='Force build of previously-failed build')
|
help='Force build of previously-failed build')
|
||||||
|
parser.add_option('--fetch-arch', type='string',
|
||||||
|
help="Fetch a toolchain for architecture FETCH_ARCH ('list' to list)."
|
||||||
|
' You can also fetch several toolchains separate by comma, or'
|
||||||
|
" 'all' to download all")
|
||||||
parser.add_option('-g', '--git', type='string',
|
parser.add_option('-g', '--git', type='string',
|
||||||
help='Git repo containing branch to build', default='.')
|
help='Git repo containing branch to build', default='.')
|
||||||
parser.add_option('-G', '--config-file', type='string',
|
parser.add_option('-G', '--config-file', type='string',
|
||||||
|
|
@ -55,11 +59,15 @@ def ParseArgs():
|
||||||
help='List available tool chains')
|
help='List available tool chains')
|
||||||
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',
|
||||||
|
default=False, help="Don't create subdirectories when building current source for a single board")
|
||||||
parser.add_option('-o', '--output-dir', type='string',
|
parser.add_option('-o', '--output-dir', type='string',
|
||||||
dest='output_dir', default='..',
|
dest='output_dir', default='..',
|
||||||
help='Directory where all builds happen and buildman has its workspace (default is ../)')
|
help='Directory where all builds happen and buildman has its workspace (default is ../)')
|
||||||
parser.add_option('-Q', '--quick', action='store_true',
|
parser.add_option('-Q', '--quick', action='store_true',
|
||||||
default=False, help='Do a rough build, with limited warning resolution')
|
default=False, help='Do a rough build, with limited warning resolution')
|
||||||
|
parser.add_option('-p', '--full-path', action='store_true',
|
||||||
|
default=False, help="Use full toolchain path in CROSS_COMPILE")
|
||||||
parser.add_option('-s', '--summary', action='store_true',
|
parser.add_option('-s', '--summary', action='store_true',
|
||||||
default=False, help='Show a build summary')
|
default=False, help='Show a build summary')
|
||||||
parser.add_option('-S', '--show-sizes', action='store_true',
|
parser.add_option('-S', '--show-sizes', action='store_true',
|
||||||
|
|
@ -74,6 +82,8 @@ def ParseArgs():
|
||||||
default=False, help='Show boards with unknown build result')
|
default=False, help='Show boards with unknown build result')
|
||||||
parser.add_option('-v', '--verbose', action='store_true',
|
parser.add_option('-v', '--verbose', action='store_true',
|
||||||
default=False, help='Show build results while the build progresses')
|
default=False, help='Show build results while the build progresses')
|
||||||
|
parser.add_option('-V', '--verbose-build', action='store_true',
|
||||||
|
default=False, help='Run make with V=1, showing all output')
|
||||||
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')
|
||||||
|
|
|
||||||
|
|
@ -118,21 +118,45 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
|
||||||
print
|
print
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
if options.fetch_arch:
|
||||||
|
if options.fetch_arch == 'list':
|
||||||
|
sorted_list = toolchains.ListArchs()
|
||||||
|
print 'Available architectures: %s\n' % ' '.join(sorted_list)
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
fetch_arch = options.fetch_arch
|
||||||
|
if fetch_arch == 'all':
|
||||||
|
fetch_arch = ','.join(toolchains.ListArchs())
|
||||||
|
print 'Downloading toolchains: %s\n' % fetch_arch
|
||||||
|
for arch in fetch_arch.split(','):
|
||||||
|
ret = toolchains.FetchAndInstall(arch)
|
||||||
|
if ret:
|
||||||
|
return ret
|
||||||
|
return 0
|
||||||
|
|
||||||
# Work out how many commits to build. We want to build everything on the
|
# Work out how many commits to build. We want to build everything on the
|
||||||
# branch. We also build the upstream commit as a control so we can see
|
# branch. We also build the upstream commit as a control so we can see
|
||||||
# problems introduced by the first commit on the branch.
|
# problems introduced by the first commit on the branch.
|
||||||
col = terminal.Color()
|
col = terminal.Color()
|
||||||
count = options.count
|
count = options.count
|
||||||
|
has_range = options.branch and '..' in options.branch
|
||||||
if count == -1:
|
if count == -1:
|
||||||
if not options.branch:
|
if not options.branch:
|
||||||
count = 1
|
count = 1
|
||||||
else:
|
else:
|
||||||
count = gitutil.CountCommitsInBranch(options.git_dir,
|
if has_range:
|
||||||
options.branch)
|
count, msg = gitutil.CountCommitsInRange(options.git_dir,
|
||||||
|
options.branch)
|
||||||
|
else:
|
||||||
|
count, msg = gitutil.CountCommitsInBranch(options.git_dir,
|
||||||
|
options.branch)
|
||||||
if count is None:
|
if count is None:
|
||||||
str = ("Branch '%s' not found or has no upstream" %
|
sys.exit(col.Color(col.RED, msg))
|
||||||
options.branch)
|
elif count == 0:
|
||||||
sys.exit(col.Color(col.RED, str))
|
sys.exit(col.Color(col.RED, "Range '%s' has no commits" %
|
||||||
|
options.branch))
|
||||||
|
if msg:
|
||||||
|
print col.Color(col.YELLOW, msg)
|
||||||
count += 1 # Build upstream commit also
|
count += 1 # Build upstream commit also
|
||||||
|
|
||||||
if not count:
|
if not count:
|
||||||
|
|
@ -172,8 +196,11 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
|
||||||
# to overwrite earlier ones by setting allow_overwrite=True
|
# to overwrite earlier ones by setting allow_overwrite=True
|
||||||
if options.branch:
|
if options.branch:
|
||||||
if count == -1:
|
if count == -1:
|
||||||
range_expr = gitutil.GetRangeInBranch(options.git_dir,
|
if has_range:
|
||||||
options.branch)
|
range_expr = options.branch
|
||||||
|
else:
|
||||||
|
range_expr = gitutil.GetRangeInBranch(options.git_dir,
|
||||||
|
options.branch)
|
||||||
upstream_commit = gitutil.GetUpstream(options.git_dir,
|
upstream_commit = gitutil.GetUpstream(options.git_dir,
|
||||||
options.branch)
|
options.branch)
|
||||||
series = patchstream.GetMetaDataForList(upstream_commit,
|
series = patchstream.GetMetaDataForList(upstream_commit,
|
||||||
|
|
@ -207,17 +234,22 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
|
||||||
if not gnu_make:
|
if not gnu_make:
|
||||||
sys.exit('GNU Make not found')
|
sys.exit('GNU Make not found')
|
||||||
|
|
||||||
# Create a new builder with the selected options
|
# Create a new builder with the selected options.
|
||||||
|
output_dir = options.output_dir
|
||||||
if options.branch:
|
if options.branch:
|
||||||
dirname = options.branch.replace('/', '_')
|
dirname = options.branch.replace('/', '_')
|
||||||
else:
|
# As a special case allow the board directory to be placed in the
|
||||||
dirname = 'current'
|
# output directory itself rather than any subdirectory.
|
||||||
output_dir = os.path.join(options.output_dir, dirname)
|
if not options.no_subdirs:
|
||||||
if clean_dir and os.path.exists(output_dir):
|
output_dir = os.path.join(options.output_dir, dirname)
|
||||||
|
if (clean_dir and output_dir != options.output_dir and
|
||||||
|
os.path.exists(output_dir)):
|
||||||
shutil.rmtree(output_dir)
|
shutil.rmtree(output_dir)
|
||||||
builder = Builder(toolchains, output_dir, options.git_dir,
|
builder = Builder(toolchains, output_dir, options.git_dir,
|
||||||
options.threads, options.jobs, gnu_make=gnu_make, checkout=True,
|
options.threads, options.jobs, gnu_make=gnu_make, checkout=True,
|
||||||
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,
|
||||||
|
verbose_build=options.verbose_build)
|
||||||
builder.force_config_on_failure = not options.quick
|
builder.force_config_on_failure = not options.quick
|
||||||
if make_func:
|
if make_func:
|
||||||
builder.do_make = make_func
|
builder.do_make = make_func
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,16 @@ import commit
|
||||||
import terminal
|
import terminal
|
||||||
import toolchain
|
import toolchain
|
||||||
|
|
||||||
|
settings_data = '''
|
||||||
|
# Buildman settings file
|
||||||
|
|
||||||
|
[toolchain]
|
||||||
|
main: /usr/sbin
|
||||||
|
|
||||||
|
[toolchain-alias]
|
||||||
|
x86: i386 x86_64
|
||||||
|
'''
|
||||||
|
|
||||||
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]
|
||||||
|
|
@ -83,6 +93,8 @@ boards = [
|
||||||
['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''],
|
['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
BASE_DIR = 'base'
|
||||||
|
|
||||||
class Options:
|
class Options:
|
||||||
"""Class that holds build options"""
|
"""Class that holds build options"""
|
||||||
pass
|
pass
|
||||||
|
|
@ -111,8 +123,11 @@ class TestBuild(unittest.TestCase):
|
||||||
self.boards.AddBoard(board.Board(*brd))
|
self.boards.AddBoard(board.Board(*brd))
|
||||||
self.boards.SelectBoards([])
|
self.boards.SelectBoards([])
|
||||||
|
|
||||||
|
# Add some test settings
|
||||||
|
bsettings.Setup(None)
|
||||||
|
bsettings.AddFile(settings_data)
|
||||||
|
|
||||||
# Set up the toolchains
|
# Set up the toolchains
|
||||||
bsettings.Setup()
|
|
||||||
self.toolchains = toolchain.Toolchains()
|
self.toolchains = toolchain.Toolchains()
|
||||||
self.toolchains.Add('arm-linux-gcc', test=False)
|
self.toolchains.Add('arm-linux-gcc', test=False)
|
||||||
self.toolchains.Add('sparc-linux-gcc', test=False)
|
self.toolchains.Add('sparc-linux-gcc', test=False)
|
||||||
|
|
@ -341,6 +356,64 @@ class TestBuild(unittest.TestCase):
|
||||||
self.assertEqual(self.boards.SelectBoards(['sandbox sandbox',
|
self.assertEqual(self.boards.SelectBoards(['sandbox sandbox',
|
||||||
'sandbox']),
|
'sandbox']),
|
||||||
{'all': 1, 'sandbox': 1})
|
{'all': 1, 'sandbox': 1})
|
||||||
|
def CheckDirs(self, build, dirname):
|
||||||
|
self.assertEqual('base%s' % dirname, build._GetOutputDir(1))
|
||||||
|
self.assertEqual('base%s/fred' % dirname,
|
||||||
|
build.GetBuildDir(1, 'fred'))
|
||||||
|
self.assertEqual('base%s/fred/done' % dirname,
|
||||||
|
build.GetDoneFile(1, 'fred'))
|
||||||
|
self.assertEqual('base%s/fred/u-boot.sizes' % dirname,
|
||||||
|
build.GetFuncSizesFile(1, 'fred', 'u-boot'))
|
||||||
|
self.assertEqual('base%s/fred/u-boot.objdump' % dirname,
|
||||||
|
build.GetObjdumpFile(1, 'fred', 'u-boot'))
|
||||||
|
self.assertEqual('base%s/fred/err' % dirname,
|
||||||
|
build.GetErrFile(1, 'fred'))
|
||||||
|
|
||||||
|
def testOutputDir(self):
|
||||||
|
build = builder.Builder(self.toolchains, BASE_DIR, None, 1, 2,
|
||||||
|
checkout=False, show_unknown=False)
|
||||||
|
build.commits = self.commits
|
||||||
|
build.commit_count = len(self.commits)
|
||||||
|
subject = self.commits[1].subject.translate(builder.trans_valid_chars)
|
||||||
|
dirname ='/%02d_of_%02d_g%s_%s' % (2, build.commit_count, commits[1][0],
|
||||||
|
subject[:20])
|
||||||
|
self.CheckDirs(build, dirname)
|
||||||
|
|
||||||
|
def testOutputDirCurrent(self):
|
||||||
|
build = builder.Builder(self.toolchains, BASE_DIR, None, 1, 2,
|
||||||
|
checkout=False, show_unknown=False)
|
||||||
|
build.commits = None
|
||||||
|
build.commit_count = 0
|
||||||
|
self.CheckDirs(build, '/current')
|
||||||
|
|
||||||
|
def testOutputDirNoSubdirs(self):
|
||||||
|
build = builder.Builder(self.toolchains, BASE_DIR, None, 1, 2,
|
||||||
|
checkout=False, show_unknown=False,
|
||||||
|
no_subdirs=True)
|
||||||
|
build.commits = None
|
||||||
|
build.commit_count = 0
|
||||||
|
self.CheckDirs(build, '')
|
||||||
|
|
||||||
|
def testToolchainAliases(self):
|
||||||
|
self.assertTrue(self.toolchains.Select('arm') != None)
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
self.toolchains.Select('no-arch')
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
self.toolchains.Select('x86')
|
||||||
|
|
||||||
|
self.toolchains = toolchain.Toolchains()
|
||||||
|
self.toolchains.Add('x86_64-linux-gcc', test=False)
|
||||||
|
self.assertTrue(self.toolchains.Select('x86') != None)
|
||||||
|
|
||||||
|
self.toolchains = toolchain.Toolchains()
|
||||||
|
self.toolchains.Add('i386-linux-gcc', test=False)
|
||||||
|
self.assertTrue(self.toolchains.Select('x86') != None)
|
||||||
|
|
||||||
|
def testToolchainDownload(self):
|
||||||
|
"""Test that we can download toolchains"""
|
||||||
|
self.assertEqual('https://www.kernel.org/pub/tools/crosstool/files/bin/x86_64/4.6.3/x86_64-gcc-4.6.3-nolibc_arm-unknown-linux-gnueabi.tar.xz',
|
||||||
|
self.toolchains.LocateArchUrl('arm'))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,42 @@
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import glob
|
import glob
|
||||||
|
from HTMLParser import HTMLParser
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import urllib2
|
||||||
|
|
||||||
import bsettings
|
import bsettings
|
||||||
import command
|
import command
|
||||||
|
|
||||||
|
# Simple class to collect links from a page
|
||||||
|
class MyHTMLParser(HTMLParser):
|
||||||
|
def __init__(self, arch):
|
||||||
|
"""Create a new parser
|
||||||
|
|
||||||
|
After the parser runs, self.links will be set to a list of the links
|
||||||
|
to .xz archives found in the page, and self.arch_link will be set to
|
||||||
|
the one for the given architecture (or None if not found).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
arch: Architecture to search for
|
||||||
|
"""
|
||||||
|
HTMLParser.__init__(self)
|
||||||
|
self.arch_link = None
|
||||||
|
self.links = []
|
||||||
|
self._match = '_%s-' % arch
|
||||||
|
|
||||||
|
def handle_starttag(self, tag, attrs):
|
||||||
|
if tag == 'a':
|
||||||
|
for tag, value in attrs:
|
||||||
|
if tag == 'href':
|
||||||
|
if value and value.endswith('.xz'):
|
||||||
|
self.links.append(value)
|
||||||
|
if self._match in value:
|
||||||
|
self.arch_link = value
|
||||||
|
|
||||||
|
|
||||||
class Toolchain:
|
class Toolchain:
|
||||||
"""A single toolchain
|
"""A single toolchain
|
||||||
|
|
||||||
|
|
@ -20,7 +51,6 @@ class Toolchain:
|
||||||
arch: Architecture of toolchain as determined from the first
|
arch: Architecture of toolchain as determined from the first
|
||||||
component of the filename. E.g. arm-linux-gcc becomes arm
|
component of the filename. E.g. arm-linux-gcc becomes arm
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, fname, test, verbose=False):
|
def __init__(self, fname, test, verbose=False):
|
||||||
"""Create a new toolchain object.
|
"""Create a new toolchain object.
|
||||||
|
|
||||||
|
|
@ -30,11 +60,18 @@ class Toolchain:
|
||||||
"""
|
"""
|
||||||
self.gcc = fname
|
self.gcc = fname
|
||||||
self.path = os.path.dirname(fname)
|
self.path = os.path.dirname(fname)
|
||||||
self.cross = os.path.basename(fname)[:-3]
|
|
||||||
|
# Find the CROSS_COMPILE prefix to use for U-Boot. For example,
|
||||||
|
# 'arm-linux-gnueabihf-gcc' turns into 'arm-linux-gnueabihf-'.
|
||||||
|
basename = os.path.basename(fname)
|
||||||
|
pos = basename.rfind('-')
|
||||||
|
self.cross = basename[:pos + 1] if pos != -1 else ''
|
||||||
|
|
||||||
|
# The architecture is the first part of the name
|
||||||
pos = self.cross.find('-')
|
pos = self.cross.find('-')
|
||||||
self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
|
self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
|
||||||
|
|
||||||
env = self.MakeEnvironment()
|
env = self.MakeEnvironment(False)
|
||||||
|
|
||||||
# As a basic sanity check, run the C compiler with --version
|
# As a basic sanity check, run the C compiler with --version
|
||||||
cmd = [fname, '--version']
|
cmd = [fname, '--version']
|
||||||
|
|
@ -74,15 +111,23 @@ class Toolchain:
|
||||||
return prio
|
return prio
|
||||||
return prio
|
return prio
|
||||||
|
|
||||||
def MakeEnvironment(self):
|
def MakeEnvironment(self, full_path):
|
||||||
"""Returns an environment for using the toolchain.
|
"""Returns an environment for using the toolchain.
|
||||||
|
|
||||||
Thie takes the current environment, adds CROSS_COMPILE and
|
Thie takes the current environment and adds CROSS_COMPILE so that
|
||||||
augments PATH so that the toolchain will operate correctly.
|
the tool chain will operate correctly.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
full_path: Return the full path in CROSS_COMPILE and don't set
|
||||||
|
PATH
|
||||||
"""
|
"""
|
||||||
env = dict(os.environ)
|
env = dict(os.environ)
|
||||||
env['CROSS_COMPILE'] = self.cross
|
if full_path:
|
||||||
env['PATH'] += (':' + self.path)
|
env['CROSS_COMPILE'] = os.path.join(self.path, self.cross)
|
||||||
|
else:
|
||||||
|
env['CROSS_COMPILE'] = self.cross
|
||||||
|
env['PATH'] = self.path + ':' + env['PATH']
|
||||||
|
|
||||||
return env
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -101,18 +146,29 @@ class Toolchains:
|
||||||
self.paths = []
|
self.paths = []
|
||||||
self._make_flags = dict(bsettings.GetItems('make-flags'))
|
self._make_flags = dict(bsettings.GetItems('make-flags'))
|
||||||
|
|
||||||
def GetSettings(self):
|
def GetPathList(self):
|
||||||
|
"""Get a list of available toolchain paths
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of strings, each a path to a toolchain mentioned in the
|
||||||
|
[toolchain] section of the settings file.
|
||||||
|
"""
|
||||||
toolchains = bsettings.GetItems('toolchain')
|
toolchains = bsettings.GetItems('toolchain')
|
||||||
if not toolchains:
|
if not toolchains:
|
||||||
print ("Warning: No tool chains - please add a [toolchain] section"
|
print ("Warning: No tool chains - please add a [toolchain] section"
|
||||||
" to your buildman config file %s. See README for details" %
|
" to your buildman config file %s. See README for details" %
|
||||||
bsettings.config_fname)
|
bsettings.config_fname)
|
||||||
|
|
||||||
|
paths = []
|
||||||
for name, value in toolchains:
|
for name, value in toolchains:
|
||||||
if '*' in value:
|
if '*' in value:
|
||||||
self.paths += glob.glob(value)
|
paths += glob.glob(value)
|
||||||
else:
|
else:
|
||||||
self.paths.append(value)
|
paths.append(value)
|
||||||
|
return paths
|
||||||
|
|
||||||
|
def GetSettings(self):
|
||||||
|
self.paths += self.GetPathList()
|
||||||
|
|
||||||
def Add(self, fname, test=True, verbose=False):
|
def Add(self, fname, test=True, verbose=False):
|
||||||
"""Add a toolchain to our list
|
"""Add a toolchain to our list
|
||||||
|
|
@ -132,6 +188,24 @@ class Toolchains:
|
||||||
if add_it:
|
if add_it:
|
||||||
self.toolchains[toolchain.arch] = toolchain
|
self.toolchains[toolchain.arch] = toolchain
|
||||||
|
|
||||||
|
def ScanPath(self, path, verbose):
|
||||||
|
"""Scan a path for a valid toolchain
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: Path to scan
|
||||||
|
verbose: True to print out progress information
|
||||||
|
Returns:
|
||||||
|
Filename of C compiler if found, else None
|
||||||
|
"""
|
||||||
|
for subdir in ['.', 'bin', 'usr/bin']:
|
||||||
|
dirname = os.path.join(path, subdir)
|
||||||
|
if verbose: print " - looking in '%s'" % dirname
|
||||||
|
for fname in glob.glob(dirname + '/*gcc'):
|
||||||
|
if verbose: print " - found '%s'" % fname
|
||||||
|
return fname
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def Scan(self, verbose):
|
def Scan(self, verbose):
|
||||||
"""Scan for available toolchains and select the best for each arch.
|
"""Scan for available toolchains and select the best for each arch.
|
||||||
|
|
||||||
|
|
@ -145,12 +219,9 @@ class Toolchains:
|
||||||
if verbose: print 'Scanning for tool chains'
|
if verbose: print 'Scanning for tool chains'
|
||||||
for path in self.paths:
|
for path in self.paths:
|
||||||
if verbose: print " - scanning path '%s'" % path
|
if verbose: print " - scanning path '%s'" % path
|
||||||
for subdir in ['.', 'bin', 'usr/bin']:
|
fname = self.ScanPath(path, verbose)
|
||||||
dirname = os.path.join(path, subdir)
|
if fname:
|
||||||
if verbose: print " - looking in '%s'" % dirname
|
self.Add(fname, True, verbose)
|
||||||
for fname in glob.glob(dirname + '/*gcc'):
|
|
||||||
if verbose: print " - found '%s'" % fname
|
|
||||||
self.Add(fname, True, verbose)
|
|
||||||
|
|
||||||
def List(self):
|
def List(self):
|
||||||
"""List out the selected toolchains for each architecture"""
|
"""List out the selected toolchains for each architecture"""
|
||||||
|
|
@ -170,9 +241,11 @@ class Toolchains:
|
||||||
returns:
|
returns:
|
||||||
toolchain object, or None if none found
|
toolchain object, or None if none found
|
||||||
"""
|
"""
|
||||||
for name, value in bsettings.GetItems('toolchain-alias'):
|
for tag, value in bsettings.GetItems('toolchain-alias'):
|
||||||
if arch == name:
|
if arch == tag:
|
||||||
arch = value
|
for alias in value.split():
|
||||||
|
if alias in self.toolchains:
|
||||||
|
return self.toolchains[alias]
|
||||||
|
|
||||||
if not arch in self.toolchains:
|
if not arch in self.toolchains:
|
||||||
raise ValueError, ("No tool chain found for arch '%s'" % arch)
|
raise ValueError, ("No tool chain found for arch '%s'" % arch)
|
||||||
|
|
@ -247,3 +320,160 @@ class Toolchains:
|
||||||
else:
|
else:
|
||||||
i += 1
|
i += 1
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
def LocateArchUrl(self, fetch_arch):
|
||||||
|
"""Find a toolchain available online
|
||||||
|
|
||||||
|
Look in standard places for available toolchains. At present the
|
||||||
|
only standard place is at kernel.org.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
arch: Architecture to look for, or 'list' for all
|
||||||
|
Returns:
|
||||||
|
If fetch_arch is 'list', a tuple:
|
||||||
|
Machine architecture (e.g. x86_64)
|
||||||
|
List of toolchains
|
||||||
|
else
|
||||||
|
URL containing this toolchain, if avaialble, else None
|
||||||
|
"""
|
||||||
|
arch = command.OutputOneLine('uname', '-m')
|
||||||
|
base = 'https://www.kernel.org/pub/tools/crosstool/files/bin'
|
||||||
|
versions = ['4.6.3', '4.6.2', '4.5.1', '4.2.4']
|
||||||
|
links = []
|
||||||
|
for version in versions:
|
||||||
|
url = '%s/%s/%s/' % (base, arch, version)
|
||||||
|
print 'Checking: %s' % url
|
||||||
|
response = urllib2.urlopen(url)
|
||||||
|
html = response.read()
|
||||||
|
parser = MyHTMLParser(fetch_arch)
|
||||||
|
parser.feed(html)
|
||||||
|
if fetch_arch == 'list':
|
||||||
|
links += parser.links
|
||||||
|
elif parser.arch_link:
|
||||||
|
return url + parser.arch_link
|
||||||
|
if fetch_arch == 'list':
|
||||||
|
return arch, links
|
||||||
|
return None
|
||||||
|
|
||||||
|
def Download(self, url):
|
||||||
|
"""Download a file to a temporary directory
|
||||||
|
|
||||||
|
Args:
|
||||||
|
url: URL to download
|
||||||
|
Returns:
|
||||||
|
Tuple:
|
||||||
|
Temporary directory name
|
||||||
|
Full path to the downloaded archive file in that directory,
|
||||||
|
or None if there was an error while downloading
|
||||||
|
"""
|
||||||
|
print "Downloading: %s" % url
|
||||||
|
leaf = url.split('/')[-1]
|
||||||
|
tmpdir = tempfile.mkdtemp('.buildman')
|
||||||
|
response = urllib2.urlopen(url)
|
||||||
|
fname = os.path.join(tmpdir, leaf)
|
||||||
|
fd = open(fname, 'wb')
|
||||||
|
meta = response.info()
|
||||||
|
size = int(meta.getheaders("Content-Length")[0])
|
||||||
|
done = 0
|
||||||
|
block_size = 1 << 16
|
||||||
|
status = ''
|
||||||
|
|
||||||
|
# Read the file in chunks and show progress as we go
|
||||||
|
while True:
|
||||||
|
buffer = response.read(block_size)
|
||||||
|
if not buffer:
|
||||||
|
print chr(8) * (len(status) + 1), '\r',
|
||||||
|
break
|
||||||
|
|
||||||
|
done += len(buffer)
|
||||||
|
fd.write(buffer)
|
||||||
|
status = r"%10d MiB [%3d%%]" % (done / 1024 / 1024,
|
||||||
|
done * 100 / size)
|
||||||
|
status = status + chr(8) * (len(status) + 1)
|
||||||
|
print status,
|
||||||
|
sys.stdout.flush()
|
||||||
|
fd.close()
|
||||||
|
if done != size:
|
||||||
|
print 'Error, failed to download'
|
||||||
|
os.remove(fname)
|
||||||
|
fname = None
|
||||||
|
return tmpdir, fname
|
||||||
|
|
||||||
|
def Unpack(self, fname, dest):
|
||||||
|
"""Unpack a tar file
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fname: Filename to unpack
|
||||||
|
dest: Destination directory
|
||||||
|
Returns:
|
||||||
|
Directory name of the first entry in the archive, without the
|
||||||
|
trailing /
|
||||||
|
"""
|
||||||
|
stdout = command.Output('tar', 'xvfJ', fname, '-C', dest)
|
||||||
|
return stdout.splitlines()[0][:-1]
|
||||||
|
|
||||||
|
def TestSettingsHasPath(self, path):
|
||||||
|
"""Check if builmand will find this toolchain
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the path is in settings, False if not
|
||||||
|
"""
|
||||||
|
paths = self.GetPathList()
|
||||||
|
return path in paths
|
||||||
|
|
||||||
|
def ListArchs(self):
|
||||||
|
"""List architectures with available toolchains to download"""
|
||||||
|
host_arch, archives = self.LocateArchUrl('list')
|
||||||
|
re_arch = re.compile('[-a-z0-9.]*_([^-]*)-.*')
|
||||||
|
arch_set = set()
|
||||||
|
for archive in archives:
|
||||||
|
# Remove the host architecture from the start
|
||||||
|
arch = re_arch.match(archive[len(host_arch):])
|
||||||
|
if arch:
|
||||||
|
arch_set.add(arch.group(1))
|
||||||
|
return sorted(arch_set)
|
||||||
|
|
||||||
|
def FetchAndInstall(self, arch):
|
||||||
|
"""Fetch and install a new toolchain
|
||||||
|
|
||||||
|
arch:
|
||||||
|
Architecture to fetch, or 'list' to list
|
||||||
|
"""
|
||||||
|
# Fist get the URL for this architecture
|
||||||
|
url = self.LocateArchUrl(arch)
|
||||||
|
if not url:
|
||||||
|
print ("Cannot find toolchain for arch '%s' - use 'list' to list" %
|
||||||
|
arch)
|
||||||
|
return 2
|
||||||
|
home = os.environ['HOME']
|
||||||
|
dest = os.path.join(home, '.buildman-toolchains')
|
||||||
|
if not os.path.exists(dest):
|
||||||
|
os.mkdir(dest)
|
||||||
|
|
||||||
|
# Download the tar file for this toolchain and unpack it
|
||||||
|
tmpdir, tarfile = self.Download(url)
|
||||||
|
if not tarfile:
|
||||||
|
return 1
|
||||||
|
print 'Unpacking to: %s' % dest,
|
||||||
|
sys.stdout.flush()
|
||||||
|
path = self.Unpack(tarfile, dest)
|
||||||
|
os.remove(tarfile)
|
||||||
|
os.rmdir(tmpdir)
|
||||||
|
print
|
||||||
|
|
||||||
|
# Check that the toolchain works
|
||||||
|
print 'Testing'
|
||||||
|
dirpath = os.path.join(dest, path)
|
||||||
|
compiler_fname = self.ScanPath(dirpath, True)
|
||||||
|
if not compiler_fname:
|
||||||
|
print 'Could not locate C compiler - fetch failed.'
|
||||||
|
return 1
|
||||||
|
toolchain = Toolchain(compiler_fname, True, True)
|
||||||
|
|
||||||
|
# Make sure that it will be found by buildman
|
||||||
|
if not self.TestSettingsHasPath(dirpath):
|
||||||
|
print ("Adding 'download' to config file '%s'" %
|
||||||
|
bsettings.config_fname)
|
||||||
|
tools_dir = os.path.dirname(dirpath)
|
||||||
|
bsettings.SetItem('toolchain', 'download', '%s/*' % tools_dir)
|
||||||
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,52 @@ def CountCommitsToBranch():
|
||||||
patch_count = int(stdout)
|
patch_count = int(stdout)
|
||||||
return patch_count
|
return patch_count
|
||||||
|
|
||||||
|
def NameRevision(commit_hash):
|
||||||
|
"""Gets the revision name for a commit
|
||||||
|
|
||||||
|
Args:
|
||||||
|
commit_hash: Commit hash to look up
|
||||||
|
|
||||||
|
Return:
|
||||||
|
Name of revision, if any, else None
|
||||||
|
"""
|
||||||
|
pipe = ['git', 'name-rev', commit_hash]
|
||||||
|
stdout = command.RunPipe([pipe], capture=True, oneline=True).stdout
|
||||||
|
|
||||||
|
# We expect a commit, a space, then a revision name
|
||||||
|
name = stdout.split(' ')[1].strip()
|
||||||
|
return name
|
||||||
|
|
||||||
|
def GuessUpstream(git_dir, branch):
|
||||||
|
"""Tries to guess the upstream for a branch
|
||||||
|
|
||||||
|
This lists out top commits on a branch and tries to find a suitable
|
||||||
|
upstream. It does this by looking for the first commit where
|
||||||
|
'git name-rev' returns a plain branch name, with no ! or ^ modifiers.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
git_dir: Git directory containing repo
|
||||||
|
branch: Name of branch
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple:
|
||||||
|
Name of upstream branch (e.g. 'upstream/master') or None if none
|
||||||
|
Warning/error message, or None if none
|
||||||
|
"""
|
||||||
|
pipe = [LogCmd(branch, git_dir=git_dir, oneline=True, count=100)]
|
||||||
|
result = command.RunPipe(pipe, capture=True, capture_stderr=True,
|
||||||
|
raise_on_error=False)
|
||||||
|
if result.return_code:
|
||||||
|
return None, "Branch '%s' not found" % branch
|
||||||
|
for line in result.stdout.splitlines()[1:]:
|
||||||
|
commit_hash = line.split(' ')[0]
|
||||||
|
name = NameRevision(commit_hash)
|
||||||
|
if '~' not in name and '^' not in name:
|
||||||
|
if name.startswith('remotes/'):
|
||||||
|
name = name[8:]
|
||||||
|
return name, "Guessing upstream as '%s'" % name
|
||||||
|
return None, "Cannot find a suitable upstream for branch '%s'" % branch
|
||||||
|
|
||||||
def GetUpstream(git_dir, branch):
|
def GetUpstream(git_dir, branch):
|
||||||
"""Returns the name of the upstream for a branch
|
"""Returns the name of the upstream for a branch
|
||||||
|
|
||||||
|
|
@ -69,7 +115,9 @@ def GetUpstream(git_dir, branch):
|
||||||
branch: Name of branch
|
branch: Name of branch
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Name of upstream branch (e.g. 'upstream/master') or None if none
|
Tuple:
|
||||||
|
Name of upstream branch (e.g. 'upstream/master') or None if none
|
||||||
|
Warning/error message, or None if none
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
remote = command.OutputOneLine('git', '--git-dir', git_dir, 'config',
|
remote = command.OutputOneLine('git', '--git-dir', git_dir, 'config',
|
||||||
|
|
@ -77,13 +125,14 @@ def GetUpstream(git_dir, branch):
|
||||||
merge = command.OutputOneLine('git', '--git-dir', git_dir, 'config',
|
merge = command.OutputOneLine('git', '--git-dir', git_dir, 'config',
|
||||||
'branch.%s.merge' % branch)
|
'branch.%s.merge' % branch)
|
||||||
except:
|
except:
|
||||||
return None
|
upstream, msg = GuessUpstream(git_dir, branch)
|
||||||
|
return upstream, msg
|
||||||
|
|
||||||
if remote == '.':
|
if remote == '.':
|
||||||
return merge
|
return merge
|
||||||
elif remote and merge:
|
elif remote and merge:
|
||||||
leaf = merge.split('/')[-1]
|
leaf = merge.split('/')[-1]
|
||||||
return '%s/%s' % (remote, leaf)
|
return '%s/%s' % (remote, leaf), None
|
||||||
else:
|
else:
|
||||||
raise ValueError, ("Cannot determine upstream branch for branch "
|
raise ValueError, ("Cannot determine upstream branch for branch "
|
||||||
"'%s' remote='%s', merge='%s'" % (branch, remote, merge))
|
"'%s' remote='%s', merge='%s'" % (branch, remote, merge))
|
||||||
|
|
@ -99,10 +148,29 @@ def GetRangeInBranch(git_dir, branch, include_upstream=False):
|
||||||
Expression in the form 'upstream..branch' which can be used to
|
Expression in the form 'upstream..branch' which can be used to
|
||||||
access the commits. If the branch does not exist, returns None.
|
access the commits. If the branch does not exist, returns None.
|
||||||
"""
|
"""
|
||||||
upstream = GetUpstream(git_dir, branch)
|
upstream, msg = GetUpstream(git_dir, branch)
|
||||||
if not upstream:
|
if not upstream:
|
||||||
return None
|
return None, msg
|
||||||
return '%s%s..%s' % (upstream, '~' if include_upstream else '', branch)
|
rstr = '%s%s..%s' % (upstream, '~' if include_upstream else '', branch)
|
||||||
|
return rstr, msg
|
||||||
|
|
||||||
|
def CountCommitsInRange(git_dir, range_expr):
|
||||||
|
"""Returns the number of commits in the given range.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
git_dir: Directory containing git repo
|
||||||
|
range_expr: Range to check
|
||||||
|
Return:
|
||||||
|
Number of patches that exist in the supplied rangem or None if none
|
||||||
|
were found
|
||||||
|
"""
|
||||||
|
pipe = [LogCmd(range_expr, git_dir=git_dir, oneline=True)]
|
||||||
|
result = command.RunPipe(pipe, capture=True, capture_stderr=True,
|
||||||
|
raise_on_error=False)
|
||||||
|
if result.return_code:
|
||||||
|
return None, "Range '%s' not found or is invalid" % range_expr
|
||||||
|
patch_count = len(result.stdout.splitlines())
|
||||||
|
return patch_count, None
|
||||||
|
|
||||||
def CountCommitsInBranch(git_dir, branch, include_upstream=False):
|
def CountCommitsInBranch(git_dir, branch, include_upstream=False):
|
||||||
"""Returns the number of commits in the given branch.
|
"""Returns the number of commits in the given branch.
|
||||||
|
|
@ -114,14 +182,10 @@ def CountCommitsInBranch(git_dir, branch, include_upstream=False):
|
||||||
Number of patches that exist on top of the branch, or None if the
|
Number of patches that exist on top of the branch, or None if the
|
||||||
branch does not exist.
|
branch does not exist.
|
||||||
"""
|
"""
|
||||||
range_expr = GetRangeInBranch(git_dir, branch, include_upstream)
|
range_expr, msg = GetRangeInBranch(git_dir, branch, include_upstream)
|
||||||
if not range_expr:
|
if not range_expr:
|
||||||
return None
|
return None, msg
|
||||||
pipe = [LogCmd(range_expr, git_dir=git_dir, oneline=True),
|
return CountCommitsInRange(git_dir, range_expr)
|
||||||
['wc', '-l']]
|
|
||||||
result = command.RunPipe(pipe, capture=True, oneline=True)
|
|
||||||
patch_count = int(result.stdout)
|
|
||||||
return patch_count
|
|
||||||
|
|
||||||
def CountCommits(commit_range):
|
def CountCommits(commit_range):
|
||||||
"""Returns the number of commits in the given range.
|
"""Returns the number of commits in the given range.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue