Collect up errors and report them instead of panicing
This commit is contained in:
parent
7d90764cbd
commit
fc07ffb480
3 changed files with 41 additions and 23 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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"] }
|
||||||
|
|
|
||||||
52
src/main.rs
52
src/main.rs
|
|
@ -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),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue