diff --git a/src/errors.rs b/src/errors.rs index 5debda75a..2473668c5 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,9 +1,5 @@ error_chain!{ - foreign_links { - Io(::std::io::Error); - StrFromUtf8(::std::str::Utf8Error); - StringFromUtf8(::std::string::FromUtf8Error); - StringFromUtf16(::std::string::FromUtf16Error); + links { + Tdb2Error(::tdb2::errors::Error, ::tdb2::errors::ErrorKind); } - } diff --git a/src/main.rs b/src/main.rs index f8b3f6f82..26a81b551 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![recursion_limit = "1024"] + extern crate chrono; extern crate uuid; #[macro_use] @@ -12,12 +14,34 @@ use std::io::stdin; use errors::*; -quick_main!(run); +fn main() { + if let Err(ref e) = run() { + use std::io::Write; + let stderr = &mut ::std::io::stderr(); + let errmsg = "Error writing to stderr"; + + writeln!(stderr, "error: {}", e).expect(errmsg); + + for e in e.iter().skip(1) { + writeln!(stderr, "caused by: {}", e).expect(errmsg); + } + + // The backtrace is not always generated. Try to run this example + // with `RUST_BACKTRACE=1`. + if let Some(backtrace) = e.backtrace() { + writeln!(stderr, "backtrace: {:?}", backtrace).expect(errmsg); + } + + ::std::process::exit(1); + } +} fn run() -> Result<()> { let input = stdin(); - parse(input.lock())?.iter().for_each(|t| { - println!("{:?}", t); - }); + parse("".to_string(), input.lock())? + .iter() + .for_each(|t| { + println!("{:?}", t); + }); Ok(()) } diff --git a/src/tdb2/errors.rs b/src/tdb2/errors.rs new file mode 100644 index 000000000..5e4b014e9 --- /dev/null +++ b/src/tdb2/errors.rs @@ -0,0 +1,15 @@ +error_chain!{ + foreign_links { + Io(::std::io::Error); + StrFromUtf8(::std::str::Utf8Error); + StringFromUtf8(::std::string::FromUtf8Error); + StringFromUtf16(::std::string::FromUtf16Error); + } + + errors { + ParseError(filename: String, line: u64) { + description("TDB2 parse error"), + display("TDB2 parse error at {}:{}", filename, line), + } + } +} diff --git a/src/tdb2/ff4.rs b/src/tdb2/ff4.rs index f51edc826..c9b253c2d 100644 --- a/src/tdb2/ff4.rs +++ b/src/tdb2/ff4.rs @@ -2,7 +2,7 @@ use std::str; use super::pig::Pig; use task::{TaskBuilder, Task}; -use errors::*; +use super::errors::*; /// Rust implementation of part of utf8_codepoint from Taskwarrior's src/utf8.cpp /// diff --git a/src/tdb2/mod.rs b/src/tdb2/mod.rs index 0e29d4c0b..4f82aa007 100644 --- a/src/tdb2/mod.rs +++ b/src/tdb2/mod.rs @@ -1,15 +1,21 @@ +//! TDB2 is Taskwarrior's on-disk database format. This module implements +//! support for the data structure as a compatibility layer. + mod pig; mod ff4; +pub(super) mod errors; use std::io::BufRead; use task::Task; use self::ff4::parse_ff4; -use errors::*; +use self::errors::*; -pub(super) fn parse(reader: impl BufRead) -> Result> { +pub(super) fn parse(filename: String, reader: impl BufRead) -> Result> { let mut tasks = vec![]; - for line in reader.lines() { - tasks.push(parse_ff4(&line?)?); + for (i, line) in reader.lines().enumerate() { + tasks.push(parse_ff4(&line?).chain_err(|| { + ErrorKind::ParseError(filename.clone(), i as u64 + 1) + })?); } Ok(tasks) } diff --git a/src/tdb2/pig.rs b/src/tdb2/pig.rs index a8995a80e..1640c777b 100644 --- a/src/tdb2/pig.rs +++ b/src/tdb2/pig.rs @@ -1,7 +1,7 @@ //! A minimal implementation of the "Pig" parsing utility from the Taskwarrior //! source. This is just enough to parse FF4 lines. -use errors::*; +use super::errors::*; pub struct Pig<'a> { input: &'a [u8],