mirror of
https://github.com/bootandy/dust.git
synced 2026-06-08 11:29:05 +03:00
feat: better error messages
Provide "No such file or directory" error if file is not found. Provide "Unknown Error" if other error found Should reduce confusion from the generic other error
This commit is contained in:
+75
-44
@@ -1,9 +1,11 @@
|
||||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::node::Node;
|
||||
use crate::progress::Operation;
|
||||
use crate::progress::PAtomicInfo;
|
||||
use crate::progress::RuntimeErrors;
|
||||
use crate::progress::ORDERING;
|
||||
use crate::utils::is_filtered_out_due_to_invert_regex;
|
||||
use crate::utils::is_filtered_out_due_to_regex;
|
||||
@@ -28,16 +30,17 @@ pub struct WalkData<'a> {
|
||||
pub ignore_hidden: bool,
|
||||
pub follow_links: bool,
|
||||
pub progress_data: Arc<PAtomicInfo>,
|
||||
pub errors: Arc<Mutex<RuntimeErrors>>,
|
||||
}
|
||||
|
||||
pub fn walk_it(dirs: HashSet<PathBuf>, walk_data: WalkData) -> Vec<Node> {
|
||||
pub fn walk_it(dirs: HashSet<PathBuf>, walk_data: &WalkData) -> Vec<Node> {
|
||||
let mut inodes = HashSet::new();
|
||||
let top_level_nodes: Vec<_> = dirs
|
||||
.into_iter()
|
||||
.filter_map(|d| {
|
||||
let prog_data = &walk_data.progress_data;
|
||||
prog_data.clear_state(&d);
|
||||
let node = walk(d, &walk_data, 0)?;
|
||||
let node = walk(d, walk_data, 0)?;
|
||||
|
||||
prog_data.state.store(Operation::PREPARING, ORDERING);
|
||||
|
||||
@@ -126,55 +129,83 @@ fn ignore_file(entry: &DirEntry, walk_data: &WalkData) -> bool {
|
||||
|
||||
fn walk(dir: PathBuf, walk_data: &WalkData, depth: usize) -> Option<Node> {
|
||||
let prog_data = &walk_data.progress_data;
|
||||
let mut children = vec![];
|
||||
let errors = &walk_data.errors;
|
||||
|
||||
if let Ok(entries) = fs::read_dir(&dir) {
|
||||
children = entries
|
||||
.into_iter()
|
||||
.par_bridge()
|
||||
.filter_map(|entry| {
|
||||
if let Ok(ref entry) = entry {
|
||||
// uncommenting the below line gives simpler code but
|
||||
// rayon doesn't parallelize as well giving a 3X performance drop
|
||||
// hence we unravel the recursion a bit
|
||||
let children = if dir.is_dir() {
|
||||
let read_dir = fs::read_dir(&dir);
|
||||
match read_dir {
|
||||
Ok(entries) => {
|
||||
entries
|
||||
.into_iter()
|
||||
.par_bridge()
|
||||
.filter_map(|entry| {
|
||||
if let Ok(ref entry) = entry {
|
||||
// uncommenting the below line gives simpler code but
|
||||
// rayon doesn't parallelize as well giving a 3X performance drop
|
||||
// hence we unravel the recursion a bit
|
||||
|
||||
// return walk(entry.path(), walk_data, depth)
|
||||
// return walk(entry.path(), walk_data, depth)
|
||||
|
||||
if !ignore_file(entry, walk_data) {
|
||||
if let Ok(data) = entry.file_type() {
|
||||
if data.is_dir() || (walk_data.follow_links && data.is_symlink()) {
|
||||
return walk(entry.path(), walk_data, depth + 1);
|
||||
if !ignore_file(entry, walk_data) {
|
||||
if let Ok(data) = entry.file_type() {
|
||||
if data.is_dir()
|
||||
|| (walk_data.follow_links && data.is_symlink())
|
||||
{
|
||||
return walk(entry.path(), walk_data, depth + 1);
|
||||
}
|
||||
|
||||
let node = build_node(
|
||||
entry.path(),
|
||||
vec![],
|
||||
walk_data.filter_regex,
|
||||
walk_data.invert_filter_regex,
|
||||
walk_data.use_apparent_size,
|
||||
data.is_symlink(),
|
||||
data.is_file(),
|
||||
walk_data.by_filecount,
|
||||
depth,
|
||||
);
|
||||
|
||||
prog_data.num_files.fetch_add(1, ORDERING);
|
||||
if let Some(ref file) = node {
|
||||
prog_data.total_file_size.fetch_add(file.size, ORDERING);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
let node = build_node(
|
||||
entry.path(),
|
||||
vec![],
|
||||
walk_data.filter_regex,
|
||||
walk_data.invert_filter_regex,
|
||||
walk_data.use_apparent_size,
|
||||
data.is_symlink(),
|
||||
data.is_file(),
|
||||
walk_data.by_filecount,
|
||||
depth,
|
||||
);
|
||||
|
||||
prog_data.num_files.fetch_add(1, ORDERING);
|
||||
if let Some(ref file) = node {
|
||||
prog_data.total_file_size.fetch_add(file.size, ORDERING);
|
||||
}
|
||||
|
||||
return node;
|
||||
} else {
|
||||
let mut editable_error = errors.lock().unwrap();
|
||||
editable_error.no_permissions = true
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
Err(failed) => {
|
||||
let mut editable_error = errors.lock().unwrap();
|
||||
match failed.kind() {
|
||||
std::io::ErrorKind::PermissionDenied => {
|
||||
editable_error.no_permissions = true;
|
||||
}
|
||||
std::io::ErrorKind::NotFound => {
|
||||
editable_error.file_not_found.insert(failed.to_string());
|
||||
}
|
||||
_ => {
|
||||
editable_error.unknown_error.insert(failed.to_string());
|
||||
}
|
||||
} else {
|
||||
prog_data.no_permissions.store(true, ORDERING)
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect();
|
||||
} else if !dir.is_file() {
|
||||
walk_data.progress_data.no_permissions.store(true, ORDERING)
|
||||
}
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !dir.is_file() {
|
||||
let mut editable_error = errors.lock().unwrap();
|
||||
let bad_file = dir.as_os_str().to_string_lossy().into();
|
||||
editable_error.file_not_found.insert(bad_file);
|
||||
}
|
||||
vec![]
|
||||
};
|
||||
build_node(
|
||||
dir,
|
||||
children,
|
||||
|
||||
Reference in New Issue
Block a user