uv_configuration/
env_file.rs

1use std::path::PathBuf;
2
3/// A collection of `.env` file paths.
4#[derive(Default, Debug, Clone, PartialEq, Eq)]
5pub struct EnvFile(Vec<PathBuf>);
6
7impl EnvFile {
8    /// Parse the env file paths from command-line arguments.
9    pub fn from_args(env_file: Vec<String>, no_env_file: bool) -> Self {
10        if no_env_file {
11            return Self::default();
12        }
13
14        if env_file.is_empty() {
15            return Self::default();
16        }
17
18        let mut paths = Vec::new();
19
20        // Split on spaces, but respect backslashes.
21        for env_file in env_file {
22            let mut current = String::new();
23            let mut escape = false;
24            for c in env_file.chars() {
25                if escape {
26                    current.push(c);
27                    escape = false;
28                } else if c == '\\' {
29                    escape = true;
30                } else if c.is_whitespace() {
31                    if !current.is_empty() {
32                        paths.push(PathBuf::from(current));
33                        current = String::new();
34                    }
35                } else {
36                    current.push(c);
37                }
38            }
39            if !current.is_empty() {
40                paths.push(PathBuf::from(current));
41            }
42        }
43
44        Self(paths)
45    }
46
47    /// Iterate over the paths in the env file.
48    pub fn iter(&self) -> impl DoubleEndedIterator<Item = &PathBuf> {
49        self.0.iter()
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_from_args_default() {
59        let env_file = EnvFile::from_args(vec![], false);
60        assert_eq!(env_file, EnvFile::default());
61    }
62
63    #[test]
64    fn test_from_args_no_env_file() {
65        let env_file = EnvFile::from_args(vec!["path1 path2".to_string()], true);
66        assert_eq!(env_file, EnvFile::default());
67    }
68
69    #[test]
70    fn test_from_args_empty_string() {
71        let env_file = EnvFile::from_args(vec![String::new()], false);
72        assert_eq!(env_file, EnvFile::default());
73    }
74
75    #[test]
76    fn test_from_args_whitespace_only() {
77        let env_file = EnvFile::from_args(vec!["   ".to_string()], false);
78        assert_eq!(env_file, EnvFile::default());
79    }
80
81    #[test]
82    fn test_from_args_single_path() {
83        let env_file = EnvFile::from_args(vec!["path1".to_string()], false);
84        assert_eq!(env_file.0, vec![PathBuf::from("path1")]);
85    }
86
87    #[test]
88    fn test_from_args_multiple_paths() {
89        let env_file = EnvFile::from_args(vec!["path1 path2 path3".to_string()], false);
90        assert_eq!(
91            env_file.0,
92            vec![
93                PathBuf::from("path1"),
94                PathBuf::from("path2"),
95                PathBuf::from("path3")
96            ]
97        );
98    }
99
100    #[test]
101    fn test_from_args_escaped_spaces() {
102        let env_file = EnvFile::from_args(vec![r"path\ with\ spaces".to_string()], false);
103        assert_eq!(env_file.0, vec![PathBuf::from("path with spaces")]);
104    }
105
106    #[test]
107    fn test_from_args_mixed_escaped_and_normal() {
108        let env_file =
109            EnvFile::from_args(vec![r"path1 path\ with\ spaces path2".to_string()], false);
110        assert_eq!(
111            env_file.0,
112            vec![
113                PathBuf::from("path1"),
114                PathBuf::from("path with spaces"),
115                PathBuf::from("path2")
116            ]
117        );
118    }
119
120    #[test]
121    fn test_from_args_escaped_backslash() {
122        let env_file = EnvFile::from_args(vec![r"path\\with\\backslashes".to_string()], false);
123        assert_eq!(env_file.0, vec![PathBuf::from(r"path\with\backslashes")]);
124    }
125
126    #[test]
127    fn test_iter() {
128        let env_file = EnvFile(vec![PathBuf::from("path1"), PathBuf::from("path2")]);
129        let paths: Vec<_> = env_file.iter().collect();
130        assert_eq!(
131            paths,
132            vec![&PathBuf::from("path1"), &PathBuf::from("path2")]
133        );
134    }
135}