gglib_core/paths/
config.rs1use std::fs::{self, OpenOptions};
7use std::io::Write;
8use std::path::{Path, PathBuf};
9
10use super::error::PathError;
11use super::platform::data_root;
12
13pub fn env_file_path() -> Result<PathBuf, PathError> {
15 Ok(data_root()?.join(".env"))
16}
17
18pub fn persist_env_value(key: &str, value: &str) -> Result<(), PathError> {
23 let env_path = env_file_path()?;
24
25 let lines: Vec<String> = if env_path.exists() {
26 fs::read_to_string(&env_path)
27 .map_err(|e| PathError::EnvFileError {
28 path: env_path.clone(),
29 reason: e.to_string(),
30 })?
31 .lines()
32 .map(std::string::ToString::to_string)
33 .collect()
34 } else {
35 Vec::new()
36 };
37
38 let mut updated = false;
39 let mut output: Vec<String> = Vec::with_capacity(lines.len() + 1);
40
41 for line in lines {
42 match line.split_once('=') {
43 Some((lhs, _)) if lhs.trim() == key => {
44 if !updated {
45 output.push(format!("{key}={value}"));
46 updated = true;
47 }
48 }
49 _ => output.push(line),
50 }
51 }
52
53 if !updated {
54 if !output.is_empty() && !output.last().unwrap().is_empty() {
55 output.push(String::new());
56 }
57 output.push(format!("{key}={value}"));
58 }
59
60 if !output.is_empty() && !output.last().unwrap().is_empty() {
62 output.push(String::new());
63 }
64
65 let mut file = OpenOptions::new()
66 .create(true)
67 .write(true)
68 .truncate(true)
69 .open(&env_path)
70 .map_err(|e| PathError::EnvFileError {
71 path: env_path.clone(),
72 reason: e.to_string(),
73 })?;
74
75 let content = output.join("\n");
76 file.write_all(content.as_bytes())
77 .map_err(|e| PathError::EnvFileError {
78 path: env_path,
79 reason: e.to_string(),
80 })?;
81
82 Ok(())
83}
84
85pub fn persist_models_dir(path: &Path) -> Result<(), PathError> {
87 let serialized = path.to_string_lossy().to_string();
88 persist_env_value("GGLIB_MODELS_DIR", &serialized)
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use crate::paths::test_utils::{ENV_LOCK, EnvVarGuard};
95 use tempfile::tempdir;
96
97 #[test]
98 fn test_persist_models_dir_writes_env_file() {
99 let _guard = ENV_LOCK.lock().unwrap();
100 let temp = tempdir().unwrap();
101
102 let _env_guard = EnvVarGuard::set("GGLIB_DATA_DIR", temp.path().to_string_lossy().as_ref());
104
105 let models_dir = temp.path().join("models");
106 persist_models_dir(&models_dir).unwrap();
107
108 let env_contents = fs::read_to_string(temp.path().join(".env")).unwrap();
109 assert!(env_contents.contains("GGLIB_MODELS_DIR"));
110 assert!(env_contents.contains(models_dir.to_string_lossy().as_ref()));
111
112 }
114}