use super::cmd::git_cmd;
use anyhow::Result;
use std::path::{Path, PathBuf};
pub struct WorktreeSnapshot {
pub repo_root: PathBuf,
pub worktree_path: PathBuf,
_tmp: tempfile::TempDir,
}
impl Drop for WorktreeSnapshot {
fn drop(&mut self) {
let _ = git_cmd()
.args(["worktree", "remove", "--force"])
.arg(&self.worktree_path)
.current_dir(&self.repo_root)
.output();
let _ = git_cmd()
.args(["worktree", "prune"])
.current_dir(&self.repo_root)
.output();
}
}
pub fn create_worktree_snapshot(repo_root: &Path, commit: &str) -> Result<WorktreeSnapshot> {
let tmp = tempfile::tempdir()?;
let worktree_path = tmp.path().join("snapshot");
let output = git_cmd()
.args(["worktree", "add", "--detach", "--force"])
.arg(&worktree_path)
.arg(commit)
.current_dir(repo_root)
.output()?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("git worktree add failed: {}", stderr.trim());
}
#[cfg(unix)]
{
let nm = repo_root.join("node_modules");
if nm.exists() {
let _ = std::os::unix::fs::symlink(&nm, worktree_path.join("node_modules"));
}
let venv = repo_root.join(".venv");
if venv.exists() {
let _ = std::os::unix::fs::symlink(&venv, worktree_path.join(".venv"));
}
}
Ok(WorktreeSnapshot {
repo_root: repo_root.to_path_buf(),
worktree_path,
_tmp: tmp,
})
}