1use std::path::Path;
2use anyhow::{Context, Result};
3use crate::graph::Graph;
4
5pub fn load_graph(path: &Path) -> Result<Graph> {
7 let content = std::fs::read_to_string(path)
8 .with_context(|| format!("Failed to read graph file: {}", path.display()))?;
9 let graph: Graph = serde_yaml::from_str(&content)
10 .with_context(|| format!("Failed to parse graph YAML: {}", path.display()))?;
11 Ok(graph)
12}
13
14pub fn save_graph(graph: &Graph, path: &Path) -> Result<()> {
16 if let Some(parent) = path.parent() {
18 std::fs::create_dir_all(parent)?;
19 }
20 let yaml = serde_yaml::to_string(graph)?;
21 std::fs::write(path, yaml)
22 .with_context(|| format!("Failed to write graph file: {}", path.display()))?;
23 Ok(())
24}
25
26pub fn find_graph_file(project_dir: &Path) -> Option<std::path::PathBuf> {
29 let candidates = [
30 project_dir.join(".gid/graph.yml"),
31 project_dir.join(".gid/graph.yaml"),
32 project_dir.join(".gid/graph.db"),
33 project_dir.join("graph.yml"),
34 project_dir.join("graph.yaml"),
35 project_dir.join("graph.db"),
36 ];
37 candidates.into_iter().find(|p| p.exists())
38}
39
40pub fn find_graph_file_walk_up(start_dir: &Path) -> Option<std::path::PathBuf> {
44 let mut current = start_dir.to_path_buf();
45 loop {
46 if let Some(found) = find_graph_file(¤t) {
47 return Some(found);
48 }
49 if !current.pop() {
50 return None;
51 }
52 }
53}
54
55pub fn find_project_root(start_dir: &Path) -> Option<std::path::PathBuf> {
58 find_graph_file_walk_up(start_dir)
59 .and_then(|graph_path| {
60 graph_path.parent()
62 .and_then(|gid_dir| gid_dir.parent())
63 .map(|p| p.to_path_buf())
64 })
65}