diff --git a/Cargo.lock b/Cargo.lock index 37ccdeb..4ccacc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,6 +66,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" + [[package]] name = "atty" version = "0.2.14" @@ -354,8 +360,9 @@ dependencies = [ [[package]] name = "time-track" -version = "0.3.1" +version = "0.3.2" dependencies = [ + "anyhow", "atty", "chrono", "clap", diff --git a/Cargo.toml b/Cargo.toml index 077c2e7..880c8e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "time-track" -version = "0.3.1" +version = "0.3.2" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.72" atty = "0.2.14" chrono = "0.4.26" clap = { version = "4.3.11", features = ["derive"] } diff --git a/src/main.rs b/src/main.rs index 28fc149..2a9e7ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use std::io::{stdin, BufRead}; use chrono::{NaiveTime, Duration, Local}; use clap::Parser; use atty::Stream; +use anyhow::Result; mod modes; use modes::Modes; @@ -15,12 +16,12 @@ struct Args { #[clap(value_enum, default_value_t = Modes::default())] mode: Modes, } -fn parse_time(time_str: &str) -> NaiveTime { - NaiveTime::parse_from_str(time_str, "%H:%M") - .expect(&format!("Failed to parse time from {time_str}")) +fn parse_time(time_str: &str) -> Result { + let time = NaiveTime::parse_from_str(time_str, "%H:%M")?; + Ok(time) } -fn all_at_once(is_terminal: bool) -> Vec { +fn all_at_once(is_terminal: bool) -> Result> { if is_terminal { 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 { let mut durations = vec![]; let mut seen: Option = None; 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 { - let first = parse_time(previous); - let mut second = parse_time(&cleaned); + let first = parse_time(previous)?; + let mut second = parse_time(&cleaned)?; if second < first { second = second + Duration::hours(12); } @@ -44,10 +45,10 @@ fn all_at_once(is_terminal: bool) -> Vec { if let Some(unpaired) = seen { println!("Ended with an open span from {unpaired}... Ignoring"); } - return durations; + return Ok(durations); } -fn live_spans() -> Vec { +fn live_spans() -> Result> { println!("Tracking Spans Live. Press ENTER to start a span\n"); let mut durations = vec![]; let mut seen: Option = None; @@ -78,21 +79,21 @@ fn live_spans() -> Vec { } durations.push(now - unpaired); } - return durations; + return Ok(durations); } -fn get_prediction() -> NaiveTime { +fn get_prediction() -> Result { println!("Calculating an end time prediction...\nWhen did you start?\n"); let mut start_time = String::new(); 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!("How many minutes were you on break?\n"); let mut break_time = String::new(); let _ = stdin().read_line(&mut break_time); - let break_duration = break_time.trim().parse::().unwrap(); + let break_duration = break_time.trim().parse::()?; let work_time = Duration::hours(8) + Duration::minutes(break_duration); - return start + work_time; + return Ok(start + work_time); } fn main() { @@ -104,19 +105,28 @@ fn main() { } 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; } - let durations = match args.mode { + let maybe_durations = match args.mode { Modes::TimeTable => all_at_once(is_terminal), 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(); - let minutes = total_minutes % 60; - let hours = total_minutes / 60; + match maybe_durations { + Ok(durations) => { + 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), + } }