use anyhow::Result;
use ignore::{WalkBuilder, WalkState};
use log::{debug, warn};
use std::path::PathBuf;
use std::sync::mpsc::Sender;
#[derive(Debug)]
pub struct FileEntry {
pub path: PathBuf,
}
pub struct FileWalker {
paths: Vec<PathBuf>,
threads: usize,
sender: Sender<FileEntry>,
}
impl FileWalker {
pub fn new(paths: Vec<PathBuf>, threads: usize, sender: Sender<FileEntry>) -> Self {
Self {
paths,
threads,
sender,
}
}
pub fn walk(&self) -> Result<()> {
let mut walker_builder = WalkBuilder::new(&self.paths[0]);
if self.paths.len() > 1 {
for path in &self.paths[1..] {
walker_builder.add(path);
}
}
walker_builder
.threads(self.threads)
.standard_filters(true)
.hidden(false);
let sender = self.sender.clone();
walker_builder.build_parallel().run(move || {
let tx = sender.clone();
Box::new(move |result| {
match result {
Ok(entry) => {
if entry.file_type().map_or(false, |ft| ft.is_file()) {
let path = entry.into_path();
debug!("Found file: {:?}", path);
if tx.send(FileEntry { path }).is_err() {
warn!("Receiver dropped, stopping file walk.");
return WalkState::Quit;
}
}
}
Err(err) => {
warn!("Error walking directory: {}", err);
}
}
WalkState::Continue
})
});
Ok(())
}
}
pub fn walk_simple(path: PathBuf) -> Result<Vec<PathBuf>> {
let mut files = Vec::new();
let walker = WalkBuilder::new(path).build();
for result in walker {
match result {
Ok(entry) => {
if entry.file_type().map_or(false, |ft| ft.is_file()) {
files.push(entry.into_path());
}
}
Err(err) => {
warn!("Error walking directory: {}", err);
}
}
}
Ok(files)
}