Skip to content

Commit

Permalink
Ignore hidden files and directories by default (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
aleury authored Sep 11, 2024
1 parent 45f441c commit 1e973ad
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 9 deletions.
37 changes: 31 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand All @@ -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<Vec<(FileSize, PathBuf)>> {
pub fn find_top_n_largest_files(
path: &str,
n: usize,
ignore_hidden: bool,
) -> io::Result<Vec<(FileSize, PathBuf)>> {
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())
Expand All @@ -36,12 +46,16 @@ impl Display for FileSize {
}
}

fn find_files_in_path(path: &str) -> io::Result<FileIter> {
fn find_files_in_path(path: &str, ignore_hidden: bool) -> io::Result<FileIter> {
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<ReadDir>,
}

Expand All @@ -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 {
Expand All @@ -67,6 +84,14 @@ impl Iterator for FileIter {
}
}

fn is_hidden_path<P: AsRef<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;
Expand Down
6 changes: 5 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
39 changes: 37 additions & 2 deletions tests/cli.rs
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -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)]
Expand Down

0 comments on commit 1e973ad

Please sign in to comment.