use std::ffi::OsStr;
use crate::EngineError;
use crate::gitio::Repo;
pub fn index_tree(repo: &Repo) -> Result<String, EngineError> {
let (idx, env_val) = temp_index()?;
let env: [(&str, &OsStr); 1] = [("GIT_INDEX_FILE", &env_val)];
seed_from_index(repo, &env)?;
let _keep = idx;
write_tree(repo, &env)
}
pub fn worktree_tree(repo: &Repo) -> Result<String, EngineError> {
let (idx, env_val) = temp_index()?;
let env: [(&str, &OsStr); 1] = [("GIT_INDEX_FILE", &env_val)];
seed_from_index(repo, &env)?;
let mut paths = repo.run(["ls-files", "-z"], None)?;
paths.extend_from_slice(&repo.run(["ls-files", "--others", "--exclude-standard", "-z"], None)?);
if !paths.is_empty() {
repo.run_env(
["update-index", "--add", "--remove", "-z", "--stdin"],
Some(&paths),
&env,
)?;
}
let _keep = idx;
write_tree(repo, &env)
}
fn temp_index() -> Result<(tempfile::TempDir, std::ffi::OsString), EngineError> {
let dir = tempfile::TempDir::new().map_err(|e| EngineError::GitSpawn { source: e })?;
let path = dir.path().join("index").into_os_string();
Ok((dir, path))
}
fn seed_from_index(repo: &Repo, env: &[(&str, &OsStr)]) -> Result<(), EngineError> {
let entries = repo.run(["ls-files", "-s", "-z"], None)?;
for record in entries.split(|&b| b == 0) {
let meta = record.split(|&b| b == b'\t').next().unwrap_or(record);
if meta.ends_with(b" 1") || meta.ends_with(b" 2") || meta.ends_with(b" 3") {
return Err(EngineError::Range(
"index has unmerged entries — resolve conflicts before reviewing \
uncommitted changes"
.into(),
));
}
}
if !entries.is_empty() {
repo.run_env(["update-index", "-z", "--index-info"], Some(&entries), env)?;
}
Ok(())
}
fn write_tree(repo: &Repo, env: &[(&str, &OsStr)]) -> Result<String, EngineError> {
let out = repo.run_env(["write-tree"], None, env)?;
Ok(String::from_utf8_lossy(&out).trim().to_string())
}