Stream docker pull progress; never rmi after a failed retag
Two pull UX/correctness fixes: (1) a multi-GB pull with captured output is minutes of silence reading as a hang -- layer progress now streams (throttled) to stderr; (2) the mirror-tag -> canonical retag could fail silently and the following rmi then deleted the ONLY tag, losing a 342s pull and forcing a full re-download -- retag is now verified and the mirror tag kept on failure. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
f4f10649df
commit
4f6e64e65c
@ -109,14 +109,41 @@ def _pull_one(image: str, verbose: bool = True) -> None:
|
||||
print(f'· pulling sandbox image {image} via {src} ...',
|
||||
file=_sys.stderr, flush=True)
|
||||
t0 = _time.monotonic()
|
||||
r = subprocess.run(['docker', 'pull', ref], capture_output=True, text=True,
|
||||
timeout=3600)
|
||||
# stream progress: a multi-GB pull with captured output is minutes
|
||||
# of silence that reads as a hang. Non-TTY docker pull emits clean
|
||||
# per-layer lines; forward the informative ones (throttled).
|
||||
proc = subprocess.Popen(['docker', 'pull', ref],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
text=True, bufsize=1)
|
||||
last_line = ''
|
||||
last_show = 0.0
|
||||
import os as _os
|
||||
for line in proc.stdout:
|
||||
last_line = line.strip()
|
||||
now = _time.monotonic()
|
||||
if verbose and (any(k in line for k in
|
||||
('Pulling from', 'Pull complete', 'Status',
|
||||
'error', 'denied'))
|
||||
or now - last_show > 10):
|
||||
print(f' {last_line[:100]}', file=_sys.stderr, flush=True)
|
||||
last_show = now
|
||||
proc.wait(timeout=3600)
|
||||
r = subprocess.CompletedProcess(proc.args, proc.returncode,
|
||||
stdout='', stderr=last_line)
|
||||
if r.returncode == 0 and verbose:
|
||||
print(f'✓ image ready in {_time.monotonic() - t0:.0f}s',
|
||||
file=_sys.stderr, flush=True)
|
||||
if r.returncode == 0:
|
||||
if ref != image: # retag the mirrored pull to the canonical name
|
||||
subprocess.run(['docker', 'tag', ref, image], check=False)
|
||||
if ref != image:
|
||||
# retag BEFORE rmi and VERIFY: a silent tag failure followed
|
||||
# by rmi deleted the only tag and lost a 342s multi-GB pull
|
||||
tag = subprocess.run(['docker', 'tag', ref, image],
|
||||
capture_output=True, text=True)
|
||||
if tag.returncode != 0:
|
||||
print(f'!! docker tag {ref} -> {image} failed: '
|
||||
f'{(tag.stderr or "")[:120]} (keeping the mirror tag)',
|
||||
file=_sys.stderr, flush=True)
|
||||
return # do NOT rmi: the mirror tag is the only handle
|
||||
subprocess.run(['docker', 'rmi', ref], check=False)
|
||||
return
|
||||
last_err = (ref, (r.stderr or '').strip()[:150])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user