Skip to main content

fond_store/
paths.rs

1use std::path::PathBuf;
2
3use directories::ProjectDirs;
4
5/// Platform-appropriate directories for fond data and config.
6///
7/// Falls back to `$HOME/.fond` when `ProjectDirs` cannot determine
8/// the standard directories (e.g., in containerised environments).
9pub struct FondPaths {
10    /// Root data directory (recipes, pantry, etc.)
11    pub data_dir: PathBuf,
12    /// Config directory
13    pub config_dir: PathBuf,
14}
15
16impl FondPaths {
17    /// Resolve paths using the platform-standard directories.
18    ///
19    /// Override the data directory with `data_dir_override` (e.g., from `--data-dir`).
20    pub fn resolve(data_dir_override: Option<PathBuf>) -> Self {
21        if let Some(dir) = data_dir_override {
22            return Self {
23                config_dir: dir.join("config"),
24                data_dir: dir,
25            };
26        }
27
28        if let Some(proj) = ProjectDirs::from("com", "kafkade", "fond") {
29            Self {
30                data_dir: proj.data_dir().to_path_buf(),
31                config_dir: proj.config_dir().to_path_buf(),
32            }
33        } else {
34            let home = dirs_fallback();
35            Self {
36                data_dir: home.join("data"),
37                config_dir: home.join("config"),
38            }
39        }
40    }
41
42    /// Ensure the data directory and its subdirectories exist.
43    pub fn ensure_dirs(&self) -> std::io::Result<()> {
44        std::fs::create_dir_all(&self.data_dir)?;
45        std::fs::create_dir_all(self.data_dir.join("recipes"))?;
46        std::fs::create_dir_all(&self.config_dir)?;
47        Ok(())
48    }
49}
50
51fn dirs_fallback() -> PathBuf {
52    #[allow(deprecated)]
53    std::env::home_dir()
54        .unwrap_or_else(|| PathBuf::from("."))
55        .join(".fond")
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn resolve_with_override() {
64        let tmp = std::env::temp_dir().join("fond-test-paths");
65        let paths = FondPaths::resolve(Some(tmp.clone()));
66        assert_eq!(paths.data_dir, tmp);
67        assert_eq!(paths.config_dir, tmp.join("config"));
68    }
69
70    #[test]
71    fn resolve_default_returns_valid_paths() {
72        let paths = FondPaths::resolve(None);
73        // Should not panic and should return non-empty paths
74        assert!(!paths.data_dir.as_os_str().is_empty());
75        assert!(!paths.config_dir.as_os_str().is_empty());
76    }
77}