gglib_core/paths/
models.rs1use std::env;
7use std::path::PathBuf;
8
9use super::error::PathError;
10use super::platform::normalize_user_path;
11
12pub const DEFAULT_MODELS_DIR_RELATIVE: &str = ".local/share/llama_models";
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum ModelsDirSource {
18 Explicit,
20 EnvVar,
22 Default,
24}
25
26#[derive(Debug, Clone)]
28pub struct ModelsDirResolution {
29 pub path: PathBuf,
31 pub source: ModelsDirSource,
33}
34
35pub fn default_models_dir() -> Result<PathBuf, PathError> {
39 let home = dirs::home_dir().ok_or(PathError::NoHomeDir)?;
40 Ok(home.join(DEFAULT_MODELS_DIR_RELATIVE))
41}
42
43pub fn resolve_models_dir(explicit: Option<&str>) -> Result<ModelsDirResolution, PathError> {
50 if let Some(path_str) = explicit {
51 return Ok(ModelsDirResolution {
52 path: normalize_user_path(path_str)?,
53 source: ModelsDirSource::Explicit,
54 });
55 }
56
57 if let Ok(env_path) = env::var("GGLIB_MODELS_DIR") {
58 if !env_path.trim().is_empty() {
59 return Ok(ModelsDirResolution {
60 path: normalize_user_path(&env_path)?,
61 source: ModelsDirSource::EnvVar,
62 });
63 }
64 }
65
66 Ok(ModelsDirResolution {
67 path: default_models_dir()?,
68 source: ModelsDirSource::Default,
69 })
70}
71
72#[cfg(test)]
73#[allow(unsafe_code)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_default_models_dir_contains_relative() {
79 let dir = default_models_dir().unwrap();
80 assert!(dir.to_string_lossy().contains(DEFAULT_MODELS_DIR_RELATIVE));
81 }
82
83 #[test]
84 fn test_resolve_models_dir_prefers_explicit() {
85 let prev = env::var("GGLIB_MODELS_DIR").ok();
86 unsafe {
87 env::set_var("GGLIB_MODELS_DIR", "/tmp/env-value");
88 }
89 let resolved = resolve_models_dir(Some("/tmp/explicit")).unwrap();
90 assert_eq!(resolved.source, ModelsDirSource::Explicit);
91 assert!(resolved.path.ends_with("explicit"));
92 restore_env("GGLIB_MODELS_DIR", prev);
93 }
94
95 #[test]
96 fn test_resolve_models_dir_env_value() {
97 let prev = env::var("GGLIB_MODELS_DIR").ok();
98 unsafe {
99 env::set_var("GGLIB_MODELS_DIR", "/tmp/from-env");
100 }
101 let resolved = resolve_models_dir(None).unwrap();
102 assert_eq!(resolved.source, ModelsDirSource::EnvVar);
103 assert!(resolved.path.ends_with("from-env"));
104 restore_env("GGLIB_MODELS_DIR", prev);
105 }
106
107 fn restore_env(key: &str, previous: Option<String>) {
108 if let Some(value) = previous {
109 unsafe {
110 env::set_var(key, value);
111 }
112 } else {
113 unsafe {
114 env::remove_var(key);
115 }
116 }
117 }
118}