move most printing/styling into own file

This commit is contained in:
Jörn-Michael Miehe 2025-06-18 18:14:09 +00:00
parent 01bcf92d9c
commit a633f4e228
2 changed files with 86 additions and 85 deletions

View file

@ -3,6 +3,7 @@ mod cachefile;
mod cli; mod cli;
mod file; mod file;
mod impl_ureq; mod impl_ureq;
mod output;
mod sharry; mod sharry;
use std::{ use std::{
@ -15,54 +16,11 @@ use std::{
use clap::Parser; use clap::Parser;
use console::style; use console::style;
use dialoguer::{Select, theme::ColorfulTheme}; use log::{info, trace};
use log::{error, info, trace};
use appstate::AppState; use appstate::AppState;
use cli::Cli; use cli::Cli;
use sharry::ClientError; use output::{Log, SHRUPL, prompt_continue};
fn prompt_continue() -> bool {
let prompt = format!(
"This operation has previously been stopped. {}",
style("How to proceed?").cyan()
);
let choices = [
format!("Load and {}", style("continue operation").green().bold()),
format!("Start a {}", style("new operation").cyan().bold()),
format!("Quit {}", style("ShrUpl").yellow().bold()),
];
let selection = Select::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.default(0)
.items(&choices)
.interact()
.unwrap_or(2);
if selection == 2 {
process::exit(255);
}
selection == 0
}
fn handle_error(e: &ClientError) {
if e.is_fatal() {
// react to fatal error
error!("fatal error: {e:?}");
eprintln!(
"{} {}",
style("Error!").red().bold(),
style(e.to_string()).cyan().italic(),
);
process::exit(1);
}
// handle recoverable error
info!("recoverable error: {e:?}");
}
fn main() { fn main() {
env_logger::init(); env_logger::init();
@ -87,11 +45,7 @@ fn main() {
let args = Cli::parse(); let args = Cli::parse();
info!("args: {args:#?}"); info!("args: {args:#?}");
println!( println!("{} to {}!", style("Welcome").magenta().bold(), *SHRUPL);
"{} to {}!",
style("Welcome").magenta().bold(),
style("ShrUpl").yellow().bold(),
);
let mut state = AppState::try_resume(&args) let mut state = AppState::try_resume(&args)
.and_then(|state| prompt_continue().then_some(state)) .and_then(|state| prompt_continue().then_some(state))
@ -101,34 +55,22 @@ fn main() {
match AppState::from_args(&args) { match AppState::from_args(&args) {
Ok(state) => { Ok(state) => {
state.save().unwrap_or_else(|e| { state.save().unwrap_or_else(|e| {
eprintln!( Log::warning(format_args!("Failed to save state: {e}"));
"{} Failed to save {} state: {e}",
style("Warning:").red().bold(),
style("ShrUpl").yellow().bold(),
);
}); });
state state
} }
Err(e) => { Err(e) => {
handle_error(&e); Log::handle(&e);
process::exit(1); Log::error(format_args!("Failed to create state: {e}"));
} }
} }
}); });
info!("continuing with state: {state:#?}"); info!("continuing with state: {state:#?}");
let fns_magenta = state let fns_magenta = output::style_all(&state.file_names(), |s| style(s).magenta()).join(", ");
.file_names()
.iter()
.map(|&n| style(n).magenta().to_string())
.collect::<Vec<_>>()
.join(", ");
println!( println!("{} is uploading: {fns_magenta}", *SHRUPL);
"{} is uploading: {fns_magenta}",
style("ShrUpl").yellow().bold(),
);
let mut buffer = vec![0; args.chunk_size * 1024 * 1024]; let mut buffer = vec![0; args.chunk_size * 1024 * 1024];
@ -137,14 +79,13 @@ fn main() {
Err(e) => { Err(e) => {
// TODO better error handling (this will just retry endlessly) // TODO better error handling (this will just retry endlessly)
// Error 404: Share might have been deleted // Error 404: Share might have been deleted
handle_error(&e); Log::handle(&e);
if let Some(s) = state.rewind() { if let Some(s) = state.rewind() {
trace!("State rewound, retrying last chunk"); trace!("State rewound, retrying last chunk");
state = s; state = s;
} else { } else {
eprintln!("{} Failed to retry chunk!", style("Error:").red().bold()); Log::error("Failed to retry chunk!");
process::exit(1);
} }
} }
Ok(false) => { Ok(false) => {
@ -157,26 +98,14 @@ fn main() {
} }
state.save().unwrap_or_else(|e| { state.save().unwrap_or_else(|e| {
eprintln!( Log::warning(format_args!("Failed to save state: {e}"));
"{} Failed to save {} state: {e}",
style("Warning:").red().bold(),
style("ShrUpl").yellow().bold(),
);
}); });
check_ctrlc(); check_ctrlc();
} }
state.clear().unwrap_or_else(|e| { state.clear().unwrap_or_else(|e| {
eprintln!( Log::warning(format_args!("Failed to remove state: {e}"));
"{} Failed to remove {} state: {e}",
style("Warning:").red().bold(),
style("ShrUpl").yellow().bold(),
);
}); });
println!( println!("{} finished {}", *SHRUPL, style("successfully!").green());
"{} finished {}",
style("ShrUpl").yellow().bold(),
style("successfully!").green()
);
} }

72
src/output.rs Normal file
View file

@ -0,0 +1,72 @@
use std::{fmt, process, sync::LazyLock};
use console::{StyledObject, style};
use dialoguer::{Select, theme::ColorfulTheme};
use log::{error, info};
use crate::sharry;
type StaticStyled<'t> = LazyLock<StyledObject<&'t str>>;
pub static SHRUPL: StaticStyled = LazyLock::new(|| style("ShrUpl").yellow().bold());
pub fn prompt_continue() -> bool {
let prompt = format!(
"This operation has previously been stopped. {}",
style("How to proceed?").cyan()
);
let choices = [
format!("Load and {}", style("continue operation").green().bold()),
format!("Start a {}", style("new operation").cyan().bold()),
format!("Quit {}", *SHRUPL),
];
let selection = Select::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.default(0)
.items(&choices)
.interact()
.unwrap_or(2);
if selection == 2 {
process::exit(0);
}
selection == 0
}
pub fn style_all<'t, F>(strs: &[&'t str], f: F) -> Vec<String>
where
F: Fn(&'t str) -> StyledObject<&'t str>,
{
strs.iter().map(|&s| f(s).to_string()).collect()
}
pub enum Log {}
impl Log {
fn eprintln(kind: impl fmt::Display, msg: impl fmt::Display) {
eprintln!("{} {}: {}", *SHRUPL, kind, style(msg).cyan().italic(),);
}
pub fn warning(msg: impl fmt::Display) {
Self::eprintln(style("Warning").magenta().bold(), msg);
}
pub fn error(msg: impl fmt::Display) -> ! {
Self::eprintln(style("Error").red().bold(), msg);
process::exit(1);
}
pub fn handle(e: &sharry::ClientError) {
if e.is_fatal() {
// react to fatal error
error!("fatal error: {e:?}");
Self::error(e);
}
// handle recoverable error
info!("recoverable error: {e:?}");
}
}