diff --git a/.gitignore b/.gitignore index 3212e45..e411b73 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,10 @@ err.log # Sandbox save/load snapshots (large runtime tarballs, not source) /hh/hh-snapshots/ +# VM-library /loop artifacts — exported snapshot tars (repo-root, when `sbx` +# is run from here) + per-run logs. Generated; the VMs live in the host registry. +/hh-snapshots/ +/.loop-runs/ # Out-of-tree experiments (not part of hack-house) /experiments/ diff --git a/hh/src/app.rs b/hh/src/app.rs index 1cdc0e4..8cd41a4 100644 --- a/hh/src/app.rs +++ b/hh/src/app.rs @@ -5,6 +5,7 @@ use crate::layout::{Dir, Layout, Resize}; use crate::net::{self, Session}; use crate::registry; use crate::sbx; +use crate::snapshot; use crate::theme::Theme; use crate::ui; use anyhow::Result; @@ -2321,7 +2322,7 @@ fn handle_command( // Index the snapshot in the host-global registry, caching // its .hh-agent manifest summary. Best-effort: an index // hiccup must never fail the save the user just asked for. - register_saved_snapshot(be, &name, &label, &created_by); + snapshot::register_saved_snapshot(be, &name, &label, &created_by); Ok::(desc) }) .await; @@ -2496,7 +2497,7 @@ fn handle_command( let tx = app_tx.clone(); tokio::spawn(async move { let res = tokio::task::spawn_blocking(move || { - publish_snapshot(&label, &tags) + snapshot::publish_snapshot(&label, &tags) }) .await; let _ = match res { @@ -3102,48 +3103,6 @@ fn closest<'a>(input: &str, candidates: &[&'a str]) -> Option<&'a str> { .map(|(_, c)| c) } -/// Record a freshly-saved snapshot in the host-global VM registry, caching the -/// `.hh-agent` manifest summary read out of the (still-running, for OCI backends) -/// container. Best-effort — never panics, never fails the save. Blocking; call -/// from inside `spawn_blocking`. -fn register_saved_snapshot(be: sbx::Backend, name: &str, label: &str, created_by: &str) { - let (artifact_kind, artifact_ref, size_bytes, manifest) = match be { - sbx::Backend::Docker | sbx::Backend::Podman => { - let engine = be.engine(); - let image = format!("{}:{}", sbx::SNAP_REPO, label); - let size = oci_image_size(engine, &image); - let manifest = registry::read_container_manifest(engine, name, "/root"); - ("image".to_string(), image, size, manifest) - } - // Multipass snapshots live in multipass's own store; the instance is - // powered off by save time, so there's no container to read a manifest - // from. Record the pointer; reconcile leaves it (no image to probe). - sbx::Backend::Multipass => ("snapshot".to_string(), label.to_string(), None, None), - sbx::Backend::Local => return, // nothing persistent to index - }; - let (purpose, status, todo) = manifest - .as_deref() - .map(registry::scan_manifest) - .unwrap_or_default(); - let entry = registry::Entry { - label: label.to_string(), - backend: be.engine().to_string(), - artifact_kind, - artifact_ref, - size_bytes, - created_unix: registry::now_unix(), - created_by: created_by.to_string(), - repo: registry::cwd_repo(), - purpose, - status, - todo, - ..Default::default() - }; - if let Err(e) = registry::upsert(entry) { - eprintln!("registry upsert failed for '{label}': {e}"); - } -} - /// Load a pulled `hh-snap-