diff --git a/src/logs.rs b/src/logs.rs new file mode 100644 index 0000000..c2275c6 --- /dev/null +++ b/src/logs.rs @@ -0,0 +1,108 @@ +use comfy_table::presets::UTF8_HORIZONTAL_BORDERS_ONLY; +use comfy_table::{Attribute, Cell, CellAlignment, ContentArrangement, Table}; +use log::error; + +use crate::errors::PaperoniError; + +pub fn display_summary( + initial_article_count: usize, + succesful_articles_table: Table, + errors: Vec, +) { + let successfully_downloaded_count = initial_article_count - errors.len(); + + println!( + "{}", + short_summary( + initial_article_count, + successfully_downloaded_count, + errors.len() + ) + ); + + if successfully_downloaded_count > 0 { + println!("{}", succesful_articles_table); + } + if !errors.is_empty() { + println!( + "{}Failed article downloads{}", + Attribute::Bold, + Attribute::NormalIntensity + ); + let mut table_failed = Table::new(); + table_failed + .load_preset(UTF8_HORIZONTAL_BORDERS_ONLY) + .set_header(vec![ + Cell::new("Link").set_alignment(CellAlignment::Center), + Cell::new("Reason").set_alignment(CellAlignment::Center), + ]) + .set_content_arrangement(ContentArrangement::Dynamic); + + for error in errors { + let error_source = error + .article_source() + .clone() + .unwrap_or_else(|| "".to_string()); + table_failed.add_row(vec![&error_source, &format!("{}", error.kind())]); + error!("{}\n - {}", error, error_source); + } + println!("{}", table_failed); + } +} + +/// Returns a string summary of the total number of failed and successful article downloads +fn short_summary(initial_count: usize, successful_count: usize, failed_count: usize) -> String { + if initial_count != successful_count + failed_count { + panic!("initial_count must be equal to the sum of failed and successful count") + } + let get_noun = |count: usize| if count == 1 { "article" } else { "articles" }; + if successful_count == initial_count { + "All articles downloaded successfully".into() + } else if successful_count == 0 { + "All articles failed to download".into() + } else { + format!( + "{} {} downloaded successfully, {} {} failed", + successful_count, + get_noun(successful_count), + failed_count, + get_noun(failed_count) + ) + } +} + +#[cfg(test)] +mod tests { + use super::short_summary; + #[test] + fn test_short_summary() { + assert_eq!( + short_summary(10, 10, 0), + "All articles downloaded successfully".to_string() + ); + assert_eq!( + short_summary(10, 0, 10), + "All articles failed to download".to_string() + ); + assert_eq!( + short_summary(10, 8, 2), + "8 articles downloaded successfully, 2 articles failed".to_string() + ); + assert_eq!( + short_summary(10, 1, 9), + "1 article downloaded successfully, 9 articles failed".to_string() + ); + assert_eq!( + short_summary(7, 6, 1), + "6 articles downloaded successfully, 1 article failed".to_string() + ); + } + + #[test] + #[should_panic( + expected = "initial_count must be equal to the sum of failed and successful count" + )] + fn test_short_summary_panics_on_invalid_input() { + short_summary(0, 12, 43); + } +} diff --git a/src/main.rs b/src/main.rs index 697b5f3..d23311d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ extern crate lazy_static; use async_std::stream; use async_std::task; use comfy_table::presets::{UTF8_FULL, UTF8_HORIZONTAL_BORDERS_ONLY}; -use comfy_table::{Attribute, Cell, CellAlignment, ContentArrangement, Table}; +use comfy_table::{ContentArrangement, Table}; use futures::stream::StreamExt; use indicatif::{ProgressBar, ProgressStyle}; use log::{debug, warn}; @@ -17,12 +17,14 @@ mod extractor; /// This module is responsible for async HTTP calls for downloading /// the HTML content and images mod http; +mod logs; mod moz_readability; use cli::AppConfig; use epub::generate_epubs; use extractor::Extractor; use http::{download_images, fetch_html}; +use logs::display_summary; fn main() { let app_config = cli::cli_init(); @@ -105,50 +107,9 @@ fn download(app_config: AppConfig) { errors.extend(gen_epub_errors); } }; - let successfully_downloaded_count = app_config.urls().len() - errors.len(); - - println!( - "{} articles downloaded successfully. {}", - if successfully_downloaded_count == app_config.urls().len() { - "All".to_string() - } else { - successfully_downloaded_count.to_string() - }, - if errors.len() > 0 { - errors.len().to_string() + " failed" - } else { - "".to_string() - } - ); - - if successfully_downloaded_count > 0 { - println!("{}", succesful_articles_table); - } - if !errors.is_empty() { - println!( - "{}Failed article downloads{}", - Attribute::Bold, - Attribute::NormalIntensity - ); - let mut table_failed = Table::new(); - table_failed - .load_preset(UTF8_HORIZONTAL_BORDERS_ONLY) - .set_header(vec![ - Cell::new("Link").set_alignment(CellAlignment::Center), - Cell::new("Reason").set_alignment(CellAlignment::Center), - ]) - .set_content_arrangement(ContentArrangement::Dynamic); - - for error in errors { - table_failed.add_row(vec![ - error - .article_source() - .clone() - .unwrap_or_else(|| "".to_string()), - format!("{}", error.kind()), - ]); - } - println!("{}", table_failed); + let has_errors = !errors.is_empty(); + display_summary(app_config.urls().len(), succesful_articles_table, errors); + if has_errors { std::process::exit(1); } }