diff options
| author | A Farzat <a@farzat.xyz> | 2026-06-06 12:59:45 +0300 |
|---|---|---|
| committer | A Farzat <a@farzat.xyz> | 2026-06-06 12:59:45 +0300 |
| commit | cc23e7734459f3e118dd6204b13296caf83591b2 (patch) | |
| tree | 0500f2a3ca9507b6e7d9a498ced96da794c44689 | |
| parent | e26d589dc129faa3018546239fb2ac4675f5753c (diff) | |
| download | repo2markdown-cc23e7734459f3e118dd6204b13296caf83591b2.tar.gz repo2markdown-cc23e7734459f3e118dd6204b13296caf83591b2.zip | |
Delegate logging management to Logger struct
Allows verbosity management in a centralized way.
| -rw-r--r-- | src/lib.rs | 1 | ||||
| -rw-r--r-- | src/logger.rs | 30 | ||||
| -rw-r--r-- | src/main.rs | 48 | ||||
| -rw-r--r-- | src/renderer.rs | 18 |
4 files changed, 82 insertions, 15 deletions
@@ -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<str>) { + 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<dyn std::error::Error>> { let mut args = env::args().skip(1); @@ -40,7 +44,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { 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<R: Read, W: Write>( root: &Path, origin_base: &Path, project_name: Option<&str>, + logger: Logger, ) -> Result<(), Box<dyn std::error::Error>> { 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<R: Read, W: Write>( + input: R, + output: W, + root: &Path, + origin_base: &Path, + project_name: Option<&str>, + ) -> Result<(), Box<dyn std::error::Error>> { + 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<W: Write> { output: W, max_file_size: u64, + logger: Logger, } impl<W: Write> Renderer<W> { @@ -19,6 +20,7 @@ impl<W: Write> Renderer<W> { Self { output, max_file_size: DEFAULT_MAX_FILE_SIZE, + logger: Logger::default(), } } @@ -27,6 +29,11 @@ impl<W: Write> Renderer<W> { 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<W: Write> Renderer<W> { } 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) + )) } } |
