use std::env;
use std::path::Path;
use std::sync::Mutex;
use globset::{GlobBuilder, GlobMatcher};
use walkdir::WalkDir;
use crate::settings::Settings;
use crate::utils::style;
pub(crate) struct GlobCollector {
pub(crate) fail_fast: bool,
pub(crate) failed: usize,
pub(crate) show_insta_hint: bool,
}
lazy_static::lazy_static! {
pub(crate) static ref GLOB_STACK: Mutex<Vec<GlobCollector>> = Mutex::default();
}
lazy_static::lazy_static! {
static ref GLOB_FILTER: Vec<GlobMatcher> = {
env::var("INSTA_GLOB_FILTER")
.unwrap_or_default()
.split(';')
.filter(|x| !x.is_empty())
.filter_map(|filter| {
GlobBuilder::new(filter)
.case_insensitive(true)
.build()
.ok()
.map(|x| x.compile_matcher())
})
.collect()
};
}
pub fn glob_exec<F: FnMut(&Path)>(base: &Path, pattern: &str, mut f: F) {
let glob = GlobBuilder::new(pattern)
.case_insensitive(true)
.literal_separator(true)
.build()
.unwrap()
.compile_matcher();
let walker = WalkDir::new(base).follow_links(true);
let mut glob_found_matches = false;
let mut settings = Settings::clone_current();
GLOB_STACK.lock().unwrap().push(GlobCollector {
failed: 0,
show_insta_hint: false,
fail_fast: std::env::var("INSTA_GLOB_FAIL_FAST").as_deref() == Ok("1"),
});
for file in walker {
let file = file.unwrap();
let path = file.path();
let stripped_path = path.strip_prefix(base).unwrap_or(path);
if !glob.is_match(stripped_path) {
continue;
}
glob_found_matches = true;
if !GLOB_FILTER.is_empty() && !GLOB_FILTER.iter().any(|x| x.is_match(stripped_path)) {
eprintln!("Skipping {} due to glob filter", stripped_path.display());
continue;
}
settings.set_input_file(&path);
settings.set_snapshot_suffix(path.file_name().unwrap().to_str().unwrap());
settings.bind(|| {
f(path);
});
}
let top = GLOB_STACK.lock().unwrap().pop().unwrap();
if !glob_found_matches && !settings.allow_empty_glob() {
panic!("the glob! macro did not match any files.");
}
if top.failed > 0 {
if top.show_insta_hint {
println!(
"{hint}",
hint = style("To update snapshots run `cargo insta review`").dim(),
);
}
if top.failed > 1 {
println!(
"{hint}",
hint = style("To enable fast failing for glob! export INSTA_GLOB_FAIL_FAST=1 as environment variable.").dim()
);
}
panic!(
"glob! resulted in {} snapshot assertion failure{}s",
top.failed,
if top.failed == 1 { "" } else { "s" },
);
}
}