##// END OF EJS Templates
rhg: Add support for environment variables in config include paths...
Simon Sapin -
r47476:91ab5190 default
parent child Browse files
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: &regex::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_path_from_bytes(bytes: &[u8]) -> &Path {
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