use std::path::Path;
use anyhow::{Context, Result};
use crate::graph::Graph;
pub fn load_graph(path: &Path) -> Result<Graph> {
let content = std::fs::read_to_string(path)
.with_context(|| format!("Failed to read graph file: {}", path.display()))?;
let graph: Graph = serde_yaml::from_str(&content)
.with_context(|| format!("Failed to parse graph YAML: {}", path.display()))?;
Ok(graph)
}
pub fn save_graph(graph: &Graph, path: &Path) -> Result<()> {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let yaml = serde_yaml::to_string(graph)?;
std::fs::write(path, yaml)
.with_context(|| format!("Failed to write graph file: {}", path.display()))?;
Ok(())
}
pub fn find_graph_file(project_dir: &Path) -> Option<std::path::PathBuf> {
let candidates = [
project_dir.join(".gid/graph.yml"),
project_dir.join(".gid/graph.yaml"),
project_dir.join(".gid/graph.db"),
project_dir.join("graph.yml"),
project_dir.join("graph.yaml"),
project_dir.join("graph.db"),
];
candidates.into_iter().find(|p| p.exists())
}
pub fn find_graph_file_walk_up(start_dir: &Path) -> Option<std::path::PathBuf> {
let mut current = start_dir.to_path_buf();
loop {
if let Some(found) = find_graph_file(¤t) {
return Some(found);
}
if !current.pop() {
return None;
}
}
}
pub fn find_project_root(start_dir: &Path) -> Option<std::path::PathBuf> {
find_graph_file_walk_up(start_dir)
.and_then(|graph_path| {
graph_path.parent()
.and_then(|gid_dir| gid_dir.parent())
.map(|p| p.to_path_buf())
})
}