From b18c6b8135bfdc884b0a0cf03196d3de0a343490 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 7 Nov 2018 19:49:21 -0500 Subject: better top level error handling --- src/db.rs | 23 ++++++++++++++++++++--- src/main.rs | 46 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/db.rs b/src/db.rs index b291e86..0d81d7e 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,6 +1,8 @@ use error::Result; use lastfm; +use failure::Fail; + const SCHEMA: &'static str = " CREATE TABLE `tracks` ( artist varchar(1024) NOT NULL, @@ -17,7 +19,14 @@ pub struct DB { impl DB { pub fn new>(path: &P) -> Result { let conn = if path.as_ref().exists() { - rusqlite::Connection::open(path)? + rusqlite::Connection::open(path) + .map_err(|e| { + let msg = format!( + "couldn't open db at {}", + path.as_ref().display() + ); + e.context(msg) + })? } else { Self::create(path)? @@ -36,8 +45,16 @@ impl DB { if let Some(parent) = path.as_ref().parent() { std::fs::create_dir_all(parent)?; - let conn = rusqlite::Connection::open(path)?; - conn.execute(SCHEMA, rusqlite::NO_PARAMS)?; + let conn = rusqlite::Connection::open(path) + .map_err(|e| { + let msg = format!( + "couldn't create db at {}", + path.as_ref().display() + ); + e.context(msg) + })?; + conn.execute(SCHEMA, rusqlite::NO_PARAMS) + .map_err(|e| e.context("failed to execute schema"))?; Ok(conn) } else { diff --git a/src/main.rs b/src/main.rs index c4c255e..4d66a92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #[macro_use] extern crate clap; extern crate directories; +#[macro_use] extern crate failure; extern crate indicatif; extern crate reqwest; @@ -17,15 +18,14 @@ mod lastfm; mod paths; mod db; -fn main() { - let opts = cli::get_options(); +use error::Result; - let db = db::DB::new(&paths::dbpath()) - .expect("failed to create db"); +fn run(opts: cli::Options) -> Result<()> { + let db = db::DB::new(&paths::dbpath())?; let lastfm = lastfm::LastFMClient::new(&opts.api_key, &opts.username); let exporter = exporter::Exporter::new(&db, &lastfm); - let to_fetch = exporter.tracks_to_sync().unwrap(); + let to_fetch = exporter.tracks_to_sync()?; println!("need to download {} tracks", to_fetch); let bar = indicatif::ProgressBar::new(to_fetch); @@ -35,8 +35,40 @@ fn main() { .template("{percent:>3}% [{wide_bar}] {eta:5}") ); - exporter.sync(|_| { bar.inc(1); }) - .expect("failed to update db"); + exporter.sync(|_| { bar.inc(1); })?; bar.finish_with_message("done"); + + Ok(()) +} + +fn program_name() -> Result { + let program = std::env::args() + .next() + .ok_or_else(|| format_err!("no program name found"))?; + let path = std::path::Path::new(&program); + let filename = path.file_name() + .ok_or_else(|| format_err!("invalid filename found"))? + .to_string_lossy() + .to_string(); + Ok(filename) +} + +fn main() { + let opts = cli::get_options(); + match run(opts) { + Ok(_) => {}, + Err(e) => { + let name = program_name() + .unwrap_or_else(|e| { + eprintln!("{}", e); + "?".to_string() + }); + let cause = e + .iter_chain() + .fold(String::new(), |acc, x| acc + ": " + &format!("{}", x)); + eprintln!("{}{}", name, cause); + std::process::exit(1); + } + } } -- cgit v1.2.3