use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WorktreeIndexMismatch {
pub worktree_root: String,
pub index_root: String,
}
pub fn git_worktree_root(dir: impl AsRef<Path>) -> Option<String> {
let output = Command::new("git")
.args(["rev-parse", "--show-toplevel"])
.current_dir(dir)
.output()
.ok()?;
if !output.status.success() {
return None;
}
let out = String::from_utf8_lossy(&output.stdout).trim().to_owned();
if out.is_empty() {
None
} else {
Some(realpath(out))
}
}
pub fn detect_worktree_index_mismatch(
start_path: impl AsRef<Path>,
index_root: impl AsRef<Path>,
) -> Option<WorktreeIndexMismatch> {
let worktree_root = git_worktree_root(start_path)?;
let resolved_index_root = realpath(index_root);
if worktree_root == resolved_index_root {
return None;
}
if git_worktree_root(&resolved_index_root).as_deref() != Some(resolved_index_root.as_str()) {
return None;
}
Some(WorktreeIndexMismatch {
worktree_root,
index_root: resolved_index_root,
})
}
pub fn worktree_mismatch_warning(m: &WorktreeIndexMismatch) -> String {
format!(
"This RustCodeGraph index belongs to a different git working tree.\n Running in: {}\n \
Index from: {}\nResults reflect that tree's code (often a different branch), not this worktree — \
symbols changed only here are missing. Run \"rustcodegraph init -i\" in this worktree \
for a worktree-local index.",
m.worktree_root, m.index_root
)
}
pub fn worktree_mismatch_notice(m: &WorktreeIndexMismatch) -> String {
format!(
"⚠ RustCodeGraph results below come from a different git worktree ({}), \
not where you're working ({}) — they may reflect another branch, \
and symbols changed only here are missing. Run \"rustcodegraph init -i\" here for a \
worktree-local index.",
m.index_root, m.worktree_root
)
}
fn realpath(path: impl AsRef<Path>) -> String {
let resolved = absolutize(path.as_ref());
fs::canonicalize(&resolved)
.unwrap_or(resolved)
.to_string_lossy()
.into_owned()
}
fn absolutize(path: &Path) -> PathBuf {
if path.is_absolute() {
path.to_path_buf()
} else {
std::env::current_dir()
.unwrap_or_else(|_| PathBuf::from("."))
.join(path)
}
}