Source code for benchbuild.utils.container
"""Container utilites."""
import logging
import os
from plumbum import TF, ProcessExecutionError, local
from benchbuild.settings import CFG
from benchbuild.utils.cmd import bash, cp, curl, cut, rm, tail
from benchbuild.utils.download import Wget
LOG = logging.getLogger(__name__)
[docs]def cached(func):
"""Memoize a function result."""
ret = None
def call_or_cache(*args, **kwargs):
nonlocal ret
if ret is None:
ret = func(*args, **kwargs)
return ret
return call_or_cache
[docs]class Container:
name = "container"
@property
def remote(self):
pass
@property
def filename(self):
image_cfg = CFG["container"]["images"].value
image_cfg = image_cfg[self.name]
tmp_dir = local.path(str(CFG["tmp_dir"]))
if os.path.isabs(image_cfg):
return image_cfg
return tmp_dir / image_cfg
@property
def local(self):
"""
Finds the current location of a container.
Also unpacks the project if necessary.
Returns:
target: The path, where the container lies in the end.
"""
assert self.name in CFG["container"]["images"].value
tmp_dir = local.path(str(CFG["tmp_dir"]))
target_dir = tmp_dir / self.name
if not target_dir.exists() or not is_valid(self, target_dir):
unpack(self, target_dir)
return target_dir
[docs]class Gentoo(Container):
name = "gentoo"
[docs] @cached
def src_file(self):
"""
Get the latest src_uri for a stage 3 tarball.
Returns (str):
Latest src_uri from gentoo's distfiles mirror.
"""
latest_txt = "http://distfiles.gentoo.org/releases/amd64/autobuilds/"\
"latest-stage3-amd64.txt"
try:
src_uri = (curl[latest_txt] | tail["-n", "+3"]
| cut["-f1", "-d "])().strip()
except ProcessExecutionError as proc_ex:
src_uri = "NOT-FOUND"
LOG.error("Could not determine latest stage3 src uri: %s",
str(proc_ex))
return src_uri
@property
def remote(self):
"""Get a remote URL of the requested container."""
return "http://distfiles.gentoo.org/releases/amd64/autobuilds/{0}" \
.format(self.src_file())
[docs]def is_valid(container, path):
"""
Checks if a container exists and is unpacked.
Args:
path: The location where the container is expected.
Returns:
True if the container is valid, False if the container needs to
unpacked or if the path does not exist yet.
"""
try:
tmp_hash_path = container.filename + ".hash"
with open(tmp_hash_path, 'r') as tmp_file:
tmp_hash = tmp_file.readline()
except IOError:
LOG.info("No .hash-file in the tmp-directory.")
container_hash_path = local.path(path) / "gentoo.tar.bz2.hash"
if container_hash_path.exists():
with open(container_hash_path, 'r') as hash_file:
container_hash = hash_file.readline()
return container_hash == tmp_hash
return False
[docs]def unpack(container, path):
"""
Unpack a container usable by uchroot.
Method that checks if a directory for the container exists,
checks if erlent support is needed and then unpacks the
container accordingly.
Args:
path: The location where the container is, that needs to be unpacked.
"""
from benchbuild.utils.run import run
from benchbuild.utils.uchroot import no_args
path = local.path(path)
c_filename = local.path(container.filename)
name = c_filename.basename
if not path.exists():
path.mkdir()
with local.cwd(path):
Wget(container.remote, name)
uchroot = no_args()
uchroot = uchroot["-E", "-A", "-C", "-r", "/", "-w",
os.path.abspath("."), "--"]
# Check, if we need erlent support for this archive.
has_erlent = bash[
"-c", "tar --list -f './{0}' | grep --silent '.erlent'".format(
name)]
has_erlent = (has_erlent & TF)
untar = local["/bin/tar"]["xf", "./" + name]
if not has_erlent:
untar = uchroot[untar]
run(untar["--exclude=dev/*"])
if not os.path.samefile(name, container.filename):
rm(name)
else:
LOG.warning("File contents do not match: %s != %s", name,
container.filename)
cp(container.filename + ".hash", path)
[docs]def in_container():
"""Check, whether we are running inside a container."""
p = local.path("/.benchbuild-container")
return p.exists()