use super::{MARK_REF_ROOT, repo_git};
use crate::template::GitRunner;
use std::io;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};
pub const CWD_REF_PREFIX: &str = "cwd/";
pub fn cwd_ref(agent_id: &str) -> String {
format!("{MARK_REF_ROOT}{CWD_REF_PREFIX}{agent_id}")
}
pub fn read(workspace: &Path, agent_id: &str, git: &dyn GitRunner) -> Option<PathBuf> {
let spec = cwd_ref(agent_id);
let out = git
.run_capture(&repo_git(workspace), &["cat-file", "blob", &spec])
.ok()?;
(!out.is_empty()).then(|| PathBuf::from(out))
}
pub fn write(workspace: &Path, agent_id: &str, dir: &Path, git: &dyn GitRunner) -> io::Result<()> {
storable(dir)?;
let repo = repo_git(workspace);
let staged = repo.join(format!("cwd-mark.{}.tmp", std::process::id()));
std::fs::write(&staged, dir.as_os_str().as_bytes())?;
let staged_str = staged.to_string_lossy().into_owned();
let hashed = git.run_capture(&repo, &["hash-object", "-w", "--", &staged_str]);
std::fs::remove_file(&staged)?;
git.run(&repo, &["update-ref", &cwd_ref(agent_id), &hashed?])
}
fn storable(dir: &Path) -> io::Result<()> {
let text = dir.to_str().filter(|s| !s.is_empty() && s.trim() == *s);
match text {
Some(_) => Ok(()),
None => Err(io::Error::other(format!(
"cannot store {dir:?} as a working directory: the mark holds trimmed UTF-8 \
text, so a path that is not UTF-8 or that leads or trails with whitespace \
would read back as a different directory (ARCH §3.3)"
))),
}
}
#[cfg(test)]
mod tests;