use std::{path::PathBuf, process::Command, sync::OnceLock};
static LOG_PATH: OnceLock<PathBuf> = OnceLock::new();
pub fn get_log_path() -> PathBuf {
LOG_PATH.get_or_init(compute_log_path).clone()
}
fn compute_log_path() -> PathBuf {
let state_dir = xdg_state_home().join("nb-mcp");
let log_name = match detect_git_info() {
Some((project, worktree)) => {
if project == worktree {
format!("{}.log", project)
} else {
format!("{}--{}.log", project, worktree)
}
}
None => "nb-mcp.log".to_string(),
};
state_dir.join(log_name)
}
fn detect_git_info() -> Option<(String, String)> {
let current_root = git_rev_parse(&["--show-toplevel"])?;
let git_common_dir = git_rev_parse(&["--git-common-dir"])?;
let git_common_dir = if git_common_dir.is_relative() {
current_root.join(&git_common_dir)
} else {
git_common_dir
};
let git_common_dir = git_common_dir.canonicalize().ok()?;
let master_root = if git_common_dir.file_name().is_some_and(|n| n == ".git") {
git_common_dir.parent()?.to_path_buf()
} else {
current_root.clone()
};
let project_name = master_root
.file_name()
.and_then(|n| n.to_str())
.map(sanitize_name)?;
let worktree_name = current_root
.file_name()
.and_then(|n| n.to_str())
.map(sanitize_name)?;
Some((project_name, worktree_name))
}
fn git_rev_parse(args: &[&str]) -> Option<PathBuf> {
let output = Command::new("git")
.args(["rev-parse"])
.args(args)
.output()
.ok()?;
if !output.status.success() {
return None;
}
let stdout = String::from_utf8(output.stdout).ok()?;
let path = stdout.trim();
if path.is_empty() {
return None;
}
Some(PathBuf::from(path))
}
fn sanitize_name(name: &str) -> String {
name.chars()
.map(|c| {
if c.is_alphanumeric() || c == '-' || c == '_' {
c
} else {
'-'
}
})
.collect()
}
fn xdg_state_home() -> PathBuf {
if let Ok(dir) = std::env::var("XDG_STATE_HOME") {
let dir = dir.trim();
if !dir.is_empty() {
return PathBuf::from(dir);
}
}
let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string());
PathBuf::from(home).join(".local/state")
}
pub fn ensure_dir(path: &std::path::Path) -> std::io::Result<()> {
if !path.is_dir() {
std::fs::create_dir_all(path)?;
}
Ok(())
}