v2: Fix warning due to include.

Various temp dir/file changes.
     Don't use "find -executable" to be compatible with Mac.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQEcBAABCAAGBQJXTqs5AAoJEMo1YkxqkXHGhRkIAIjmtKdjKaR2KkdqeziD/enB
 FCY5Kvm90UvZxpEmQuA0SXyOuxP3gRPSTG5XU96tNqd40fbhkWTaLzo6PjyS3d/P
 6GzEsi4R6zu4q664z7akwvY2Q6mpph5iPtSc9PIrWv2GB4h3j4Hwps/X67smaME0
 zstaU8A+LhxNFMS7x0TBNXwy56NmAirOrdIWdKwx+RQBGYDdC10FtrMbgLh3G0So
 oZM5MSqAAeieN6QEzQM8QFEmmiJgDhnwi7TM82tUgqTrww4QVZnhMYaZzope0ias
 tA1LvbkfMXIH4NtBJET5ZMlr/fxrvfDVcxDUOUgLzi35h1tjLd56d7hFzAJd27E=
 =hPhl
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/famz/tags/pull-docker-20160601' into staging

v2: Fix warning due to include.
    Various temp dir/file changes.
    Don't use "find -executable" to be compatible with Mac.

# gpg: Signature made Wed 01 Jun 2016 10:30:33 BST using RSA key ID 6A9171C6
# gpg: Good signature from "Fam Zheng <famz@redhat.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 5003 7CB7 9706 0F76 F021  AD56 CA35 624C 6A91 71C6

* remotes/famz/tags/pull-docker-20160601:
  .gitignore: Ignore docker source copy
  MAINTAINERS: Add tests/docker
  docker: Add EXTRA_CONFIGURE_OPTS
  docs: Add text for tests/docker in build-system.txt
  docker: Add travis tool
  docker: Add mingw test
  docker: Add clang test
  docker: Add full test
  docker: Add quick test
  docker: Add common.rc
  docker: Add test runner
  docker: Add images
  Makefile: Rules for docker testing
  Makefile: Always include rules.mak
  rules.mak: Add "COMMA" constant
  tests: Add utilities for docker testing

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-06-02 13:42:52 +01:00
commit cbd614870f
18 changed files with 619 additions and 2 deletions

1
.gitignore vendored
View File

@ -108,4 +108,5 @@
cscope.*
tags
TAGS
docker-src.*
*~

View File

@ -1615,3 +1615,10 @@ Build system architecture
M: Daniel P. Berrange <berrange@redhat.com>
S: Odd Fixes
F: docs/build-system.txt
Docker testing
--------------
Docker based testing framework and cases
M: Fam Zheng <famz@redhat.com>
S: Maintained
F: tests/docker/

View File

@ -6,7 +6,7 @@ BUILD_DIR=$(CURDIR)
# Before including a proper config-host.mak, assume we are in the source tree
SRC_PATH=.
UNCHECKED_GOALS := %clean TAGS cscope ctags
UNCHECKED_GOALS := %clean TAGS cscope ctags docker docker-%
# All following code might depend on configuration variables
ifneq ($(wildcard config-host.mak),)
@ -30,7 +30,6 @@ CONFIG_ALL=y
-include config-all-devices.mak
-include config-all-disas.mak
include $(SRC_PATH)/rules.mak
config-host.mak: $(SRC_PATH)/configure
@echo $@ is out-of-date, running configure
@# TODO: The next lines include code which supports a smooth
@ -49,6 +48,8 @@ ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fa
endif
endif
include $(SRC_PATH)/rules.mak
GENERATED_HEADERS = config-host.h qemu-options.def
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h qapi-event.h
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c
@ -643,3 +644,5 @@ endif
# Include automatically generated dependency files
# Dependencies in Makefile.objs files come from our recursive subdir rules
-include $(wildcard *.d tests/*.d)
include $(SRC_PATH)/tests/docker/Makefile.include

View File

@ -438,6 +438,11 @@ top level Makefile, so anything defined in this file will influence the
entire build system. Care needs to be taken when writing rules for tests
to ensure they only apply to the unit test execution / build.
- tests/docker/Makefile.include
Rules for Docker tests. Like tests/Makefile, this file is included
directly by the top level Makefile, anything defined in this file will
influence the entire build system.
- po/Makefile

View File

@ -1,4 +1,6 @@
COMMA := ,
# Don't use implicit rules or variables
# we have explicit rules for everything
MAKEFLAGS += -rR

View File

@ -0,0 +1,126 @@
# Makefile for Docker tests
.PHONY: docker docker-test docker-clean docker-image docker-qemu-src
DOCKER_SUFFIX := .docker
DOCKER_FILES_DIR := $(SRC_PATH)/tests/docker/dockerfiles
DOCKER_IMAGES := $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker)))
DOCKER_TARGETS := $(patsubst %,docker-image-%,$(DOCKER_IMAGES))
# Use a global constant ccache directory to speed up repetitive builds
DOCKER_CCACHE_DIR := $$HOME/.cache/qemu-docker-ccache
DOCKER_TESTS := $(notdir $(shell \
find $(SRC_PATH)/tests/docker/ -name 'test-*' -type f))
DOCKER_TOOLS := travis
TESTS ?= %
IMAGES ?= %
# Make archive from git repo $1 to tar.gz $2
make-archive-maybe = $(if $(wildcard $1/*), \
$(call quiet-command, \
(cd $1; if git diff-index --quiet HEAD -- &>/dev/null; then \
git archive -1 HEAD --format=tar.gz -o $2; \
else \
git archive -1 $$(git stash create) --format=tar.gz -o $2; \
fi), \
" ARCHIVE $(notdir $2)"))
CUR_TIME := $(shell date +%Y-%m-%d-%H.%M.%S.$$$$)
# Makes the definition constant after the first expansion
DOCKER_SRC_COPY = $(eval DOCKER_SRC_COPY := docker-src.$(CUR_TIME))$(DOCKER_SRC_COPY)
$(DOCKER_SRC_COPY):
@mkdir $@
$(call make-archive-maybe, $(SRC_PATH), $@/qemu.tgz)
$(call make-archive-maybe, $(SRC_PATH)/dtc, $@/dtc.tgz)
$(call make-archive-maybe, $(SRC_PATH)/pixman, $@/pixman.tgz)
$(call quiet-command, cp $(SRC_PATH)/tests/docker/run $@/run, \
" COPY RUNNER")
docker-qemu-src: $(DOCKER_SRC_COPY)
docker-image: ${DOCKER_TARGETS}
# General rule for building docker images
docker-image-%: $(DOCKER_FILES_DIR)/%.docker
$(call quiet-command,\
$(SRC_PATH)/tests/docker/docker.py build qemu:$* $< \
$(if $V,,--quiet) $(if $(NOCACHE),--no-cache),\
" BUILD $*")
# Expand all the pre-requistes for each docker image and test combination
$(foreach i,$(DOCKER_IMAGES), \
$(foreach t,$(DOCKER_TESTS) $(DOCKER_TOOLS), \
$(eval .PHONY: docker-$t@$i) \
$(eval docker-$t@$i: docker-image-$i docker-run-$t@$i) \
) \
$(foreach t,$(DOCKER_TESTS), \
$(eval docker-test: docker-$t@$i) \
) \
)
docker:
@echo 'Build QEMU and run tests inside Docker containers'
@echo
@echo 'Available targets:'
@echo
@echo ' docker: Print this help.'
@echo ' docker-test: Run all image/test combinations.'
@echo ' docker-clean: Kill and remove residual docker testing containers.'
@echo ' docker-TEST@IMAGE: Run "TEST" in container "IMAGE".'
@echo ' Note: "TEST" is one of the listed test name,'
@echo ' or a script name under $$QEMU_SRC/tests/docker/;'
@echo ' "IMAGE" is one of the listed container name."'
@echo ' docker-image: Build all images.'
@echo ' docker-image-IMAGE: Build image "IMAGE".'
@echo
@echo 'Available container images:'
@echo ' $(DOCKER_IMAGES)'
@echo
@echo 'Available tests:'
@echo ' $(DOCKER_TESTS)'
@echo
@echo 'Available tools:'
@echo ' $(DOCKER_TOOLS)'
@echo
@echo 'Special variables:'
@echo ' TARGET_LIST=a,b,c Override target list in builds.'
@echo ' EXTRA_CONFIGURE_OPTS="..."'
@echo ' Extra configure options.'
@echo ' IMAGES="a b c ..": Filters which images to build or run.'
@echo ' TESTS="x y z .." Filters which tests to run (for docker-test).'
@echo ' J=[0..9]* Overrides the -jN parameter for make commands'
@echo ' (default is 1)'
@echo ' DEBUG=1 Stop and drop to shell in the created container'
@echo ' before running the command.'
@echo ' NOCACHE=1 Ignore cache when build images.'
docker-run-%: CMD = $(shell echo '$@' | sed -e 's/docker-run-\([^@]*\)@\(.*\)/\1/')
docker-run-%: IMAGE = $(shell echo '$@' | sed -e 's/docker-run-\([^@]*\)@\(.*\)/\2/')
docker-run-%: docker-qemu-src
@mkdir -p "$(DOCKER_CCACHE_DIR)"
@if test -z "$(IMAGE)" || test -z "$(CMD)"; \
then echo "Invalid target"; exit 1; \
fi
$(if $(filter $(TESTS),$(CMD)),$(if $(filter $(IMAGES),$(IMAGE)), \
$(call quiet-command,\
$(SRC_PATH)/tests/docker/docker.py run $(if $V,,--rm) \
-t \
$(if $(DEBUG),-i,--net=none) \
-e TARGET_LIST=$(TARGET_LIST) \
-e EXTRA_CONFIGURE_OPTS=$(EXTRA_CONFIGURE_OPTS) \
-e V=$V -e J=$J -e DEBUG=$(DEBUG)\
-e CCACHE_DIR=/var/tmp/ccache \
-v $$(realpath $(DOCKER_SRC_COPY)):/var/tmp/qemu:z$(COMMA)ro \
-v $(DOCKER_CCACHE_DIR):/var/tmp/ccache:z \
-w /var/tmp/qemu \
qemu:$(IMAGE) \
$(if $V,/bin/bash -x ,) \
./run \
$(CMD); \
, " RUN $(CMD) in $(IMAGE)")))
docker-clean:
$(call quiet-command, $(SRC_PATH)/tests/docker/docker.py clean)

32
tests/docker/common.rc Executable file
View File

@ -0,0 +1,32 @@
#!/bin/sh
#
# Common routines for docker test scripts.
#
# Copyright (c) 2016 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
requires()
{
for c in $@; do
if ! echo "$FEATURES" | grep -wq -e "$c"; then
echo "Prerequisite '$c' not present, skip"
exit 0
fi
done
}
build_qemu()
{
$QEMU_SRC/configure \
--target-list="${TARGET_LIST}" \
--prefix="$PWD/install" \
$EXTRA_CONFIGURE_OPTS \
"$@"
make $MAKEFLAGS
}

194
tests/docker/docker.py Executable file
View File

@ -0,0 +1,194 @@
#!/usr/bin/env python2
#
# Docker controlling module
#
# Copyright (c) 2016 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
import os
import sys
import subprocess
import json
import hashlib
import atexit
import uuid
import argparse
import tempfile
from shutil import copy
def _text_checksum(text):
"""Calculate a digest string unique to the text content"""
return hashlib.sha1(text).hexdigest()
def _guess_docker_command():
""" Guess a working docker command or raise exception if not found"""
commands = [["docker"], ["sudo", "-n", "docker"]]
for cmd in commands:
if subprocess.call(cmd + ["images"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE) == 0:
return cmd
commands_txt = "\n".join([" " + " ".join(x) for x in commands])
raise Exception("Cannot find working docker command. Tried:\n%s" % \
commands_txt)
class Docker(object):
""" Running Docker commands """
def __init__(self):
self._command = _guess_docker_command()
self._instances = []
atexit.register(self._kill_instances)
def _do(self, cmd, quiet=True, **kwargs):
if quiet:
kwargs["stdout"] = subprocess.PIPE
return subprocess.call(self._command + cmd, **kwargs)
def _do_kill_instances(self, only_known, only_active=True):
cmd = ["ps", "-q"]
if not only_active:
cmd.append("-a")
for i in self._output(cmd).split():
resp = self._output(["inspect", i])
labels = json.loads(resp)[0]["Config"]["Labels"]
active = json.loads(resp)[0]["State"]["Running"]
if not labels:
continue
instance_uuid = labels.get("com.qemu.instance.uuid", None)
if not instance_uuid:
continue
if only_known and instance_uuid not in self._instances:
continue
print "Terminating", i
if active:
self._do(["kill", i])
self._do(["rm", i])
def clean(self):
self._do_kill_instances(False, False)
return 0
def _kill_instances(self):
return self._do_kill_instances(True)
def _output(self, cmd, **kwargs):
return subprocess.check_output(self._command + cmd,
stderr=subprocess.STDOUT,
**kwargs)
def get_image_dockerfile_checksum(self, tag):
resp = self._output(["inspect", tag])
labels = json.loads(resp)[0]["Config"].get("Labels", {})
return labels.get("com.qemu.dockerfile-checksum", "")
def build_image(self, tag, dockerfile, df_path, quiet=True, argv=None):
if argv == None:
argv = []
tmp_dir = tempfile.mkdtemp(prefix="docker_build")
tmp_df = tempfile.NamedTemporaryFile(dir=tmp_dir, suffix=".docker")
tmp_df.write(dockerfile)
tmp_df.write("\n")
tmp_df.write("LABEL com.qemu.dockerfile-checksum=%s" %
_text_checksum(dockerfile))
tmp_df.flush()
self._do(["build", "-t", tag, "-f", tmp_df.name] + argv + \
[tmp_dir],
quiet=quiet)
def image_matches_dockerfile(self, tag, dockerfile):
try:
checksum = self.get_image_dockerfile_checksum(tag)
except Exception:
return False
return checksum == _text_checksum(dockerfile)
def run(self, cmd, keep, quiet):
label = uuid.uuid1().hex
if not keep:
self._instances.append(label)
ret = self._do(["run", "--label",
"com.qemu.instance.uuid=" + label] + cmd,
quiet=quiet)
if not keep:
self._instances.remove(label)
return ret
class SubCommand(object):
"""A SubCommand template base class"""
name = None # Subcommand name
def shared_args(self, parser):
parser.add_argument("--quiet", action="store_true",
help="Run quietly unless an error occured")
def args(self, parser):
"""Setup argument parser"""
pass
def run(self, args, argv):
"""Run command.
args: parsed argument by argument parser.
argv: remaining arguments from sys.argv.
"""
pass
class RunCommand(SubCommand):
"""Invoke docker run and take care of cleaning up"""
name = "run"
def args(self, parser):
parser.add_argument("--keep", action="store_true",
help="Don't remove image when command completes")
def run(self, args, argv):
return Docker().run(argv, args.keep, quiet=args.quiet)
class BuildCommand(SubCommand):
""" Build docker image out of a dockerfile. Arguments: <tag> <dockerfile>"""
name = "build"
def args(self, parser):
parser.add_argument("tag",
help="Image Tag")
parser.add_argument("dockerfile",
help="Dockerfile name")
def run(self, args, argv):
dockerfile = open(args.dockerfile, "rb").read()
tag = args.tag
dkr = Docker()
if dkr.image_matches_dockerfile(tag, dockerfile):
if not args.quiet:
print "Image is up to date."
return 0
dkr.build_image(tag, dockerfile, args.dockerfile,
quiet=args.quiet, argv=argv)
return 0
class CleanCommand(SubCommand):
"""Clean up docker instances"""
name = "clean"
def run(self, args, argv):
Docker().clean()
return 0
def main():
parser = argparse.ArgumentParser(description="A Docker helper",
usage="%s <subcommand> ..." % os.path.basename(sys.argv[0]))
subparsers = parser.add_subparsers(title="subcommands", help=None)
for cls in SubCommand.__subclasses__():
cmd = cls()
subp = subparsers.add_parser(cmd.name, help=cmd.__doc__)
cmd.shared_args(subp)
cmd.args(subp)
subp.set_defaults(cmdobj=cmd)
args, argv = parser.parse_known_args()
return args.cmdobj.run(args, argv)
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,6 @@
FROM centos:6
RUN yum install -y \
tar git make gcc g++ \
zlib-devel glib2-devel SDL-devel pixman-devel \
epel-release
RUN yum install -y libfdt-devel ccache

View File

@ -0,0 +1,7 @@
FROM fedora:23
RUN dnf install -y \
ccache git tar \
glib2-devel pixman-devel zlib-devel SDL-devel libfdt-devel \
gcc gcc-c++ clang make perl which bc findutils \
mingw{32,64}-{pixman,glib2,gmp,SDL,pkg-config,gtk2,gtk3,gnutls,nettle,libtasn1,libjpeg-turbo,libpng,curl,libssh2,bzip2}
ENV FEATURES mingw clang

View File

@ -0,0 +1,11 @@
FROM ubuntu:14.04
RUN echo "deb http://archive.ubuntu.com/ubuntu/ trusty universe multiverse" >> \
/etc/apt/sources.list
RUN apt-get update
RUN apt-get -y install \
libusb-1.0-0-dev libiscsi-dev librados-dev libncurses5-dev \
libseccomp-dev libgnutls-dev libssh2-1-dev libspice-server-dev \
libspice-protocol-dev libnss3-dev libfdt-dev \
libgtk-3-dev libvte-2.90-dev libsdl1.2-dev libpng12-dev libpixman-1-dev \
git make ccache python-yaml gcc clang sparse
ENV FEATURES clang ccache pyyaml

58
tests/docker/run Executable file
View File

@ -0,0 +1,58 @@
#!/bin/bash -e
#
# Docker test runner
#
# Copyright (c) 2016 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
# Prepare the environment
. /etc/profile || true
export PATH=/usr/lib/ccache:$PATH
if test -n "$J"; then
export MAKEFLAGS="$MAKEFLAGS -j$J"
fi
# We are in the container so the whole file system belong to us
export TEST_DIR=/tmp/qemu-test
mkdir -p $TEST_DIR/{src,build,install}
# Extract the source tarballs
tar -C $TEST_DIR/src -xzf qemu.tgz
for p in dtc pixman; do
if test -f $p.tgz; then
tar -C $TEST_DIR/src/$p -xzf $p.tgz
export FEATURES="$FEATURES $p"
fi
done
export QEMU_SRC="$TEST_DIR/src"
cd "$QEMU_SRC/tests/docker"
CMD="$QEMU_SRC/tests/docker/$@"
if test -n "$DEBUG"; then
echo "* Prepared to run command:"
echo " $CMD"
echo "* Hit Ctrl-D to continue, or type 'exit 1' to abort"
echo
$SHELL
fi
if "$CMD"; then
exit 0
elif test -n "$DEBUG"; then
echo "* Command failed:"
echo " $CMD"
echo "* Hit Ctrl-D to exit"
echo
# Force error after shell exits
$SHELL && exit 1
fi

26
tests/docker/test-clang Executable file
View File

@ -0,0 +1,26 @@
#!/bin/bash -e
#
# Compile and check with clang.
#
# Copyright (c) 2016 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
. common.rc
requires clang
OPTS="--enable-debug --cxx=clang++ --cc=clang --host-cc=clang"
# -fsanitize=undefined is broken on Fedora 23, skip it for now
# See also: https://bugzilla.redhat.com/show_bug.cgi?id=1263834
#OPTS="$OPTS --extra-cflags=-fsanitize=undefined \
#--extra-cflags=-fno-sanitize=float-divide-by-zero"
DEF_TARGET_LIST="$(echo {x86_64,aarch64}-softmmu)"
TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \
build_qemu $OPTS
make $MAKEFLAGS check

17
tests/docker/test-full Executable file
View File

@ -0,0 +1,17 @@
#!/bin/bash -e
#
# Compile all the targets.
#
# Copyright (c) 2016 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
. common.rc
build_qemu
make check $MAKEFLAGS

34
tests/docker/test-mingw Executable file
View File

@ -0,0 +1,34 @@
#!/bin/bash -e
#
# Cross compile QEMU with mingw toolchain on Linux.
#
# Copyright (c) 2016 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
. common.rc
requires mingw dtc
for prefix in x86_64-w64-mingw32- i686-w64-mingw32-; do
TARGET_LIST=x86_64-softmmu,aarch64-softmmu \
build_qemu --cross-prefix=$prefix \
--enable-trace-backends=simple \
--enable-debug \
--enable-gnutls \
--enable-nettle \
--enable-curl \
--enable-vnc \
--enable-bzip2 \
--enable-guest-agent \
--with-sdlabi=1.2 \
--with-gtkabi=2.0
make clean
done

19
tests/docker/test-quick Executable file
View File

@ -0,0 +1,19 @@
#!/bin/bash -e
#
# Quick compiling test that everyone already does. But why not automate it?
#
# Copyright (c) 2016 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
. common.rc
DEF_TARGET_LIST="$(echo {x86_64,aarch64}-softmmu)"
TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \
build_qemu
make check $MAKEFLAGS

21
tests/docker/travis Executable file
View File

@ -0,0 +1,21 @@
#!/bin/bash -e
#
# Mimic a travis testing matrix
#
# Copyright (c) 2016 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
. common.rc
requires pyyaml
cmdfile=/tmp/travis_cmd_list.sh
$QEMU_SRC/tests/docker/travis.py $QEMU_SRC/.travis.yml > $cmdfile
chmod +x $cmdfile
cd "$QEMU_SRC"
$cmdfile

48
tests/docker/travis.py Executable file
View File

@ -0,0 +1,48 @@
#!/usr/bin/env python
#
# Travis YAML config parser
#
# Copyright (c) 2016 Red Hat Inc.
#
# Authors:
# Fam Zheng <famz@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2
# or (at your option) any later version. See the COPYING file in
# the top-level directory.
import sys
import yaml
import itertools
def load_yaml(fname):
return yaml.load(open(fname, "r").read())
def conf_iter(conf):
def env_to_list(env):
return env if isinstance(env, list) else [env]
global_env = conf["env"]["global"]
for entry in conf["matrix"]["include"]:
yield {"env": global_env + env_to_list(entry["env"]),
"compiler": entry["compiler"]}
for entry in itertools.product(conf["compiler"],
conf["env"]["matrix"]):
yield {"env": global_env + env_to_list(entry[1]),
"compiler": entry[0]}
def main():
if len(sys.argv) < 2:
sys.stderr.write("Usage: %s <travis-file>\n" % sys.argv[0])
return 1
conf = load_yaml(sys.argv[1])
for config in conf_iter(conf):
print "("
print "\n".join(config["env"])
print "alias cc=" + config["compiler"]
print "\n".join(conf["before_script"])
print "\n".join(conf["script"])
print ")"
return 0
if __name__ == "__main__":
sys.exit(main())