Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 5 additions & 71 deletions src/runtime/lima.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,8 @@ impl Runtime for LimaRuntime {
"NixOS"
};

if opts.cached_image.is_some() {
println!("Creating {image_label} VM '{vm}' from cache...");
} else {
println!("Creating {image_label} VM '{vm}'...");
println!(" (first run downloads {image_label} image, this may take a few minutes)");
}
println!("Creating {image_label} VM '{vm}'...");
println!(" (first run downloads {image_label} image, this may take a few minutes)");
run_ok(
"limactl",
&[
Expand All @@ -195,21 +191,6 @@ impl Runtime for LimaRuntime {
)
.await?;

// If we have a cached disk, copy it over before first start.
// Lima creates the disk structure during `create`; we overwrite
// `diffdisk` with the cached provisioned state before `start` boots it.
if let Some(cached_disk) = &opts.cached_image {
let home = dirs::home_dir().unwrap_or_default();
let diffdisk = home.join(format!(".lima/{vm}/diffdisk"));
println!("Restoring cached disk image...");
// Use cp -c for APFS clone (instant, zero-cost on macOS)
let _ = run_cmd(
"cp",
&["-c", cached_disk, &diffdisk.to_string_lossy()],
)
.await;
}

println!("Starting {image_label} VM '{vm}'...");
run_ok("limactl", &["start", &vm]).await?;

Expand Down Expand Up @@ -398,56 +379,9 @@ impl Runtime for LimaRuntime {
Ok(())
}

async fn cached_image(&self, cache_key: &str) -> Option<String> {
let cache_path = dirs::home_dir()?
.join(format!(".devbox/cache/lima-{cache_key}.disk"));
if cache_path.exists() {
Some(cache_path.to_string_lossy().to_string())
} else {
None
}
}

async fn cache_image(&self, name: &str, cache_key: &str) -> Result<()> {
let vm = Self::vm_name(name);
let home = dirs::home_dir().unwrap_or_default();
let diffdisk = home.join(format!(".lima/{vm}/diffdisk"));

if !diffdisk.exists() {
bail!("Lima disk not found at {}", diffdisk.display());
}

let cache_dir = home.join(".devbox/cache");
std::fs::create_dir_all(&cache_dir)?;
let cache_path = cache_dir.join(format!("lima-{cache_key}.disk"));

println!("Caching provisioned image...");

// Stop VM before copying disk for consistency
let _ = run_cmd("limactl", &["stop", &vm]).await;

// Use cp -c for APFS clone (instant, zero-cost on macOS)
let result = run_cmd(
"cp",
&["-c", &diffdisk.to_string_lossy(), &cache_path.to_string_lossy()],
)
.await;

// Fall back to regular copy if APFS clone fails (non-APFS filesystem)
if result.is_err() || result.as_ref().is_ok_and(|r| r.exit_code != 0) {
let _ = run_cmd(
"cp",
&[&diffdisk.to_string_lossy(), &cache_path.to_string_lossy()],
)
.await;
}

// Restart the VM
run_ok("limactl", &["start", &vm]).await?;

println!("Image cached successfully.");
Ok(())
}
// Lima caching disabled — the stop/copy-disk/restart cycle adds ~1 minute
// overhead on macOS, which isn't worth it for typical single-VM usage.
// Caching remains active for Incus (Linux) where `incus publish` is fast.
}

fn chrono_now() -> String {
Expand Down
Loading