redacter 0.16.2

Copy & Redact cli tool to securely copy and redact files removing Personal Identifiable Information (PII) across various filesystems.
use crate::file_systems::DetectFileSystem;
use crate::file_systems::FileSystemConnection;
use crate::file_tools::FileMatcher;
use crate::AppResult;
use console::{pad_str, Alignment, Style, Term};
use indicatif::{HumanBytes, TermLike};
use rvstruct::ValueStruct;

#[derive(Debug, Clone)]
pub struct LsCommandOptions {
    pub file_matcher: FileMatcher,
}

impl LsCommandOptions {
    pub fn new(filename_filter: Option<globset::Glob>, max_size_limit: Option<usize>) -> Self {
        let filename_matcher = filename_filter
            .as_ref()
            .map(|filter| filter.compile_matcher());
        LsCommandOptions {
            file_matcher: FileMatcher::new(filename_matcher, max_size_limit),
        }
    }
}

pub async fn command_ls(term: &Term, source: &str, options: LsCommandOptions) -> AppResult<()> {
    let bold_style = Style::new().bold();
    let highlighted = bold_style.clone().white();
    let dimmed_style = Style::new().dim();
    term.write_line(format!("Listing files in {}.", bold_style.apply_to(source)).as_str())?;
    let app_reporter = crate::reporter::AppReporter::from(term);
    let mut source_fs = DetectFileSystem::open(source, &app_reporter).await?;
    let list_files_result = source_fs
        .list_files(Some(&options.file_matcher), None)
        .await?;
    let total_size: usize = list_files_result
        .files
        .iter()
        .map(|f| f.file_size.unwrap_or(0))
        .sum();

    if !list_files_result.files.is_empty() {
        let max_filename_width = std::cmp::min(
            list_files_result
                .files
                .iter()
                .map(|f| f.relative_path.value().len())
                .max()
                .unwrap_or(25)
                + 5,
            (term.width() * 2 / 3) as usize,
        );
        term.write_line(
            format!(
                "\n  {} {} {}",
                dimmed_style.apply_to(pad_str(
                    "Filename",
                    max_filename_width,
                    Alignment::Left,
                    None
                )),
                dimmed_style.apply_to(pad_str("Media Type", 40, Alignment::Left, None)),
                dimmed_style.apply_to(pad_str("Size", 16, Alignment::Left, None))
            )
            .as_str(),
        )?;

        for file in &list_files_result.files {
            term.write_line(
                format!(
                    "- {} {} {}",
                    highlighted.apply_to(pad_str(
                        file.relative_path.value(),
                        max_filename_width,
                        Alignment::Left,
                        Some("...")
                    )),
                    pad_str(
                        file.media_type
                            .as_ref()
                            .map(|mime| mime.to_string())
                            .unwrap_or("".to_string())
                            .as_str(),
                        40,
                        Alignment::Left,
                        None
                    ),
                    highlighted.apply_to(pad_str(
                        format!(
                            "{}",
                            HumanBytes(file.file_size.map(|sz| sz as u64).unwrap_or(0))
                        )
                        .as_str(),
                        16,
                        Alignment::Left,
                        None
                    ))
                )
                .as_str(),
            )?;
        }
        term.write_line("")?;
    }
    term.write_line(
        format!(
            "{} files found. Total size: {}",
            highlighted.apply_to(list_files_result.files.len()),
            highlighted.apply_to(HumanBytes(total_size as u64))
        )
        .as_str(),
    )?;
    term.write_line(
        format!(
            "{} files skipped/filtered out.",
            dimmed_style.apply_to(list_files_result.skipped.to_string())
        )
        .as_str(),
    )?;
    source_fs.close().await?;
    Ok(())
}