From 4bbd0b2137929bba3b125eb111517cc88edc3805 Mon Sep 17 00:00:00 2001 From: Katharina Fey Date: Thu, 25 Feb 2021 00:43:49 +0100 Subject: [PATCH] koffice: improve cass error handling, reporting, and logging --- apps/koffice/libko/src/cass/data.rs | 4 ++- apps/koffice/libko/src/cass/error.rs | 44 ++++++++++++++++++++---- apps/koffice/libko/src/cass/format/ir.rs | 20 ++++++++++- apps/koffice/libko/src/cass/timeline.rs | 14 +++++--- 4 files changed, 69 insertions(+), 13 deletions(-) diff --git a/apps/koffice/libko/src/cass/data.rs b/apps/koffice/libko/src/cass/data.rs index 4ff4dc93020..456cb2c6d1f 100644 --- a/apps/koffice/libko/src/cass/data.rs +++ b/apps/koffice/libko/src/cass/data.rs @@ -54,7 +54,9 @@ impl TimeFile { tt: IrType::Invoice(date), lo, } => Ok(self.timeline.invoice(date).map(|_| ())?), - _ => Err(ParseError::Unknown), + _ => Ok(()), // Any other IrType will be ignored, and thus + // we simply return Ok(()) to signal to the + // parser to keep going. } } } diff --git a/apps/koffice/libko/src/cass/error.rs b/apps/koffice/libko/src/cass/error.rs index 24bbb496549..5ed176d2bba 100644 --- a/apps/koffice/libko/src/cass/error.rs +++ b/apps/koffice/libko/src/cass/error.rs @@ -1,5 +1,5 @@ //! A set of error types for cassiopeia - +use crate::cass::{Date, Time}; use std::fmt::{self, Display, Formatter}; use std::{error::Error, io}; @@ -12,18 +12,28 @@ use std::{error::Error, io}; #[derive(Debug)] pub enum UserError { /// Trying to start a session when one exists - ActiveSessionExists, + ActiveSessionExists(Time), /// Trying to stop a session when none exists - NoActiveSession, + NoActiveSession(Time), /// Trying to create a second invoice on the same day - SameDayInvoice, + SameDayInvoice(Date), /// No work was done since the last invoice - NoWorkInvoice, + NoWorkInvoice(Date), } impl Display for UserError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "You're doing it wrong!") + write!( + f, + "{}", + match self { + Self::ActiveSessionExists(t) => + format!("Session since '{}' in progress", t.to_string()), + Self::NoActiveSession(t) => format!("No session before '{}'", t.to_string()), + Self::SameDayInvoice(d) => format!("More than one invoice on '{}'", d.to_string()), + Self::NoWorkInvoice(d) => format!("No work done before '{}'", d.to_string()), + } + ) } } @@ -59,13 +69,33 @@ pub enum ParseError { BadTimestamp { line: usize, tokn: String }, /// A bad date was found BadDate { line: usize, tokn: String }, + /// An unexpected sequence was found + Unexpected { line: usize, tokn: String }, /// An unknown parse error occured Unknown, } impl Display for ParseError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "The parsed file was bad :(") + write!( + f, + "{}", + match self { + Self::User(err) => format!("User error: {}", err), + Self::NoSuchFile => "The file does not exist".into(), + Self::BadPermissions => "Insufficient permissions to read the file".into(), + Self::FileNotWritable => "Insufficient permissions to write the file".into(), + Self::FileUnknown(file) => format!("System I/O error: {}", file), + Self::BadKeyword { line, tokn } => + format!("Invalid keyword '{}' on line {}", tokn, line), + Self::BadTimestamp { line, tokn } => + format!("Invalid timestamp '{}' on line {}", tokn, line), + Self::BadDate { line, tokn } => format!("Invalid date '{}' on line {}", tokn, line), + Self::Unexpected { line, tokn } => + format!("Unexpected token '{}' on line {}", tokn, line), + Self::Unknown => "An unknown error occured".into(), + } + ) } } diff --git a/apps/koffice/libko/src/cass/format/ir.rs b/apps/koffice/libko/src/cass/format/ir.rs index d1a3a62c150..e90ed5d7030 100644 --- a/apps/koffice/libko/src/cass/format/ir.rs +++ b/apps/koffice/libko/src/cass/format/ir.rs @@ -1,5 +1,5 @@ use crate::cass::{format::LineCfg, Date, Time, TimeFile}; -use std::collections::BTreeMap; +use std::{collections::BTreeMap, string::ToString}; /// A set of IR parsed items that makes up a whole cass file pub(crate) type IrStream = Vec; @@ -39,6 +39,24 @@ pub(crate) enum IrType { Ignore, } +impl ToString for IrType { + fn to_string(&self) -> String { + match self { + Self::Header(map) => format!( + "Header map [{}]", + map.iter().fold(String::new(), |mut s, (k, v)| { + s.push_str(&format!("{}={}", k, v)); + s + }) + ), + Self::Start(t) => format!("Start (time = {})", t.to_string()), + Self::Stop(t) => format!("Stop (time = {})", t.to_string()), + Self::Invoice(d) => format!("Invoice (date = {})", d.to_string()), + Self::Ignore => "Ignored line".into(), + } + } +} + /// Generate a stream of IR items from the raw parser output pub(crate) fn generate_ir(buf: impl Iterator) -> IrStream { buf.enumerate().fold(vec![], |mut buf, (lo, item)| { diff --git a/apps/koffice/libko/src/cass/timeline.rs b/apps/koffice/libko/src/cass/timeline.rs index b9a2826de5c..2751d8ae6e6 100644 --- a/apps/koffice/libko/src/cass/timeline.rs +++ b/apps/koffice/libko/src/cass/timeline.rs @@ -92,19 +92,22 @@ impl Timeline { /// Start a new session, if no active session is already in progress pub fn start(&mut self, time: Time) -> UserResult { + trace!("Starting session {}", time.to_string()); match self.last_session() { - Some(s) if !s.finished() => Err(UserError::ActiveSessionExists), + Some(s) if !s.finished() => Err(UserError::ActiveSessionExists(time.clone())), _ => Ok(()), }?; self.inner.push(Session::start(time.clone()).into()); + self.last_session(); Ok(Delta::Start(time)) } /// Stop an ongoing session, if one exists pub fn stop(&mut self, time: Time) -> UserResult { + trace!("Stopping session {}", time.to_string()); match self.last_session() { - Some(s) if s.finished() => Err(UserError::NoActiveSession), + Some(s) if s.finished() => Err(UserError::NoActiveSession(time.clone())), _ => Ok(()), }?; @@ -114,11 +117,14 @@ impl Timeline { /// Create a new invoice on the given day pub fn invoice(&mut self, date: Date) -> UserResult { + trace!("Applying invoice {}", date.to_string()); match self.last_invoice() { // If an invoice on the same day exists already - Some(i) if i.date == date => Err(UserError::SameDayInvoice), + Some(i) if i.date == date => Err(UserError::SameDayInvoice(date.clone())), // If there was no work since the last invoice - Some(ref i) if self.session_iter(&i.date).len() == 0 => Err(UserError::NoWorkInvoice), + Some(ref i) if self.session_iter(&i.date).len() == 0 => { + Err(UserError::NoWorkInvoice(date.clone())) + } // Otherwise everything is coolio _ => Ok(()), }?;