use crate::errors::{Result, WrappedError};
use std::fs::{self, DirEntry};
use std::path::{Path, PathBuf};
pub fn ls_dir<C, E>(path: impl AsRef<Path>, cb: &mut C, cb_err: &mut E) -> Result<()>
where
C: FnMut(&DirEntry),
E: FnMut(&WrappedError),
{
let dir_iter = fs::read_dir(&path)
.map_err(|base_error| WrappedError::io_error(base_error, PathBuf::from(path.as_ref())))?;
for dir_entry in dir_iter {
match dir_entry {
Ok(dir_entry) => {
cb(&dir_entry);
}
Err(err) => cb_err(&WrappedError::io_error(err, PathBuf::from(path.as_ref()))),
}
}
Ok(())
}
pub fn walk<C, E>(path: impl AsRef<Path>, cb: &mut C, cb_err: &mut E) -> Result<()>
where
C: FnMut(&DirEntry),
E: FnMut(&WrappedError),
{
let mut iter_list = vec![];
let root = fs::read_dir(path.as_ref())
.map_err(|err| WrappedError::io_error(err, PathBuf::from(path.as_ref())))?;
iter_list.push(root.collect::<Vec<_>>().into_iter());
while let Some(current) = iter_list.pop() {
for dir_entry in current {
match dir_entry {
Ok(dir_entry) => {
if let Ok(ft) = dir_entry.file_type() {
if ft.is_dir() && !ft.is_symlink() {
if let Ok(read_dir) = fs::read_dir(dir_entry.path()) {
iter_list.push(read_dir.collect::<Vec<_>>().into_iter());
}
}
}
cb(&dir_entry)
}
Err(base_error) => cb_err(&WrappedError::io_error(
base_error,
PathBuf::from(path.as_ref()),
)),
}
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::OsString;
use std::io;
#[test]
fn walk_directory() {
let mut all_files = vec![];
let result = walk(
"..",
&mut |entry| all_files.push(entry.file_name()),
&mut |_| {},
);
assert!(result.is_ok());
assert!(all_files.contains(&OsString::from("lib.rs")));
assert!(all_files.contains(&OsString::from("dir.rs")));
assert!(all_files.contains(&OsString::from("fs.rs")));
}
#[test]
fn walk_file() {
let result = walk("Cargo.toml", &mut |_| {}, &mut |_| {});
assert!(result.is_err());
let _ = result.map_err(|err| {
let inner = err.get_io_error();
assert!(inner.is_some());
let base_error = inner.unwrap();
assert_eq!(base_error.kind(), io::ErrorKind::Other);
assert_eq!(20, base_error.raw_os_error().unwrap());
err
});
}
#[test]
fn walk_404() {
let result = walk("404", &mut |_| {}, &mut |_| {});
assert!(result.is_err());
let _ = result.map_err(|err| {
let inner = err.get_io_error();
assert!(inner.is_some());
let base_error = inner.unwrap();
assert_eq!(base_error.kind(), io::ErrorKind::NotFound);
assert_eq!(2, base_error.raw_os_error().unwrap());
err
});
}
#[test]
fn ls_directory() {
let mut all_files = vec![];
let result = ls_dir(
"src",
&mut |entry| all_files.push(entry.file_name()),
&mut |_| {},
);
assert!(result.is_ok());
assert!(all_files.contains(&OsString::from("lib.rs")));
assert!(all_files.contains(&OsString::from("fs.rs")));
assert!(all_files.contains(&OsString::from("fs")));
}
#[test]
fn ls_file() {
let result = ls_dir("Cargo.toml", &mut |_| {}, &mut |_| {});
assert!(result.is_err());
let _ = result.map_err(|err| {
let e: std::result::Result<Box<io::Error>, _> =
err.into_inner().unwrap().downcast::<io::Error>();
assert!(e.is_ok());
let base_error = e.unwrap();
assert_eq!(base_error.kind(), io::ErrorKind::Other);
assert_eq!(20, base_error.raw_os_error().unwrap());
});
}
#[test]
fn ls_404() {
let result = ls_dir("404", &mut |_| {}, &mut |_| {});
assert!(result.is_err());
let _ = result.map_err(|err| {
let inner = err.get_io_error();
assert!(inner.is_some());
let base_error = inner.unwrap();
assert_eq!(base_error.kind(), io::ErrorKind::NotFound);
assert_eq!(2, base_error.raw_os_error().unwrap());
err
});
}
}