diff --git a/kindelia/src/config.rs b/kindelia/src/config.rs index 921c0d94..717ecc92 100644 --- a/kindelia/src/config.rs +++ b/kindelia/src/config.rs @@ -1,7 +1,7 @@ use std::{path::PathBuf, str::FromStr}; use crate::files::FileInput; -use anyhow::anyhow; +use anyhow::{anyhow, Context}; // ConfigSettings // ============== @@ -86,18 +86,17 @@ where if let Some(config_values) = config_values { let value = Self::get_prop(config_values, &prop_path); if let Some(value) = value { - return T::arg_from(value).map(|v| Some(v)).map_err(|e| { - anyhow!( - "Could not convert value of '{}' into desired type: {}", - prop_path, - e - ) - }); + return T::arg_from(value).map(|v| Some(v)).context(anyhow!( + "Could not convert value of '{}' into desired type", + prop_path + )); } } Ok(None) } else { - panic!("Cannot resolve from config file config without 'prop' field set") + Err(anyhow!( + "Cannot resolve from config file config without 'prop' field set" + )) } } @@ -108,16 +107,14 @@ where where T: ArgumentFrom, { - let value = Self::get_prop(config_values, prop_path).ok_or_else(|| { - anyhow!("Could not find prop '{}' in config file.", prop_path) - })?; - T::arg_from(value).map_err(|e| { - anyhow!( - "Could not convert value of '{}' into desired type: {}", - prop_path, - e - ) - }) + let value = Self::get_prop(config_values, prop_path).context(anyhow!( + "Could not find prop '{}' in config file.", + prop_path + ))?; + T::arg_from(value).context(anyhow!( + "Could not convert value of '{}' into desired type", + prop_path, + )) } fn get_prop(mut value: &toml::Value, prop_path: &str) -> Option { @@ -149,13 +146,13 @@ impl ArgumentFrom for String { impl ArgumentFrom for u32 { fn arg_from(t: String) -> anyhow::Result { - t.parse().map_err(|e| anyhow!("Invalid integer: `{}`", e)) + t.parse().context(anyhow!("Invalid integer: `{}`", t)) } } impl ArgumentFrom for u64 { fn arg_from(t: String) -> anyhow::Result { - t.parse().map_err(|e| anyhow!("Invalid integer: `{}`", e)) + t.parse().context(anyhow!("Invalid integer: `{}`", t)) } } @@ -166,7 +163,7 @@ impl ArgumentFrom for u32 { toml::Value::String(s) => { let s = s.trim_start_matches("0x"); let num = u32::from_str_radix(s, 16) - .map_err(|e| anyhow!("Invalid hexadecimal '{}': {}", s, e))?; + .context(anyhow!("Invalid hexadecimal '{}'", s))?; Ok(num) } _ => Err(anyhow!("Invalid integer '{}'", value)), @@ -181,7 +178,7 @@ impl ArgumentFrom for u64 { toml::Value::String(s) => { let s = s.trim_start_matches("0x"); let num = u64::from_str_radix(s, 16) - .map_err(|e| anyhow!("Invalid hexadecimal '{}': {}", s, e))?; + .context(anyhow!("Invalid hexadecimal '{}'", s))?; Ok(num) } _ => Err(anyhow!("Invalid integer '{}'", value)), @@ -210,45 +207,44 @@ impl ArgumentFrom for bool { impl ArgumentFrom for PathBuf { fn arg_from(t: String) -> anyhow::Result { if let Some(path) = t.strip_prefix("~/") { - let home_dir = dirs::home_dir() - .ok_or_else(|| anyhow!("Could not find $HOME directory."))?; + let home_dir = + dirs::home_dir().context("Could not find $HOME directory.")?; Ok(home_dir.join(path)) } else { - PathBuf::from_str(&t).map_err(|_| anyhow!("Invalid path: {}", t)) + PathBuf::from_str(&t).context(anyhow!("Invalid path: {}", t)) } } } impl ArgumentFrom for PathBuf { fn arg_from(value: toml::Value) -> anyhow::Result { - let t: String = value - .try_into() - .map_err(|_| anyhow!("Could not convert value to PathBuf"))?; + let t: String = + value.try_into().context("Could not convert value to PathBuf")?; PathBuf::arg_from(t) } } impl ArgumentFrom for String { fn arg_from(t: toml::Value) -> anyhow::Result { - t.try_into().map_err(|_| anyhow!("Could not convert value into String")) + t.try_into().context("Could not convert value into String") } } impl ArgumentFrom for Vec { fn arg_from(t: toml::Value) -> anyhow::Result { - t.try_into().map_err(|_| anyhow!("Could not convert value into array")) + t.try_into().context("Could not convert value into array") } } impl ArgumentFrom for bool { fn arg_from(t: toml::Value) -> anyhow::Result { - t.as_bool().ok_or_else(|| anyhow!("Invalid boolean value: {}", t)) + t.as_bool().context(anyhow!("Invalid boolean value: {}", t)) } } impl ArgumentFrom for kindelia_core::config::ApiConfig { fn arg_from(t: toml::Value) -> anyhow::Result { - t.try_into().map_err(|_| anyhow!("Could not convert value into array")) + t.try_into().context("Could not convert value into array") } } @@ -258,9 +254,8 @@ pub fn arg_from_file_or_stdin>( match file { FileInput::Path { path } => { // read from file - let content = std::fs::read_to_string(&path).map_err(|err| { - anyhow!("Cannot read from '{:?}' file: {}", path, err) - })?; + let content = std::fs::read_to_string(&path) + .context(anyhow!("Cannot read from '{:?}'", path))?; T::arg_from(content) } FileInput::Stdin => { diff --git a/kindelia/src/files.rs b/kindelia/src/files.rs index 98c94a18..c0762a29 100644 --- a/kindelia/src/files.rs +++ b/kindelia/src/files.rs @@ -1,4 +1,4 @@ -use anyhow::anyhow; +use anyhow::Context; use std::fmt::{Display, Formatter}; use std::io::Read; use std::path::PathBuf; @@ -46,14 +46,14 @@ impl FileInput { FileInput::Path { path } => { // read from file std::fs::read_to_string(path) - .map_err(|e| anyhow!("Cannot read from '{:?}' cause: {}", path, e)) + .context(format!("Cannot read from '{:?}'", path)) } FileInput::Stdin => { // read from stdin let mut buff = String::new(); std::io::stdin() .read_to_string(&mut buff) - .map_err(|e| anyhow!("Could not read from stdin: {}", e))?; + .context("Could not read from stdin")?; Ok(buff) } } diff --git a/kindelia/src/main.rs b/kindelia/src/main.rs index b51c279a..0107b17c 100644 --- a/kindelia/src/main.rs +++ b/kindelia/src/main.rs @@ -3,7 +3,7 @@ mod config; mod files; mod util; -use anyhow::anyhow; +use anyhow::{anyhow, Context}; use std::future::Future; use std::net::{SocketAddr, UdpSocket}; use std::path::Path; @@ -57,10 +57,8 @@ macro_rules! resolve_cfg { ConfigSettingsBuilder::default() .env($env) .default_value($default) - .build() - .unwrap() - .resolve($cli, None) - .map_err(|e| anyhow!(e))? + .build()? + .resolve($cli, None)? }; // No default value @@ -69,10 +67,8 @@ macro_rules! resolve_cfg { .env($env) .prop($prop) .default_value($default) - .build() - .unwrap() - .resolve($cli, None) - .map_err(|e| anyhow!(e))? + .build()? + .resolve($cli, None)? }; // Resolve config value with file @@ -84,10 +80,8 @@ macro_rules! resolve_cfg { .env($env) .prop($prop) .default_value(|| Ok($default)) - .build() - .unwrap() - .resolve($cli, $cfg) - .map_err(|e| anyhow!(e))? + .build()? + .resolve($cli, $cfg)? }; // No default value @@ -96,10 +90,8 @@ macro_rules! resolve_cfg { .env($env) .prop($prop) .default_value(|| Err($default)) - .build() - .unwrap() - .resolve($cli, $cfg) - .map_err(|e| anyhow!(e))? + .build()? + .resolve($cli, $cfg)? }; } @@ -109,8 +101,7 @@ macro_rules! resolve_cfg { pub fn run_cli() -> anyhow::Result<()> { let parsed = Cli::parse(); let default_base_path = || { - let home_dir = - dirs::home_dir().ok_or_else(|| anyhow!("Could not find $HOME path"))?; + let home_dir = dirs::home_dir().context("Could not find $HOME path")?; Ok::<_, anyhow::Error>(home_dir.join(".kindelia")) }; let default_node_data_path = @@ -183,9 +174,8 @@ pub fn run_cli() -> anyhow::Result<()> { CliCommand::Sign { file, secret_file, encoded, encoded_output } => { let skey: String = arg_from_file_or_stdin(secret_file.into())?; let skey = skey.trim(); - let skey = hex::decode(skey).map_err(|err| { - anyhow!("Secret key should be valid hex string: {}", err) - })?; + let skey = + hex::decode(skey).context("Secret key should be valid hex string")?; let skey: [u8; 32] = skey .try_into() .map_err(|_| anyhow!("Secret key should have exactly 64 bytes"))?; @@ -204,8 +194,9 @@ pub fn run_cli() -> anyhow::Result<()> { CliCommand::RunRemote { file, encoded } => { // TODO: client timeout let code = file.read_to_string()?; - let f = - |client: ApiClient, stmts| async move { client.run_code(stmts).await }; + let f = |client: ApiClient, stmts| async move { + client.run_code(stmts).await.map_err(|e| anyhow!(e)) + }; let stmts = if encoded { statements_from_hex_seq(&code)? } else { @@ -232,7 +223,7 @@ pub fn run_cli() -> anyhow::Result<()> { } CliCommand::Get { kind, json } => { let prom = get_info(kind, json, &api_url); - run_async_blocking(prom).map_err(|e| anyhow!(e)) + run_async_blocking(prom) } CliCommand::Init => { let path = default_config_path()?; @@ -262,8 +253,9 @@ pub fn run_cli() -> anyhow::Result<()> { .join(format!("{:#02X}", network_id)); match command { - NodeCommand::Clean { command } => clean(&data_path, command) - .map_err(|err| anyhow!("Could not clean kindelia's data: {}", err)), + NodeCommand::Clean { command } => { + clean(&data_path, command).context("Could not clean kindelia's data") + } NodeCommand::Start { initial_peers, mine, json } => { // TODO: refactor config resolution out of command handling (how?) @@ -304,7 +296,7 @@ pub fn run_cli() -> anyhow::Result<()> { let node_comm = init_socket().expect("Could not open a UDP socket"); let initial_peers = initial_peers .into_iter() - .map(|x| net::parse_address(&x).map_err(|e| anyhow!(e))) + .map(|x| net::parse_address(&x).context("parsing peer addr")) .collect::, anyhow::Error>>()?; let node_cfg = NodeConfig { @@ -332,8 +324,7 @@ pub fn run_cli() -> anyhow::Result<()> { .map(|s| s.strip_prefix("0x").unwrap_or(s)) .map(hex::decode) .collect(); - let data = - data.map_err(|err| anyhow!("Invalid hex string: {}", err))?; + let data = data.context("Invalid hex string")?; let nums = data.iter().map(|v| bytes_to_u128(v)); for num in nums { if let Some(num) = num { @@ -361,11 +352,11 @@ fn run_on_remote( ) -> anyhow::Result where F: FnOnce(ApiClient, Vec) -> P, - P: Future>, + P: Future>, { let stmts: Vec = stmts.into_iter().map(|s| s.into()).collect(); let client = ApiClient::new(api_url, None)?; - run_async_blocking(f(client, stmts)).map_err(|e| anyhow!(e)) + run_async_blocking(f(client, stmts)) } fn print_json_else( @@ -391,22 +382,24 @@ pub async fn get_info( kind: GetKind, json: bool, host_url: &str, -) -> Result<(), String> { - let client = ApiClient::new(host_url, None).map_err(|e| e.to_string())?; +) -> anyhow::Result<()> { + let client = ApiClient::new(host_url, None)?; match kind { GetKind::BlockHash { index } => { - let block_hash = client.get_block_hash(index).await?; + let block_hash = + client.get_block_hash(index).await.map_err(|e| anyhow!(e))?; println!("{}", block_hash); Ok(()) } GetKind::Block { hash } => { - let hash = Hash::try_from(hash.as_str())?; - let block = client.get_block(hash).await?; + let hash = Hash::try_from(hash.as_str()).map_err(|e| anyhow!(e))?; + let block = client.get_block(hash).await.map_err(|e| anyhow!(e))?; println!("{:#?}", block); Ok(()) } GetKind::Ctr { name, stat } => { - let ctr_info = client.get_constructor(name).await?; + let ctr_info = + client.get_constructor(name).await.map_err(|e| anyhow!(e))?; match stat { GetCtrKind::Arity => { println!("{}", ctr_info.arit) @@ -423,7 +416,8 @@ pub async fn get_info( } GetKind::Fun { name, stat } => match stat { GetFunKind::Code => { - let func_info = client.get_function(name).await?; + let func_info = + client.get_function(name).await.map_err(|e| anyhow!(e))?; print_json_else(json, func_info, |func_info| { let func = func_info.func; let statement = ast::Statement::Fun { @@ -438,14 +432,16 @@ pub async fn get_info( Ok(()) } GetFunKind::State => { - let state = client.get_function_state(name).await?; + let state = + client.get_function_state(name).await.map_err(|e| anyhow!(e))?; print_json_else(json, &state, |state| println!("{}", state)); Ok(()) } GetFunKind::Slots => todo!(), }, GetKind::Reg { name, stat } => { - let reg_info = client.get_reg_info(&name).await?; + let reg_info = + client.get_reg_info(&name).await.map_err(|e| anyhow!(e))?; match stat { GetRegKind::Owner => { println!("{:x}", *(reg_info.ownr)) @@ -459,7 +455,7 @@ pub async fn get_info( Ok(()) } GetKind::Stats { stat_kind } => { - let stats = client.get_stats().await?; + let stats = client.get_stats().await.map_err(|e| anyhow!(e))?; match stat_kind { None => { print_json_else(json, &stats, |stats| println!("{:#?}", stats)); @@ -494,7 +490,7 @@ pub async fn get_info( Ok(()) } GetKind::Peers { all } => { - let peers = client.get_peers::(all).await?; + let peers = client.get_peers::(all).await.map_err(|e| anyhow!(e))?; for peer in peers { println!("{}", peer.address) } @@ -571,10 +567,10 @@ fn statements_from_hex_seq(txt: &str) -> anyhow::Result> { } fn statement_from_hex(hex: &str) -> anyhow::Result { - let bytes = hex::decode(hex) - .map_err(|err| anyhow!("Invalid hexadecimal '{}': {}", hex, err))?; + let bytes = + hex::decode(hex).context(anyhow!("Invalid hexadecimal '{}'", hex))?; ast::Statement::proto_deserialized(&bytes_to_bitvec(&bytes)) - .ok_or_else(|| anyhow!("Failed to deserialize '{}'", hex)) + .context(anyhow!("Failed to deserialize '{}'", hex)) } pub fn publish_code( api_url: &str, @@ -589,8 +585,10 @@ pub fn publish_code( let peer_urls: Vec = if hosts.is_empty() { // obtain list of active peers known to "our" node. - let prom = async move { client.get_peers::(false).await }; - let peers = runtime.block_on(prom).map_err(|e| anyhow!(e))?; + let prom = async move { + client.get_peers::(false).await.map_err(|e| anyhow!(e)) + }; + let peers = runtime.block_on(prom)?; let mut urls: Vec = peers .iter() .map(|p| match p.address { @@ -877,11 +875,11 @@ pub fn start_node( fn print_shell_completions(shell: Shell) -> anyhow::Result<()> { // obtain name of present executable let exec_name = std::env::current_exe() - .map_err(|e| anyhow!("Error getting current executable: {}", e))? + .context("getting current executable")? .file_name() - .ok_or_else(|| anyhow!("Error getting executable file name"))? + .context("getting executable file name")? .to_str() - .ok_or_else(|| anyhow!("Error decoding executable name as utf8"))? + .context("decoding executable name as utf8")? .to_string(); // Generates completions for and prints to stdout diff --git a/kindelia/src/util.rs b/kindelia/src/util.rs index a0bc5d54..c3344628 100644 --- a/kindelia/src/util.rs +++ b/kindelia/src/util.rs @@ -20,9 +20,9 @@ pub fn bytes_to_u128(bytes: &[u8]) -> Option { // Async // ===== -pub fn run_async_blocking(prom: P) -> Result +pub fn run_async_blocking(prom: P) -> anyhow::Result where - P: Future>, + P: Future>, { let runtime = tokio::runtime::Runtime::new().unwrap(); runtime.block_on(prom)