use std::collections::BTreeMap;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::{env, fs};
use once_cell::sync::Lazy;
use crate::utils::is_ci;
static WORKSPACES: Lazy<Mutex<BTreeMap<String, Arc<PathBuf>>>> =
Lazy::new(|| Mutex::new(BTreeMap::new()));
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SnapshotUpdate {
InPlace,
NewFile,
NoUpdate,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OutputBehavior {
Diff,
Summary,
Minimal,
Nothing,
}
pub fn force_update_snapshots() -> bool {
match env::var("INSTA_FORCE_UPDATE_SNAPSHOTS").ok().as_deref() {
None | Some("") | Some("0") => false,
Some("1") => true,
_ => panic!("invalid value for INSTA_FORCE_UPDATE_SNAPSHOTS"),
}
}
pub fn force_pass() -> bool {
match env::var("INSTA_FORCE_PASS").ok().as_deref() {
None | Some("") | Some("0") => false,
Some("1") => true,
_ => panic!("invalid value for INSTA_FORCE_PASS"),
}
}
pub fn get_output_behavior() -> OutputBehavior {
match env::var("INSTA_OUTPUT").ok().as_deref() {
None | Some("") | Some("diff") => OutputBehavior::Diff,
Some("summary") => OutputBehavior::Summary,
Some("minimal") => OutputBehavior::Minimal,
Some("none") => OutputBehavior::Nothing,
_ => panic!("invalid value for INSTA_OUTPUT"),
}
}
pub fn get_snapshot_update_behavior(unseen: bool) -> SnapshotUpdate {
match env::var("INSTA_UPDATE").ok().as_deref() {
None | Some("") | Some("auto") => {
if is_ci() {
SnapshotUpdate::NoUpdate
} else {
SnapshotUpdate::NewFile
}
}
Some("always") | Some("1") => SnapshotUpdate::InPlace,
Some("new") => SnapshotUpdate::NewFile,
Some("unseen") => {
if unseen {
SnapshotUpdate::NewFile
} else {
SnapshotUpdate::InPlace
}
}
Some("no") => SnapshotUpdate::NoUpdate,
_ => panic!("invalid value for INSTA_UPDATE"),
}
}
pub fn get_cargo_workspace(manifest_dir: &str) -> Arc<PathBuf> {
let mut workspaces = WORKSPACES.lock().unwrap_or_else(|x| x.into_inner());
if let Some(rv) = workspaces.get(manifest_dir) {
rv.clone()
} else {
let path = if let Ok(workspace_root) = std::env::var("INSTA_WORKSPACE_ROOT") {
Arc::new(PathBuf::from(workspace_root))
} else {
let output = std::process::Command::new(
env::var("CARGO")
.ok()
.unwrap_or_else(|| "cargo".to_string()),
)
.arg("metadata")
.arg("--format-version=1")
.arg("--no-deps")
.current_dir(manifest_dir)
.output()
.unwrap();
let docs =
yaml_rust::YamlLoader::load_from_str(std::str::from_utf8(&output.stdout).unwrap())
.unwrap();
let manifest = docs.get(0).expect("Unable to parse cargo manifest");
let workspace_root = PathBuf::from(manifest["workspace_root"].as_str().unwrap());
Arc::new(workspace_root)
};
workspaces.insert(manifest_dir.to_string(), path.clone());
path
}
}
pub fn memoize_snapshot_file(snapshot_file: &Path) {
if let Ok(path) = env::var("INSTA_SNAPSHOT_REFERENCES_FILE") {
let mut f = fs::OpenOptions::new()
.write(true)
.append(true)
.create(true)
.open(path)
.unwrap();
f.write_all(format!("{}\n", snapshot_file.display()).as_bytes())
.unwrap();
}
}