fix: make version detection infallible (#1916)

This commit is contained in:
Matthias Seitz 2022-12-01 15:14:51 +01:00 committed by GitHub
parent 4b685621ed
commit 0ce6b107d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 55 additions and 14 deletions

View File

@ -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| {