grimoire_css_lib/core/
filesystem.rs

1//! File system operations for the Grimoire CSS system.
2//!
3//! This module provides a unified interface for filesystem operations such as:
4//! - Managing configuration directories and files
5//! - Creating and maintaining the Grimoire CSS directory structure
6//! - Handling path resolution for configuration and other resources
7//!
8//! The directory structure follows the convention:
9//! ```text
10//! ./grimoire/
11//!   └── config/
12//!       └── grimoire.config.json
13//! ```
14
15use super::GrimoireCssError;
16use crate::buffer::add_message;
17use std::{
18    fs,
19    path::{Path, PathBuf},
20};
21
22/// Provides filesystem operations for the Grimoire CSS system.
23///
24/// This struct implements methods for managing the file system structure
25/// required by Grimoire CSS, including configuration directories and files.
26pub struct Filesystem;
27
28impl Filesystem {
29    /// Retrieves or creates the path for the configuration file.
30    ///
31    /// This method ensures that the necessary directory structure exists
32    /// and returns the path to the grimoire.config.json file.
33    ///
34    /// # Arguments
35    ///
36    /// * `current_dir` - The base directory path to create the configuration in
37    ///
38    /// # Returns
39    ///
40    /// Returns a `PathBuf` pointing to the configuration file location
41    ///
42    /// # Errors
43    ///
44    /// Returns a `GrimoireCSSError` if:
45    /// - The directory structure cannot be created
46    /// - File system permissions prevent access
47    pub fn get_config_path(current_dir: &Path) -> Result<PathBuf, GrimoireCssError> {
48        let grimoire_dir = Self::get_or_create_grimoire_path(current_dir)?;
49        let config_path = grimoire_dir.join("config");
50        if !config_path.exists() {
51            fs::create_dir(&config_path)?;
52        }
53        Ok(config_path.join("grimoire.config.json"))
54    }
55
56    /// Gets or creates the path for the GrimoireCSS folder.
57    ///
58    /// This method ensures the existence of the Grimoire directory structure.
59    /// If the directories don't exist, it creates them and adds a success message
60    /// to the notification buffer.
61    ///
62    /// # Arguments
63    ///
64    /// * `cwd` - The current working directory where the Grimoire folder should be created
65    ///
66    /// # Returns
67    ///
68    /// Returns a `PathBuf` pointing to the Grimoire directory
69    ///
70    /// # Errors
71    ///
72    /// Returns a `GrimoireCSSError` if:
73    /// - Directory creation fails
74    /// - File system operations are not permitted
75    pub fn get_or_create_grimoire_path(cwd: &Path) -> Result<PathBuf, GrimoireCssError> {
76        let grimoire_path = cwd.join("grimoire");
77        if !grimoire_path.exists() {
78            fs::create_dir(&grimoire_path)?;
79            let config_path = grimoire_path.join("config");
80            if !config_path.exists() {
81                fs::create_dir(&config_path)?;
82            }
83            add_message(format!(
84                "Configuration and directories created successfully at `{}`.",
85                "./grimoire"
86            ));
87        }
88        Ok(grimoire_path)
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95    use std::fs;
96    use tempfile::tempdir;
97
98    #[test]
99    fn test_get_or_create_grimoire_path_creates_directory() {
100        let temp_dir = tempdir().unwrap();
101        let cwd = temp_dir.path();
102
103        let grimoire_path = cwd.join("grimoire");
104        assert!(!grimoire_path.exists());
105
106        let result = Filesystem::get_or_create_grimoire_path(cwd)
107            .expect("Failed to get or create grimoire path");
108        assert_eq!(result, grimoire_path);
109
110        assert!(grimoire_path.exists());
111        assert!(grimoire_path.is_dir());
112
113        let config_path = grimoire_path.join("config");
114        assert!(config_path.exists());
115        assert!(config_path.is_dir());
116    }
117
118    #[test]
119    fn test_get_or_create_grimoire_path_does_not_create_if_exists() {
120        let temp_dir = tempdir().unwrap();
121        let cwd = temp_dir.path();
122
123        let grimoire_path = cwd.join("grimoire");
124        let config_path = grimoire_path.join("config");
125        fs::create_dir(&grimoire_path).unwrap();
126        fs::create_dir(&config_path).unwrap();
127
128        let result = Filesystem::get_or_create_grimoire_path(cwd)
129            .expect("Failed to get or create grimoire path");
130        assert_eq!(result, grimoire_path);
131
132        assert!(grimoire_path.exists());
133        assert!(grimoire_path.is_dir());
134        assert!(config_path.exists());
135        assert!(config_path.is_dir());
136    }
137
138    #[test]
139    fn test_get_config_path_creates_config_file_path() {
140        let temp_dir = tempdir().unwrap();
141        let cwd = temp_dir.path();
142
143        let result = Filesystem::get_config_path(cwd).expect("Failed to get or create config path");
144
145        let expected_path = cwd.join("grimoire/config/grimoire.config.json");
146        assert_eq!(result, expected_path);
147
148        let grimoire_path = cwd.join("grimoire");
149        let config_dir = grimoire_path.join("config");
150        assert!(grimoire_path.exists());
151        assert!(grimoire_path.is_dir());
152        assert!(config_dir.exists());
153        assert!(config_dir.is_dir());
154    }
155
156    #[test]
157    fn test_get_config_path_does_not_create_if_exists() {
158        let temp_dir = tempdir().unwrap();
159        let cwd = temp_dir.path();
160
161        let grimoire_path = cwd.join("grimoire");
162        let config_dir = grimoire_path.join("config");
163        let config_file_path = config_dir.join("grimoire.config.json");
164        fs::create_dir(&grimoire_path).unwrap();
165        fs::create_dir(&config_dir).unwrap();
166        fs::write(&config_file_path, b"{}").unwrap();
167
168        let result = Filesystem::get_config_path(cwd).expect("Failed to get or create config path");
169        assert_eq!(result, config_file_path);
170
171        assert!(grimoire_path.exists());
172        assert!(grimoire_path.is_dir());
173        assert!(config_dir.exists());
174        assert!(config_dir.is_dir());
175        assert!(config_file_path.exists());
176    }
177}