diff options
author | Joffrey F <f.joffrey@gmail.com> | 2018-01-26 16:32:29 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-26 16:32:29 -0800 |
commit | 9c0332eb2e2225bef6fb291c5c1220566a1426a0 (patch) | |
tree | 7d605cd7451cf94f0698b8a318721c8e7c627e91 | |
parent | deb8222d6994dca12be65146189859c9b76ed9a5 (diff) | |
parent | 631cc3c1215441edb075a999a77061c1275c5e5a (diff) | |
download | docker-py-9c0332eb2e2225bef6fb291c5c1220566a1426a0.tar.gz |
Merge pull request #1875 from docker/1702-build-logs-dockerclient
ImageCollection.build now also returns build logs
-rw-r--r-- | docker/errors.py | 7 | ||||
-rw-r--r-- | docker/models/images.py | 14 | ||||
-rw-r--r-- | tests/integration/models_images_test.py | 17 |
3 files changed, 24 insertions, 14 deletions
diff --git a/docker/errors.py b/docker/errors.py index eeeac57..0253695 100644 --- a/docker/errors.py +++ b/docker/errors.py @@ -140,8 +140,11 @@ class StreamParseError(RuntimeError): self.msg = reason -class BuildError(Exception): - pass +class BuildError(DockerException): + def __init__(self, reason, build_log): + super(BuildError, self).__init__(reason) + self.msg = reason + self.build_log = build_log class ImageLoadError(DockerException): diff --git a/docker/models/images.py b/docker/models/images.py index dcdeac9..c4e727b 100644 --- a/docker/models/images.py +++ b/docker/models/images.py @@ -1,3 +1,4 @@ +import itertools import re import six @@ -160,7 +161,9 @@ class ImageCollection(Collection): platform (str): Platform in the format ``os[/arch[/variant]]``. Returns: - (:py:class:`Image`): The built image. + (tuple): The first item is the :py:class:`Image` object for the + image that was build. The second item is a generator of the + build logs as JSON-decoded objects. Raises: :py:class:`docker.errors.BuildError` @@ -175,9 +178,10 @@ class ImageCollection(Collection): return self.get(resp) last_event = None image_id = None - for chunk in json_stream(resp): + result_stream, internal_stream = itertools.tee(json_stream(resp)) + for chunk in internal_stream: if 'error' in chunk: - raise BuildError(chunk['error']) + raise BuildError(chunk['error'], result_stream) if 'stream' in chunk: match = re.search( r'(^Successfully built |sha256:)([0-9a-f]+)$', @@ -187,8 +191,8 @@ class ImageCollection(Collection): image_id = match.group(2) last_event = chunk if image_id: - return self.get(image_id) - raise BuildError(last_event or 'Unknown') + return (self.get(image_id), result_stream) + raise BuildError(last_event or 'Unknown', result_stream) def get(self, name): """ diff --git a/tests/integration/models_images_test.py b/tests/integration/models_images_test.py index 8840e15..900555d 100644 --- a/tests/integration/models_images_test.py +++ b/tests/integration/models_images_test.py @@ -10,27 +10,30 @@ class ImageCollectionTest(BaseIntegrationTest): def test_build(self): client = docker.from_env(version=TEST_API_VERSION) - image = client.images.build(fileobj=io.BytesIO( + image, _ = client.images.build(fileobj=io.BytesIO( "FROM alpine\n" "CMD echo hello world".encode('ascii') )) self.tmp_imgs.append(image.id) assert client.containers.run(image) == b"hello world\n" - @pytest.mark.xfail(reason='Engine 1.13 responds with status 500') + # @pytest.mark.xfail(reason='Engine 1.13 responds with status 500') def test_build_with_error(self): client = docker.from_env(version=TEST_API_VERSION) with self.assertRaises(docker.errors.BuildError) as cm: client.images.build(fileobj=io.BytesIO( "FROM alpine\n" - "NOTADOCKERFILECOMMAND".encode('ascii') + "RUN exit 1".encode('ascii') )) - assert str(cm.exception) == ("Unknown instruction: " - "NOTADOCKERFILECOMMAND") + print(cm.exception) + assert str(cm.exception) == ( + "The command '/bin/sh -c exit 1' returned a non-zero code: 1" + ) + assert cm.exception.build_log def test_build_with_multiple_success(self): client = docker.from_env(version=TEST_API_VERSION) - image = client.images.build( + image, _ = client.images.build( tag='some-tag', fileobj=io.BytesIO( "FROM alpine\n" "CMD echo hello world".encode('ascii') @@ -41,7 +44,7 @@ class ImageCollectionTest(BaseIntegrationTest): def test_build_with_success_build_output(self): client = docker.from_env(version=TEST_API_VERSION) - image = client.images.build( + image, _ = client.images.build( tag='dup-txt-tag', fileobj=io.BytesIO( "FROM alpine\n" "CMD echo Successfully built abcd1234".encode('ascii') |