--- a/taskcluster/taskgraph/util/docker.py
+++ b/taskcluster/taskgraph/util/docker.py
@@ -47,27 +47,27 @@ def docker_image(name, by_tag=False):
try:
with open(os.path.join(IMAGE_DIR, name, 'VERSION')) as f:
tag = f.read().strip()
except IOError:
tag = 'latest'
return '{}/{}:{}'.format(registry, name, tag)
+class VoidWriter(object):
+ """A file object with write capabilities that does nothing with the written
+ data."""
+ def write(self, buf):
+ pass
+
+
def generate_context_hash(topsrcdir, image_path, image_name, args=None):
"""Generates a sha256 hash for context directory used to build an image."""
- # It is a bit unfortunate we have to create a temp file here - it would
- # be nicer to use an in-memory buffer.
- fd, p = tempfile.mkstemp()
- os.close(fd)
- try:
- return create_context_tar(topsrcdir, image_path, p, image_name, args)
- finally:
- os.unlink(p)
+ return stream_context_tar(topsrcdir, image_path, VoidWriter(), image_name, args)
class HashingWriter(object):
"""A file object with write capabilities that hashes the written data at
the same time it passes down to a real file object."""
def __init__(self, writer):
self._hash = hashlib.sha256()
self._writer = writer
@@ -98,16 +98,23 @@ def create_context_tar(topsrcdir, contex
If a line in the Dockerfile has the form ``# %ARG <name>``, occurrences of
the string ``$<name>`` in subsequent lines are replaced with the value
found in the ``args`` argument. Exception: this doesn't apply to VOLUME
definitions.
Returns the SHA-256 hex digest of the created archive.
"""
+ with open(out_path, 'wb') as fh:
+ return stream_context_tar(topsrcdir, context_dir, fh, prefix, args)
+
+
+def stream_context_tar(topsrcdir, context_dir, out_file, prefix, args=None):
+ """Like create_context_tar, but streams the tar file to the `out_file` file
+ object."""
archive_files = {}
replace = []
for root, dirs, files in os.walk(context_dir):
for f in files:
source_path = os.path.join(root, f)
rel = source_path[len(context_dir) + 1:]
archive_path = os.path.join(prefix, rel)
@@ -154,20 +161,19 @@ def create_context_tar(topsrcdir, contex
archive_files[archive_path] = source_path
else:
archive_path = os.path.join(prefix, 'topsrcdir', p)
archive_files[archive_path] = fs_path
archive_files[os.path.join(prefix, 'Dockerfile')] = \
GeneratedFile(b''.join(content))
- with open(out_path, 'wb') as fh:
- writer = HashingWriter(fh)
- create_tar_gz_from_files(writer, archive_files, '%s.tar.gz' % prefix)
- return writer.hexdigest()
+ writer = HashingWriter(out_file)
+ create_tar_gz_from_files(writer, archive_files, '%s.tar.gz' % prefix)
+ return writer.hexdigest()
def build_from_context(docker_bin, context_path, prefix, tag=None):
"""Build a Docker image from a context archive.
Given the path to a `docker` binary, a image build tar.gz (produced with
``create_context_tar()``, a prefix in that context containing files, and
an optional ``tag`` for the produced image, build that Docker image.