Show More
@@ -150,6 +150,7 b' impl ConfigLayer {' | |||
|
150 | 150 | let line = Some(index + 1); |
|
151 | 151 | if let Some(m) = INCLUDE_RE.captures(&bytes) { |
|
152 | 152 | let filename_bytes = &m[1]; |
|
153 | let filename_bytes = crate::utils::expand_vars(filename_bytes); | |
|
153 | 154 | // `Path::parent` only fails for the root directory, |
|
154 | 155 | // which `src` can’t be since we’ve managed to open it as a |
|
155 | 156 | // file. |
@@ -241,6 +241,59 b' pub fn current_exe() -> Result<std::path' | |||
|
241 | 241 | }) |
|
242 | 242 | } |
|
243 | 243 | |
|
244 | /// Expand `$FOO` and `${FOO}` environment variables in the given byte string | |
|
245 | pub fn expand_vars(s: &[u8]) -> std::borrow::Cow<[u8]> { | |
|
246 | lazy_static::lazy_static! { | |
|
247 | /// https://github.com/python/cpython/blob/3.9/Lib/posixpath.py#L301 | |
|
248 | /// The `x` makes whitespace ignored. | |
|
249 | /// `-u` disables the Unicode flag, which makes `\w` like Python with the ASCII flag. | |
|
250 | static ref VAR_RE: regex::bytes::Regex = | |
|
251 | regex::bytes::Regex::new(r"(?x-u) | |
|
252 | \$ | |
|
253 | (?: | |
|
254 | (\w+) | |
|
255 | | | |
|
256 | \{ | |
|
257 | ([^}]*) | |
|
258 | \} | |
|
259 | ) | |
|
260 | ").unwrap(); | |
|
261 | } | |
|
262 | VAR_RE.replace_all(s, |captures: ®ex::bytes::Captures| { | |
|
263 | let var_name = files::get_os_str_from_bytes( | |
|
264 | captures | |
|
265 | .get(1) | |
|
266 | .or_else(|| captures.get(2)) | |
|
267 | .expect("either side of `|` must participate in match") | |
|
268 | .as_bytes(), | |
|
269 | ); | |
|
270 | std::env::var_os(var_name) | |
|
271 | .map(files::get_bytes_from_os_str) | |
|
272 | .unwrap_or_else(|| { | |
|
273 | // Referencing an environment variable that does not exist. | |
|
274 | // Leave the $FOO reference as-is. | |
|
275 | captures[0].to_owned() | |
|
276 | }) | |
|
277 | }) | |
|
278 | } | |
|
279 | ||
|
280 | #[test] | |
|
281 | fn test_expand_vars() { | |
|
282 | // Modifying process-global state in a test isn’t great, | |
|
283 | // but hopefully this won’t collide with anything. | |
|
284 | std::env::set_var("TEST_EXPAND_VAR", "1"); | |
|
285 | assert_eq!( | |
|
286 | expand_vars(b"before/$TEST_EXPAND_VAR/after"), | |
|
287 | &b"before/1/after"[..] | |
|
288 | ); | |
|
289 | assert_eq!( | |
|
290 | expand_vars(b"before${TEST_EXPAND_VAR}${TEST_EXPAND_VAR}${TEST_EXPAND_VAR}after"), | |
|
291 | &b"before111after"[..] | |
|
292 | ); | |
|
293 | let s = b"before $SOME_LONG_NAME_THAT_WE_ASSUME_IS_NOT_AN_ACTUAL_ENV_VAR after"; | |
|
294 | assert_eq!(expand_vars(s), &s[..]); | |
|
295 | } | |
|
296 | ||
|
244 | 297 | pub(crate) enum MergeResult<V> { |
|
245 | 298 | UseLeftValue, |
|
246 | 299 | UseRightValue, |
@@ -23,7 +23,7 b' use std::iter::FusedIterator;' | |||
|
23 | 23 | use std::ops::Deref; |
|
24 | 24 | use std::path::{Path, PathBuf}; |
|
25 | 25 | |
|
26 |
pub fn get_ |
|
|
26 | pub fn get_os_str_from_bytes(bytes: &[u8]) -> &OsStr { | |
|
27 | 27 | let os_str; |
|
28 | 28 | #[cfg(unix)] |
|
29 | 29 | { |
@@ -33,8 +33,11 b' pub fn get_path_from_bytes(bytes: &[u8])' | |||
|
33 | 33 | // TODO Handle other platforms |
|
34 | 34 | // TODO: convert from WTF8 to Windows MBCS (ANSI encoding). |
|
35 | 35 | // Perhaps, the return type would have to be Result<PathBuf>. |
|
36 | os_str | |
|
37 | } | |
|
36 | 38 | |
|
37 | Path::new(os_str) | |
|
39 | pub fn get_path_from_bytes(bytes: &[u8]) -> &Path { | |
|
40 | Path::new(get_os_str_from_bytes(bytes)) | |
|
38 | 41 | } |
|
39 | 42 | |
|
40 | 43 | // TODO: need to convert from WTF8 to MBCS bytes on Windows. |
General Comments 0
You need to be logged in to leave comments.
Login now