use anyhow::{Context, Result};
use std::path::{Path, PathBuf};
pub fn enumerate_session_files(root: &Path) -> Result<Vec<PathBuf>> {
use std::process::Command;
let session = crate::session::read_session(root);
let baseline = session
.as_ref()
.filter(|s| crate::session::is_session_alive(s))
.map(|s| s.baseline_sha.as_str());
let mut paths: Vec<PathBuf> = Vec::new();
if let Some(base) = baseline {
let mut any_failed = false;
let diff_base = Command::new("git")
.args(["diff", "--name-only", "-z", &format!("{base}..HEAD"), "--"])
.current_dir(root)
.output()
.context("git diff baseline..HEAD")?;
if diff_base.status.success() {
extend_from_nul_list(&mut paths, root, &diff_base.stdout);
} else {
any_failed = true;
}
let diff_head = Command::new("git")
.args(["diff", "--name-only", "-z", "HEAD", "--"])
.current_dir(root)
.output()
.context("git diff HEAD")?;
if diff_head.status.success() {
extend_from_nul_list(&mut paths, root, &diff_head.stdout);
} else {
any_failed = true;
}
let diff_cached = Command::new("git")
.args(["diff", "--cached", "--name-only", "-z", "--"])
.current_dir(root)
.output()
.context("git diff --cached")?;
if diff_cached.status.success() {
extend_from_nul_list(&mut paths, root, &diff_cached.stdout);
} else {
any_failed = true;
}
if any_failed {
paths.clear();
let ls_output = Command::new("git")
.args(["ls-files", "-z"])
.current_dir(root)
.output()
.context("git ls-files (fallback)")?;
if ls_output.status.success() {
extend_from_nul_list(&mut paths, root, &ls_output.stdout);
}
}
} else {
let ls_output = Command::new("git")
.args(["ls-files", "-z"])
.current_dir(root)
.output()
.context("git ls-files")?;
if ls_output.status.success() {
extend_from_nul_list(&mut paths, root, &ls_output.stdout);
}
}
let status_output = Command::new("git")
.args(["status", "--porcelain=v1", "-z", "--untracked-files=all"])
.current_dir(root)
.output()
.context("git status --porcelain")?;
if status_output.status.success() {
for record in status_output.stdout.split(|&b| b == 0) {
if record.len() >= 3 && &record[..3] == b"?? " {
let path_bytes = &record[3..];
let rel = String::from_utf8_lossy(path_bytes);
paths.push(root.join(rel.as_ref()));
}
}
}
paths.sort();
paths.dedup();
Ok(paths)
}
fn extend_from_nul_list(paths: &mut Vec<PathBuf>, root: &Path, stdout: &[u8]) {
for record in stdout.split(|&b| b == 0) {
if !record.is_empty() {
let rel = String::from_utf8_lossy(record);
paths.push(root.join(rel.as_ref()));
}
}
}