91e75e620b
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled
64 lines
2.1 KiB
Python
64 lines
2.1 KiB
Python
"""Local image cache at ~/.cua/cua-sandbox/images/."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import shutil
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
CACHE_ROOT = Path.home() / ".cua" / "cua-sandbox" / "images"
|
|
|
|
|
|
class ImageCache:
|
|
"""Manages locally cached VM/container images."""
|
|
|
|
def __init__(self, root: Optional[Path] = None):
|
|
self.root = root or CACHE_ROOT
|
|
self.root.mkdir(parents=True, exist_ok=True)
|
|
|
|
def image_dir(self, registry: str, org: str, name: str, tag: str) -> Path:
|
|
return self.root / registry / org / name / tag
|
|
|
|
def is_cached(self, registry: str, org: str, name: str, tag: str) -> bool:
|
|
return (self.image_dir(registry, org, name, tag) / "manifest.json").exists()
|
|
|
|
def save_manifest(self, registry: str, org: str, name: str, tag: str, manifest: dict) -> Path:
|
|
d = self.image_dir(registry, org, name, tag)
|
|
d.mkdir(parents=True, exist_ok=True)
|
|
p = d / "manifest.json"
|
|
p.write_text(json.dumps(manifest, indent=2))
|
|
return d
|
|
|
|
def get_manifest(self, registry: str, org: str, name: str, tag: str) -> Optional[dict]:
|
|
p = self.image_dir(registry, org, name, tag) / "manifest.json"
|
|
if p.exists():
|
|
return json.loads(p.read_text())
|
|
return None
|
|
|
|
def list_images(self) -> list[dict]:
|
|
images = []
|
|
for p in self.root.rglob("manifest.json"):
|
|
try:
|
|
parts = p.relative_to(self.root).parts
|
|
if len(parts) >= 4:
|
|
images.append(
|
|
{
|
|
"registry": parts[0],
|
|
"org": parts[1],
|
|
"name": parts[2],
|
|
"tag": parts[3],
|
|
"path": str(p.parent),
|
|
}
|
|
)
|
|
except Exception:
|
|
pass
|
|
return images
|
|
|
|
def remove(self, registry: str, org: str, name: str, tag: str) -> bool:
|
|
d = self.image_dir(registry, org, name, tag)
|
|
if d.exists():
|
|
shutil.rmtree(d)
|
|
return True
|
|
return False
|