Skip to content

Commit ac0def4

Browse files
committed
Use CLI to push docker image
Preserves existing authentication information handling behavior: 1. If registry_credentials are present, they are used but not leaked on to existing ~/.docker/config 2. If registry_credentials are not present, they are not used 3. Regardless of registry_credentials being present, we still will use existing authentication info in DOCKER_CONFIG
1 parent 17a23c4 commit ac0def4

File tree

1 file changed

+41
-11
lines changed

1 file changed

+41
-11
lines changed

repo2docker/docker.py

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22
Docker container engine for repo2docker
33
"""
44

5+
import os
56
import shutil
7+
import subprocess
68
import tarfile
79
import tempfile
10+
from contextlib import contextmanager
11+
from pathlib import Path
812

913
from iso8601 import parse_date
1014
from traitlets import Dict, List, Unicode
@@ -58,7 +62,7 @@ class DockerEngine(ContainerEngine):
5862
https://docker-py.readthedocs.io/en/4.2.0/api.html#module-docker.api.build
5963
"""
6064

61-
string_output = False
65+
string_output = True
6266

6367
extra_init_args = Dict(
6468
{},
@@ -141,18 +145,12 @@ def build(
141145

142146
args += [d]
143147

144-
for line in execute_cmd(args, True):
145-
# Simulate structured JSON output from buildx build, since we
146-
# do get structured json output from pushing and running
147-
yield {"stream": line}
148+
yield from execute_cmd(args, True)
148149
else:
149150
# Assume 'path' is passed in
150151
args += [path]
151152

152-
for line in execute_cmd(args, True):
153-
# Simulate structured JSON output from buildx build, since we
154-
# do get structured json output from pushing and running
155-
yield {"stream": line}
153+
yield from execute_cmd(args, True)
156154

157155
def images(self):
158156
images = self._apiclient.images()
@@ -162,10 +160,42 @@ def inspect_image(self, image):
162160
image = self._apiclient.inspect_image(image)
163161
return Image(tags=image["RepoTags"], config=image["Config"])
164162

163+
@contextmanager
164+
def docker_login(self, username, password, registry):
165+
# Determine existing DOCKER_CONFIG
166+
dc_path = Path(
167+
os.environ.get("DOCKER_CONFIG", os.path.expanduser("~/.docker/config.json"))
168+
)
169+
170+
with tempfile.TemporaryDirectory() as d:
171+
new_dc_path = Path(d) / "config.json"
172+
if dc_path.exists():
173+
# If there is an existing DOCKER_CONFIG, copy it to new location so we inherit
174+
# whatever configuration the user has already set
175+
shutil.copy2(dc_path, new_dc_path)
176+
177+
env = os.environ.copy()
178+
subprocess.check_call(
179+
# FIXME: This should be using --password-stdin instead
180+
[
181+
"docker",
182+
"login",
183+
"--username",
184+
username,
185+
"--password",
186+
password,
187+
registry,
188+
],
189+
env=env,
190+
)
191+
yield
192+
165193
def push(self, image_spec):
166194
if self.registry_credentials:
167-
self._apiclient.login(**self.registry_credentials)
168-
return self._apiclient.push(image_spec, stream=True)
195+
with self.docker_login(**self.registry_credentials):
196+
yield from execute_cmd(["docker", "push", image_spec], capture=True)
197+
else:
198+
yield from execute_cmd(["docker", "push", image_spec], capture=True)
169199

170200
def run(
171201
self,

0 commit comments

Comments
 (0)