Collect up errors and report them instead of panicing

This commit is contained in:
Campbell Alden 2023-07-26 15:40:31 +09:00
parent 7d90764cbd
commit fc07ffb480
3 changed files with 41 additions and 23 deletions

9
Cargo.lock generated
View file

@ -66,6 +66,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "anyhow"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@ -354,8 +360,9 @@ dependencies = [
[[package]] [[package]]
name = "time-track" name = "time-track"
version = "0.3.1" version = "0.3.2"
dependencies = [ dependencies = [
"anyhow",
"atty", "atty",
"chrono", "chrono",
"clap", "clap",

View file

@ -1,11 +1,12 @@
[package] [package]
name = "time-track" name = "time-track"
version = "0.3.1" version = "0.3.2"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1.0.72"
atty = "0.2.14" atty = "0.2.14"
chrono = "0.4.26" chrono = "0.4.26"
clap = { version = "4.3.11", features = ["derive"] } clap = { version = "4.3.11", features = ["derive"] }

View file

@ -3,6 +3,7 @@ use std::io::{stdin, BufRead};
use chrono::{NaiveTime, Duration, Local}; use chrono::{NaiveTime, Duration, Local};
use clap::Parser; use clap::Parser;
use atty::Stream; use atty::Stream;
use anyhow::Result;
mod modes; mod modes;
use modes::Modes; use modes::Modes;
@ -15,12 +16,12 @@ struct Args {
#[clap(value_enum, default_value_t = Modes::default())] #[clap(value_enum, default_value_t = Modes::default())]
mode: Modes, mode: Modes,
} }
fn parse_time(time_str: &str) -> NaiveTime { fn parse_time(time_str: &str) -> Result<NaiveTime> {
NaiveTime::parse_from_str(time_str, "%H:%M") let time = NaiveTime::parse_from_str(time_str, "%H:%M")?;
.expect(&format!("Failed to parse time from {time_str}")) Ok(time)
} }
fn all_at_once(is_terminal: bool) -> Vec<Duration> { fn all_at_once(is_terminal: bool) -> Result<Vec<Duration>> {
if is_terminal { if is_terminal {
println!("Enter simple times one per line. Send an EOF character to sum all time spans"); println!("Enter simple times one per line. Send an EOF character to sum all time spans");
} }
@ -28,10 +29,10 @@ fn all_at_once(is_terminal: bool) -> Vec<Duration> {
let mut durations = vec![]; let mut durations = vec![];
let mut seen: Option<String> = None; let mut seen: Option<String> = None;
for line in stdin().lock().lines() { for line in stdin().lock().lines() {
let cleaned = line.expect("failed to read a line").trim().to_string(); let cleaned = line?.trim().to_string();
if let Some(previous) = &seen { if let Some(previous) = &seen {
let first = parse_time(previous); let first = parse_time(previous)?;
let mut second = parse_time(&cleaned); let mut second = parse_time(&cleaned)?;
if second < first { if second < first {
second = second + Duration::hours(12); second = second + Duration::hours(12);
} }
@ -44,10 +45,10 @@ fn all_at_once(is_terminal: bool) -> Vec<Duration> {
if let Some(unpaired) = seen { if let Some(unpaired) = seen {
println!("Ended with an open span from {unpaired}... Ignoring"); println!("Ended with an open span from {unpaired}... Ignoring");
} }
return durations; return Ok(durations);
} }
fn live_spans() -> Vec<Duration> { fn live_spans() -> Result<Vec<Duration>> {
println!("Tracking Spans Live. Press ENTER to start a span\n"); println!("Tracking Spans Live. Press ENTER to start a span\n");
let mut durations = vec![]; let mut durations = vec![];
let mut seen: Option<NaiveTime> = None; let mut seen: Option<NaiveTime> = None;
@ -78,21 +79,21 @@ fn live_spans() -> Vec<Duration> {
} }
durations.push(now - unpaired); durations.push(now - unpaired);
} }
return durations; return Ok(durations);
} }
fn get_prediction() -> NaiveTime { fn get_prediction() -> Result<NaiveTime> {
println!("Calculating an end time prediction...\nWhen did you start?\n"); println!("Calculating an end time prediction...\nWhen did you start?\n");
let mut start_time = String::new(); let mut start_time = String::new();
let _ = stdin().read_line(&mut start_time); let _ = stdin().read_line(&mut start_time);
let start = parse_time(start_time.trim()); let start = parse_time(start_time.trim())?;
println!("Started at {0}", start.format("%H:%M")); println!("Started at {0}", start.format("%H:%M"));
println!("How many minutes were you on break?\n"); println!("How many minutes were you on break?\n");
let mut break_time = String::new(); let mut break_time = String::new();
let _ = stdin().read_line(&mut break_time); let _ = stdin().read_line(&mut break_time);
let break_duration = break_time.trim().parse::<i64>().unwrap(); let break_duration = break_time.trim().parse::<i64>()?;
let work_time = Duration::hours(8) + Duration::minutes(break_duration); let work_time = Duration::hours(8) + Duration::minutes(break_duration);
return start + work_time; return Ok(start + work_time);
} }
fn main() { fn main() {
@ -104,19 +105,28 @@ fn main() {
} }
if args.mode == Modes::Prediction { if args.mode == Modes::Prediction {
println!("Your work will end at {}", get_prediction()); if let Ok(prediction) = get_prediction() {
println!("Your work will end at {}", prediction);
} else {
println!("Something went wrong...");
}
return; return;
} }
let durations = match args.mode { let maybe_durations = match args.mode {
Modes::TimeTable => all_at_once(is_terminal), Modes::TimeTable => all_at_once(is_terminal),
Modes::Live => live_spans(), Modes::Live => live_spans(),
Modes::Prediction => panic!("Should have already returned before this"), Modes::Prediction => Err(anyhow::anyhow!("Should have already returned before this")),
}; };
let total_minutes: i64 = durations.iter().map(|d| { d.num_minutes() }).sum(); match maybe_durations {
let minutes = total_minutes % 60; Ok(durations) => {
let hours = total_minutes / 60; let total_minutes: i64 = durations.iter().map(|d| { d.num_minutes() }).sum();
let minutes = total_minutes % 60;
let hours = total_minutes / 60;
println!("You have been working for {hours} hour(s) and {minutes} minute(s)"); println!("You have been working for {hours} hour(s) and {minutes} minute(s)");
},
Err(err) => eprintln!("{}\nExiting...", err),
}
} }