refactor: replace anyhow with eyre (#858)
* refactor: replace anyhow with eyre * chore: update changelog * refactor: simplify bail logic for duplicate method signatures * refactor: simplify bail logic throughout * refactor: use eyre::ensure * refactor: more idiomatic use of eyre
This commit is contained in:
parent
885aa9c967
commit
7e4e8e200a
|
@ -28,6 +28,8 @@
|
|||
- Significantly refactor `MultiAbigen` module generation. Now allows for lib
|
||||
generation, and does not make unnecessary disk writes.
|
||||
[#854](https://github.com/gakonst/ethers-rs/pull/852)
|
||||
- Refactor `ethers-contract-abigen` to use `eyre` instead of `anyhow` via
|
||||
[#858](https://github.com/gakonst/ethers-rs/pull/858)
|
||||
|
||||
## ethers-contract-abigen
|
||||
|
||||
|
|
|
@ -1179,10 +1179,10 @@ name = "ethers-contract-abigen"
|
|||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
"cfg-if 1.0.0",
|
||||
"dunce",
|
||||
"ethers-core",
|
||||
"eyre",
|
||||
"getrandom 0.2.4",
|
||||
"hex",
|
||||
"once_cell",
|
||||
|
@ -1418,6 +1418,16 @@ dependencies = [
|
|||
"wee_alloc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc225d8f637923fe585089fcf03e705c222131232d2c1fb622e84ecf725d0eb8"
|
||||
dependencies = [
|
||||
"indenter",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
|
@ -1881,6 +1891,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indenter"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.8.0"
|
||||
|
|
|
@ -12,7 +12,6 @@ keywords = ["ethereum", "web3", "celo", "ethers"]
|
|||
[dependencies]
|
||||
ethers-core = { version = "^0.6.0", path = "../../ethers-core", features = ["macros"] }
|
||||
|
||||
anyhow = "1.0.37"
|
||||
Inflector = "0.11"
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
|
@ -26,6 +25,7 @@ once_cell = "1.8.0"
|
|||
cfg-if = "1.0.0"
|
||||
dunce = "1.0.2"
|
||||
walkdir = "2.3.2"
|
||||
eyre = "0.6.6"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
# NOTE: this enables wasm compatibility for getrandom indirectly
|
||||
|
|
|
@ -7,11 +7,11 @@ mod types;
|
|||
|
||||
use super::{util, Abigen};
|
||||
use crate::{contract::structs::InternalStructs, rawabi::RawAbi};
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use ethers_core::{
|
||||
abi::{Abi, AbiParser},
|
||||
macros::{ethers_contract_crate, ethers_core_crate, ethers_providers_crate},
|
||||
};
|
||||
use eyre::{eyre, Context as _, Result};
|
||||
|
||||
use crate::contract::methods::MethodAlias;
|
||||
use proc_macro2::{Ident, Literal, TokenStream};
|
||||
|
@ -153,7 +153,7 @@ impl Context {
|
|||
pub fn from_abigen(args: Abigen) -> Result<Self> {
|
||||
// get the actual ABI string
|
||||
let mut abi_str =
|
||||
args.abi_source.get().map_err(|e| anyhow!("failed to get ABI JSON: {}", e))?;
|
||||
args.abi_source.get().map_err(|e| eyre!("failed to get ABI JSON: {}", e))?;
|
||||
|
||||
let (abi, human_readable, abi_parser) = parse_abi(&abi_str)?;
|
||||
|
||||
|
@ -199,7 +199,7 @@ impl Context {
|
|||
};
|
||||
|
||||
if method_aliases.insert(signature.clone(), alias).is_some() {
|
||||
return Err(anyhow!("duplicate method signature '{}' in method aliases", signature,))
|
||||
eyre::bail!("duplicate method signature '{}' in method aliases", signature)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use super::{types, util, Context};
|
||||
use anyhow::Result;
|
||||
use ethers_core::{
|
||||
abi::{Event, EventExt, EventParam, ParamType, SolStruct},
|
||||
macros::{ethers_contract_crate, ethers_core_crate},
|
||||
};
|
||||
use eyre::Result;
|
||||
use inflector::Inflector;
|
||||
use proc_macro2::{Ident, Literal, TokenStream};
|
||||
use quote::quote;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::{btree_map::Entry, BTreeMap, HashMap};
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
use eyre::{Context as _, Result};
|
||||
use inflector::Inflector;
|
||||
use proc_macro2::{Literal, TokenStream};
|
||||
use quote::quote;
|
||||
|
@ -428,33 +428,33 @@ impl Context {
|
|||
0 => {
|
||||
// this may happen if there are functions with different casing,
|
||||
// like `INDEX`and `index`
|
||||
if overloaded_fun.name != first_fun.name {
|
||||
let overloaded_id = overloaded_fun.name.to_snake_case();
|
||||
let first_fun_id = first_fun.name.to_snake_case();
|
||||
if first_fun_id != overloaded_id {
|
||||
// no conflict
|
||||
overloaded_id
|
||||
} else {
|
||||
let overloaded_alias = MethodAlias {
|
||||
function_name: util::safe_ident(&overloaded_fun.name),
|
||||
struct_name: util::safe_ident(&overloaded_fun.name),
|
||||
};
|
||||
aliases.insert(overloaded_fun.abi_signature(), overloaded_alias);
|
||||
|
||||
let first_fun_alias = MethodAlias {
|
||||
function_name: util::safe_ident(&first_fun.name),
|
||||
struct_name: util::safe_ident(&first_fun.name),
|
||||
};
|
||||
aliases.insert(first_fun.abi_signature(), first_fun_alias);
|
||||
continue
|
||||
}
|
||||
// this should not happen since functions with same
|
||||
// name and inputs are illegal
|
||||
eyre::ensure!(
|
||||
overloaded_fun.name != first_fun.name,
|
||||
"Function with same name and parameter types defined twice: {}",
|
||||
overloaded_fun.name
|
||||
);
|
||||
|
||||
let overloaded_id = overloaded_fun.name.to_snake_case();
|
||||
let first_fun_id = first_fun.name.to_snake_case();
|
||||
if first_fun_id != overloaded_id {
|
||||
// no conflict
|
||||
overloaded_id
|
||||
} else {
|
||||
// this should not happen since functions with same name and inputs are
|
||||
// illegal
|
||||
anyhow::bail!(
|
||||
"Function with same name and parameter types defined twice: {}",
|
||||
overloaded_fun.name
|
||||
);
|
||||
let overloaded_alias = MethodAlias {
|
||||
function_name: util::safe_ident(&overloaded_fun.name),
|
||||
struct_name: util::safe_ident(&overloaded_fun.name),
|
||||
};
|
||||
aliases.insert(overloaded_fun.abi_signature(), overloaded_alias);
|
||||
|
||||
let first_fun_alias = MethodAlias {
|
||||
function_name: util::safe_ident(&first_fun.name),
|
||||
struct_name: util::safe_ident(&first_fun.name),
|
||||
};
|
||||
aliases.insert(first_fun.abi_signature(), first_fun_alias);
|
||||
continue
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Methods for expanding structs
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
use eyre::{eyre, Result};
|
||||
use inflector::Inflector;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
@ -55,17 +55,18 @@ impl Context {
|
|||
|
||||
/// Generates the type definition for the name that matches the given identifier
|
||||
fn generate_internal_struct(&self, id: &str) -> Result<TokenStream> {
|
||||
let sol_struct = self.internal_structs.structs.get(id).context("struct not found")?;
|
||||
let sol_struct =
|
||||
self.internal_structs.structs.get(id).ok_or_else(|| eyre!("struct not found"))?;
|
||||
let struct_name = self
|
||||
.internal_structs
|
||||
.rust_type_names
|
||||
.get(id)
|
||||
.context(format!("No types found for {}", id))?;
|
||||
.ok_or_else(|| eyre!("No types found for {}", id))?;
|
||||
let tuple = self
|
||||
.internal_structs
|
||||
.struct_tuples
|
||||
.get(id)
|
||||
.context(format!("No types found for {}", id))?
|
||||
.ok_or_else(|| eyre!("No types found for {}", id))?
|
||||
.clone();
|
||||
self.expand_internal_struct(struct_name, sol_struct, tuple)
|
||||
}
|
||||
|
@ -102,11 +103,7 @@ impl Context {
|
|||
fields.push(quote! { pub #field_name: #ty });
|
||||
}
|
||||
FieldType::Mapping(_) => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Mapping types in struct `{}` are not supported {:?}",
|
||||
name,
|
||||
field
|
||||
))
|
||||
eyre::bail!("Mapping types in struct `{}` are not supported {:?}", name, field)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +134,8 @@ impl Context {
|
|||
}
|
||||
|
||||
fn generate_human_readable_struct(&self, name: &str) -> Result<TokenStream> {
|
||||
let sol_struct = self.abi_parser.structs.get(name).context("struct not found")?;
|
||||
let sol_struct =
|
||||
self.abi_parser.structs.get(name).ok_or_else(|| eyre!("struct not found"))?;
|
||||
let mut fields = Vec::with_capacity(sol_struct.fields().len());
|
||||
let mut param_types = Vec::with_capacity(sol_struct.fields().len());
|
||||
for field in sol_struct.fields() {
|
||||
|
@ -157,18 +155,14 @@ impl Context {
|
|||
.abi_parser
|
||||
.struct_tuples
|
||||
.get(name)
|
||||
.context(format!("No types found for {}", name))?
|
||||
.ok_or_else(|| eyre!("No types found for {}", name))?
|
||||
.clone();
|
||||
let tuple = ParamType::Tuple(tuple);
|
||||
|
||||
param_types.push(struct_ty.as_param(tuple));
|
||||
}
|
||||
FieldType::Mapping(_) => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Mapping types in struct `{}` are not supported {:?}",
|
||||
name,
|
||||
field
|
||||
))
|
||||
eyre::bail!("Mapping types in struct `{}` are not supported {:?}", name, field)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use ethers_core::{abi::ParamType, macros::ethers_core_crate};
|
||||
use eyre::{bail, Result};
|
||||
use proc_macro2::{Literal, TokenStream};
|
||||
use quote::quote;
|
||||
|
||||
|
@ -16,7 +16,7 @@ pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
|
|||
5..=8 => Ok(quote! { i64 }),
|
||||
9..=16 => Ok(quote! { i128 }),
|
||||
17..=32 => Ok(quote! { I256 }),
|
||||
_ => Err(anyhow!("unsupported solidity type int{}", n)),
|
||||
_ => bail!("unsupported solidity type int{}", n),
|
||||
},
|
||||
ParamType::Uint(n) => match n / 8 {
|
||||
1 => Ok(quote! { u8 }),
|
||||
|
@ -25,7 +25,7 @@ pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
|
|||
5..=8 => Ok(quote! { u64 }),
|
||||
9..=16 => Ok(quote! { u128 }),
|
||||
17..=32 => Ok(quote! { #ethers_core::types::U256 }),
|
||||
_ => Err(anyhow!("unsupported solidity type uint{}", n)),
|
||||
_ => bail!("unsupported solidity type uint{}", n),
|
||||
},
|
||||
ParamType::Bool => Ok(quote! { bool }),
|
||||
ParamType::String => Ok(quote! { String }),
|
||||
|
@ -46,9 +46,7 @@ pub(crate) fn expand(kind: &ParamType) -> Result<TokenStream> {
|
|||
Ok(quote! { [#inner; #size] })
|
||||
}
|
||||
ParamType::Tuple(members) => {
|
||||
if members.is_empty() {
|
||||
return Err(anyhow!("Tuple must have at least 1 member"))
|
||||
}
|
||||
eyre::ensure!(!members.is_empty(), "Tuple must have at least 1 member");
|
||||
|
||||
let members = members.iter().map(expand).collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(quote! { (#(#members,)*) })
|
||||
|
|
|
@ -26,7 +26,7 @@ pub use ethers_core::types::Address;
|
|||
pub use source::Source;
|
||||
pub use util::parse_address;
|
||||
|
||||
use anyhow::Result;
|
||||
use eyre::Result;
|
||||
use inflector::Inflector;
|
||||
use proc_macro2::TokenStream;
|
||||
use std::{collections::HashMap, fs::File, io::Write, path::Path};
|
||||
|
@ -90,9 +90,9 @@ impl Abigen {
|
|||
let name = path
|
||||
.as_ref()
|
||||
.file_stem()
|
||||
.ok_or_else(|| anyhow::format_err!("Missing file stem in path"))?
|
||||
.ok_or_else(|| eyre::format_err!("Missing file stem in path"))?
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow::format_err!("Unable to convert file stem to string"))?;
|
||||
.ok_or_else(|| eyre::format_err!("Unable to convert file stem to string"))?;
|
||||
|
||||
Self::new(name, std::fs::read_to_string(path.as_ref())?)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! TODO
|
||||
|
||||
use anyhow::Result;
|
||||
use eyre::Result;
|
||||
use inflector::Inflector;
|
||||
use std::{collections::BTreeMap, fs, io::Write, path::Path};
|
||||
|
||||
|
@ -388,7 +388,7 @@ impl MultiBindings {
|
|||
/// # Returns
|
||||
///
|
||||
/// `Ok(())` if the freshly generated bindings match with the
|
||||
/// existing bindings. Otherwise an `Err(_)` containing an `anyhow::Report`
|
||||
/// existing bindings. Otherwise an `Err(_)` containing an `eyre::Report`
|
||||
/// with more information.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -437,7 +437,7 @@ impl MultiBindings {
|
|||
/// # Returns
|
||||
///
|
||||
/// `Ok(())` if the freshly generated bindings match with the
|
||||
/// existing bindings. Otherwise an `Err(_)` containing an `anyhow::Report`
|
||||
/// existing bindings. Otherwise an `Err(_)` containing an `eyre::Report`
|
||||
/// with more information.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -468,13 +468,13 @@ impl MultiBindings {
|
|||
}
|
||||
|
||||
fn check_file_in_dir(dir: &Path, file_name: &str, expected_contents: &[u8]) -> Result<()> {
|
||||
anyhow::ensure!(dir.is_dir(), "Not a directory: {}", dir.display());
|
||||
eyre::ensure!(dir.is_dir(), "Not a directory: {}", dir.display());
|
||||
|
||||
let file_path = dir.join(file_name);
|
||||
anyhow::ensure!(file_path.is_file(), "Not a file: {}", file_path.display());
|
||||
eyre::ensure!(file_path.is_file(), "Not a file: {}", file_path.display());
|
||||
|
||||
let contents = fs::read(file_path).expect("Unable to read file");
|
||||
anyhow::ensure!(contents == expected_contents, "file contents do not match");
|
||||
eyre::ensure!(contents == expected_contents, "file contents do not match");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! This module implements basic `rustfmt` code formatting.
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use eyre::{eyre, Result};
|
||||
use std::{
|
||||
io::Write,
|
||||
process::{Command, Stdio},
|
||||
|
@ -18,18 +18,18 @@ where
|
|||
let stdin = rustfmt
|
||||
.stdin
|
||||
.as_mut()
|
||||
.ok_or_else(|| anyhow!("stdin was not created for `rustfmt` child process"))?;
|
||||
.ok_or_else(|| eyre!("stdin was not created for `rustfmt` child process"))?;
|
||||
stdin.write_all(source.as_ref().as_bytes())?;
|
||||
}
|
||||
|
||||
let output = rustfmt.wait_with_output()?;
|
||||
if !output.status.success() {
|
||||
return Err(anyhow!(
|
||||
"`rustfmt` exited with code {}:\n{}",
|
||||
output.status,
|
||||
String::from_utf8_lossy(&output.stderr),
|
||||
))
|
||||
}
|
||||
|
||||
eyre::ensure!(
|
||||
output.status.success(),
|
||||
"`rustfmt` exited with code {}:\n{}",
|
||||
output.status,
|
||||
String::from_utf8_lossy(&output.stderr),
|
||||
);
|
||||
|
||||
let stdout = String::from_utf8(output.stdout)?;
|
||||
Ok(stdout)
|
||||
|
|
|
@ -3,8 +3,8 @@ use super::util;
|
|||
use ethers_core::types::Address;
|
||||
|
||||
use crate::util::resolve_path;
|
||||
use anyhow::{anyhow, Context, Error, Result};
|
||||
use cfg_if::cfg_if;
|
||||
use eyre::{eyre, Context, Error, Result};
|
||||
use std::{env, fs, path::Path, str::FromStr};
|
||||
use url::Url;
|
||||
|
||||
|
@ -88,10 +88,10 @@ impl Source {
|
|||
format!("{}", root.display())
|
||||
};
|
||||
let base = Url::parse(&root)
|
||||
.map_err(|_| anyhow!("root path '{}' is not absolute", root))?;
|
||||
.map_err(|_| eyre!("root path '{}' is not absolute", root))?;
|
||||
} else {
|
||||
let base = Url::from_directory_path(root)
|
||||
.map_err(|_| anyhow!("root path '{}' is not absolute", root.display()))?;
|
||||
.map_err(|_| eyre!("root path '{}' is not absolute", root.display()))?;
|
||||
}
|
||||
}
|
||||
let url = base.join(source)?;
|
||||
|
@ -103,19 +103,19 @@ impl Source {
|
|||
url.path()
|
||||
.rsplit('/')
|
||||
.next()
|
||||
.ok_or_else(|| anyhow!("HTTP URL does not have a path"))?,
|
||||
.ok_or_else(|| eyre!("HTTP URL does not have a path"))?,
|
||||
),
|
||||
Some("polygonscan.com") => Source::polygonscan(
|
||||
url.path()
|
||||
.rsplit('/')
|
||||
.next()
|
||||
.ok_or_else(|| anyhow!("HTTP URL does not have a path"))?,
|
||||
.ok_or_else(|| eyre!("HTTP URL does not have a path"))?,
|
||||
),
|
||||
Some("snowtrace.io") => Source::snowtrace(
|
||||
url.path()
|
||||
.rsplit('/')
|
||||
.next()
|
||||
.ok_or_else(|| anyhow!("HTTP URL does not have a path"))?,
|
||||
.ok_or_else(|| eyre!("HTTP URL does not have a path"))?,
|
||||
),
|
||||
_ => Ok(Source::Http(url)),
|
||||
},
|
||||
|
@ -123,7 +123,7 @@ impl Source {
|
|||
"polygonscan" => Source::polygonscan(url.path()),
|
||||
"snowtrace" => Source::snowtrace(url.path()),
|
||||
"npm" => Ok(Source::npm(url.path())),
|
||||
_ => Err(anyhow!("unsupported URL '{}'", url)),
|
||||
_ => Err(eyre!("unsupported URL '{}'", url)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,7 @@ fn get_local_contract(path: impl AsRef<str>) -> Result<String> {
|
|||
contract_path = dunce::canonicalize(&path)?;
|
||||
}
|
||||
if !contract_path.exists() {
|
||||
anyhow::bail!("Unable to find local contract \"{}\"", path.display())
|
||||
eyre::bail!("Unable to find local contract \"{}\"", path.display())
|
||||
}
|
||||
contract_path
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ethers_core::types::Address;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use eyre::Result;
|
||||
use inflector::Inflector;
|
||||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||
use quote::quote;
|
||||
|
@ -76,9 +76,7 @@ where
|
|||
S: AsRef<str>,
|
||||
{
|
||||
let address_str = address_str.as_ref();
|
||||
if !address_str.starts_with("0x") {
|
||||
return Err(anyhow!("address must start with '0x'"))
|
||||
}
|
||||
eyre::ensure!(address_str.starts_with("0x"), "address must start with '0x'");
|
||||
Ok(address_str[2..].parse()?)
|
||||
}
|
||||
|
||||
|
@ -89,7 +87,7 @@ pub fn http_get(_url: &str) -> Result<String> {
|
|||
if #[cfg(feature = "reqwest")]{
|
||||
Ok(reqwest::blocking::get(_url)?.text()?)
|
||||
} else {
|
||||
Err(anyhow!("HTTP is unsupported"))
|
||||
eyre::bail!("HTTP is unsupported")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +108,7 @@ pub fn resolve_path(raw: &str) -> Result<PathBuf> {
|
|||
unprocessed = rest;
|
||||
}
|
||||
None => {
|
||||
anyhow::bail!("Unable to parse a variable from \"{}\"", tail)
|
||||
eyre::bail!("Unable to parse a variable from \"{}\"", tail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue