use std::path::Path;
use ignore::WalkBuilder;
use ignore::overrides::OverrideBuilder;
use ignore::types::TypesBuilder;
use crate::error::AtomwriteError;
const INCLUDE_WHAT: &str = "invalid include glob";
const EXCLUDE_WHAT: &str = "invalid exclude glob";
const SET_WHAT: &str = "invalid glob set";
pub fn add_overrides(
walker: &mut WalkBuilder,
root: &Path,
include: &[String],
exclude: &[String],
) -> Result<(), AtomwriteError> {
if include.is_empty() && exclude.is_empty() {
return Ok(());
}
walker.overrides(compile_overrides(root, include, exclude)?);
Ok(())
}
pub fn add_include_types(
walker: &mut WalkBuilder,
include: &[String],
) -> Result<(), AtomwriteError> {
if include.is_empty() {
return Ok(());
}
let mut types = TypesBuilder::new();
for glob in include {
types
.add_def(&format!("custom:{glob}"))
.map_err(|e| AtomwriteError::invalid(INCLUDE_WHAT, e))?;
}
types.select("custom");
walker.types(
types
.build()
.map_err(|e| AtomwriteError::invalid(INCLUDE_WHAT, e))?,
);
Ok(())
}
pub fn validate(include: &[String], exclude: &[String]) -> Result<(), AtomwriteError> {
compile_overrides(Path::new("."), include, exclude).map(|_| ())
}
fn compile_overrides(
root: &Path,
include: &[String],
exclude: &[String],
) -> Result<ignore::overrides::Override, AtomwriteError> {
let mut overrides = OverrideBuilder::new(root);
for glob in include {
overrides
.add(glob)
.map_err(|e| AtomwriteError::invalid(INCLUDE_WHAT, e))?;
}
for glob in exclude {
overrides
.add(&format!("!{glob}"))
.map_err(|e| AtomwriteError::invalid(EXCLUDE_WHAT, e))?;
}
overrides
.build()
.map_err(|e| AtomwriteError::invalid(SET_WHAT, e))
}
#[cfg(test)]
mod tests {
use super::*;
fn globs(items: &[&str]) -> Vec<String> {
items.iter().map(|s| (*s).to_string()).collect()
}
#[test]
fn every_entry_point_rejects_a_glob_that_does_not_compile() {
let bad = globs(&["["]);
let mut walker = WalkBuilder::new(".");
for result in [
add_overrides(&mut walker, Path::new("."), &bad, &[]),
add_overrides(&mut walker, Path::new("."), &[], &bad),
add_include_types(&mut walker, &bad),
validate(&bad, &[]),
validate(&[], &bad),
] {
let err = result.expect_err("the glob must be refused");
assert_eq!(err.error_code(), "INVALID_INPUT", "{err}");
assert_eq!(err.exit_code(), 65);
assert!(!err.to_string().contains('\n'), "short message: {err}");
}
}
#[test]
fn valid_globs_and_empty_lists_pass() {
let mut walker = WalkBuilder::new(".");
assert!(add_overrides(&mut walker, Path::new("."), &[], &[]).is_ok());
assert!(
add_overrides(
&mut walker,
Path::new("."),
&globs(&["*.rs"]),
&globs(&["target"])
)
.is_ok()
);
assert!(add_include_types(&mut walker, &globs(&["*.rs"])).is_ok());
assert!(add_include_types(&mut walker, &[]).is_ok());
assert!(validate(&globs(&["*.rs"]), &globs(&["*.bak.*"])).is_ok());
}
}