blob: a189c1d1c2dfce87bc22817056a27c1707436c08 [file] [log] [blame]
use std::env;
use std::process::Command;
use camino::{Utf8Path, Utf8PathBuf};
#[cfg(test)]
mod tests;
pub fn make_new_path(path: &str) -> String {
assert!(cfg!(windows));
// Windows just uses PATH as the library search path, so we have to
// maintain the current value while adding our own
match env::var(lib_path_env_var()) {
Ok(curr) => format!("{}{}{}", path, path_div(), curr),
Err(..) => path.to_owned(),
}
}
pub fn lib_path_env_var() -> &'static str {
"PATH"
}
fn path_div() -> &'static str {
";"
}
pub trait Utf8PathBufExt {
/// Append an extension to the path, even if it already has one.
fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf;
}
impl Utf8PathBufExt for Utf8PathBuf {
fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf {
if extension.is_empty() {
self.clone()
} else {
let mut fname = self.file_name().unwrap().to_string();
if !extension.starts_with('.') {
fname.push_str(".");
}
fname.push_str(extension);
self.with_file_name(fname)
}
}
}
/// The name of the environment variable that holds dynamic library locations.
pub fn dylib_env_var() -> &'static str {
if cfg!(any(windows, target_os = "cygwin")) {
"PATH"
} else if cfg!(target_vendor = "apple") {
"DYLD_LIBRARY_PATH"
} else if cfg!(target_os = "haiku") {
"LIBRARY_PATH"
} else if cfg!(target_os = "aix") {
"LIBPATH"
} else {
"LD_LIBRARY_PATH"
}
}
/// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
/// If the dylib_path_var is already set for this cmd, the old value will be overwritten!
pub fn add_dylib_path(
cmd: &mut Command,
paths: impl Iterator<Item = impl Into<std::path::PathBuf>>,
) {
let path_env = env::var_os(dylib_env_var());
let old_paths = path_env.as_ref().map(env::split_paths);
let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten());
cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap());
}
pub fn copy_dir_all(src: &Utf8Path, dst: &Utf8Path) -> std::io::Result<()> {
std::fs::create_dir_all(dst.as_std_path())?;
for entry in std::fs::read_dir(src.as_std_path())? {
let entry = entry?;
let path = Utf8PathBuf::try_from(entry.path()).unwrap();
let file_name = path.file_name().unwrap();
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all(&path, &dst.join(file_name))?;
} else {
std::fs::copy(path.as_std_path(), dst.join(file_name).as_std_path())?;
}
}
Ok(())
}
macro_rules! static_regex {
($re:literal) => {{
static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new();
RE.get_or_init(|| ::regex::Regex::new($re).unwrap())
}};
}
pub(crate) use static_regex;
macro_rules! string_enum {
($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => {
$(#[$meta])*
$vis enum $name {
$($variant,)*
}
impl $name {
#[allow(dead_code)]
$vis const VARIANTS: &'static [Self] = &[$(Self::$variant,)*];
#[allow(dead_code)]
$vis const STR_VARIANTS: &'static [&'static str] = &[$(Self::$variant.to_str(),)*];
$vis const fn to_str(&self) -> &'static str {
match self {
$(Self::$variant => $repr,)*
}
}
}
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::std::fmt::Display::fmt(self.to_str(), f)
}
}
impl ::std::str::FromStr for $name {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
$($repr => Ok(Self::$variant),)*
_ => Err(format!(concat!("unknown `", stringify!($name), "` variant: `{}`"), s)),
}
}
}
}
}
pub(crate) use string_enum;