From dea860819e7c0439debfcdd3050408e1e6cef10f Mon Sep 17 00:00:00 2001 From: Akshay Date: Sat, 20 May 2023 17:43:05 +0530 Subject: add base cli --- src/error.rs | 2 +- src/feed.rs | 3 +- src/lib.rs | 17 +++++++ src/main.rs | 138 +++++++++++++++++++++++++++++++++++++++++++++------------ src/manager.rs | 11 +++-- src/status.rs | 35 +++++++++++---- 6 files changed, 162 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/error.rs b/src/error.rs index 8a2059e..2638fc2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,7 +10,7 @@ pub enum Error { #[error("error parsing entry: {0}")] Entry(#[from] EntryError), - #[error("error adding field: {0}")] + #[error("error adding feed: {0}")] Add(#[from] AddError), } diff --git a/src/feed.rs b/src/feed.rs index 3926fd4..2875667 100644 --- a/src/feed.rs +++ b/src/feed.rs @@ -87,10 +87,11 @@ impl Feed { .partition(Result::is_ok); // pull status + let title = self.title.clone(); let count = entries.len().saturating_sub(self.total_count()); let errors = errors.into_iter().map(Result::unwrap_err).collect(); - let pull_status = PullStatus::new(count, errors); + let pull_status = PullStatus::new(title, count, errors); // update entries self.entries = entries.into_iter().map(Result::unwrap).collect(); diff --git a/src/lib.rs b/src/lib.rs index b66a7b4..867a09c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,3 +3,20 @@ pub mod error; pub mod feed; pub mod manager; pub mod status; + +pub trait PrintResult { + fn print(&self); +} + +impl PrintResult for Result +where + T: std::fmt::Display, + E: std::fmt::Display, +{ + fn print(&self) { + match self { + Ok(ok) => println!("{ok}"), + Err(err) => eprintln!("{err}"), + } + } +} diff --git a/src/main.rs b/src/main.rs index fccc7fd..65de274 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,37 +1,117 @@ -use syn::manager::Manager; +use clap::{Args, Parser, Subcommand, ValueEnum}; +use syn::{manager::Manager, PrintResult}; -#[tokio::main(flavor = "current_thread")] -async fn main() { - let mut manager = Manager::default(); - - let feeds = vec![ - "https://peppe.rs/index.xml", - "https://jvns.ca/atom.xml", - // "https://www.youtube.com/feeds/videos.xml?channel_id=UCuTaETsuCOkJ0H_GAztWt0Q", - ]; - - for f in feeds { - match manager.add_feed(f).await { - Ok(s) => println!("{s}"), - Err(e) => println!("{e}"), - } - } +// #[tokio::main(flavor = "current_thread")] +// async fn main() { +// let mut manager = Manager::load().unwrap(); +// +// let feeds = vec![ +// "https://peppe.rs/index.xml", +// "https://jvns.ca/atom.xml", +// // "https://www.youtube.com/feeds/videos.xml?channel_id=UCuTaETsuCOkJ0H_GAztWt0Q", +// ]; +// +// for f in feeds { +// match manager.add_feed(f).await { +// Ok(s) => println!("{s}"), +// Err(e) => println!("{e}"), +// } +// } +// +// for entry in manager.list_entries() { +// println!("{entry}"); +// } +// +// match manager.store() { +// Ok(s) => println!("{s}"), +// Err(e) => eprintln!("{e}"), +// } +// +// // let mut feed = Feed::new(url); +// +// // feed.resolve().await.unwrap(); +// +// // let last_read = DateTime::parse_from_rfc2822("Mon, 16 Mar 2020 18:30:00 +0000") +// // .unwrap() +// // .with_timezone(&Utc); +// +// // feed.last_read = last_read; +// +// // for i in feed.unread().unwrap() { +// // println!("{}", i.title.as_ref().unwrap().content) +// // } +// } - for entry in manager.list_entries() { - println!("{entry}"); - } +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Cli { + #[command(subcommand)] + command: Option, +} - // let mut feed = Feed::new(url); +#[derive(Subcommand)] +enum Command { + Add(AddCommand), + List(ListCommand), + Pull(PullCommand), +} - // feed.resolve().await.unwrap(); +#[derive(Args)] +struct AddCommand { + url: String, +} - // let last_read = DateTime::parse_from_rfc2822("Mon, 16 Mar 2020 18:30:00 +0000") - // .unwrap() - // .with_timezone(&Utc); +#[derive(Args)] +struct ListCommand { + #[arg(value_enum)] + target: ListTarget, +} - // feed.last_read = last_read; +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +enum ListTarget { + Feeds, + Entries, +} - // for i in feed.unread().unwrap() { - // println!("{}", i.title.as_ref().unwrap().content) - // } +#[derive(Args)] +struct PullCommand { + target: Option, +} + +#[tokio::main(flavor = "current_thread")] +async fn main() { + let opts = Cli::parse(); + match &opts.command { + Some(Command::Add(AddCommand { url })) => { + let mut manager = Manager::load().unwrap_or_else(|e| { + eprintln!("{e}"); + Manager::default() + }); + + manager.add_feed(&url).await.print(); + manager.store().print(); + } + Some(Command::List(ListCommand { target })) => { + let manager = Manager::load().unwrap_or_else(|e| { + eprintln!("{e}"); + Manager::default() + }); + match target { + ListTarget::Feeds => manager.list_feeds().for_each(|f| println!("{f}")), + ListTarget::Entries => manager.list_entries().for_each(|f| println!("{f}")), + } + } + Some(Command::Pull(PullCommand { .. })) => { + let mut manager = Manager::load().unwrap_or_else(|e| { + eprintln!("{e}"); + Manager::default() + }); + let (status, errors): (Vec<_>, Vec<_>) = + manager.pull().await.into_iter().partition(Result::is_ok); + status.iter().for_each(PrintResult::print); + errors.iter().for_each(PrintResult::print); + manager.store().print(); + } + _ => {} + } } diff --git a/src/manager.rs b/src/manager.rs index 839c8dc..74f449b 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -49,15 +49,18 @@ impl Manager { self.feeds.iter() } - pub async fn store(&self) -> Result { + pub fn store(&self) -> Result { let path = crate::dirs::store_path().ok_or(IOError::MissingStorePath)?; let content = serde_yaml::to_string(&self.feeds)?; - std::fs::write(path, content)?; - Ok(StoreStatus::new(self.feeds.len())) + std::fs::write(&path, content)?; + + let count = self.feeds.len(); + let location = path; + Ok(StoreStatus::new(count, location)) } - pub async fn load() -> Result { + pub fn load() -> Result { let path = crate::dirs::store_path().ok_or(IOError::MissingStorePath)?; let content = std::fs::read_to_string(path)?; let feeds = serde_yaml::from_str(&content)?; diff --git a/src/status.rs b/src/status.rs index 6874e88..7e51160 100644 --- a/src/status.rs +++ b/src/status.rs @@ -1,15 +1,23 @@ +use std::{fmt, path::PathBuf}; + use crate::error::EntryError; -use std::fmt; + +use ansi_term::Style; #[derive(Debug)] pub struct PullStatus { + title: String, count: usize, errors: Vec, } impl PullStatus { - pub fn new(count: usize, errors: Vec) -> Self { - Self { count, errors } + pub fn new(title: String, count: usize, errors: Vec) -> Self { + Self { + title, + count, + errors, + } } } @@ -17,9 +25,10 @@ impl fmt::Display for PullStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "pulled {} entries with {} errors", - self.count, - self.errors.len() + "{:<20}: pulled {:>4} entries with {:>4} errors", + Style::new().bold().paint(self.title.to_ascii_lowercase()), + Style::new().bold().paint(self.count.to_string()), + Style::new().bold().paint(self.errors.len().to_string()) ) } } @@ -27,16 +36,24 @@ impl fmt::Display for PullStatus { #[derive(Debug)] pub struct StoreStatus { count: usize, + location: PathBuf, } impl StoreStatus { - pub fn new(count: usize) -> Self { - Self { count } + pub fn new(count: usize, location: PathBuf) -> Self { + Self { count, location } } } impl fmt::Display for StoreStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "stored {} feeds", self.count,) + write!( + f, + "cached {: >4} feeds to {}", + Style::new().bold().paint(self.count.to_string()), + Style::new() + .bold() + .paint(self.location.display().to_string()) + ) } } -- cgit v1.2.3