use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::{Mutex, MutexGuard, PoisonError};
pub(crate) static TEST_LOCK: Mutex<()> = Mutex::new(());
pub(crate) fn git(dir: &Path, args: &[&str]) {
let st = Command::new("git")
.args(args)
.current_dir(dir)
.status()
.unwrap();
assert!(st.success(), "git {args:?} failed in {dir:?}");
}
pub(crate) fn configure(clone: &Path) {
git(clone, &["config", "user.name", "test"]);
git(clone, &["config", "user.email", "test@example.com"]);
git(clone, &["config", "commit.gpgsign", "false"]);
}
fn lock() -> MutexGuard<'static, ()> {
TEST_LOCK.lock().unwrap_or_else(PoisonError::into_inner)
}
struct EnvGuard {
prev_dir: Option<PathBuf>,
prev_config: Option<OsString>,
_lock: MutexGuard<'static, ()>,
}
impl Drop for EnvGuard {
fn drop(&mut self) {
if let Some(dir) = self.prev_dir.take() {
if let Err(e) = std::env::set_current_dir(&dir) {
eprintln!("testutil: failed to restore cwd to {dir:?}: {e}");
}
}
match self.prev_config.take() {
Some(v) => unsafe { std::env::set_var("WORKTRUNK_CONFIG_PATH", v) },
None => unsafe { std::env::remove_var("WORKTRUNK_CONFIG_PATH") },
}
}
}
pub(crate) fn in_dir<T>(dir: &Path, f: impl FnOnce() -> T) -> T {
let lock = lock();
let _guard = EnvGuard {
prev_dir: Some(std::env::current_dir().expect("cwd exists at capture")),
prev_config: std::env::var_os("WORKTRUNK_CONFIG_PATH"),
_lock: lock,
};
std::env::set_current_dir(dir).unwrap();
unsafe { std::env::set_var("WORKTRUNK_CONFIG_PATH", dir.join("no-such-config.toml")) };
f()
}
pub(crate) fn with_env_config<T>(path: &Path, f: impl FnOnce() -> T) -> T {
let lock = lock();
let _guard = EnvGuard {
prev_dir: None,
prev_config: std::env::var_os("WORKTRUNK_CONFIG_PATH"),
_lock: lock,
};
unsafe { std::env::set_var("WORKTRUNK_CONFIG_PATH", path) };
f()
}