mirror of
https://github.com/bootandy/dust.git
synced 2026-06-08 11:29:05 +03:00
eprint problematic folders
This commit is contained in:
+41
-34
@@ -142,44 +142,49 @@ fn walk(dir: PathBuf, walk_data: &WalkData, depth: usize) -> Option<Node> {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.par_bridge()
|
.par_bridge()
|
||||||
.filter_map(|entry| {
|
.filter_map(|entry| {
|
||||||
if let Ok(ref entry) = entry {
|
match entry {
|
||||||
// uncommenting the below line gives simpler code but
|
Ok(ref entry) => {
|
||||||
// rayon doesn't parallelize as well giving a 3X performance drop
|
// uncommenting the below line gives simpler code but
|
||||||
// hence we unravel the recursion a bit
|
// 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 !ignore_file(entry, walk_data) {
|
||||||
if let Ok(data) = entry.file_type() {
|
if let Ok(data) = entry.file_type() {
|
||||||
if data.is_dir()
|
if data.is_dir()
|
||||||
|| (walk_data.follow_links && data.is_symlink())
|
|| (walk_data.follow_links && data.is_symlink())
|
||||||
{
|
{
|
||||||
return walk(entry.path(), walk_data, depth + 1);
|
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 {
|
Err(ref failed) => {
|
||||||
let mut editable_error = errors.lock().unwrap();
|
let mut editable_error = errors.lock().unwrap();
|
||||||
editable_error.no_permissions = true
|
editable_error.no_permissions.insert(failed.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
@@ -189,7 +194,9 @@ fn walk(dir: PathBuf, walk_data: &WalkData, depth: usize) -> Option<Node> {
|
|||||||
let mut editable_error = errors.lock().unwrap();
|
let mut editable_error = errors.lock().unwrap();
|
||||||
match failed.kind() {
|
match failed.kind() {
|
||||||
std::io::ErrorKind::PermissionDenied => {
|
std::io::ErrorKind::PermissionDenied => {
|
||||||
editable_error.no_permissions = true;
|
editable_error
|
||||||
|
.no_permissions
|
||||||
|
.insert(dir.to_string_lossy().into());
|
||||||
}
|
}
|
||||||
std::io::ErrorKind::NotFound => {
|
std::io::ErrorKind::NotFound => {
|
||||||
editable_error.file_not_found.insert(failed.to_string());
|
editable_error.file_not_found.insert(failed.to_string());
|
||||||
|
|||||||
+8
-3
@@ -252,7 +252,6 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let final_errors = walk_data.errors.lock().unwrap();
|
let final_errors = walk_data.errors.lock().unwrap();
|
||||||
let failed_permissions = final_errors.no_permissions;
|
|
||||||
if !final_errors.file_not_found.is_empty() {
|
if !final_errors.file_not_found.is_empty() {
|
||||||
let err = final_errors
|
let err = final_errors
|
||||||
.file_not_found
|
.file_not_found
|
||||||
@@ -262,8 +261,14 @@ fn main() {
|
|||||||
.join(", ");
|
.join(", ");
|
||||||
eprintln!("No such file or directory: {}", err);
|
eprintln!("No such file or directory: {}", err);
|
||||||
}
|
}
|
||||||
if failed_permissions {
|
if !final_errors.no_permissions.is_empty() {
|
||||||
eprintln!("Did not have permissions for all directories");
|
let err = final_errors
|
||||||
|
.no_permissions
|
||||||
|
.iter()
|
||||||
|
.map(|a| a.as_ref())
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.join(", ");
|
||||||
|
eprintln!("Did not have permissions for directories: {}", err);
|
||||||
}
|
}
|
||||||
if !final_errors.unknown_error.is_empty() {
|
if !final_errors.unknown_error.is_empty() {
|
||||||
let err = final_errors
|
let err = final_errors
|
||||||
|
|||||||
+1
-1
@@ -70,7 +70,7 @@ impl PAtomicInfo {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RuntimeErrors {
|
pub struct RuntimeErrors {
|
||||||
pub no_permissions: bool,
|
pub no_permissions: HashSet<String>,
|
||||||
pub file_not_found: HashSet<String>,
|
pub file_not_found: HashSet<String>,
|
||||||
pub unknown_error: HashSet<String>,
|
pub unknown_error: HashSet<String>,
|
||||||
pub abort: bool,
|
pub abort: bool,
|
||||||
|
|||||||
+55
-17
@@ -41,7 +41,11 @@ fn initialize() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exact_output_test<T: AsRef<OsStr>>(valid_outputs: Vec<String>, command_args: Vec<T>) {
|
fn exact_output_test<T: AsRef<OsStr>>(
|
||||||
|
command_args: Vec<T>,
|
||||||
|
valid_outputs: Vec<String>,
|
||||||
|
error_outputs: Vec<String>,
|
||||||
|
) {
|
||||||
initialize();
|
initialize();
|
||||||
|
|
||||||
let mut a = &mut Command::cargo_bin("dust").unwrap();
|
let mut a = &mut Command::cargo_bin("dust").unwrap();
|
||||||
@@ -50,17 +54,32 @@ fn exact_output_test<T: AsRef<OsStr>>(valid_outputs: Vec<String>, command_args:
|
|||||||
a = a.arg(p);
|
a = a.arg(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = str::from_utf8(&a.unwrap().stdout).unwrap().to_owned();
|
if !valid_outputs.is_empty() {
|
||||||
|
let stdout_output = str::from_utf8(&a.unwrap().stdout).unwrap().to_owned();
|
||||||
let will_fail = valid_outputs.iter().any(|i| output.contains(i));
|
let will_fail = valid_outputs.iter().any(|i| stdout_output.contains(i));
|
||||||
if !will_fail {
|
if !will_fail {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"output:\n{}\ndoes not contain any of:\n{}",
|
"output(stdout):\n{}\ndoes not contain any of:\n{}",
|
||||||
output,
|
stdout_output,
|
||||||
valid_outputs.join("\n\n")
|
valid_outputs.join("\n\n")
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
assert!(will_fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check stderr
|
||||||
|
if !error_outputs.is_empty() {
|
||||||
|
let stderr_output = str::from_utf8(&a.unwrap().stderr).unwrap().to_owned();
|
||||||
|
let will_fail = error_outputs.iter().any(|i| stderr_output.contains(i));
|
||||||
|
if !will_fail {
|
||||||
|
eprintln!(
|
||||||
|
"output(stderr):\n{}\ndoes not contain any of:\n{}",
|
||||||
|
stderr_output,
|
||||||
|
valid_outputs.join("\n\n")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assert!(will_fail);
|
||||||
}
|
}
|
||||||
assert!(will_fail)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// "windows" result data can vary by host (size seems to be variable by one byte); fix code vs test and re-enable
|
// "windows" result data can vary by host (size seems to be variable by one byte); fix code vs test and re-enable
|
||||||
@@ -68,7 +87,7 @@ fn exact_output_test<T: AsRef<OsStr>>(valid_outputs: Vec<String>, command_args:
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn test_main_basic() {
|
pub fn test_main_basic() {
|
||||||
// -c is no color mode - This makes testing much simpler
|
// -c is no color mode - This makes testing much simpler
|
||||||
exact_output_test(main_output(), vec!["-c", "-B", "/tmp/test_dir/"])
|
exact_output_test(vec!["-c", "-B", "/tmp/test_dir/"], main_output(), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(target_os = "windows", ignore)]
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
@@ -81,7 +100,7 @@ pub fn test_main_multi_arg() {
|
|||||||
"/tmp/test_dir",
|
"/tmp/test_dir",
|
||||||
"/tmp/test_dir",
|
"/tmp/test_dir",
|
||||||
];
|
];
|
||||||
exact_output_test(main_output(), command_args);
|
exact_output_test(command_args, main_output(), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_output() -> Vec<String> {
|
fn main_output() -> Vec<String> {
|
||||||
@@ -112,7 +131,7 @@ fn main_output() -> Vec<String> {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn test_main_long_paths() {
|
pub fn test_main_long_paths() {
|
||||||
let command_args = vec!["-c", "-p", "-B", "/tmp/test_dir/"];
|
let command_args = vec!["-c", "-p", "-B", "/tmp/test_dir/"];
|
||||||
exact_output_test(main_output_long_paths(), command_args);
|
exact_output_test(command_args, main_output_long_paths(), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_output_long_paths() -> Vec<String> {
|
fn main_output_long_paths() -> Vec<String> {
|
||||||
@@ -140,7 +159,7 @@ fn main_output_long_paths() -> Vec<String> {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn test_substring_of_names_and_long_names() {
|
pub fn test_substring_of_names_and_long_names() {
|
||||||
let command_args = vec!["-c", "-B", "/tmp/test_dir2"];
|
let command_args = vec!["-c", "-B", "/tmp/test_dir2"];
|
||||||
exact_output_test(no_substring_of_names_output(), command_args);
|
exact_output_test(command_args, no_substring_of_names_output(), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_substring_of_names_output() -> Vec<String> {
|
fn no_substring_of_names_output() -> Vec<String> {
|
||||||
@@ -174,7 +193,7 @@ fn no_substring_of_names_output() -> Vec<String> {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn test_unicode_directories() {
|
pub fn test_unicode_directories() {
|
||||||
let command_args = vec!["-c", "-B", "/tmp/test_dir_unicode"];
|
let command_args = vec!["-c", "-B", "/tmp/test_dir_unicode"];
|
||||||
exact_output_test(unicode_dir(), command_args);
|
exact_output_test(command_args, unicode_dir(), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unicode_dir() -> Vec<String> {
|
fn unicode_dir() -> Vec<String> {
|
||||||
@@ -201,7 +220,7 @@ fn unicode_dir() -> Vec<String> {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn test_apparent_size() {
|
pub fn test_apparent_size() {
|
||||||
let command_args = vec!["-c", "-s", "-b", "/tmp/test_dir"];
|
let command_args = vec!["-c", "-s", "-b", "/tmp/test_dir"];
|
||||||
exact_output_test(apparent_size_output(), command_args);
|
exact_output_test(command_args, apparent_size_output(), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apparent_size_output() -> Vec<String> {
|
fn apparent_size_output() -> Vec<String> {
|
||||||
@@ -222,3 +241,22 @@ fn apparent_size_output() -> Vec<String> {
|
|||||||
|
|
||||||
vec![one_space_before, two_space_before]
|
vec![one_space_before, two_space_before]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
|
#[test]
|
||||||
|
pub fn test_permission() {
|
||||||
|
Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg("mkdir -p /tmp/unreadable_folder && chmod 000 /tmp/unreadable_folder")
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
let command_args = vec!["/tmp/unreadable_folder"];
|
||||||
|
let permission_msg = r#"Did not have permissions"#.trim().to_string();
|
||||||
|
exact_output_test(command_args, vec![], vec![permission_msg]);
|
||||||
|
|
||||||
|
Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg("chmod 555 /tmp/unreadable_folder")
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user