diff --git a/src/lib.rs b/src/lib.rs index d817d8e..f245bc3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,13 @@ //! Find large files on your system. mod bytes; -use std::{collections::BTreeMap, fmt::Display, fs::ReadDir, io, path::PathBuf}; +use std::{ + collections::BTreeMap, + fmt::Display, + fs::ReadDir, + io, + path::{Path, PathBuf}, +}; /// Returns the top `n` largest files under the provided path. /// @@ -14,13 +20,17 @@ use std::{collections::BTreeMap, fmt::Display, fs::ReadDir, io, path::PathBuf}; /// ``` /// use spacehog::find_top_n_largest_files; /// -/// let results = find_top_n_largest_files("testdata", 5).unwrap(); +/// let results = find_top_n_largest_files("testdata", 5, false).unwrap(); /// /// assert_eq!(results.len(), 4); /// ``` -pub fn find_top_n_largest_files(path: &str, n: usize) -> io::Result> { +pub fn find_top_n_largest_files( + path: &str, + n: usize, + ignore_hidden: bool, +) -> io::Result> { let mut results = BTreeMap::new(); - for entry in find_files_in_path(path)? { + for entry in find_files_in_path(path, ignore_hidden)? { results.insert(entry.clone(), entry); } Ok(results.into_values().rev().take(n).collect()) @@ -36,12 +46,16 @@ impl Display for FileSize { } } -fn find_files_in_path(path: &str) -> io::Result { +fn find_files_in_path(path: &str, ignore_hidden: bool) -> io::Result { let dir = std::fs::read_dir(path)?; - Ok(FileIter { stack: vec![dir] }) + Ok(FileIter { + ignore_hidden, + stack: vec![dir], + }) } struct FileIter { + ignore_hidden: bool, stack: Vec, } @@ -54,6 +68,9 @@ impl Iterator for FileIter { if let Some(entry) = dir.next() { let entry = entry.ok()?; let path = entry.path(); + if self.ignore_hidden && is_hidden_path(&path) { + continue; + } if path.is_dir() { self.stack.push(std::fs::read_dir(path).ok()?); } else { @@ -67,6 +84,14 @@ impl Iterator for FileIter { } } +fn is_hidden_path>(path: P) -> bool { + if let Some(name) = path.as_ref().file_name() { + name.to_str().map_or(false, |s| s.starts_with('.')) + } else { + false + } +} + #[cfg(test)] mod tests { use crate::FileSize; diff --git a/src/main.rs b/src/main.rs index 671cf1d..94bcfde 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,13 +11,17 @@ struct Args { #[arg(short, default_value_t = 5)] number: usize, + + #[arg(long, default_value_t = false)] + hidden: bool, } fn main() -> anyhow::Result<()> { let args = Args::parse(); + let ignore_hidden = !args.hidden; let mut sp = Spinner::new(spinners::Dots, "Scanning files...", Color::Blue); - let results = find_top_n_largest_files(&args.path, args.number)?; + let results = find_top_n_largest_files(&args.path, args.number, ignore_hidden)?; sp.clear(); if results.is_empty() { diff --git a/tests/cli.rs b/tests/cli.rs index 45366a2..c547acc 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -1,7 +1,8 @@ -use std::io::BufRead; +use std::io::Write; +use std::{fs::File, io::BufRead}; use assert_cmd::Command; -use tempfile::TempDir; +use tempfile::{tempdir, tempdir_in, TempDir}; #[test] fn binary_with_version_flag_prints_version() { @@ -80,6 +81,40 @@ fn binary_reports_that_the_directory_is_empty_if_it_contains_zero_files() { .stdout(predicates::str::contains("No files found.")); } +#[test] +fn binary_ignores_hidden_files_and_directories_by_default() { + use std::io::Write; + let parent_dir = tempdir().expect("failed to create temporary directory"); + let hidden_dir = tempdir_in(parent_dir.path()).expect("failed to create temporary directory"); + let temp_file_path = hidden_dir.path().join("test.txt"); + let mut temp_file = File::create(temp_file_path).expect("failed to create temporary file"); + write!(temp_file, "hello test").unwrap(); + + Command::cargo_bin("spacehog") + .unwrap() + .arg(parent_dir.path()) + .assert() + .success() + .stdout(predicates::str::contains("No files found.")); +} + +#[test] +fn binary_includes_hidden_files_and_directories_when_given_hidden_flag() { + let parent_dir = tempdir().expect("failed to create temporary directory"); + let hidden_dir = tempdir_in(parent_dir.path()).expect("failed to create temporary directory"); + let temp_file_path = hidden_dir.path().join("test.txt"); + let mut temp_file = File::create(temp_file_path).expect("failed to create temporary file"); + write!(temp_file, "hello test").unwrap(); + + Command::cargo_bin("spacehog") + .unwrap() + .arg(parent_dir.path()) + .arg("--hidden") + .assert() + .success() + .stdout(predicates::str::contains("*** Top 1 largest files ***")); +} + #[test] fn binary_with_invalid_path_arg_prints_an_error_message_and_exits_with_failure_code() { #[cfg(windows)]