use std::{
path::{Path, PathBuf},
sync::{Arc, mpsc},
};
use ignore::{WalkBuilder, WalkState, types::TypesBuilder};
use crate::{
error::{Error, Result},
prelude::OrPanic as _,
};
pub fn find_sol_files<T: AsRef<Path>>(
paths: &[T],
exclude: &[T],
sort: bool,
) -> Result<Vec<PathBuf>> {
let exclude = exclude
.iter()
.map(|p| {
dunce::canonicalize(p.as_ref()).map_err(|err| Error::IOError {
path: p.as_ref().to_path_buf(),
err,
})
})
.collect::<Result<Vec<_>>>()?;
let exclude = Arc::new(exclude.iter().map(PathBuf::as_path).collect::<Vec<_>>());
let types = TypesBuilder::new()
.add_defaults()
.select("solidity")
.build()
.or_panic("types builder should build");
let mut walker: Option<WalkBuilder> = None;
for path in paths {
let path = dunce::canonicalize(path.as_ref()).map_err(|err| Error::IOError {
path: path.as_ref().to_path_buf(),
err,
})?;
if let Some(ext) = path.extension()
&& ext != "sol"
{
continue;
}
if let Some(ref mut w) = walker {
w.add(path);
} else {
walker = Some(WalkBuilder::new(path));
}
}
let Some(mut walker) = walker else {
return Ok(Vec::new());
};
walker
.hidden(false)
.git_global(false)
.git_exclude(false)
.add_custom_ignore_filename(".nsignore")
.types(types);
let walker = walker.build_parallel();
let (tx, rx) = mpsc::channel::<PathBuf>();
walker.run(|| {
let tx = tx.clone();
let exclude = Arc::clone(&exclude);
Box::new(move |result| {
let Ok(entry) = result else {
return WalkState::Continue;
};
let path = entry.path();
if exclude.contains(&path) {
return WalkState::Skip;
}
if path.is_dir() {
return WalkState::Continue;
}
tx.send(path.to_path_buf()).ok();
WalkState::Continue
})
});
drop(tx);
let mut files = Vec::new();
while let Ok(path) = rx.recv() {
files.push(path);
}
if sort {
files.sort_unstable();
}
Ok(files)
}