fix: make version detection infallible (#1916)
This commit is contained in:
parent
4b685621ed
commit
0ce6b107d6
|
@ -8,10 +8,13 @@ use std::{
|
||||||
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
||||||
fs,
|
fs,
|
||||||
io::Write,
|
io::Write,
|
||||||
path::Path,
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
|
/// The default ethers dependency to generate.
|
||||||
|
const DEFAULT_ETHERS_DEP: &str = "ethers = { git = \"https://github.com/gakonst/ethers-rs\", default-features = false, features = [\"abigen\"] }";
|
||||||
|
|
||||||
/// Collects Abigen structs for a series of contracts, pending generation of
|
/// Collects Abigen structs for a series of contracts, pending generation of
|
||||||
/// the contract bindings.
|
/// the contract bindings.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -211,12 +214,17 @@ impl MultiExpansion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiExpansionResult { contracts: expansions, dirty_contracts, shared_types }
|
MultiExpansionResult { root: None, contracts: expansions, dirty_contracts, shared_types }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an intermediary result of [`MultiExpansion::expand()`]
|
/// Represents an intermediary result of [`MultiExpansion::expand()`]
|
||||||
pub struct MultiExpansionResult {
|
pub struct MultiExpansionResult {
|
||||||
|
/// The root dir at which this should be executed.
|
||||||
|
///
|
||||||
|
/// This is used to check if there's an existing `Cargo.toml`, from which we can derive the
|
||||||
|
/// proper `ethers` dependencies.
|
||||||
|
root: Option<PathBuf>,
|
||||||
contracts: Vec<(ExpandedContract, Context)>,
|
contracts: Vec<(ExpandedContract, Context)>,
|
||||||
/// contains the indices of contracts with structs that need to be updated
|
/// contains the indices of contracts with structs that need to be updated
|
||||||
dirty_contracts: HashSet<usize>,
|
dirty_contracts: HashSet<usize>,
|
||||||
|
@ -251,6 +259,14 @@ impl MultiExpansionResult {
|
||||||
tokens
|
tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the directory from which this type should expand from.
|
||||||
|
///
|
||||||
|
/// This is used to try to find the proper `ethers` dependency if the `root` is an existing
|
||||||
|
/// workspace. By default, the cwd is assumed to be the `root`.
|
||||||
|
pub fn set_root(&mut self, root: impl Into<PathBuf>) {
|
||||||
|
self.root = Some(root.into());
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the path to the shared types module according to the value of `single_file`
|
/// Sets the path to the shared types module according to the value of `single_file`
|
||||||
///
|
///
|
||||||
/// If `single_file` then it's expected that types will be written to `shared_types.rs`
|
/// If `single_file` then it's expected that types will be written to `shared_types.rs`
|
||||||
|
@ -278,7 +294,7 @@ impl MultiExpansionResult {
|
||||||
/// Converts this result into [`MultiBindingsInner`]
|
/// Converts this result into [`MultiBindingsInner`]
|
||||||
fn into_bindings(mut self, single_file: bool, rustfmt: bool) -> MultiBindingsInner {
|
fn into_bindings(mut self, single_file: bool, rustfmt: bool) -> MultiBindingsInner {
|
||||||
self.set_shared_import_path(single_file);
|
self.set_shared_import_path(single_file);
|
||||||
let Self { contracts, shared_types, .. } = self;
|
let Self { contracts, shared_types, root, .. } = self;
|
||||||
let bindings = contracts
|
let bindings = contracts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(expanded, ctx)| ContractBindings {
|
.map(|(expanded, ctx)| ContractBindings {
|
||||||
|
@ -310,7 +326,7 @@ impl MultiExpansionResult {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
MultiBindingsInner { bindings, shared_types }
|
MultiBindingsInner { root, bindings, shared_types }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,6 +548,11 @@ impl MultiBindings {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MultiBindingsInner {
|
struct MultiBindingsInner {
|
||||||
|
/// The root dir at which this should be executed.
|
||||||
|
///
|
||||||
|
/// This is used to check if there's an existing `Cargo.toml`, from which we can derive the
|
||||||
|
/// proper `ethers` dependencies.
|
||||||
|
root: Option<PathBuf>,
|
||||||
/// Abigen objects to be written
|
/// Abigen objects to be written
|
||||||
bindings: BTreeMap<String, ContractBindings>,
|
bindings: BTreeMap<String, ContractBindings>,
|
||||||
/// contains the content of the shared types if any
|
/// contains the content of the shared types if any
|
||||||
|
@ -569,16 +590,24 @@ impl MultiBindingsInner {
|
||||||
Ok(toml)
|
Ok(toml)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// parses the active Cargo.toml to get what version of ethers we are using
|
/// Returns the ethers crate version to use.
|
||||||
fn find_crate_version(&self) -> Result<String> {
|
///
|
||||||
let cargo_toml = std::env::current_dir()?.join("Cargo.toml");
|
/// If we fail to detect a matching `ethers` dependency, this returns the [`DEFAULT_ETHERS_DEP`]
|
||||||
|
/// version.
|
||||||
|
fn crate_version(&self) -> String {
|
||||||
|
self.try_find_crate_version().unwrap_or_else(|_| DEFAULT_ETHERS_DEP.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
let default_dep = || {
|
/// parses the active Cargo.toml to get what version of ethers we are using.
|
||||||
"ethers = { git = \"https://github.com/gakonst/ethers-rs\", default-features = false, features = [\"abigen\"] }".to_string()
|
///
|
||||||
};
|
/// Fails if the existing `Cargo.toml` does not contain a valid ethers dependency
|
||||||
|
fn try_find_crate_version(&self) -> Result<String> {
|
||||||
|
let cargo_toml =
|
||||||
|
if let Some(root) = self.root.clone() { root } else { std::env::current_dir()? }
|
||||||
|
.join("Cargo.toml");
|
||||||
|
|
||||||
if !cargo_toml.exists() {
|
if !cargo_toml.exists() {
|
||||||
return Ok(default_dep())
|
return Ok(DEFAULT_ETHERS_DEP.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = fs::read_to_string(cargo_toml)?;
|
let data = fs::read_to_string(cargo_toml)?;
|
||||||
|
@ -597,7 +626,7 @@ impl MultiBindingsInner {
|
||||||
version
|
version
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(default_dep())
|
Ok(DEFAULT_ETHERS_DEP.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,7 +637,7 @@ impl MultiBindingsInner {
|
||||||
name: impl AsRef<str>,
|
name: impl AsRef<str>,
|
||||||
version: impl AsRef<str>,
|
version: impl AsRef<str>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let crate_version = self.find_crate_version()?;
|
let crate_version = self.crate_version();
|
||||||
let contents = self.generate_cargo_toml(name, version, crate_version)?;
|
let contents = self.generate_cargo_toml(name, version, crate_version)?;
|
||||||
|
|
||||||
let mut file = fs::OpenOptions::new()
|
let mut file = fs::OpenOptions::new()
|
||||||
|
@ -746,7 +775,7 @@ impl MultiBindingsInner {
|
||||||
|
|
||||||
if check_cargo_toml {
|
if check_cargo_toml {
|
||||||
// additionally check the contents of the cargo
|
// additionally check the contents of the cargo
|
||||||
let crate_version = self.find_crate_version()?;
|
let crate_version = self.crate_version();
|
||||||
let cargo_contents = self.generate_cargo_toml(name, version, crate_version)?;
|
let cargo_contents = self.generate_cargo_toml(name, version, crate_version)?;
|
||||||
check_file_in_dir(crate_path, "Cargo.toml", &cargo_contents)?;
|
check_file_in_dir(crate_path, "Cargo.toml", &cargo_contents)?;
|
||||||
}
|
}
|
||||||
|
@ -870,6 +899,18 @@ mod tests {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_find_ethers_dep() {
|
||||||
|
run_test(|context| {
|
||||||
|
let Context { multi_gen, mod_root } = context;
|
||||||
|
|
||||||
|
let single_file = true;
|
||||||
|
let mut inner = multi_gen.clone().build().unwrap().into_inner(single_file);
|
||||||
|
inner.root = Some(PathBuf::from("this does not exist"));
|
||||||
|
inner.write_to_module(mod_root, single_file).unwrap();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_generate_single_file_module() {
|
fn can_generate_single_file_module() {
|
||||||
run_test(|context| {
|
run_test(|context| {
|
||||||
|
|
Loading…
Reference in New Issue