use anyhow::Error;
use bstr::ByteVec;
use cfg_if::cfg_if;
use clap::Parser;
use crossbeam_channel::bounded;
use ignore::DirEntry;
use ignore::WalkState;
use itertools::Itertools;
use std::io;
use std::io::{BufWriter, Write};
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
mod args;
mod filetype;
mod glob;
mod interrupt;
mod regex;
mod walk;
cfg_if! {
if #[cfg(all(target_os = "linux", target_arch = "x86_64"))] {
use_jemalloc!();
} else if #[cfg(all(target_os = "linux", target_arch = "aarch64"))] {
use_jemalloc!();
} else if #[cfg(target_os = "macos")] {
use_jemalloc!();
}
}
fn main() -> Result<(), Error> {
let args = args::Args::parse();
let shutdown = &Arc::new(AtomicBool::new(false));
interrupt::reset_sigpipe();
interrupt::setup_interrupt_handler(shutdown)?;
let glob_name =
glob::build_glob_set(args.name.as_ref(), args.case_insensitive)?;
let glob_enabled = args.name.is_some();
let regex_name =
regex::build_regex_set(args.regex.as_ref(), args.case_insensitive)?;
let regex_enabled = args.regex.is_some();
let (tx, rx) = bounded::<DirEntry>(16 * (args.threads - 1));
let print_thread = thread::spawn(move || {
let mut stdout = BufWriter::new(io::stdout().lock());
for dir_entry in rx {
if glob_enabled && !glob_name.is_match(dir_entry.file_name()) {
continue;
}
if regex_enabled
&& !regex_name
.is_match(regex::path_to_bytes(&dir_entry.path()))
{
continue;
}
stdout
.write_all(&Vec::from_path_lossy(dir_entry.path()))
.unwrap_or(());
stdout.write_all(b"\n").unwrap_or(());
}
stdout.flush().unwrap_or(());
});
let unique_paths =
&args.path.clone().into_iter().unique().collect::<Vec<PathBuf>>();
let walker = walk::build_walker(&args, unique_paths);
walker.run(|| {
let tx = tx.clone();
let filetype = filetype::FileType::new(&args.file_type);
Box::new(move |dir_entry| {
if let Ok(dir_entry) = dir_entry {
if filetype.ignore_filetype(&dir_entry) {
return WalkState::Continue;
}
match tx.send(dir_entry) {
Ok(()) => {}
Err(_) => {
return WalkState::Quit;
}
}
}
if shutdown.load(Ordering::Relaxed) {
WalkState::Quit
} else {
WalkState::Continue
}
})
});
drop(tx);
print_thread.join().unwrap();
Ok(())
}
#[macro_export]
macro_rules! use_jemalloc {
() => {
use tikv_jemallocator::Jemalloc;
#[global_allocator]
static GLOBAL: Jemalloc = Jemalloc;
};
}