compiletest/
util.rs

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