rez_lsp_server/config/
provider.rs1use async_trait::async_trait;
4use std::env;
5use std::path::PathBuf;
6use tracing::{debug, info, warn};
7
8use super::Config;
9use crate::core::{ConfigError, ConfigProvider, Result};
10
11#[derive(Debug)]
13pub struct RezConfigProvider {
14 config: Config,
15}
16
17impl RezConfigProvider {
18 pub fn new() -> Self {
20 Self {
21 config: Config::new(),
22 }
23 }
24
25 pub async fn load_from_environment(&mut self) -> Result<()> {
37 info!("Loading Rez configuration from environment");
38
39 self.config.packages_path = self.get_packages_path_from_env().await?;
40 self.config.local_packages_path = self.get_local_packages_path_from_env().await?;
41 self.config.release_packages_path = self.get_release_packages_path_from_env().await?;
42 self.config.debug_logging = self.get_debug_logging_from_env().await;
43
44 debug!("Packages path: {:?}", self.config.packages_path);
45 debug!("Local packages path: {:?}", self.config.local_packages_path);
46 debug!(
47 "Release packages path: {:?}",
48 self.config.release_packages_path
49 );
50
51 Ok(())
52 }
53
54 pub fn config(&self) -> &Config {
56 &self.config
57 }
58
59 async fn get_packages_path_from_env(&self) -> Result<Vec<PathBuf>> {
61 match env::var("REZ_PACKAGES_PATH") {
62 Ok(path_str) => {
63 let paths: Vec<PathBuf> = path_str
64 .split(if cfg!(windows) { ';' } else { ':' })
65 .filter(|s| !s.is_empty())
66 .map(PathBuf::from)
67 .collect();
68
69 if paths.is_empty() {
70 warn!("REZ_PACKAGES_PATH is empty, using default paths");
71 Ok(self.get_default_packages_path())
72 } else {
73 info!("Found {} package paths in REZ_PACKAGES_PATH", paths.len());
74 Ok(paths)
75 }
76 }
77 Err(_) => {
78 warn!("REZ_PACKAGES_PATH not set, using default paths");
79 Ok(self.get_default_packages_path())
80 }
81 }
82 }
83
84 fn get_default_packages_path(&self) -> Vec<PathBuf> {
86 let mut paths = Vec::new();
87
88 if let Some(home_dir) = dirs::home_dir() {
90 paths.push(home_dir.join("packages"));
91 }
92
93 if cfg!(windows) {
95 paths.push(PathBuf::from("C:\\rez\\packages"));
96 } else {
97 paths.push(PathBuf::from("/opt/rez/packages"));
98 paths.push(PathBuf::from("/usr/local/rez/packages"));
99 }
100
101 paths
102 }
103
104 async fn get_local_packages_path_from_env(&self) -> Result<Option<PathBuf>> {
106 Ok(env::var("REZ_LOCAL_PACKAGES_PATH").ok().map(PathBuf::from))
107 }
108
109 async fn get_release_packages_path_from_env(&self) -> Result<Option<PathBuf>> {
111 Ok(env::var("REZ_RELEASE_PACKAGES_PATH")
112 .ok()
113 .map(PathBuf::from))
114 }
115
116 async fn get_debug_logging_from_env(&self) -> bool {
118 env::var("REZ_LSP_DEBUG")
119 .map(|v| v.to_lowercase() == "true" || v == "1")
120 .unwrap_or(false)
121 }
122}
123
124#[async_trait]
125impl ConfigProvider for RezConfigProvider {
126 async fn get_package_paths(&self) -> Result<Vec<PathBuf>> {
127 Ok(self.config.packages_path.clone())
128 }
129
130 async fn get_local_packages_path(&self) -> Result<Option<PathBuf>> {
131 Ok(self.config.local_packages_path.clone())
132 }
133
134 async fn get_release_packages_path(&self) -> Result<Option<PathBuf>> {
135 Ok(self.config.release_packages_path.clone())
136 }
137
138 async fn validate(&self) -> Result<()> {
139 self.config.validate()?;
140
141 let mut valid_paths = 0;
142 for path in &self.config.packages_path {
143 if path.exists() && path.is_dir() {
144 valid_paths += 1;
145 } else {
146 warn!(
147 "Package path does not exist or is not a directory: {:?}",
148 path
149 );
150 }
151 }
152
153 if valid_paths == 0 {
154 return Err(ConfigError::NoValidPaths.into());
155 }
156
157 info!(
158 "Rez configuration validated: {}/{} paths are valid",
159 valid_paths,
160 self.config.packages_path.len()
161 );
162 Ok(())
163 }
164
165 async fn reload(&mut self) -> Result<()> {
166 self.load_from_environment().await
167 }
168}
169
170impl Default for RezConfigProvider {
171 fn default() -> Self {
172 Self::new()
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179 use std::env;
180
181 #[tokio::test]
182 async fn test_config_provider_creation() {
183 let provider = RezConfigProvider::new();
184 assert!(provider.config.packages_path.is_empty());
185 }
186
187 #[tokio::test]
188 async fn test_default_packages_path() {
189 let provider = RezConfigProvider::new();
190 let paths = provider.get_default_packages_path();
191 assert!(!paths.is_empty());
192 }
193
194 #[tokio::test]
195 async fn test_packages_path_parsing() {
196 env::set_var("REZ_PACKAGES_PATH", "/path1:/path2:/path3");
198 let mut provider = RezConfigProvider::new();
199 provider.load_from_environment().await.unwrap();
200
201 if !cfg!(windows) {
202 assert_eq!(provider.config.packages_path.len(), 3);
203 assert_eq!(provider.config.packages_path[0], PathBuf::from("/path1"));
204 assert_eq!(provider.config.packages_path[1], PathBuf::from("/path2"));
205 assert_eq!(provider.config.packages_path[2], PathBuf::from("/path3"));
206 }
207
208 env::remove_var("REZ_PACKAGES_PATH");
209 }
210}