diff --git a/evalharness/sandbox/prefetch.py b/evalharness/sandbox/prefetch.py index 385adfe..991ad32 100644 --- a/evalharness/sandbox/prefetch.py +++ b/evalharness/sandbox/prefetch.py @@ -117,16 +117,44 @@ def _pull_one(image: str, verbose: bool = True) -> None: text=True, bufsize=1) last_line = '' last_show = 0.0 + layer_prog = {} # layer id -> (done_bytes, total_bytes): the raw + # per-layer events give no sense of OVERALL progress -- sum them import os as _os + import re as _re + + def _bytes(s): + s = s.strip() + mult = {'kB': 1e3, 'KB': 1e3, 'MB': 1e6, 'GB': 1e9, 'B': 1} + for suf, m in mult.items(): + if s.endswith(suf): + return int(float(s[:-len(suf)]) * m) + return int(float(s or 0)) + for line in proc.stdout: last_line = line.strip() + m = _re.match(r'^([0-9a-f]{12}): Downloading.*?([\d.]+[kKMG]?B)/([\d.]+[kKMG]?B)', line) + if m: + layer_prog[m.group(1)] = (_bytes(m.group(2)), _bytes(m.group(3))) + if 'Pull complete' in line: + lid = line.split(':')[0] + if lid in layer_prog: + layer_prog[lid] = (layer_prog[lid][1], layer_prog[lid][1]) now = _time.monotonic() - if verbose and (any(k in line for k in - ('Pulling from', 'Pull complete', 'Status', - 'error', 'denied', 'Extracting', 'Verifying')) - or now - last_show > 3): # Downloading snapshots + key_evt = any(k in line for k in + ('Pulling from', 'Status', 'error', 'denied')) + if verbose and key_evt: print(f' {last_line[:100]}', file=_sys.stderr, flush=True) last_show = now + elif verbose and now - last_show > 3 and layer_prog: + done = sum(v[0] for v in layer_prog.values()) + tot = sum(v[1] for v in layer_prog.values()) + if tot: + pct = done / tot * 100 + big = max(layer_prog.items(), key=lambda kv: kv[1][1] - kv[1][0]) + print(f' ⏳ {done / 1e9:.2f}/{tot / 1e9:.2f} GB ({pct:.0f}%)' + f' · 最大层 {big[0]}: {big[1][0] / 1e9:.2f}/{big[1][1] / 1e9:.2f} GB', + file=_sys.stderr, flush=True) + last_show = now proc.wait(timeout=3600) r = subprocess.CompletedProcess(proc.args, proc.returncode, stdout='', stderr=last_line)