diff --git a/varlink-certification/Cargo.toml b/varlink-certification/Cargo.toml index 3718220..daac6ef 100644 --- a/varlink-certification/Cargo.toml +++ b/varlink-certification/Cargo.toml @@ -13,7 +13,7 @@ serde = "1.0.102" serde_derive = "1.0.102" serde_json = "1.0.41" getopts = "0.2.21" -chainerror = "1" +thiserror = "2.0.3" [build-dependencies] varlink_generator = { path = "../varlink_generator" } diff --git a/varlink-certification/src/main.rs b/varlink-certification/src/main.rs index b8117da..cba8233 100644 --- a/varlink-certification/src/main.rs +++ b/varlink-certification/src/main.rs @@ -8,7 +8,6 @@ use std::time::Instant; pub type Result = std::result::Result>; -use chainerror::Context; use varlink::{Connection, StringHashMap, StringHashSet, VarlinkService}; mod org_varlink_certification { @@ -72,7 +71,7 @@ fn main() -> Result<()> { let connection = match matches.opt_str("varlink") { None => match matches.opt_str("bridge") { Some(bridge) => Connection::with_bridge(&bridge) - .context(format!("Connection::with_bridge({})", bridge))?, + .map_err(|e| format!("Connection::with_bridge({bridge}): {e}"))?, None => Connection::with_activate(&format!( "{} \ --varlink=$VARLINK_ADDRESS", @@ -80,7 +79,7 @@ fn main() -> Result<()> { ))?, }, Some(address) => Connection::with_address(&address) - .context(format!("Connection::with_address({})", address))?, + .map_err(|e| format!("Connection::with_address({address}): {e}"))?, }; run_client(connection)? } else if let Some(address) = matches.opt_str("varlink") { diff --git a/varlink-cli/Cargo.toml b/varlink-cli/Cargo.toml index ad4d971..0998710 100644 --- a/varlink-cli/Cargo.toml +++ b/varlink-cli/Cargo.toml @@ -18,11 +18,11 @@ path = "src/main.rs" [dependencies] varlink = { version = "11", path = "../varlink" } varlink_stdinterfaces = { version = "11", path = "../varlink_stdinterfaces" } -varlink_parser = { version = "4.3", path = "../varlink_parser" } +varlink_parser = { version = "5.0", path = "../varlink_parser" } serde = "1.0.102" serde_json = "1.0.41" clap = "2.33.0" colored_json = "2.1.0" -chainerror = "0.8.0" +anyhow = "1.0.93" libc = { version = "0.2.126", default-features = false } bitflags = "1.2.1" diff --git a/varlink-cli/src/main.rs b/varlink-cli/src/main.rs index 7923a38..d308e92 100644 --- a/varlink-cli/src/main.rs +++ b/varlink-cli/src/main.rs @@ -5,7 +5,6 @@ use std::io::prelude::*; use std::path::Path; use std::str; -use chainerror::prelude::v1::*; use clap::{App, Arg, SubCommand}; use colored_json::{ColorMode, ColoredFormatter, Colour, Output, PrettyFormatter, Style, Styler}; @@ -26,14 +25,12 @@ pub type Result = std::result::Result, should_colorize: bool) -> Result<()> { let mut buffer = String::new(); File::open(Path::new(filename)) - .context(format!("Failed to open '{}'", filename))? + .map_err(|e| format!("Failed to open '{filename}': {e}"))? .read_to_string(&mut buffer) - .context(format!("Failed to read '{}'", filename))?; + .map_err(|e| format!("Failed to read '{filename}': {e}"))?; - let idl = IDL::try_from(buffer.as_str()).map_context(|e| { - let v: Vec<_> = e.iter().map(ToString::to_string).collect(); - v.join("\n") - })?; + let idl = + IDL::try_from(buffer.as_str()).map_err(|e| format!("Failed to parse '{filename}': {e}"))?; if should_colorize { println!( @@ -64,25 +61,26 @@ fn varlink_info( let connection = match activate { Some(activate) => Connection::with_activate(activate) - .context(format!("Failed to connect with activate '{}'", activate))?, + .map_err(|e| format!("Failed to connect with activate '{activate}': {e}"))?, None => match bridge { Some(bridge) => Connection::with_bridge(bridge) - .context(format!("Failed to connect with bridge '{}'", bridge))?, + .map_err(|e| format!("Failed to connect with bridge '{bridge}': {e}"))?, None => { let address = address.unwrap(); if address.rfind(':').is_none() { - let conn = Connection::new(resolver) - .context(format!("Failed to connect with resolver '{}'", resolver))?; + let conn = Connection::new(resolver).map_err(|e| { + format!("Failed to connect with resolver '{resolver}': {e}") + })?; let mut resolver = VarlinkClient::new(conn); let address = match resolver.resolve(address.into()).call() { Ok(r) => r.address, _ => return Err(format!("Interface '{}' not found", address).into()), }; Connection::with_address(&address) - .context(format!("Failed to connect to '{}'", address))? + .map_err(|e| format!("Failed to connect to '{address}': {e}"))? } else { Connection::with_address(&address) - .context(format!("Failed to connect to '{}'", address))? + .map_err(|e| format!("Failed to connect to '{address}': {e}"))? } } }, @@ -91,7 +89,7 @@ fn varlink_info( let mut call = OrgVarlinkServiceClient::new(connection); let info = call .get_info() - .context("Cannot call GetInfo()".to_string())?; + .map_err(|e| format!("Cannot call GetInfo(): {e}"))?; println!("{} {}", bold("Vendor:"), info.vendor); println!("{} {}", bold("Product:"), info.product); @@ -120,25 +118,27 @@ fn varlink_help( let connection = if let Some(del) = url.rfind('/') { address = &url[0..del]; interface = &url[(del + 1)..]; - Connection::with_address(&address).context(format!("Cannot connect to '{}'", address))? + Connection::with_address(&address) + .map_err(|e| format!("Cannot connect to '{address}': {e}"))? } else { interface = url; match activate { Some(activate) => Connection::with_activate(activate) - .context(format!("Failed to connect with activate '{}'", activate))?, + .map_err(|e| format!("Failed to connect with activate '{activate}': {e}"))?, None => match bridge { Some(bridge) => Connection::with_bridge(bridge) - .context(format!("Failed to connect with bridge '{}'", bridge))?, + .map_err(|e| format!("Failed to connect with bridge '{bridge}': {e}"))?, None => { - let conn = Connection::new(resolver) - .context(format!("Failed to connect with resolver '{}'", resolver))?; + let conn = Connection::new(resolver).map_err(|e| { + format!("Failed to connect with resolver '{resolver}': {e}") + })?; let mut resolver = VarlinkClient::new(conn); let address = match resolver.resolve(interface.into()).call() { Ok(r) => r.address, - _ => return Err(format!("Interface '{}' not found", interface).into()), + _ => return Err(format!("Interface '{interface}' not found").into()), }; Connection::with_address(&address) - .context(format!("Failed to connect to '{}'", address))? + .map_err(|e| format!("Failed to connect to '{address}': {e}"))? } }, } @@ -151,10 +151,8 @@ fn varlink_help( let mut call = OrgVarlinkServiceClient::new(connection); match call .get_interface_description(interface.to_string()) - .context(format!( - "Can't get interface description for '{}'", - interface - ))? { + .map_err(|e| format!("Can't get interface description for '{interface}': {e}"))? + { GetInterfaceDescriptionReply { description: Some(desc), } => { @@ -162,7 +160,7 @@ fn varlink_help( println!( "{}", IDL::try_from(desc.as_str()) - .context(format!("Can't parse '{}'", desc))? + .map_err(|e| format!("Can't parse '{desc}': {e}"))? .get_multiline_colored( 0, columns.unwrap_or("80").parse::().unwrap_or(80), @@ -172,7 +170,7 @@ fn varlink_help( println!( "{}", IDL::try_from(desc.as_str()) - .context(format!("Can't parse '{}'", desc))? + .map_err(|e| format!("Can't parse '{desc}': {e}"))? .get_multiline(0, columns.unwrap_or("80").parse::().unwrap_or(80)) ); } @@ -201,13 +199,13 @@ fn varlink_call( Some(activate) => { method = url; Connection::with_activate(activate) - .context(format!("Failed to connect with activate '{}'", activate))? + .map_err(|e| format!("Failed to connect with activate '{activate}': {e}"))? } None => match bridge { Some(bridge) => { method = url; Connection::with_bridge(bridge) - .context(format!("Failed to connect with bridge '{}'", bridge))? + .map_err(|e| format!("Failed to connect with bridge '{bridge}': {e}"))? } None => { if let Some(del) = url.rfind('/') { @@ -226,8 +224,9 @@ fn varlink_call( } else { return Err(format!("Invalid address {}", url).into()); } - let conn = Connection::new(resolver) - .context(format!("Failed to connect with resolver '{}'", resolver))?; + let conn = Connection::new(resolver).map_err(|e| { + format!("Failed to connect with resolver '{resolver}': {e}") + })?; let mut resolver = VarlinkClient::new(conn); address = match resolver.resolve(interface.into()).call() { Ok(r) => { @@ -238,15 +237,14 @@ fn varlink_call( }; } Connection::with_address(address) - .context(format!("Failed to connect to '{}'", address))? + .map_err(|e| format!("Failed to connect to '{address}': {e}"))? } }, }; let args = match args { - Some(args) => { - serde_json::from_str(args).context(format!("Failed to parse JSON for '{}'", args))? - } + Some(args) => serde_json::from_str(args) + .map_err(|e| format!("Failed to parse JSON for '{args}': {e}"))?, None => serde_json::Value::Null, }; @@ -283,7 +281,7 @@ fn varlink_call( } else { for ret in call .more() - .context(format!("Failed to call method '{}({})'", method, args))? + .map_err(|e| format!("Failed to call method '{method}({args})': {e}"))? { print_call_ret(color_mode, cf.clone(), ret, should_colorize, method, &args)? } @@ -306,9 +304,9 @@ fn print_call_ret( |w| w.to_string() }; - let reply = ret.map_context({ + let reply = ret.map_err(|e| { let cf = cf.clone(); - |e| match e.kind() { + match e.kind() { varlink::ErrorKind::InterfaceNotFound(s) => format!( "Call failed with error: {}: {}", red("InterfaceNotFound"), @@ -346,7 +344,7 @@ fn print_call_ret( println!( "{}", cf.to_colored_json(&reply, color_mode) - .context(format!("Failed to print json for '{}'", reply))? + .map_err(|e| format!("Failed to print json for '{reply}': {e}"))? ); Ok(()) @@ -363,30 +361,31 @@ fn varlink_bridge( let connection = match activate { Some(activate) => Connection::with_activate_no_rw(activate) - .context(format!("Failed to connect with activate '{}'", activate))?, + .map_err(|e| format!("Failed to connect with activate '{activate}': {e}"))?, None => match bridge { Some(bridge) => Connection::with_bridge_no_rw(bridge) - .context(format!("Failed to connect with bridge '{}'", bridge))?, + .map_err(|e| format!("Failed to connect with bridge '{bridge}': {e}"))?, None => { if let Some(address) = address { if address.rfind(':').is_none() { - let conn = Connection::new(resolver) - .context(format!("Failed to connect with resolver '{}'", resolver))?; + let conn = Connection::new(resolver).map_err(|e| { + format!("Failed to connect with resolver '{resolver}': {e}") + })?; let mut resolver = VarlinkClient::new(conn); let address = match resolver.resolve(address.into()).call() { Ok(r) => r.address, _ => return Err(format!("Interface '{}' not found", address).into()), }; Connection::with_address_no_rw(&address) - .context(format!("Failed to connect to '{}'", address))? + .map_err(|e| format!("Failed to connect to '{address}': {e}"))? } else { Connection::with_address_no_rw(&address) - .context(format!("Failed to connect to '{}'", address))? + .map_err(|e| format!("Failed to connect to '{address}': {e}"))? } } else { let stdin = ::std::io::stdin(); let stdout = ::std::io::stdout(); - handle(resolver, stdin, stdout).context("Bridging".to_string())?; + handle(resolver, stdin, stdout).map_err(|e| format!("Bridging: {e}"))?; return Ok(()); } } @@ -405,7 +404,7 @@ fn varlink_bridge( } } } - r.context("Bridging".to_string())?; + r.map_err(|e| format!("Bridging: {e}"))?; Ok(()) } @@ -628,7 +627,7 @@ fn do_main(app: &mut App) -> Result<()> { let address = sub_matches.value_of("ADDRESS"); if address.is_none() && activate.is_none() && bridge.is_none() { app.print_help() - .context("Couldn't print help".to_string())?; + .map_err(|e| format!("Couldn't print help: {e}"))?; println!(); return Err("No ADDRESS or activation or bridge".to_string().into()); } @@ -661,7 +660,7 @@ fn do_main(app: &mut App) -> Result<()> { } (_, _) => { app.print_help() - .context("Couldn't print help".to_string())?; + .map_err(|e| format!("Couldn't print help: {e}"))?; println!(); } } diff --git a/varlink-cli/src/proxy.rs b/varlink-cli/src/proxy.rs index 0499582..dc44b1a 100644 --- a/varlink-cli/src/proxy.rs +++ b/varlink-cli/src/proxy.rs @@ -3,7 +3,6 @@ use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::{Arc, RwLock}; use std::thread; -use chainerror::prelude::v1::*; use serde_json::{from_slice, from_value, to_string}; use varlink::{ @@ -21,7 +20,7 @@ where W: Write + AsRawFd + Send + 'static, { let conn = Connection::new(resolver) - .context(format!("Failed to connect to resolver '{}'", resolver))?; + .map_err(|e| format!("Failed to connect to resolver '{resolver}': {e}"))?; let mut client_bufreader = unsafe { ::std::io::BufReader::new(::std::fs::File::from_raw_fd(client_reader.as_raw_fd())) @@ -46,7 +45,8 @@ where // pop the last zero byte buf.pop(); - let mut req: Request = from_slice(&buf).context("Error from slice".to_string())?; + let mut req: Request = + from_slice(&buf).map_err(|e| format!("Error from slice: {e}"))?; if req.method == "org.varlink.service.GetInfo" { req.method = "org.varlink.resolver.GetInfo".into(); diff --git a/varlink_derive/Cargo.toml b/varlink_derive/Cargo.toml index 1305509..2341e92 100644 --- a/varlink_derive/Cargo.toml +++ b/varlink_derive/Cargo.toml @@ -16,5 +16,4 @@ name = "varlink_derive" path = "src/lib.rs" [dependencies] -varlink_generator = { version = "10.1", path = "../varlink_generator" } - +varlink_generator = { version = "11.0", path = "../varlink_generator" } diff --git a/varlink_derive/src/lib.rs b/varlink_derive/src/lib.rs index e4851fd..bae8e63 100644 --- a/varlink_derive/src/lib.rs +++ b/varlink_derive/src/lib.rs @@ -151,17 +151,7 @@ fn parse_varlink_args(input: TokenStream) -> (String, String, Span) { } fn expand_varlink(name: String, source: String) -> TokenStream { - let code = match varlink_generator::compile(source) { - Ok(code) => code, - Err(e) => { - let mut s = String::new(); - for i in e.iter() { - s += &i.to_string(); - s += "\n"; - } - panic!("{}", s) - } - }; + let code = varlink_generator::compile(source).unwrap(); format!("mod {} {{ {} }}", name, code).parse().unwrap() } diff --git a/varlink_generator/Cargo.toml b/varlink_generator/Cargo.toml index 35dfe81..ba9b7ce 100644 --- a/varlink_generator/Cargo.toml +++ b/varlink_generator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "varlink_generator" -version = "10.1.1" +version = "11.0.0" authors = ["Harald Hoyer "] edition = "2018" rust-version = "1.70.0" @@ -24,12 +24,12 @@ name = "varlink-rust-generator" path = "src/bin/varlink-rust-generator.rs" [dependencies] -varlink_parser = { version = "4.3", path = "../varlink_parser" } +varlink_parser = { version = "5.0", path = "../varlink_parser" } quote = "1.0.2" proc-macro2 = "1.0.6" getopts = "0.2.21" syn = "2.0" -chainerror = "1" +thiserror = "2.0.3" [dev-dependencies] unified-diff = "0.2.1" diff --git a/varlink_generator/src/bin/varlink-rust-generator.rs b/varlink_generator/src/bin/varlink-rust-generator.rs index a22b150..14536f5 100644 --- a/varlink_generator/src/bin/varlink-rust-generator.rs +++ b/varlink_generator/src/bin/varlink-rust-generator.rs @@ -19,7 +19,6 @@ use std::io; use std::io::{Read, Write}; use std::path::Path; -use chainerror::Context; use varlink_generator::generate; fn print_usage(program: &str, opts: &getopts::Options) { @@ -59,7 +58,7 @@ fn main() -> std::result::Result<(), Box> { } else { Box::new( File::open(Path::new(&matches.free[0])) - .context(format!("Failed to open '{}'", &matches.free[0]))?, + .map_err(|e| format!("Failed to open '{}': {e}", &matches.free[0]))?, ) } } diff --git a/varlink_generator/src/lib.rs b/varlink_generator/src/lib.rs index b2d8d9c..bd4ef73 100644 --- a/varlink_generator/src/lib.rs +++ b/varlink_generator/src/lib.rs @@ -40,14 +40,20 @@ use std::path::{Path, PathBuf}; use std::process::{exit, Command}; use std::str::FromStr; -use chainerror::Context; use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote}; use varlink_parser::{Typedef, VEnum, VError, VStruct, VStructOrEnum, VType, VTypeExt, IDL}; -chainerror::str_context!(Error); -pub type Result = chainerror::Result; +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("{0}")] + Parse(varlink_parser::Error), + #[error("I/O error: {0}")] + Io(std::io::Error), +} + +pub type Result = std::result::Result; trait ToRustString<'short, 'long: 'short> { fn to_rust_string( @@ -793,8 +799,7 @@ fn generate_error_code( } pub fn compile(source: String) -> Result { - let idl = - IDL::try_from(source.as_str()).context(Error("Error compiling varlink".to_string()))?; + let idl = IDL::try_from(source.as_str()).map_err(Error::Parse)?; varlink_to_rust( &idl, &GeneratorOptions { @@ -827,17 +832,14 @@ pub fn generate_with_options( ) -> Result<()> { let mut buffer = String::new(); - reader - .read_to_string(&mut buffer) - .context(Error("Failed to read from buffer".to_string()))?; - - let idl = IDL::try_from(buffer.as_str()).context(Error("Failed to parse".to_string()))?; + reader.read_to_string(&mut buffer).map_err(Error::Io)?; + let idl = IDL::try_from(buffer.as_str()).map_err(Error::Parse)?; let ts = varlink_to_rust(&idl, options, tosource)?; + writer .write_all(ts.to_string().as_bytes()) - .context(Error("Failed to write to buffer".to_string()))?; - Ok(()) + .map_err(Error::Io) } /// cargo build helper function @@ -982,15 +984,10 @@ where })); if let Err(e) = generate_with_options(reader, writer, options, false) { - let mut s = String::new(); - for i in e.iter() { - s += &i.to_string(); - s += "\n"; - } eprintln!( "Could not generate rust code from varlink file `{}`: {}", input_path.display(), - s + e, ); exit(1); @@ -1104,15 +1101,10 @@ pub fn cargo_build_tosource_options + ?Sized>( })); if let Err(e) = generate_with_options(reader, writer, options, true) { - let mut s = String::new(); - for i in e.iter() { - s += &i.to_string(); - s += "\n"; - } eprintln!( "Could not generate rust code from varlink file `{}`: {}", input_path.display(), - s + e, ); exit(1); } diff --git a/varlink_parser/Cargo.toml b/varlink_parser/Cargo.toml index 0dde77d..9adb5e3 100644 --- a/varlink_parser/Cargo.toml +++ b/varlink_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "varlink_parser" -version = "4.3.0" +version = "5.0.0" authors = ["Harald Hoyer "] edition = "2018" rust-version = "1.70.0" @@ -20,5 +20,5 @@ travis-ci = { repository = "varlink/rust" } [dependencies] colored = "2.1.0" -chainerror = "1" +thiserror = "2.0.3" peg = "0.6.3" diff --git a/varlink_parser/src/lib.rs b/varlink_parser/src/lib.rs index 77ca648..ca81c0d 100644 --- a/varlink_parser/src/lib.rs +++ b/varlink_parser/src/lib.rs @@ -44,8 +44,6 @@ html_favicon_url = "https://varlink.org/images/varlink-small.png" )] -use chainerror::Context; - use self::varlink_grammar::ParseInterface; use std::collections::BTreeMap; use std::collections::HashSet; @@ -60,7 +58,13 @@ mod test; mod varlink_grammar; -chainerror::str_context!(Error); +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Varlink parse error\n{line}\n{marker:>column$}", marker = "^")] + Parse { line: String, column: usize }, + #[error("Interface definition error: {0}")] + Idl(String), +} pub enum VType<'a> { Bool, @@ -219,32 +223,30 @@ impl<'a> IDL<'a> { } #[deprecated(since = "4.1.0", note = "please use `IDL::try_from` instead")] - pub fn from_string(s: &'a str) -> chainerror::Result { + pub fn from_string(s: &'a str) -> Result { IDL::try_from(s) } } impl<'a> TryFrom<&'a str> for IDL<'a> { - type Error = chainerror::Error; + type Error = Error; fn try_from(value: &'a str) -> Result { - let interface = ParseInterface(value).map_context(|e| { + let interface = ParseInterface(value).map_err(|e| { let line = value.split('\n').nth(e.location.line - 1).unwrap(); - Error(format!( - "Varlink parse error\n{}\n{marker:>col$}", - line, - marker = "^", - col = e.location.column - )) + Error::Parse { + line: line.to_string(), + column: e.location.column, + } })?; if !interface.error.is_empty() { let mut v: Vec<_> = interface.error.into_iter().collect(); v.sort(); - let s = v.join("\n"); + let mut s = v.join("\n"); + s.push('\n'); - Err("Interface definition error".to_string()) - .context(Error(format!("Interface definition error: '{}'\n", s))) + Err(Error::Idl(s)) } else { Ok(interface) } diff --git a/varlink_parser/src/test.rs b/varlink_parser/src/test.rs index 96bd58a..a39ecf9 100644 --- a/varlink_parser/src/test.rs +++ b/varlink_parser/src/test.rs @@ -330,10 +330,10 @@ method F() -> () .unwrap(); assert_eq!( e.to_string(), - "Interface definition error: '\ + "Interface definition error: \ Interface `foo.example`: multiple definitions of method `F`! Interface `foo.example`: multiple definitions of type `Device`! -Interface `foo.example`: multiple definitions of type `T`!' +Interface `foo.example`: multiple definitions of type `T`! " ); } diff --git a/varlink_stdinterfaces/Cargo.toml b/varlink_stdinterfaces/Cargo.toml index 4b596ec..90bd563 100644 --- a/varlink_stdinterfaces/Cargo.toml +++ b/varlink_stdinterfaces/Cargo.toml @@ -19,7 +19,7 @@ serde_derive = "1.0.102" serde_json = "1.0.41" [build-dependencies] -varlink_generator = { version = "10", path = "../varlink_generator" } +varlink_generator = { version = "11", path = "../varlink_generator" } [dev-dependencies] static_assertions = "1.1.0"