compiletest/
util.rs

1use std::env;
2use std::ffi::OsStr;
3use std::path::{Path, PathBuf};
4use std::process::Command;
5
6use tracing::*;
7
8use crate::common::Config;
9
10#[cfg(test)]
11mod tests;
12
13pub fn make_new_path(path: &str) -> String {
14    assert!(cfg!(windows));
15    // Windows just uses PATH as the library search path, so we have to
16    // maintain the current value while adding our own
17    match env::var(lib_path_env_var()) {
18        Ok(curr) => format!("{}{}{}", path, path_div(), curr),
19        Err(..) => path.to_owned(),
20    }
21}
22
23pub fn lib_path_env_var() -> &'static str {
24    "PATH"
25}
26fn path_div() -> &'static str {
27    ";"
28}
29
30pub fn logv(config: &Config, s: String) {
31    debug!("{}", s);
32    if config.verbose {
33        println!("{}", s);
34    }
35}
36
37pub trait PathBufExt {
38    /// Append an extension to the path, even if it already has one.
39    fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf;
40}
41
42impl PathBufExt for PathBuf {
43    fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
44        if extension.as_ref().is_empty() {
45            self.clone()
46        } else {
47            let mut fname = self.file_name().unwrap().to_os_string();
48            if !extension.as_ref().to_str().unwrap().starts_with('.') {
49                fname.push(".");
50            }
51            fname.push(extension);
52            self.with_file_name(fname)
53        }
54    }
55}
56
57/// The name of the environment variable that holds dynamic library locations.
58pub fn dylib_env_var() -> &'static str {
59    if cfg!(windows) {
60        "PATH"
61    } else if cfg!(target_vendor = "apple") {
62        "DYLD_LIBRARY_PATH"
63    } else if cfg!(target_os = "haiku") {
64        "LIBRARY_PATH"
65    } else if cfg!(target_os = "aix") {
66        "LIBPATH"
67    } else {
68        "LD_LIBRARY_PATH"
69    }
70}
71
72/// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
73/// If the dylib_path_var is already set for this cmd, the old value will be overwritten!
74pub fn add_dylib_path(cmd: &mut Command, paths: impl Iterator<Item = impl Into<PathBuf>>) {
75    let path_env = env::var_os(dylib_env_var());
76    let old_paths = path_env.as_ref().map(env::split_paths);
77    let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten());
78    cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap());
79}
80
81pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> {
82    std::fs::create_dir_all(&dst)?;
83    for entry in std::fs::read_dir(src)? {
84        let entry = entry?;
85        let ty = entry.file_type()?;
86        if ty.is_dir() {
87            copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
88        } else {
89            std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
90        }
91    }
92    Ok(())
93}
94
95macro_rules! static_regex {
96    ($re:literal) => {{
97        static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new();
98        RE.get_or_init(|| ::regex::Regex::new($re).unwrap())
99    }};
100}
101pub(crate) use static_regex;