Skip to main content

compiletest/
util.rs

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