1use std::env;
2use std::process::Command;
3
4use camino::{Utf8Path, Utf8PathBuf};
5
6#[cfg(test)]
7mod tests;
8
9pub(crate) fn make_new_path(path: &str) -> String {
10 assert!(cfg!(windows));
11 match env::var(lib_path_env_var()) {
14 Ok(curr) => format!("{}{}{}", path, path_div(), curr),
15 Err(..) => path.to_owned(),
16 }
17}
18
19pub(crate) fn lib_path_env_var() -> &'static str {
20 "PATH"
21}
22fn path_div() -> &'static str {
23 ";"
24}
25
26pub(crate) trait Utf8PathBufExt {
27 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
46pub(crate) 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
61pub(crate) 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(crate) 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 (
99 $(#[$meta:meta])*
100 $vis:vis enum $name:ident {
101 $(
102 $(#[$variant_meta:meta])*
103 $variant:ident => $repr:expr,
104 )*
105 }
106 ) => {
107 $(#[$meta])*
108 $vis enum $name {
109 $(
110 $(#[$variant_meta])*
111 $variant,
112 )*
113 }
114
115 impl $name {
116 #[allow(dead_code)]
117 $vis const VARIANTS: &'static [Self] = &[
118 $( Self::$variant, )*
119 ];
120 #[allow(dead_code)]
121 $vis const STR_VARIANTS: &'static [&'static str] = &[
122 $( Self::$variant.to_str(), )*
123 ];
124
125 $vis const fn to_str(&self) -> &'static str {
126 match self {
127 $( Self::$variant => $repr, )*
128 }
129 }
130 }
131
132 impl ::std::fmt::Display for $name {
133 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
134 ::std::fmt::Display::fmt(self.to_str(), f)
135 }
136 }
137
138 impl ::std::str::FromStr for $name {
139 type Err = String;
140
141 fn from_str(s: &str) -> Result<Self, Self::Err> {
142 match s {
143 $( $repr => Ok(Self::$variant), )*
144 _ => Err(format!(concat!("unknown `", stringify!($name), "` variant: `{}`"), s)),
145 }
146 }
147 }
148 }
149}
150
151pub(crate) use string_enum;