hte-cli 0.2.9__py3-none-any.whl → 0.2.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
hte_cli/cli.py
CHANGED
|
@@ -310,42 +310,83 @@ def session_join(ctx, session_id: str, force_setup: bool):
|
|
|
310
310
|
cached_images.append(img)
|
|
311
311
|
continue
|
|
312
312
|
|
|
313
|
-
# Need to pull - show progress
|
|
314
|
-
|
|
313
|
+
# Need to pull - show aggregated progress across all layers
|
|
314
|
+
import re
|
|
315
|
+
layer_progress: dict[str, dict] = {} # layer_id -> {current, total, phase}
|
|
316
|
+
last_display = [""]
|
|
317
|
+
|
|
318
|
+
def parse_size(s: str) -> float:
|
|
319
|
+
"""Parse size string like '10.5MB' or '1.2GB' to bytes."""
|
|
320
|
+
if not s:
|
|
321
|
+
return 0
|
|
322
|
+
s = s.strip()
|
|
323
|
+
multipliers = {"B": 1, "KB": 1024, "MB": 1024**2, "GB": 1024**3}
|
|
324
|
+
for suffix, mult in multipliers.items():
|
|
325
|
+
if s.upper().endswith(suffix):
|
|
326
|
+
try:
|
|
327
|
+
return float(s[:-len(suffix)].strip()) * mult
|
|
328
|
+
except ValueError:
|
|
329
|
+
return 0
|
|
330
|
+
try:
|
|
331
|
+
return float(s)
|
|
332
|
+
except ValueError:
|
|
333
|
+
return 0
|
|
334
|
+
|
|
335
|
+
def format_size(b: float) -> str:
|
|
336
|
+
"""Format bytes to human readable."""
|
|
337
|
+
if b >= 1024**3:
|
|
338
|
+
return f"{b/1024**3:.1f}GB"
|
|
339
|
+
elif b >= 1024**2:
|
|
340
|
+
return f"{b/1024**2:.0f}MB"
|
|
341
|
+
elif b >= 1024:
|
|
342
|
+
return f"{b/1024:.0f}KB"
|
|
343
|
+
return f"{b:.0f}B"
|
|
344
|
+
|
|
315
345
|
with console.status(f"[yellow]↓[/yellow] {short_name} [dim]connecting...[/dim]") as status:
|
|
316
346
|
def show_progress(image: str, line: str):
|
|
317
|
-
# Parse
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
347
|
+
# Parse: "abc123: Downloading 10.5MB/50MB" or "abc123: Extracting 10MB/50MB"
|
|
348
|
+
size_match = re.search(
|
|
349
|
+
r"([a-f0-9]+):\s*(Downloading|Extracting)\s+(\d+\.?\d*\s*[kMGT]?B)/(\d+\.?\d*\s*[kMGT]?B)",
|
|
350
|
+
line, re.IGNORECASE
|
|
351
|
+
)
|
|
352
|
+
if size_match:
|
|
353
|
+
layer_id = size_match.group(1)
|
|
354
|
+
phase = size_match.group(2)
|
|
355
|
+
current = parse_size(size_match.group(3))
|
|
356
|
+
total = parse_size(size_match.group(4))
|
|
357
|
+
layer_progress[layer_id] = {"current": current, "total": total, "phase": phase}
|
|
358
|
+
|
|
359
|
+
# Check for completed layers
|
|
360
|
+
complete_match = re.search(r"([a-f0-9]+):\s*(Pull complete|Download complete|Already exists)", line)
|
|
361
|
+
if complete_match:
|
|
362
|
+
layer_id = complete_match.group(1)
|
|
363
|
+
if layer_id in layer_progress:
|
|
364
|
+
layer_progress[layer_id]["current"] = layer_progress[layer_id]["total"]
|
|
365
|
+
layer_progress[layer_id]["phase"] = "done"
|
|
366
|
+
|
|
367
|
+
# Aggregate progress
|
|
368
|
+
total_current = sum(lp.get("current", 0) for lp in layer_progress.values())
|
|
369
|
+
total_size = sum(lp.get("total", 0) for lp in layer_progress.values())
|
|
370
|
+
active_layers = sum(1 for lp in layer_progress.values() if lp.get("phase") in ("Downloading", "Extracting"))
|
|
371
|
+
done_layers = sum(1 for lp in layer_progress.values() if lp.get("phase") == "done")
|
|
372
|
+
|
|
373
|
+
if total_size > 0:
|
|
374
|
+
pct = (total_current / total_size) * 100
|
|
375
|
+
display = f"{format_size(total_current)}/{format_size(total_size)} ({pct:.0f}%)"
|
|
376
|
+
if active_layers > 0:
|
|
377
|
+
display += f" - {active_layers} active"
|
|
378
|
+
if done_layers > 0:
|
|
379
|
+
display += f", {done_layers} done"
|
|
380
|
+
elif "Pulling" in line or "Waiting" in line:
|
|
381
|
+
display = "preparing layers..."
|
|
343
382
|
elif line.strip():
|
|
344
|
-
|
|
383
|
+
display = line[:40]
|
|
384
|
+
else:
|
|
385
|
+
return
|
|
345
386
|
|
|
346
|
-
if
|
|
347
|
-
|
|
348
|
-
status.update(f"[yellow]↓[/yellow] {short_name} [dim]{
|
|
387
|
+
if display != last_display[0]:
|
|
388
|
+
last_display[0] = display
|
|
389
|
+
status.update(f"[yellow]↓[/yellow] {short_name} [dim]{display}[/dim]")
|
|
349
390
|
|
|
350
391
|
success = pull_image_with_progress(img, on_progress=show_progress)
|
|
351
392
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
hte_cli/__init__.py,sha256=fDGXp-r8bIoLtlQnn5xJ_CpwMhonvk9bGjZQsjA2mDI,914
|
|
2
2
|
hte_cli/__main__.py,sha256=63n0gNGfskidWDU0aAIF2N8lylVCLYKVIkrN9QiORoo,107
|
|
3
3
|
hte_cli/api_client.py,sha256=m42kfFZS72Nu_VuDwxRsLNy4ziCcvgk7KNWBh9gwqy0,9257
|
|
4
|
-
hte_cli/cli.py,sha256=
|
|
4
|
+
hte_cli/cli.py,sha256=Aw7KmH4irG6FlCEfNOWcVmVRncARVQAifrhZcqXu2hs,44529
|
|
5
5
|
hte_cli/config.py,sha256=42Xv__YMSeRLs2zhGukJkIXFKtnBtYCHnONfViGyt2g,3387
|
|
6
6
|
hte_cli/errors.py,sha256=1J5PpxcUKBu6XjigMMCPOq4Zc12tnv8LhAsiaVFWLQM,2762
|
|
7
7
|
hte_cli/events.py,sha256=Zn-mroqaLHNzdT4DFf8st1Qclglshihdc09dBfCN070,5522
|
|
@@ -9,7 +9,7 @@ hte_cli/image_utils.py,sha256=TLwJdswUQrSD2bQcAXW03R8j8WG2pbHzd12TWcE7zy4,6418
|
|
|
9
9
|
hte_cli/runner.py,sha256=DhC8FMjHwfLR193iP4thLDRZrNssYA9KH1WYKU2JKeg,13535
|
|
10
10
|
hte_cli/scorers.py,sha256=sFoPJePRt-K191-Ga4cVmrldruJclYXTOLkU_C9nCDI,6025
|
|
11
11
|
hte_cli/version_check.py,sha256=WVZyGy2XfAghQYdd2N9-0Qfg-7pgp9gt4761-PnmacI,1708
|
|
12
|
-
hte_cli-0.2.
|
|
13
|
-
hte_cli-0.2.
|
|
14
|
-
hte_cli-0.2.
|
|
15
|
-
hte_cli-0.2.
|
|
12
|
+
hte_cli-0.2.10.dist-info/METADATA,sha256=FBr7HFYE_HjrjCOoEIn-cM2b3t-L07HXvkwAqfK0kPw,3768
|
|
13
|
+
hte_cli-0.2.10.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
+
hte_cli-0.2.10.dist-info/entry_points.txt,sha256=XbyEEi1H14DFAt0Kdl22e_IRVEGzimSzYSh5HlhKlFA,41
|
|
15
|
+
hte_cli-0.2.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|