Convert dbus code and brightclt to anyhow

More migrating away from failure.  Use anyhow for the binary.
4 files changed, 92 insertions(+), 71 deletions(-)

M Cargo.lock
M Cargo.toml
M src/bin/brightctl.rs
M src/dbus.rs
M Cargo.lock +7 -0
@@ 25,6 25,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "anyhow"
+version = "1.0.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
+
+[[package]]
 name = "argon2rs"
 version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"

          
@@ 100,6 106,7 @@ dependencies = [
 name = "bright"
 version = "3.0.0"
 dependencies = [
+ "anyhow",
  "backtrace",
  "clap",
  "ctrlc",

          
M Cargo.toml +1 -0
@@ 9,6 9,7 @@ build = "build.rs"
 edition = "2018"
 
 [dependencies]
+anyhow = "1.0.33"
 backtrace = "0.3.53"
 clap = "2.31"
 ctrlc = {version = "3.1.2", features = ["termination"]}

          
M src/bin/brightctl.rs +38 -47
@@ 1,21 1,21 @@ 
 use std::collections::HashMap;
 
+use anyhow::{Context, Result};
 use clap::value_t;
-use failure::format_err;
 
-// Application configuration
+/// Application configuration
 #[derive(Debug)]
 struct AppConfig {
-    // Which main action to complete.  One for each subcommand.
+    /// Which main action to complete.  One for each subcommand.
     action: Action,
 
-    // If non-empty, a list of device names to limit operations to.
+    /// If non-empty, a list of device names to limit operations to.
     devices: Vec<String>,
 
-    // D-Bus mode
+    /// D-Bus mode
     bustype: DBusType,
 
-    // Minimum brightness value
+    /// Minimum brightness value
     minimum: Option<u32>,
 }
 

          
@@ 27,18 27,23 @@ enum DBusType {
     None,
 }
 
-// The actions the main program can execute
+/// The actions the main program can execute.
 #[derive(Debug)]
 enum Action {
-    Incr(u32), // Increment brightness by %
-    Decr(u32), // Decrement brightness by %
-    Set(u32),  // Set brightness to absolute %
-    Get,       // Print curent brightness as %
-    Watch,     // Watch for changes
+    /// Increment brightness by %.
+    Incr(u32),
+    /// Decrement brightness by %.
+    Decr(u32),
+    /// Set brightness to absolute %.
+    Set(u32),
+    /// Print curent brightness as %.
+    Get,
+    /// Watch for changes.
+    Watch,
 }
 
 impl AppConfig {
-    fn new(argv: &[String]) -> Result<AppConfig, failure::Error> {
+    fn new(argv: &[String]) -> Result<AppConfig> {
         let matches = bright::cli::brightctl_app().get_matches_from(argv);
         let action: Action = match matches.subcommand() {
             ("get", _) => Action::Get,

          
@@ 84,15 89,8 @@ impl AppConfig {
     }
 }
 
-fn main() {
+fn main() -> Result<()> {
     let argv: Vec<String> = std::env::args().collect();
-    run(argv).unwrap_or_else(|err| {
-        print_error(err);
-        std::process::exit(1);
-    });
-}
-
-fn run(argv: Vec<String>) -> Result<(), failure::Error> {
     let appcfg = AppConfig::new(&argv)?;
     match appcfg.action {
         Action::Get => get_brightness(appcfg),

          
@@ 101,14 99,7 @@ fn run(argv: Vec<String>) -> Result<(), 
     }
 }
 
-fn print_error(err: failure::Error) {
-    eprintln!("{}", err);
-    // for cause in err.causes() {
-    //     eprintln!("{}", cause)
-    // }
-}
-
-fn get_brightness(cfg: AppConfig) -> Result<(), failure::Error> {
+fn get_brightness(cfg: AppConfig) -> Result<()> {
     match cfg.bustype {
         DBusType::Auto => match get_brightness_dbus(&cfg) {
             Ok(_) => Ok(()),

          
@@ 119,7 110,7 @@ fn get_brightness(cfg: AppConfig) -> Res
     }
 }
 
-fn get_brightness_dbus(cfg: &AppConfig) -> Result<(), failure::Error> {
+fn get_brightness_dbus(cfg: &AppConfig) -> Result<()> {
     // let client = bright::dbus::Client::new(cfg.bustype, bright::dbus::BUSNAME);
 
     let client = dbus_client(&cfg.bustype)?;

          
@@ 134,7 125,7 @@ fn get_brightness_dbus(cfg: &AppConfig) 
     Ok(())
 }
 
-fn get_brightness_direct(cfg: &AppConfig) -> Result<(), failure::Error> {
+fn get_brightness_direct(cfg: &AppConfig) -> Result<()> {
     let devices = bright::create_devices(cfg.devices.clone())?;
     for dev in devices.iter() {
         println!("{}/{}", dev.name(), dev.get()?);

          
@@ 142,7 133,7 @@ fn get_brightness_direct(cfg: &AppConfig
     Ok(())
 }
 
-fn set_brightness(cfg: AppConfig) -> Result<(), failure::Error> {
+fn set_brightness(cfg: AppConfig) -> Result<()> {
     match cfg.bustype {
         DBusType::Auto => match set_brightness_dbus(&cfg) {
             Ok(_) => Ok(()),

          
@@ 153,7 144,7 @@ fn set_brightness(cfg: AppConfig) -> Res
     }
 }
 
-fn set_brightness_dbus(cfg: &AppConfig) -> Result<(), failure::Error> {
+fn set_brightness_dbus(cfg: &AppConfig) -> Result<()> {
     let client = dbus_client(&cfg.bustype)?;
     for objpath in client.devices()?.iter() {
         let name = client.name(objpath.to_owned())?;

          
@@ 186,7 177,7 @@ fn set_brightness_dbus(cfg: &AppConfig) 
     Ok(())
 }
 
-fn set_brightness_direct(cfg: &AppConfig) -> Result<(), failure::Error> {
+fn set_brightness_direct(cfg: &AppConfig) -> Result<()> {
     let devices = bright::create_devices(cfg.devices.clone())?;
     for dev in devices.iter() {
         match cfg.action {

          
@@ 219,9 210,9 @@ fn set_brightness_direct(cfg: &AppConfig
     Ok(())
 }
 
-fn watch(_cfg: AppConfig) -> Result<(), failure::Error> {
+fn watch(_cfg: AppConfig) -> Result<()> {
     let conn = dbus::Connection::get_private(dbus::BusType::Session)
-        .map_err(|e| failure::err_msg(format!("Failed to create D-Bus connection: {:?}", e)))?;
+        .context("Failed to create D-Bus connection")?;
     conn.add_match("type='signal',sender='be.devork.dbus.bright',interface='org.freedesktop.DBus.Properties',path_namespace='/be/devork/dbus/bright/devices',arg0='be.devork.dbus.bright.BacklightDevice'").unwrap();
     loop {
         for msg in conn.incoming(1000) {

          
@@ 241,13 232,13 @@ fn watch(_cfg: AppConfig) -> Result<(), 
     }
 }
 
-// Create the D-Bus connection.
-//
-// This creates the D-Bus connection and checks the
-// be.devork.dbus.bright busname is registered, respecting the
-// DBusType to connct to the correct bus.  This must not be called
-// with DBusType::None as that does not make sense.
-fn dbus_client(bustype: &DBusType) -> Result<bright::dbus::Client, failure::Error> {
+/// Create the D-Bus connection.
+///
+/// This creates the D-Bus connection and checks the
+/// `be.devork.dbus.bright` busname is registered, respecting the
+/// DBusType to connct to the correct bus.  This must not be called
+/// with [DBusType::None] as that does not make sense.
+fn dbus_client(bustype: &DBusType) -> Result<bright::dbus::Client> {
     if *bustype == DBusType::None {
         panic!("Should not call dbus_connection with DBusType::None");
     }

          
@@ 261,7 252,7 @@ fn dbus_client(bustype: &DBusType) -> Re
             Ok(_) => return Ok(client),
             Err(e) => match *bustype {
                 DBusType::System | DBusType::Session => {
-                    return Err(format_err!(
+                    return Err(anyhow::anyhow!(
                         "{} not found on {:?}: {}",
                         bright::dbus::BUSNAME,
                         bus,

          
@@ 274,7 265,7 @@ fn dbus_client(bustype: &DBusType) -> Re
         },
         Err(e) => match *bustype {
             DBusType::System | DBusType::Session => {
-                return Err(format_err!("Failed to connect to {:?}: {}", bus, e))
+                return Err(anyhow::anyhow!("Failed to connect to {:?}: {}", bus, e))
             }
             DBusType::Auto => (),
             DBusType::None => panic!("oops"),

          
@@ 283,13 274,13 @@ fn dbus_client(bustype: &DBusType) -> Re
     match bright::dbus::Client::new(dbus::BusType::System, bright::dbus::BUSNAME) {
         Ok(client) => match client.ping() {
             Ok(_) => Ok(client),
-            Err(e) => Err(format_err!(
+            Err(e) => Err(anyhow::anyhow!(
                 "{} not found on {:?}: {}",
                 bright::dbus::BUSNAME,
                 bus,
                 e
             )),
         },
-        Err(e) => Err(format_err!("Failed to connect to any D-Bus bus: {}", e)),
+        Err(e) => Err(anyhow::anyhow!("Failed to connect to any D-Bus bus: {}", e)),
     }
 }

          
M src/dbus.rs +46 -24
@@ 29,14 29,16 @@ 
 //!    ever acquire these object paths from the manager.
 
 use std::collections::HashMap;
+use std::error::Error;
+use std::fmt;
 use std::rc::Rc;
 use std::sync::Arc;
 
 use dbus::{self, stdintf::org_freedesktop_dbus::Properties};
-use failure::ResultExt;
-use failure_derive::Fail;
 use log::{debug, error, info};
 
+use crate::error::ErrInfo;
+
 // The public DBus names we use.
 pub static BUSNAME: &str = "be.devork.dbus.bright";
 pub static MANAGER_PATH: &str = "/be/devork/dbus/bright/manager";

          
@@ 619,53 621,73 @@ impl<'a> Client<'a> {
     }
 }
 
-#[derive(Debug)]
 pub struct ClientError {
-    inner: failure::Context<ClientErrorKind>,
+    inner: Box<ErrInfo<ClientErrorKind>>,
 }
 
-#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
 pub enum ClientErrorKind {
-    #[fail(display = "The D-Bus method call return value had an unexpected type")]
     BadReturnType,
-    #[fail(display = "The D-Bus method call failed")]
     CallFailed,
-    #[fail(display = "The brightness value is out of range")]
     BrightnessRange,
 }
 
-impl failure::Fail for ClientError {
-    fn cause(&self) -> Option<&dyn failure::Fail> {
-        self.inner.cause()
-    }
-
-    fn backtrace(&self) -> Option<&failure::Backtrace> {
-        self.inner.backtrace()
+impl fmt::Display for ClientErrorKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            ClientErrorKind::BadReturnType => write!(
+                f,
+                "The D-Bus method call return value had an unexpected type"
+            ),
+            ClientErrorKind::CallFailed => write!(f, "The D-Bus method call failed"),
+            ClientErrorKind::BrightnessRange => write!(f, "The brightness value is out of range"),
+        }
     }
 }
 
-impl std::fmt::Display for ClientError {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-        std::fmt::Display::fmt(&self.inner, f)
+impl fmt::Display for ClientError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(&self.inner, f)
+    }
+}
+
+impl fmt::Debug for ClientError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&self.inner, f)
+    }
+}
+
+impl Error for ClientError {
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        self.inner.source()
     }
 }
 
 impl ClientError {
     pub fn kind(&self) -> ClientErrorKind {
-        *self.inner.get_context()
+        *self.inner.data()
     }
 }
 
 impl From<ClientErrorKind> for ClientError {
     fn from(kind: ClientErrorKind) -> ClientError {
-        ClientError {
-            inner: failure::Context::new(kind),
+        Self {
+            inner: ErrInfo::boxed(kind),
         }
     }
 }
 
-impl From<failure::Context<ClientErrorKind>> for ClientError {
-    fn from(inner: failure::Context<ClientErrorKind>) -> ClientError {
-        ClientError { inner }
+trait ResultExt<T, E> {
+    fn context(self, kind: ClientErrorKind) -> Result<T, ClientError>;
+}
+
+impl<T, E> ResultExt<T, E> for Result<T, E>
+where
+    E: std::error::Error + Send + Sync + 'static,
+{
+    fn context(self, kind: ClientErrorKind) -> Result<T, ClientError> {
+        self.map_err(|err| ClientError {
+            inner: ErrInfo::boxed_with_source(kind, err),
+        })
     }
 }