use std::path::{Path, PathBuf};
use std::process::Command;
use anyhow::{anyhow, Context, Result};
use uuid::Uuid;
const SCE_CHECKOUT_DIR: &str = "sce";
const CHECKOUT_ID_FILE: &str = "checkout-id";
pub fn resolve_git_dir(repo_root: &Path) -> Result<PathBuf> {
let output = Command::new("git")
.args(["rev-parse", "--git-dir"])
.current_dir(repo_root)
.output()
.with_context(|| {
format!(
"Failed to run git rev-parse --git-dir in '{}'",
repo_root.display()
)
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
return Err(anyhow!(
"git rev-parse --git-dir failed in '{}': {}",
repo_root.display(),
stderr
));
}
let git_dir_relative = String::from_utf8(output.stdout)
.with_context(|| "git rev-parse --git-dir emitted invalid UTF-8")?
.trim()
.to_string();
let git_dir = PathBuf::from(&git_dir_relative);
if git_dir.is_absolute() {
Ok(git_dir)
} else {
Ok(repo_root.join(git_dir))
}
}
pub fn read_checkout_id(git_dir: &Path) -> Result<Option<String>> {
let checkout_id_path = git_dir.join(SCE_CHECKOUT_DIR).join(CHECKOUT_ID_FILE);
if !checkout_id_path.exists() {
return Ok(None);
}
let content = std::fs::read_to_string(&checkout_id_path).with_context(|| {
format!(
"Failed to read checkout ID from '{}'",
checkout_id_path.display()
)
})?;
let id = content.trim().to_string();
if id.is_empty() {
return Err(anyhow!(
"Checkout ID file '{}' is empty",
checkout_id_path.display()
));
}
Uuid::parse_str(&id).with_context(|| {
format!(
"Invalid checkout ID '{}' in '{}'",
id,
checkout_id_path.display()
)
})?;
Ok(Some(id))
}
pub fn get_or_create_checkout_id(git_dir: &Path) -> Result<String> {
if let Some(existing_id) = read_checkout_id(git_dir)? {
return Ok(existing_id);
}
let checkout_id = Uuid::now_v7().to_string();
let checkout_dir = git_dir.join(SCE_CHECKOUT_DIR);
std::fs::create_dir_all(&checkout_dir).with_context(|| {
format!(
"Failed to create checkout directory '{}'",
checkout_dir.display()
)
})?;
let checkout_id_path = checkout_dir.join(CHECKOUT_ID_FILE);
std::fs::write(&checkout_id_path, &checkout_id).with_context(|| {
format!(
"Failed to write checkout ID to '{}'",
checkout_id_path.display()
)
})?;
Ok(checkout_id)
}