ci: New CI image builder infrastructure

pull/6843/head
Daniel Mensinger 5 years ago
parent 934863ba3b
commit 6310f188be
No known key found for this signature in database
GPG Key ID: 54DD94C131E277D4
  1. 2
      ci/ciimage/.gitignore
  2. 4
      ci/ciimage/arch/Dockerfile
  3. 6
      ci/ciimage/arch/image.json
  4. 2
      ci/ciimage/arch/install.sh
  5. 182
      ci/ciimage/build.py
  6. 4
      ci/ciimage/fedora/Dockerfile
  7. 8
      ci/ciimage/fedora/image.json
  8. 2
      ci/ciimage/fedora/install.sh
  9. 4
      ci/ciimage/opensuse/Dockerfile
  10. 9
      ci/ciimage/opensuse/image.json
  11. 16
      ci/ciimage/opensuse/install.sh

@ -0,0 +1,2 @@
/build_*
/test_*

@ -1,4 +0,0 @@
FROM archlinux:latest
ADD install.sh /usr/sbin/docker-arch-install
RUN docker-arch-install

@ -0,0 +1,6 @@
{
"base_image": "archlinux:latest",
"env": {
"CI": "1"
}
}

@ -1,5 +1,7 @@
#!/bin/bash
set -e
# Inspired by https://github.com/greyltc/docker-archlinux-aur/blob/master/add-aur.sh
pkgs=(

@ -0,0 +1,182 @@
#!/usr/bin/env python3
import json
import argparse
import stat
import textwrap
import shutil
import subprocess
from tempfile import TemporaryDirectory
from pathlib import Path
import typing as T
image_namespace = 'mesonbuild'
image_def_file = 'image.json'
install_script = 'install.sh'
class ImageDef:
def __init__(self, image_dir: Path) -> None:
path = image_dir / image_def_file
data = json.loads(path.read_text())
assert isinstance(data, dict)
assert all([x in data for x in ['base_image', 'env']])
assert isinstance(data['base_image'], str)
assert isinstance(data['env'], dict)
self.base_image: str = data['base_image']
self.env: T.Dict[str, str] = data['env']
class BuilderBase():
def __init__(self, data_dir: Path, temp_dir: Path) -> None:
self.data_dir = data_dir
self.temp_dir = temp_dir
self.validate_data_dir()
self.image_def = ImageDef(self.data_dir)
self.docker = shutil.which('docker')
self.git = shutil.which('git')
if self.docker is None:
raise RuntimeError('Unable to find docker')
if self.git is None:
raise RuntimeError('Unable to find git')
def validate_data_dir(self) -> None:
files = [
self.data_dir / image_def_file,
self.data_dir / install_script,
]
if not self.data_dir.exists():
raise RuntimeError(f'{self.data_dir.as_posix()} does not exist')
for i in files:
if not i.exists():
raise RuntimeError(f'{i.as_posix()} does not exist')
if not i.is_file():
raise RuntimeError(f'{i.as_posix()} is not a regular file')
class Builder(BuilderBase):
def gen_bashrc(self) -> None:
out_file = self.temp_dir / 'env_vars.sh'
out_data = ''
for key, val in self.image_def.env.items():
out_data += f'export {key}="{val}"\n'
out_file.write_text(out_data)
# make it executable
mode = out_file.stat().st_mode
out_file.chmod(mode | stat.S_IEXEC)
def gen_dockerfile(self) -> None:
out_file = self.temp_dir / 'Dockerfile'
out_data = textwrap.dedent(f'''\
FROM {self.image_def.base_image}
ADD install.sh /usr/sbin/docker-do-install
ADD env_vars.sh /env_vars.sh
RUN docker-do-install
''')
out_file.write_text(out_data)
def do_build(self) -> None:
# copy files
for i in self.data_dir.iterdir():
shutil.copy(str(i), str(self.temp_dir))
self.gen_bashrc()
self.gen_dockerfile()
cmd_git = [self.git, 'rev-parse', '--short', 'HEAD']
res = subprocess.run(cmd_git, cwd=self.data_dir, stdout=subprocess.PIPE)
if res.returncode != 0:
raise RuntimeError('Failed to get the current commit hash')
commit_hash = res.stdout.decode().strip()
cmd = [
self.docker, 'build',
'-t', f'{image_namespace}/{self.data_dir.name}:latest',
'-t', f'{image_namespace}/{self.data_dir.name}:{commit_hash}',
'--pull',
self.temp_dir.as_posix(),
]
if subprocess.run(cmd).returncode != 0:
raise RuntimeError('Failde to build the docker image')
class ImageTester(BuilderBase):
def __init__(self, data_dir: Path, temp_dir: Path, ci_root: Path) -> None:
super().__init__(data_dir, temp_dir)
self.meson_root = ci_root.parent.parent.resolve()
def gen_dockerfile(self) -> None:
out_file = self.temp_dir / 'Dockerfile'
out_data = textwrap.dedent(f'''\
FROM {image_namespace}/{self.data_dir.name}
ADD meson /meson
''')
out_file.write_text(out_data)
def copy_meson(self) -> None:
shutil.copytree(
self.meson_root,
self.temp_dir / 'meson',
ignore=shutil.ignore_patterns(
'.git',
'*_cache',
'work area',
self.temp_dir.name,
)
)
def do_test(self):
self.copy_meson()
self.gen_dockerfile()
try:
build_cmd = [
self.docker, 'build',
'-t', 'meson_test_image',
self.temp_dir.as_posix(),
]
if subprocess.run(build_cmd).returncode != 0:
raise RuntimeError('Failde to build the test docker image')
test_cmd = [
self.docker, 'run', '--rm', '-t', 'meson_test_image',
'/usr/bin/bash', '-c', 'source /env_vars.sh; cd meson; ./run_tests.py'
]
if subprocess.run(test_cmd).returncode != 0:
raise RuntimeError('Running tests failed')
finally:
cleanup_cmd = [self.docker, 'rmi', '-f', 'meson_test_image']
subprocess.run(cleanup_cmd).returncode
def main() -> None:
parser = argparse.ArgumentParser(description='Meson CI image builder')
parser.add_argument('what', type=str, help='Which image to build / test')
parser.add_argument('-t', '--type', choices=['build', 'test'], help='What to do', required=True)
args = parser.parse_args()
ci_root = Path(__file__).parent
ci_data = ci_root / args.what
with TemporaryDirectory(prefix=f'{args.type}_{args.what}_', dir=ci_root) as td:
ci_build = Path(td)
print(f'Build dir: {ci_build}')
if args.type == 'build':
builder = Builder(ci_data, ci_build)
builder.do_build()
elif args.type == 'test':
tester = ImageTester(ci_data, ci_build, ci_root)
tester.do_test()
if __name__ == '__main__':
main()

@ -1,4 +0,0 @@
FROM fedora:latest
ADD install.sh /usr/sbin/docker-fedora-install
RUN docker-fedora-install

@ -0,0 +1,8 @@
{
"base_image": "fedora:latest",
"env": {
"CI": "1",
"SKIP_SCIENTIFIC": "1",
"SKIP_STATIC_BOOST": "1"
}
}

@ -1,5 +1,7 @@
#!/bin/bash
set -e
pkgs=(
python python-setuptools python-wheel python-pip python-pytest-xdist pygobject3 python3-devel python2-devel
ninja-build make git autoconf automake patch python3-Cython python2-Cython python3-jsonschema

@ -1,4 +0,0 @@
FROM opensuse/tumbleweed:latest
ADD install.sh /usr/sbin/docker-opensuse-install
RUN docker-opensuse-install

@ -0,0 +1,9 @@
{
"base_image": "opensuse/tumbleweed:latest",
"env": {
"CI": "1",
"SKIP_SCIENTIFIC": "1",
"SKIP_STATIC_BOOST": "1",
"SINGLE_DUB_COMPILER": "1"
}
}

@ -1,5 +1,7 @@
#!/bin/bash
set -e
pkgs=(
python3-setuptools python3-wheel python3-pip python3-pytest-xdist python3 python2
ninja make git autoconf automake patch python3-Cython python2-Cython python3-jsonschema
@ -17,22 +19,22 @@ pkgs=(
)
# Sys update
zypper patch --with-update --with-optional
zypper update
zypper --non-interactive patch --with-update --with-optional
zypper --non-interactive update
# Install deps
zypper install -y "${pkgs[@]}"
python3 -m pip install hotdoc gobject PyGObject
echo 'export PKG_CONFIG_PATH="/usr/lib64/mpi/gcc/openmpi3/lib64/pkgconfig:$PKG_CONFIG_PATH"' >> ~/.bashrc
echo 'export PKG_CONFIG_PATH="/usr/lib64/mpi/gcc/openmpi3/lib64/pkgconfig:$PKG_CONFIG_PATH"' >> /env_vars.sh
# dmd is very special on OpenSUSE (as in the packages do not work)
# see https://bugzilla.opensuse.org/show_bug.cgi?id=1162408
curl -fsS https://dlang.org/install.sh | bash -s dmd | tee dmd_out.txt
cat dmd_out.txt | grep source | sed 's/^[^`]*`//g' | sed 's/`.*//g' >> ~/.bashrc
chmod +x ~/.bashrc
cat dmd_out.txt | grep source | sed 's/^[^`]*`//g' | sed 's/`.*//g' >> /env_vars.sh
chmod +x /env_vars.sh
source ~/.bashrc
source /env_vars.sh
dub fetch urld
dub build urld --compiler=dmd
@ -41,4 +43,4 @@ dub build dubtestproject:test1 --compiler=dmd
dub build dubtestproject:test2 --compiler=dmd
# Cleanup
zypper clean --all
zypper --non-interactive clean --all

Loading…
Cancel
Save