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