From cc23e7734459f3e118dd6204b13296caf83591b2 Mon Sep 17 00:00:00 2001 From: A Farzat Date: Sat, 6 Jun 2026 12:59:45 +0300 Subject: Delegate logging management to Logger struct Allows verbosity management in a centralized way. --- src/lib.rs | 1 + src/logger.rs | 30 ++++++++++++++++++++++++++++++ src/main.rs | 48 +++++++++++++++++++++++++++++++++++++----------- src/renderer.rs | 18 ++++++++++++++---- 4 files changed, 82 insertions(+), 15 deletions(-) create mode 100644 src/logger.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index c9d1a45..ba1aacf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +pub mod logger; pub mod normalizer; pub mod renderer; mod util; diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 0000000..a1db035 --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,30 @@ +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Verbosity { + Quiet, + Normal, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Logger { + verbosity: Verbosity, +} + +impl Logger { + pub fn new(verbosity: Verbosity) -> Self { + Self { verbosity } + } + + pub fn warn(&self, message: impl AsRef) { + if self.verbosity != Verbosity::Quiet { + eprintln!("{}", message.as_ref()); + } + } +} + +impl Default for Logger { + fn default() -> Self { + Self { + verbosity: Verbosity::Quiet, + } + } +} diff --git a/src/main.rs b/src/main.rs index 4d52ca3..f95c372 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,11 @@ use std::{ path::Path, }; -use repo2markdown::{normalizer::Normalizer, renderer::Renderer}; +use repo2markdown::{ + logger::{Logger, Verbosity}, + normalizer::Normalizer, + renderer::Renderer, +}; fn main() -> Result<(), Box> { let mut args = env::args().skip(1); @@ -40,7 +44,15 @@ fn main() -> Result<(), Box> { let stdin = io::stdin(); let stdout = io::stdout(); - run(stdin.lock(), stdout.lock(), root, origin, name.as_deref()) + let logger = Logger::new(Verbosity::Normal); + run( + stdin.lock(), + stdout.lock(), + root, + origin, + name.as_deref(), + logger, + ) } const DEFAULT_PROJECT_NAME: &str = "Project Outline"; @@ -51,13 +63,14 @@ pub fn run( root: &Path, origin_base: &Path, project_name: Option<&str>, + logger: Logger, ) -> Result<(), Box> { let mut buf = Vec::new(); input.read_to_end(&mut buf)?; let normalizer = Normalizer::new(root, origin_base)?; - let mut renderer = Renderer::new(output); + let mut renderer = Renderer::new(output).with_logger(logger); let project_name = project_name.unwrap_or_else(|| derive_project_name(root)); renderer.render_header(project_name)?; @@ -87,10 +100,11 @@ fn derive_project_name(root: &Path) -> &str { mod tests { use std::ffi::OsStr; use std::fs; - use std::io::Cursor; + use std::io::{Cursor, Read, Write}; use std::os::unix::ffi::OsStrExt; use std::path::Path; + use repo2markdown::logger::Logger; use tempfile::tempdir; use super::{DEFAULT_PROJECT_NAME, derive_project_name, run}; @@ -104,6 +118,17 @@ mod tests { output } + fn run_with_default_logger( + input: R, + output: W, + root: &Path, + origin_base: &Path, + project_name: Option<&str>, + ) -> Result<(), Box> { + let logger = Logger::default(); + run(input, output, root, origin_base, project_name, logger) + } + #[test] fn cli_with_empty_input_produces_empty_project_with_specified_project_name() { let temp_dir = tempdir().unwrap(); @@ -112,7 +137,8 @@ mod tests { let root = temp_dir.path(); let origin_base = temp_dir.path(); - run(input, &mut output, root, origin_base, Some("Project name")).unwrap(); + run_with_default_logger(input, &mut output, root, origin_base, Some("Project name")) + .unwrap(); assert_eq!(String::from_utf8(output).unwrap(), "# Project name\n"); } @@ -127,7 +153,7 @@ mod tests { fs::write(origin_base.join("test_main.rs"), "fn main() {}").unwrap(); - run(input, &mut output, root, origin_base, None).unwrap(); + run_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); let output_str = String::from_utf8(output).unwrap(); @@ -146,7 +172,7 @@ mod tests { fs::write(origin_base.join("a.rs"), "A").unwrap(); fs::write(origin_base.join("b.rs"), "B").unwrap(); - run(input, &mut output, root, origin_base, None).unwrap(); + run_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); let output = String::from_utf8(output).unwrap(); @@ -168,7 +194,7 @@ mod tests { fs::create_dir_all(&write_dir).unwrap(); fs::write(write_dir.join("main.rs"), "fn main() {}").unwrap(); - run(input, &mut output, root, origin_base, None).unwrap(); + run_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); let output = String::from_utf8(output).unwrap(); @@ -186,7 +212,7 @@ mod tests { fs::create_dir_all(&origin_base).unwrap(); fs::write(origin_base.join("main.rs"), "fn main() {}").unwrap(); - run(input, &mut output, &root, &origin_base, None).unwrap(); + run_with_default_logger(input, &mut output, &root, &origin_base, None).unwrap(); let output = String::from_utf8(output).unwrap(); @@ -208,7 +234,7 @@ mod tests { let root = temp_dir2.path(); fs::write(&filepath, "fn main() {}").unwrap(); - run(input, &mut output, root, origin_base, None).unwrap(); + run_with_default_logger(input, &mut output, root, origin_base, None).unwrap(); let output = String::from_utf8(output).unwrap(); @@ -224,7 +250,7 @@ mod tests { let mut output = Vec::new(); let root = temp_dir.path().join("repo2markdown"); - run(input, &mut output, &root, origin_base, None).unwrap(); + run_with_default_logger(input, &mut output, &root, origin_base, None).unwrap(); let output_str = String::from_utf8(output).unwrap(); diff --git a/src/renderer.rs b/src/renderer.rs index bb21100..6ebc8ba 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -4,7 +4,7 @@ use std::{ path::Path, }; -use crate::{normalizer::NormalizedPath, util::path_display::display_path}; +use crate::{logger::Logger, normalizer::NormalizedPath, util::path_display::display_path}; const DEFAULT_MAX_FILE_SIZE: u64 = 1_000_000; @@ -12,6 +12,7 @@ const DEFAULT_MAX_FILE_SIZE: u64 = 1_000_000; pub struct Renderer { output: W, max_file_size: u64, + logger: Logger, } impl Renderer { @@ -19,6 +20,7 @@ impl Renderer { Self { output, max_file_size: DEFAULT_MAX_FILE_SIZE, + logger: Logger::default(), } } @@ -27,6 +29,11 @@ impl Renderer { self } + pub fn with_logger(mut self, logger: Logger) -> Self { + self.logger = logger; + self + } + pub fn render_header(&mut self, project_name: &str) -> std::io::Result<()> { writeln!(self.output, "# {}", project_name) } @@ -75,16 +82,19 @@ impl Renderer { } fn warn_about_filesize(&self, filename: &Path, filesize: u64) { - eprintln!( + self.logger.warn(format!( "Warning: skipping large file: {} ({} > limit {})", display_path(filename), human_readable_size(filesize), human_readable_size(self.max_file_size), - ) + )) } fn warn_about_binary_file(&self, filename: &Path) { - eprintln!("Warning: skipping binary file: {}", display_path(filename)) + self.logger.warn(format!( + "Warning: skipping binary file: {}", + display_path(filename) + )) } } -- cgit v1.3.1