Skip to main content

ix_core/
paths.rs

1use std::path::{Path, PathBuf};
2
3use anyhow::{Context, Result};
4
5use crate::entity::{EntityKind, kind_from_id};
6
7pub const IXCHEL_DIR_NAME: &str = ".ixchel";
8
9#[derive(Debug, Clone)]
10pub struct IxchelPaths {
11    repo_root: PathBuf,
12}
13
14impl IxchelPaths {
15    #[must_use]
16    pub const fn new(repo_root: PathBuf) -> Self {
17        Self { repo_root }
18    }
19
20    #[must_use]
21    pub fn repo_root(&self) -> &Path {
22        &self.repo_root
23    }
24
25    #[must_use]
26    pub fn ixchel_dir(&self) -> PathBuf {
27        self.repo_root.join(IXCHEL_DIR_NAME)
28    }
29
30    #[must_use]
31    pub fn config_path(&self) -> PathBuf {
32        self.ixchel_dir().join("config.toml")
33    }
34
35    #[must_use]
36    pub fn data_dir(&self) -> PathBuf {
37        self.ixchel_dir().join("data")
38    }
39
40    #[must_use]
41    pub fn kind_dir(&self, kind: EntityKind) -> PathBuf {
42        self.ixchel_dir().join(kind.directory_name())
43    }
44
45    #[must_use]
46    pub fn entity_path(&self, id: &str) -> Option<PathBuf> {
47        let kind = kind_from_id(id)?;
48        Some(self.kind_dir(kind).join(format!("{id}.md")))
49    }
50
51    pub fn ensure_layout(&self) -> Result<()> {
52        std::fs::create_dir_all(self.data_dir())
53            .with_context(|| format!("Failed to create {}", self.data_dir().display()))?;
54
55        for kind in [
56            EntityKind::Decision,
57            EntityKind::Issue,
58            EntityKind::Idea,
59            EntityKind::Report,
60            EntityKind::Source,
61            EntityKind::Citation,
62            EntityKind::Agent,
63            EntityKind::Session,
64        ] {
65            let dir = self.kind_dir(kind);
66            std::fs::create_dir_all(&dir)
67                .with_context(|| format!("Failed to create {}", dir.display()))?;
68        }
69
70        Ok(())
71    }
72}
73
74#[must_use]
75pub fn find_git_root(start: &Path) -> Option<PathBuf> {
76    let mut current = Some(start);
77    while let Some(dir) = current {
78        if dir.join(".git").exists() {
79            return Some(dir.to_path_buf());
80        }
81        current = dir.parent();
82    }
83    None
84}