Skip to main content

gid_core/
parser.rs

1use std::path::Path;
2use anyhow::{Context, Result};
3use crate::graph::Graph;
4
5/// Load a graph from a YAML file.
6pub 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
14/// Save a graph to a YAML file.
15pub fn save_graph(graph: &Graph, path: &Path) -> Result<()> {
16    // Ensure parent directory exists
17    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
26/// Find the graph file in a project directory.
27/// Searches: .gid/graph.yml, .gid/graph.yaml, graph.yml, graph.yaml
28pub 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
40/// Find the graph file by walking up from a starting directory.
41/// Like `git` searching for `.git/`, this walks up the directory tree
42/// until it finds a `.gid/graph.yml` (or reaches the filesystem root).
43pub 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(&current) {
47            return Some(found);
48        }
49        if !current.pop() {
50            return None;
51        }
52    }
53}
54
55/// Find the `.gid/` directory by walking up from a starting directory.
56/// Returns the parent directory that contains `.gid/`, not the `.gid/` path itself.
57pub 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 is like /foo/bar/.gid/graph.yml → parent.parent = /foo/bar
61            graph_path.parent()
62                .and_then(|gid_dir| gid_dir.parent())
63                .map(|p| p.to_path_buf())
64        })
65}