Skip to content

Commit 5467658

Browse files
authored
Merge pull request #2169 from docker/2124-image-save-with-name
Add named parameter to image.save to identify which repository name to use in the resulting tarball
2 parents 7252086 + e237c0e commit 5467658

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

docker/models/images.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,20 @@ def history(self):
5959
"""
6060
return self.client.api.history(self.id)
6161

62-
def save(self, chunk_size=DEFAULT_DATA_CHUNK_SIZE):
62+
def save(self, chunk_size=DEFAULT_DATA_CHUNK_SIZE, named=False):
6363
"""
6464
Get a tarball of an image. Similar to the ``docker save`` command.
6565
6666
Args:
6767
chunk_size (int): The generator will return up to that much data
6868
per iteration, but may return less. If ``None``, data will be
6969
streamed as it is received. Default: 2 MB
70+
named (str or bool): If ``False`` (default), the tarball will not
71+
retain repository and tag information for this image. If set
72+
to ``True``, the first tag in the :py:attr:`~tags` list will
73+
be used to identify the image. Alternatively, any element of
74+
the :py:attr:`~tags` list can be used as an argument to use
75+
that specific tag as the saved identifier.
7076
7177
Returns:
7278
(generator): A stream of raw archive data.
@@ -83,7 +89,17 @@ def save(self, chunk_size=DEFAULT_DATA_CHUNK_SIZE):
8389
>>> f.write(chunk)
8490
>>> f.close()
8591
"""
86-
return self.client.api.get_image(self.id, chunk_size)
92+
img = self.id
93+
if named:
94+
img = self.tags[0] if self.tags else img
95+
if isinstance(named, six.string_types):
96+
if named not in self.tags:
97+
raise InvalidArgument(
98+
"{} is not a valid tag for this image".format(named)
99+
)
100+
img = named
101+
102+
return self.client.api.get_image(img, chunk_size)
87103

88104
def tag(self, repository, tag=None, **kwargs):
89105
"""

tests/integration/models_images_test.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import pytest
66

77
from .base import BaseIntegrationTest, BUSYBOX, TEST_API_VERSION
8+
from ..helpers import random_name
89

910

1011
class ImageCollectionTest(BaseIntegrationTest):
@@ -108,6 +109,32 @@ def test_save_and_load(self):
108109
assert len(result) == 1
109110
assert result[0].id == image.id
110111

112+
def test_save_and_load_repo_name(self):
113+
client = docker.from_env(version=TEST_API_VERSION)
114+
image = client.images.get(BUSYBOX)
115+
additional_tag = random_name()
116+
image.tag(additional_tag)
117+
self.tmp_imgs.append(additional_tag)
118+
image.reload()
119+
with tempfile.TemporaryFile() as f:
120+
stream = image.save(named='{}:latest'.format(additional_tag))
121+
for chunk in stream:
122+
f.write(chunk)
123+
124+
f.seek(0)
125+
client.images.remove(additional_tag, force=True)
126+
result = client.images.load(f.read())
127+
128+
assert len(result) == 1
129+
assert result[0].id == image.id
130+
assert '{}:latest'.format(additional_tag) in result[0].tags
131+
132+
def test_save_name_error(self):
133+
client = docker.from_env(version=TEST_API_VERSION)
134+
image = client.images.get(BUSYBOX)
135+
with pytest.raises(docker.errors.InvalidArgument):
136+
image.save(named='sakuya/izayoi')
137+
111138

112139
class ImageTest(BaseIntegrationTest):
113140

0 commit comments

Comments
 (0)