hfile 0.5.2

Hfile is a command-line interface (CLI) tool for generating hash values of files
Documentation
use super::Action;
use crate::{checksum, hash, walkdir};
use anyhow::{Context, Result, bail};
use path_clean::PathClean;
use std::{
    fs,
    io::{self, BufWriter, Write},
    path::Path,
};

pub fn execute(action: &Action) -> Result<()> {
    match action {
        Action::HashFile {
            file,
            algorithm,
            size,
        } => hash_single_file(file, *algorithm, *size),
        Action::HashPath {
            path,
            algorithm,
            size,
        } => hash_path(path, *algorithm, *size),
        Action::FindDuplicates { path, algorithm } => find_duplicates(path, *algorithm),
        Action::CheckChecksums {
            checksum_file,
            algorithm,
        } => check_checksums(checksum_file, *algorithm),
    }
}

fn check_checksums(checksum_file: &str, algorithm: crate::cli::commands::Algorithm) -> Result<()> {
    checksum::check(Path::new(checksum_file), algorithm)?;
    Ok(())
}

fn hash_single_file(
    file_arg: &str,
    algorithm: crate::cli::commands::Algorithm,
    size: bool,
) -> Result<()> {
    let file = Path::new(file_arg);
    let metadata = fs::metadata(file)
        .with_context(|| format!("failed to read metadata for {}", file.display()))?;
    if metadata.is_dir() {
        bail!("Use option -p to pass a directory");
    }

    let hash = hash::hash_file(algorithm, file)?;
    let stdout = io::stdout();
    let mut output = BufWriter::new(stdout.lock());
    if size {
        writeln!(
            output,
            "{}\t{}\t{}",
            hash,
            file.clean().display(),
            bytesize::to_string(metadata.len(), true)
        )?;
    } else {
        writeln!(output, "{hash}\t{}", file.clean().display())?;
    }
    output.flush()?;

    Ok(())
}

fn hash_path(path: &str, algorithm: crate::cli::commands::Algorithm, size: bool) -> Result<()> {
    walkdir::read(path, algorithm, size)?;
    Ok(())
}

fn find_duplicates(path: &str, algorithm: crate::cli::commands::Algorithm) -> Result<()> {
    let duplicates = walkdir::find_duplicates(path, algorithm)?;
    let stdout = io::stdout();
    let mut output = BufWriter::new(stdout.lock());
    for (index, (hash, paths)) in duplicates.iter().enumerate() {
        writeln!(output, "{hash}")?;
        for path in paths {
            writeln!(output, "\t{}", path.clean().display())?;
        }

        if index + 1 < duplicates.len() {
            writeln!(output)?;
        }
    }
    output.flush()?;

    Ok(())
}