blob: 26b1f9a3037a865723a2411c14f6496048cf71a4 [file] [log] [blame]
# Run this as "python mk/update-travis-yml.py"
# Copyright 2015 Brian Smith.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND BRIAN SMITH AND THE AUTHORS DISCLAIM
# ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL BRIAN SMITH OR THE AUTHORS
# BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import re
import shutil
latest_clang = "clang-3.9"
rusts = [
"stable",
"nightly",
"beta",
]
linux_compilers = [
# GCC 4.6 is supported almost exclusively because it is the default
# compiler for Ubuntu 12.04 LTS, and in particular Travis CI. This is run
# first because it is the one most likely to break, especially since it is
# not supported by BoringSSL.
"gcc",
# Pre-release of clang.
# XXX: clang 3.9 doesn't work:
# https://github.com/travis-ci/apt-package-whitelist/issues/2764
# "clang-3.9",
# Newest clang and GCC.
# XXX: clang builds are disabled because the LLVM project turned off its
# APT servers, which we need to download clang.
# "clang-3.8",
# XXX: GCC 6 doesn't work:
# https://github.com/travis-ci/apt-package-whitelist/issues/2294
"gcc-5",
]
# Clang 3.4 and GCC are already installed by default.
linux_default_clang = "clang-3.4"
linux_default_gcc = "gcc"
osx_compilers = [
"clang",
]
compilers = {
"linux" : linux_compilers,
"osx" : osx_compilers,
}
modes = [
"DEBUG",
"RELWITHDEBINFO"
]
# Mac OS X is first because we don't want to have to wait until all the Linux
# configurations have been built to find out that there is a failure on Mac.
oss = [
"osx",
"linux",
]
targets = {
"osx" : [
"x86_64-apple-darwin",
],
"linux" : [
"i686-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
],
}
def format_entries():
return "\n".join([format_entry(os, target, compiler, rust, mode)
for rust in rusts
for os in oss
for compiler in compilers[os]
for target in targets[os]
for mode in modes])
# We use alternative names (the "_X" suffix) so that, in mk/travis.sh, we can
# enure that we set the specific variables we want and that no relevant
# variables are unintentially inherited into the build process. Also, we have
# to set |USE_CC| and |USE_CXX| instead of |CC| and |CXX| since Travis sets
# |CC| and |CXX| to their default values *after* processing the |env:|
# directive here. Also, we keep these variable names short so that the env
# line does not get cut off in the Travis CI UI.
entry_template = """
- env: TARGET_X=%(target)s CC_X=%(cc)s CXX_X=%(cxx)s MODE_X=%(mode)s KCOV=%(kcov)s
rust: %(rust)s
os: %(os)s"""
entry_indent = " "
entry_packages_template = """
addons:
apt:
packages:
%(packages)s"""
entry_sources_template = """
sources:
%(sources)s"""
def format_entry(os, target, compiler, rust, mode):
# Currently kcov only runs on Linux.
#
# GCC 5 was picked arbitrarily to restrict coverage report to one build for
# efficiency reasons.
#
# Cargo passes RUSTFLAGS to rustc only in Rust 1.9 and later. When Rust 1.9
# is released then we can change this to run (also) on the stable channel.
#
# DEBUG mode is needed because debug symbols are needed for coverage
# tracking.
kcov = (os == "linux" and compiler == "gcc-5" and rust == "nightly" and
mode == "DEBUG")
target_words = target.split("-")
arch = target_words[0]
vendor = target_words[1]
sys = target_words[2]
def prefix_all(prefix, xs):
return [prefix + x for x in xs]
template = entry_template
if sys == "linux":
packages = sorted(get_linux_packages_to_install(compiler, arch, kcov))
sources_with_dups = sum([get_sources_for_package(p) for p in packages],[])
sources = sorted(list(set(sources_with_dups)))
if packages:
template += entry_packages_template
if sources:
template += entry_sources_template
else:
packages = []
sources = []
cc = get_cc(sys, compiler)
cxx = replace_cc_with_cxx(sys, compiler)
if os == "osx":
os += "\n" + entry_indent + "osx_image: xcode7.2"
return template % {
"cc" : cc,
"cxx" : cxx,
"mode" : mode,
"kcov": "1" if kcov == True else "0",
"packages" : "\n ".join(prefix_all("- ", packages)),
"rust" : rust,
"sources" : "\n ".join(prefix_all("- ", sources)),
"target" : target,
"os" : os,
}
def get_linux_packages_to_install(compiler, arch, kcov):
if compiler in [linux_default_clang, linux_default_gcc]:
packages = []
elif compiler.startswith("clang-"):
packages = [compiler]
elif compiler.startswith("gcc-"):
packages = [compiler, replace_cc_with_cxx("linux", compiler)]
else:
raise ValueError("unexpected compiler: %s" % compiler)
if arch == "i686":
if kcov == True:
packages += ["libcurl3:i386",
"libcurl4-openssl-dev:i386",
"libdw-dev:i386",
"libelf-dev:i386",
"libkrb5-dev:i386",
"libssl-dev:i386"]
if compiler.startswith("clang-") or compiler == linux_default_gcc:
packages += ["libc6-dev-i386",
"gcc-multilib",
"g++-multilib"]
elif compiler.startswith("gcc-"):
packages += [compiler + "-multilib",
replace_cc_with_cxx("linux", compiler) + "-multilib",
"linux-libc-dev:i386"]
else:
raise ValueError("unexpected compiler: %s" % compiler)
elif arch == "x86_64":
if kcov == True:
packages += ["libcurl4-openssl-dev",
"libelf-dev",
"libdw-dev",
"binutils-dev"]
else:
raise ValueError("unexpected arch: %s" % arch)
return packages
def get_sources_for_package(package):
ubuntu_toolchain = "ubuntu-toolchain-r-test"
if package.startswith("clang-"):
if package == latest_clang:
llvm_toolchain = "llvm-toolchain-precise"
else:
_, version = package.split("-")
llvm_toolchain = "llvm-toolchain-precise-%s" % version
# Stuff in llvm-toolchain-precise depends on stuff in the toolchain
# packages.
return [llvm_toolchain, ubuntu_toolchain]
else:
return [ubuntu_toolchain]
def get_cc(sys, compiler):
if sys == "linux" and compiler == linux_default_clang:
return "clang"
return compiler
def replace_cc_with_cxx(sys, compiler):
return get_cc(sys, compiler) \
.replace("gcc", "g++") \
.replace("clang", "clang++")
def main():
# Make a backup of the file we are about to update.
shutil.copyfile(".travis.yml", ".travis.yml~")
with open(".travis.yml", "r+b") as file:
begin = " # BEGIN GENERATED\n"
end = " # END GENERATED\n"
old_contents = file.read()
new_contents = re.sub("%s(.*?)\n[ ]*%s" % (begin, end),
"".join([begin, format_entries(), "\n\n", end]),
old_contents, flags=re.S)
if old_contents == new_contents:
print "No changes"
return
file.seek(0)
file.write(new_contents)
file.truncate()
print new_contents
if __name__ == '__main__':
main()