use crate::error::Result;
use crate::util::xvcignore::COMMON_IGNORE_PATTERNS;
use crate::{XvcPath, XvcRoot, XVCIGNORE_FILENAME};
use clap::Parser;
use log::trace;
use std::io::BufRead;
use std::path::{Path, PathBuf};
use xvc_logging::{output, XvcOutputSender};
use xvc_walker::{build_ignore_patterns, IgnoreRules, MatchResult, WalkOptions};
#[derive(Debug, Clone, PartialEq, Eq, Parser)]
#[command()]
pub struct CheckIgnoreCLI {
#[arg(
long,
default_value = XVCIGNORE_FILENAME,
)]
ignore_filename: String,
#[arg(value_hint=clap::ValueHint::AnyPath)]
targets: Vec<String>,
}
pub fn cmd_check_ignore<R: BufRead>(
input: R,
output_snd: &XvcOutputSender,
xvc_root: &XvcRoot,
opts: CheckIgnoreCLI,
) -> Result<()> {
let current_dir = xvc_root.current_dir();
let walk_options = WalkOptions {
ignore_filename: Some(opts.ignore_filename.clone()),
include_dirs: true,
};
let ignore_rules = build_ignore_patterns(
COMMON_IGNORE_PATTERNS,
xvc_root,
&walk_options.ignore_filename.unwrap_or_default(),
)?;
if !opts.targets.is_empty() {
let xvc_paths = opts
.targets
.iter()
.map(|p| XvcPath::new(xvc_root, current_dir, &PathBuf::from(p)))
.collect::<Result<Vec<XvcPath>>>()?;
check_ignore_paths(xvc_root, &ignore_rules, &xvc_paths)
} else {
check_ignore_stdin(input, output_snd, xvc_root, &ignore_rules)
}
}
fn check_ignore_stdin<R: BufRead>(
input: R,
output_snd: &XvcOutputSender,
xvc_root: &XvcRoot,
ignore_rules: &IgnoreRules,
) -> Result<()> {
let current_dir = xvc_root.current_dir();
let mut buffer = String::new();
let lines_iter = input.lines();
lines_iter
.map_while(|line| {
if let Ok(line) = line {
XvcPath::new(xvc_root, current_dir, &PathBuf::from(line)).ok()
} else {
None
}
})
.for_each(|xvc_path| {
let absolute_path = xvc_path.to_absolute_path(xvc_root);
let res = check_ignore_line(ignore_rules, &absolute_path);
if !res.trim().is_empty() {
output!(output_snd, "{}", res);
}
buffer.clear();
});
Ok(())
}
fn check_ignore_paths(
xvc_root: &XvcRoot,
ignore_rules: &IgnoreRules,
xvc_paths: &[XvcPath],
) -> Result<()> {
for path in xvc_paths {
let absolute_path = path.to_absolute_path(xvc_root);
let output = check_ignore_line(ignore_rules, &absolute_path);
trace!("output: {}", output);
println!("{}", output)
}
Ok(())
}
fn check_ignore_line(ignore_rules: &IgnoreRules, absolute_path: &Path) -> String {
match ignore_rules.check(absolute_path) {
MatchResult::NoMatch => {
format!("[NO MATCH] {}", absolute_path.to_string_lossy())
}
MatchResult::Ignore => {
format!("[IGNORE] {}", absolute_path.to_string_lossy())
}
MatchResult::Whitelist => {
format!("[WHITELIST] {}", absolute_path.to_string_lossy())
}
}
}