compiletest/
util.rs

1use std::env;
2use std::process::Command;
3
4use camino::{Utf8Path, Utf8PathBuf};
5
6#[cfg(test)]
7mod tests;
8
9pub fn make_new_path(path: &str) -> String {
10    assert!(cfg!(windows));
11    // Windows just uses PATH as the library search path, so we have to
12    // maintain the current value while adding our own
13    match env::var(lib_path_env_var()) {
14        Ok(curr) => format!("{}{}{}", path, path_div(), curr),
15        Err(..) => path.to_owned(),
16    }
17}
18
19pub fn lib_path_env_var() -> &'static str {
20    "PATH"
21}
22fn path_div() -> &'static str {
23    ";"
24}
25
26pub trait Utf8PathBufExt {
27    /// Append an extension to the path, even if it already has one.
28    fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf;
29}
30
31impl Utf8PathBufExt for Utf8PathBuf {
32    fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf {
33        if extension.is_empty() {
34            self.clone()
35        } else {
36            let mut fname = self.file_name().unwrap().to_string();
37            if !extension.starts_with('.') {
38                fname.push_str(".");
39            }
40            fname.push_str(extension);
41            self.with_file_name(fname)
42        }
43    }
44}
45
46/// The name of the environment variable that holds dynamic library locations.
47pub fn dylib_env_var() -> &'static str {
48    if cfg!(any(windows, target_os = "cygwin")) {
49        "PATH"
50    } else if cfg!(target_vendor = "apple") {
51        "DYLD_LIBRARY_PATH"
52    } else if cfg!(target_os = "haiku") {
53        "LIBRARY_PATH"
54    } else if cfg!(target_os = "aix") {
55        "LIBPATH"
56    } else {
57        "LD_LIBRARY_PATH"
58    }
59}
60
61/// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
62/// If the dylib_path_var is already set for this cmd, the old value will be overwritten!
63pub fn add_dylib_path(
64    cmd: &mut Command,
65    paths: impl Iterator<Item = impl Into<std::path::PathBuf>>,
66) {
67    let path_env = env::var_os(dylib_env_var());
68    let old_paths = path_env.as_ref().map(env::split_paths);
69    let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten());
70    cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap());
71}
72
73pub fn copy_dir_all(src: &Utf8Path, dst: &Utf8Path) -> std::io::Result<()> {
74    std::fs::create_dir_all(dst.as_std_path())?;
75    for entry in std::fs::read_dir(src.as_std_path())? {
76        let entry = entry?;
77        let path = Utf8PathBuf::try_from(entry.path()).unwrap();
78        let file_name = path.file_name().unwrap();
79        let ty = entry.file_type()?;
80        if ty.is_dir() {
81            copy_dir_all(&path, &dst.join(file_name))?;
82        } else {
83            std::fs::copy(path.as_std_path(), dst.join(file_name).as_std_path())?;
84        }
85    }
86    Ok(())
87}
88
89macro_rules! static_regex {
90    ($re:literal) => {{
91        static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new();
92        RE.get_or_init(|| ::regex::Regex::new($re).unwrap())
93    }};
94}
95pub(crate) use static_regex;
96
97macro_rules! string_enum {
98    ($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => {
99        $(#[$meta])*
100        $vis enum $name {
101            $($variant,)*
102        }
103
104        impl $name {
105            $vis const VARIANTS: &'static [Self] = &[$(Self::$variant,)*];
106            $vis const STR_VARIANTS: &'static [&'static str] = &[$(Self::$variant.to_str(),)*];
107
108            $vis const fn to_str(&self) -> &'static str {
109                match self {
110                    $(Self::$variant => $repr,)*
111                }
112            }
113        }
114
115        impl ::std::fmt::Display for $name {
116            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
117                ::std::fmt::Display::fmt(self.to_str(), f)
118            }
119        }
120
121        impl ::std::str::FromStr for $name {
122            type Err = String;
123
124            fn from_str(s: &str) -> Result<Self, Self::Err> {
125                match s {
126                    $($repr => Ok(Self::$variant),)*
127                    _ => Err(format!(concat!("unknown `", stringify!($name), "` variant: `{}`"), s)),
128                }
129            }
130        }
131    }
132}
133
134pub(crate) use string_enum;