refactor(solc): unify find/remove api (#1449)

* refactor(solc): unify find/remove api

* fix: update docs
This commit is contained in:
Matthias Seitz 2022-07-04 20:53:49 +02:00 committed by GitHub
parent c31eec5008
commit 3c1de64240
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 324 additions and 116 deletions

View File

@ -19,8 +19,10 @@ use std::{
borrow::Cow, borrow::Cow,
collections::{btree_map::BTreeMap, HashSet}, collections::{btree_map::BTreeMap, HashSet},
fmt, fs, io, fmt, fs, io,
ops::Deref,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
mod configurable; mod configurable;
pub use configurable::*; pub use configurable::*;
@ -64,7 +66,7 @@ impl ArtifactId {
} }
/// Represents an artifact file representing a [`crate::Contract`] /// Represents an artifact file representing a [`crate::Contract`]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct ArtifactFile<T> { pub struct ArtifactFile<T> {
/// The Artifact that was written /// The Artifact that was written
pub artifact: T, pub artifact: T,
@ -102,7 +104,7 @@ impl<T> ArtifactFile<T> {
pub(crate) type ArtifactsMap<T> = FileToContractsMap<Vec<ArtifactFile<T>>>; pub(crate) type ArtifactsMap<T> = FileToContractsMap<Vec<ArtifactFile<T>>>;
/// Represents a set of Artifacts /// Represents a set of Artifacts
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Artifacts<T>(pub ArtifactsMap<T>); pub struct Artifacts<T>(pub ArtifactsMap<T>);
impl<T> From<ArtifactsMap<T>> for Artifacts<T> { impl<T> From<ArtifactsMap<T>> for Artifacts<T> {
@ -149,6 +151,14 @@ impl<T> AsMut<ArtifactsMap<T>> for Artifacts<T> {
} }
} }
impl<T> Deref for Artifacts<T> {
type Target = ArtifactsMap<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: Serialize> Artifacts<T> { impl<T: Serialize> Artifacts<T> {
/// Writes all artifacts into the given `artifacts_root` folder /// Writes all artifacts into the given `artifacts_root` folder
pub fn write_all(&self) -> Result<()> { pub fn write_all(&self) -> Result<()> {
@ -264,18 +274,49 @@ impl<T> Artifacts<T> {
} }
/// Finds the first artifact `T` with a matching contract name /// Finds the first artifact `T` with a matching contract name
pub fn find(&self, contract_name: impl AsRef<str>) -> Option<&T> { pub fn find_first(&self, contract_name: impl AsRef<str>) -> Option<&T> {
let contract_name = contract_name.as_ref(); let contract_name = contract_name.as_ref();
self.0.iter().find_map(|(_file, contracts)| { self.0.iter().find_map(|(_file, contracts)| {
contracts.get(contract_name).and_then(|c| c.get(0).map(|a| &a.artifact)) contracts.get(contract_name).and_then(|c| c.get(0).map(|a| &a.artifact))
}) })
} }
/// Finds the artifact with matching path and name
pub fn find(&self, path: impl AsRef<str>, contract: impl AsRef<str>) -> Option<&T> {
let contract_path = path.as_ref();
let contract_name = contract.as_ref();
self.0.iter().filter(|(path, _)| path.as_str() == contract_path).find_map(
|(_file, contracts)| {
contracts.get(contract_name).and_then(|c| c.get(0).map(|a| &a.artifact))
},
)
}
/// Removes the artifact with matching file and name
pub fn remove(&mut self, path: impl AsRef<str>, contract: impl AsRef<str>) -> Option<T> {
let contract_path = path.as_ref();
let contract_name = contract.as_ref();
self.0.iter_mut().filter(|(path, _)| path.as_str() == contract_path).find_map(
|(_file, contracts)| {
let mut artifact = None;
if let Some((c, mut artifacts)) = contracts.remove_entry(contract_name) {
if !artifacts.is_empty() {
artifact = Some(artifacts.remove(0).artifact);
}
if !artifacts.is_empty() {
contracts.insert(c, artifacts);
}
}
artifact
},
)
}
/// Removes the first artifact `T` with a matching contract name /// Removes the first artifact `T` with a matching contract name
/// ///
/// *Note:* if there are multiple artifacts (contract compiled with different solc) then this /// *Note:* if there are multiple artifacts (contract compiled with different solc) then this
/// returns the first artifact in that set /// returns the first artifact in that set
pub fn remove(&mut self, contract_name: impl AsRef<str>) -> Option<T> { pub fn remove_first(&mut self, contract_name: impl AsRef<str>) -> Option<T> {
let contract_name = contract_name.as_ref(); let contract_name = contract_name.as_ref();
self.0.iter_mut().find_map(|(_file, contracts)| { self.0.iter_mut().find_map(|(_file, contracts)| {
let mut artifact = None; let mut artifact = None;

View File

@ -498,7 +498,7 @@ impl<'a> CompactContractRef<'a> {
/// use ethers_solc::artifacts::*; /// use ethers_solc::artifacts::*;
/// # fn demo(project: Project) { /// # fn demo(project: Project) {
/// let output = project.compile().unwrap().output(); /// let output = project.compile().unwrap().output();
/// let contract = output.find("Greeter").unwrap(); /// let contract = output.find_first("Greeter").unwrap();
/// let contract = contract.unwrap(); /// let contract = contract.unwrap();
/// # } /// # }
/// ``` /// ```

View File

@ -4,7 +4,7 @@ use crate::artifacts::{
}; };
use semver::Version; use semver::Version;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, path::Path}; use std::{collections::BTreeMap, ops::Deref, path::Path};
/// file -> [(contract name -> Contract + solc version)] /// file -> [(contract name -> Contract + solc version)]
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
@ -34,16 +34,41 @@ impl VersionedContracts {
/// use ethers_solc::artifacts::*; /// use ethers_solc::artifacts::*;
/// # fn demo(project: Project) { /// # fn demo(project: Project) {
/// let output = project.compile().unwrap().output(); /// let output = project.compile().unwrap().output();
/// let contract = output.find("Greeter").unwrap(); /// let contract = output.find_first("Greeter").unwrap();
/// # } /// # }
/// ``` /// ```
pub fn find(&self, contract: impl AsRef<str>) -> Option<CompactContractRef> { pub fn find_first(&self, contract: impl AsRef<str>) -> Option<CompactContractRef> {
let contract_name = contract.as_ref(); let contract_name = contract.as_ref();
self.contracts().find_map(|(name, contract)| { self.contracts().find_map(|(name, contract)| {
(name == contract_name).then(|| CompactContractRef::from(contract)) (name == contract_name).then(|| CompactContractRef::from(contract))
}) })
} }
/// Finds the contract with matching path and name
///
/// # Example
///
/// ```
/// use ethers_solc::Project;
/// use ethers_solc::artifacts::*;
/// # fn demo(project: Project) {
/// let output = project.compile().unwrap().output();
/// let contract = output.contracts.find("src/Greeter.sol", "Greeter").unwrap();
/// # }
/// ```
pub fn find(
&self,
path: impl AsRef<str>,
contract: impl AsRef<str>,
) -> Option<CompactContractRef> {
let contract_path = path.as_ref();
let contract_name = contract.as_ref();
self.contracts_with_files().find_map(|(path, name, contract)| {
(path == contract_path && name == contract_name)
.then(|| CompactContractRef::from(contract))
})
}
/// Removes the _first_ contract with the given name from the set /// Removes the _first_ contract with the given name from the set
/// ///
/// # Example /// # Example
@ -231,6 +256,14 @@ impl AsMut<FileToContractsMap<Vec<VersionedContract>>> for VersionedContracts {
} }
} }
impl Deref for VersionedContracts {
type Target = FileToContractsMap<Vec<VersionedContract>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl IntoIterator for VersionedContracts { impl IntoIterator for VersionedContracts {
type Item = (String, BTreeMap<String, Vec<VersionedContract>>); type Item = (String, BTreeMap<String, Vec<VersionedContract>>);
type IntoIter = type IntoIter =

View File

@ -53,6 +53,28 @@ impl<T: ArtifactOutput> ProjectCompileOutput<T> {
cached_artifacts.into_artifacts::<T>().chain(compiled_artifacts.into_artifacts::<T>()) cached_artifacts.into_artifacts::<T>().chain(compiled_artifacts.into_artifacts::<T>())
} }
/// This returns a chained iterator of both cached and recompiled contract artifacts that yields
/// the contract name and the corresponding artifact
///
/// # Example
///
/// ```no_run
/// use std::collections::btree_map::BTreeMap;
/// use ethers_solc::ConfigurableContractArtifact;
/// use ethers_solc::Project;
///
/// let project = Project::builder().build().unwrap();
/// let artifacts: BTreeMap<String, &ConfigurableContractArtifact> = project.compile().unwrap().artifacts().collect();
/// ```
pub fn artifacts(&self) -> impl Iterator<Item = (String, &T::Artifact)> {
self.cached_artifacts
.artifact_files()
.chain(self.compiled_artifacts.artifact_files())
.filter_map(|artifact| {
T::contract_name(&artifact.file).map(|name| (name, &artifact.artifact))
})
}
/// All artifacts together with their contract file and name as tuple `(file, contract /// All artifacts together with their contract file and name as tuple `(file, contract
/// name, artifact)` /// name, artifact)`
/// ///
@ -151,15 +173,6 @@ impl<T: ArtifactOutput> ProjectCompileOutput<T> {
self.compiler_output.has_warning(&self.ignored_error_codes) self.compiler_output.has_warning(&self.ignored_error_codes)
} }
/// Finds the first contract with the given name and removes it from the set
pub fn remove(&mut self, contract_name: impl AsRef<str>) -> Option<T::Artifact> {
let contract_name = contract_name.as_ref();
if let artifact @ Some(_) = self.compiled_artifacts.remove(contract_name) {
return artifact
}
self.cached_artifacts.remove(contract_name)
}
/// Returns the set of `Artifacts` that were cached and got reused during /// Returns the set of `Artifacts` that were cached and got reused during
/// [`crate::Project::compile()`] /// [`crate::Project::compile()`]
pub fn cached_artifacts(&self) -> &Artifacts<T::Artifact> { pub fn cached_artifacts(&self) -> &Artifacts<T::Artifact> {
@ -188,19 +201,140 @@ impl<T: ArtifactOutput> ProjectCompileOutput<T> {
} }
contracts contracts
} }
}
impl<T: ArtifactOutput> ProjectCompileOutput<T> /// Removes the contract with matching path and name using the `<path>:<contractname>` pattern
where /// where `path` is optional.
T::Artifact: Clone, ///
{ /// If the `path` segment is `None`, then the first matching `Contract` is returned, see
/// Finds the first contract with the given name /// [Self::remove_first]
pub fn find(&self, contract_name: impl AsRef<str>) -> Option<&T::Artifact> { ///
let contract_name = contract_name.as_ref(); /// # Example
if let artifact @ Some(_) = self.compiled_artifacts.find(contract_name) { ///
///
/// ```
/// use ethers_solc::Project;
/// use ethers_solc::artifacts::*;
/// use ethers_solc::info::ContractInfo;
///
/// # fn demo(project: Project) {
/// let output = project.compile().unwrap();
/// let info = ContractInfo::new("src/Greeter.sol:Greeter");
/// let contract = output.find_contract(&info).unwrap();
/// # }
/// ```
pub fn find_contract<'a>(&self, info: impl Into<ContractInfoRef<'a>>) -> Option<&T::Artifact> {
let ContractInfoRef { path, name } = info.into();
if let Some(path) = path {
self.find(path, name)
} else {
self.find_first(name)
}
}
/// Finds the artifact with matching path and name
///
/// # Example
///
/// ```
/// use ethers_solc::Project;
/// use ethers_solc::artifacts::*;
/// # fn demo(project: Project) {
/// let output = project.compile().unwrap();
/// let contract = output.find("src/Greeter.sol", "Greeter").unwrap();
/// # }
/// ```
pub fn find(&self, path: impl AsRef<str>, contract: impl AsRef<str>) -> Option<&T::Artifact> {
let contract_path = path.as_ref();
let contract_name = contract.as_ref();
if let artifact @ Some(_) = self.compiled_artifacts.find(contract_path, contract_name) {
return artifact return artifact
} }
self.cached_artifacts.find(contract_name) self.cached_artifacts.find(contract_path, contract_name)
}
/// Finds the first contract with the given name
pub fn find_first(&self, contract_name: impl AsRef<str>) -> Option<&T::Artifact> {
let contract_name = contract_name.as_ref();
if let artifact @ Some(_) = self.compiled_artifacts.find_first(contract_name) {
return artifact
}
self.cached_artifacts.find_first(contract_name)
}
/// Finds the artifact with matching path and name
///
/// # Example
///
/// ```
/// use ethers_solc::Project;
/// use ethers_solc::artifacts::*;
/// # fn demo(project: Project) {
/// let output = project.compile().unwrap();
/// let contract = output.find("src/Greeter.sol", "Greeter").unwrap();
/// # }
/// ```
pub fn remove(
&mut self,
path: impl AsRef<str>,
contract: impl AsRef<str>,
) -> Option<T::Artifact> {
let contract_path = path.as_ref();
let contract_name = contract.as_ref();
if let artifact @ Some(_) = self.compiled_artifacts.remove(contract_path, contract_name) {
return artifact
}
self.cached_artifacts.remove(contract_path, contract_name)
}
/// Removes the _first_ contract with the given name from the set
///
/// # Example
///
/// ```
/// use ethers_solc::Project;
/// use ethers_solc::artifacts::*;
/// # fn demo(project: Project) {
/// let mut output = project.compile().unwrap();
/// let contract = output.remove_first("Greeter").unwrap();
/// # }
/// ```
pub fn remove_first(&mut self, contract_name: impl AsRef<str>) -> Option<T::Artifact> {
let contract_name = contract_name.as_ref();
if let artifact @ Some(_) = self.compiled_artifacts.remove_first(contract_name) {
return artifact
}
self.cached_artifacts.remove_first(contract_name)
}
/// Removes the contract with matching path and name using the `<path>:<contractname>` pattern
/// where `path` is optional.
///
/// If the `path` segment is `None`, then the first matching `Contract` is returned, see
/// [Self::remove_first]
///
///
/// # Example
///
/// ```
/// use ethers_solc::Project;
/// use ethers_solc::artifacts::*;
/// use ethers_solc::info::ContractInfo;
/// # fn demo(project: Project) {
/// let mut output = project.compile().unwrap();
/// let info = ContractInfo::new("src/Greeter.sol:Greeter");
/// let contract = output.remove_contract(&info).unwrap();
/// # }
/// ```
pub fn remove_contract<'a>(
&mut self,
info: impl Into<ContractInfoRef<'a>>,
) -> Option<T::Artifact> {
let ContractInfoRef { path, name } = info.into();
if let Some(path) = path {
self.remove(path, name)
} else {
self.remove_first(name)
}
} }
} }
@ -340,11 +474,11 @@ impl AggregatedCompilerOutput {
/// use ethers_solc::artifacts::*; /// use ethers_solc::artifacts::*;
/// # fn demo(project: Project) { /// # fn demo(project: Project) {
/// let output = project.compile().unwrap().output(); /// let output = project.compile().unwrap().output();
/// let contract = output.find("Greeter").unwrap(); /// let contract = output.find_first("Greeter").unwrap();
/// # } /// # }
/// ``` /// ```
pub fn find(&self, contract: impl AsRef<str>) -> Option<CompactContractRef> { pub fn find_first(&self, contract: impl AsRef<str>) -> Option<CompactContractRef> {
self.contracts.find(contract) self.contracts.find_first(contract)
} }
/// Removes the _first_ contract with the given name from the set /// Removes the _first_ contract with the given name from the set
@ -548,7 +682,7 @@ impl<'a> OutputDiagnostics<'a> {
return true return true
} }
self.compiler_output.find(&contract_path).map_or(false, |contract| { self.compiler_output.find_first(&contract_path).map_or(false, |contract| {
contract.abi.map_or(false, |abi| abi.functions.contains_key("IS_TEST")) contract.abi.map_or(false, |abi| abi.functions.contains_key("IS_TEST"))
}) })
} }

View File

@ -55,21 +55,21 @@ fn can_compile_hardhat_sample() {
let project = TempProject::<ConfigurableArtifacts>::new(paths).unwrap(); let project = TempProject::<ConfigurableArtifacts>::new(paths).unwrap();
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Greeter").is_some()); assert!(compiled.find_first("Greeter").is_some());
assert!(compiled.find("console").is_some()); assert!(compiled.find_first("console").is_some());
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
// nothing to compile // nothing to compile
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Greeter").is_some()); assert!(compiled.find_first("Greeter").is_some());
assert!(compiled.find("console").is_some()); assert!(compiled.find_first("console").is_some());
assert!(compiled.is_unchanged()); assert!(compiled.is_unchanged());
// delete artifacts // delete artifacts
std::fs::remove_dir_all(&project.paths().artifacts).unwrap(); std::fs::remove_dir_all(&project.paths().artifacts).unwrap();
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Greeter").is_some()); assert!(compiled.find_first("Greeter").is_some());
assert!(compiled.find("console").is_some()); assert!(compiled.find_first("console").is_some());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
} }
@ -80,12 +80,12 @@ fn can_compile_dapp_sample() {
let project = TempProject::<ConfigurableArtifacts>::new(paths).unwrap(); let project = TempProject::<ConfigurableArtifacts>::new(paths).unwrap();
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Dapp").is_some()); assert!(compiled.find_first("Dapp").is_some());
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
// nothing to compile // nothing to compile
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Dapp").is_some()); assert!(compiled.find_first("Dapp").is_some());
assert!(compiled.is_unchanged()); assert!(compiled.is_unchanged());
let cache = SolFilesCache::read(project.cache_path()).unwrap(); let cache = SolFilesCache::read(project.cache_path()).unwrap();
@ -93,7 +93,7 @@ fn can_compile_dapp_sample() {
// delete artifacts // delete artifacts
std::fs::remove_dir_all(&project.paths().artifacts).unwrap(); std::fs::remove_dir_all(&project.paths().artifacts).unwrap();
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Dapp").is_some()); assert!(compiled.find_first("Dapp").is_some());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
let updated_cache = SolFilesCache::read(project.cache_path()).unwrap(); let updated_cache = SolFilesCache::read(project.cache_path()).unwrap();
@ -107,14 +107,14 @@ fn can_compile_yul_sample() {
let project = TempProject::<ConfigurableArtifacts>::new(paths).unwrap(); let project = TempProject::<ConfigurableArtifacts>::new(paths).unwrap();
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Dapp").is_some()); assert!(compiled.find_first("Dapp").is_some());
assert!(compiled.find("SimpleStore").is_some()); assert!(compiled.find_first("SimpleStore").is_some());
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
// nothing to compile // nothing to compile
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Dapp").is_some()); assert!(compiled.find_first("Dapp").is_some());
assert!(compiled.find("SimpleStore").is_some()); assert!(compiled.find_first("SimpleStore").is_some());
assert!(compiled.is_unchanged()); assert!(compiled.is_unchanged());
let cache = SolFilesCache::read(project.cache_path()).unwrap(); let cache = SolFilesCache::read(project.cache_path()).unwrap();
@ -122,8 +122,8 @@ fn can_compile_yul_sample() {
// delete artifacts // delete artifacts
std::fs::remove_dir_all(&project.paths().artifacts).unwrap(); std::fs::remove_dir_all(&project.paths().artifacts).unwrap();
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Dapp").is_some()); assert!(compiled.find_first("Dapp").is_some());
assert!(compiled.find("SimpleStore").is_some()); assert!(compiled.find_first("SimpleStore").is_some());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
let updated_cache = SolFilesCache::read(project.cache_path()).unwrap(); let updated_cache = SolFilesCache::read(project.cache_path()).unwrap();
@ -149,7 +149,7 @@ fn can_compile_configured() {
let settings = handler.settings(); let settings = handler.settings();
let project = TempProject::with_artifacts(paths, handler).unwrap().with_settings(settings); let project = TempProject::with_artifacts(paths, handler).unwrap().with_settings(settings);
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
let artifact = compiled.find("Dapp").unwrap(); let artifact = compiled.find_first("Dapp").unwrap();
assert!(artifact.metadata.is_some()); assert!(artifact.metadata.is_some());
assert!(artifact.raw_metadata.is_some()); assert!(artifact.raw_metadata.is_some());
assert!(artifact.ir.is_some()); assert!(artifact.ir.is_some());
@ -195,13 +195,13 @@ fn can_compile_dapp_detect_changes_in_libs() {
assert_eq!(graph.files().clone(), HashMap::from([(src, 0), (lib, 1),])); assert_eq!(graph.files().clone(), HashMap::from([(src, 0), (lib, 1),]));
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Foo").is_some()); assert!(compiled.find_first("Foo").is_some());
assert!(compiled.find("Bar").is_some()); assert!(compiled.find_first("Bar").is_some());
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
// nothing to compile // nothing to compile
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Foo").is_some()); assert!(compiled.find_first("Foo").is_some());
assert!(compiled.is_unchanged()); assert!(compiled.is_unchanged());
let cache = SolFilesCache::read(&project.paths().cache).unwrap(); let cache = SolFilesCache::read(&project.paths().cache).unwrap();
@ -224,8 +224,8 @@ fn can_compile_dapp_detect_changes_in_libs() {
assert_eq!(graph.files().len(), 2); assert_eq!(graph.files().len(), 2);
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Foo").is_some()); assert!(compiled.find_first("Foo").is_some());
assert!(compiled.find("Bar").is_some()); assert!(compiled.find_first("Bar").is_some());
// ensure change is detected // ensure change is detected
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
} }
@ -269,14 +269,14 @@ fn can_compile_dapp_detect_changes_in_sources() {
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("DssSpellTest").is_some()); assert!(compiled.find_first("DssSpellTest").is_some());
assert!(compiled.find("DssSpellTestBase").is_some()); assert!(compiled.find_first("DssSpellTestBase").is_some());
// nothing to compile // nothing to compile
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.is_unchanged()); assert!(compiled.is_unchanged());
assert!(compiled.find("DssSpellTest").is_some()); assert!(compiled.find_first("DssSpellTest").is_some());
assert!(compiled.find("DssSpellTestBase").is_some()); assert!(compiled.find_first("DssSpellTestBase").is_some());
let cache = SolFilesCache::read(&project.paths().cache).unwrap(); let cache = SolFilesCache::read(&project.paths().cache).unwrap();
assert_eq!(cache.files.len(), 2); assert_eq!(cache.files.len(), 2);
@ -303,8 +303,8 @@ fn can_compile_dapp_detect_changes_in_sources() {
assert_eq!(graph.files().len(), 2); assert_eq!(graph.files().len(), 2);
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("DssSpellTest").is_some()); assert!(compiled.find_first("DssSpellTest").is_some());
assert!(compiled.find("DssSpellTestBase").is_some()); assert!(compiled.find_first("DssSpellTestBase").is_some());
// ensure change is detected // ensure change is detected
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
@ -377,26 +377,26 @@ fn can_compile_dapp_sample_with_cache() {
// first compile // first compile
let project = Project::builder().paths(paths).build().unwrap(); let project = Project::builder().paths(paths).build().unwrap();
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Dapp").is_some()); assert!(compiled.find_first("Dapp").is_some());
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
// cache is used when nothing to compile // cache is used when nothing to compile
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Dapp").is_some()); assert!(compiled.find_first("Dapp").is_some());
assert!(compiled.is_unchanged()); assert!(compiled.is_unchanged());
// deleted artifacts cause recompile even with cache // deleted artifacts cause recompile even with cache
std::fs::remove_dir_all(&project.artifacts_path()).unwrap(); std::fs::remove_dir_all(&project.artifacts_path()).unwrap();
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Dapp").is_some()); assert!(compiled.find_first("Dapp").is_some());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
// new file is compiled even with partial cache // new file is compiled even with partial cache
std::fs::copy(cache_testdata_dir.join("NewContract.sol"), root.join("src/NewContract.sol")) std::fs::copy(cache_testdata_dir.join("NewContract.sol"), root.join("src/NewContract.sol"))
.unwrap(); .unwrap();
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Dapp").is_some()); assert!(compiled.find_first("Dapp").is_some());
assert!(compiled.find("NewContract").is_some()); assert!(compiled.find_first("NewContract").is_some());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
assert_eq!( assert_eq!(
compiled.into_artifacts().map(|(artifact_id, _)| artifact_id.name).collect::<HashSet<_>>(), compiled.into_artifacts().map(|(artifact_id, _)| artifact_id.name).collect::<HashSet<_>>(),
@ -424,7 +424,7 @@ fn can_compile_dapp_sample_with_cache() {
// deleted artifact is not taken from the cache // deleted artifact is not taken from the cache
std::fs::remove_file(&project.paths.sources.join("Dapp.sol")).unwrap(); std::fs::remove_file(&project.paths.sources.join("Dapp.sol")).unwrap();
let compiled: ProjectCompileOutput<_> = project.compile().unwrap(); let compiled: ProjectCompileOutput<_> = project.compile().unwrap();
assert!(compiled.find("Dapp").is_none()); assert!(compiled.find_first("Dapp").is_none());
} }
fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> { fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
@ -1022,7 +1022,7 @@ fn can_compile_single_files() {
let compiled = tmp.project().compile_file(f.clone()).unwrap(); let compiled = tmp.project().compile_file(f.clone()).unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("Foo").is_some()); assert!(compiled.find_first("Foo").is_some());
let bar = tmp let bar = tmp
.add_contract( .add_contract(
@ -1037,8 +1037,8 @@ fn can_compile_single_files() {
let compiled = tmp.project().compile_files(vec![f, bar]).unwrap(); let compiled = tmp.project().compile_files(vec![f, bar]).unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("Foo").is_some()); assert!(compiled.find_first("Foo").is_some());
assert!(compiled.find("Bar").is_some()); assert!(compiled.find_first("Bar").is_some());
} }
#[test] #[test]
@ -1066,7 +1066,7 @@ contract LinkTest {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
let contract = compiled.find("LinkTest").unwrap(); let contract = compiled.find_first("LinkTest").unwrap();
let bytecode = &contract.bytecode.as_ref().unwrap().object; let bytecode = &contract.bytecode.as_ref().unwrap().object;
assert!(bytecode.is_unlinked()); assert!(bytecode.is_unlinked());
let s = bytecode.as_str().unwrap(); let s = bytecode.as_str().unwrap();
@ -1111,8 +1111,8 @@ library MyLib {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("MyLib").is_some()); assert!(compiled.find_first("MyLib").is_some());
let contract = compiled.find("LinkTest").unwrap(); let contract = compiled.find_first("LinkTest").unwrap();
let bytecode = &contract.bytecode.as_ref().unwrap().object; let bytecode = &contract.bytecode.as_ref().unwrap().object;
assert!(bytecode.is_unlinked()); assert!(bytecode.is_unlinked());
@ -1126,8 +1126,8 @@ library MyLib {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("MyLib").is_some()); assert!(compiled.find_first("MyLib").is_some());
let contract = compiled.find("LinkTest").unwrap(); let contract = compiled.find_first("LinkTest").unwrap();
let bytecode = &contract.bytecode.as_ref().unwrap().object; let bytecode = &contract.bytecode.as_ref().unwrap().object;
assert!(!bytecode.is_unlinked()); assert!(!bytecode.is_unlinked());
@ -1138,8 +1138,8 @@ library MyLib {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("MyLib").is_some()); assert!(compiled.find_first("MyLib").is_some());
let contract = compiled.find("LinkTest").unwrap(); let contract = compiled.find_first("LinkTest").unwrap();
let bytecode = &contract.bytecode.as_ref().unwrap().object; let bytecode = &contract.bytecode.as_ref().unwrap().object;
assert!(!bytecode.is_unlinked()); assert!(!bytecode.is_unlinked());
} }
@ -1183,8 +1183,8 @@ library MyLib {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("MyLib").is_some()); assert!(compiled.find_first("MyLib").is_some());
let contract = compiled.find("LinkTest").unwrap(); let contract = compiled.find_first("LinkTest").unwrap();
let bytecode = &contract.bytecode.as_ref().unwrap().object; let bytecode = &contract.bytecode.as_ref().unwrap().object;
assert!(bytecode.is_unlinked()); assert!(bytecode.is_unlinked());
@ -1195,8 +1195,8 @@ library MyLib {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("MyLib").is_some()); assert!(compiled.find_first("MyLib").is_some());
let contract = compiled.find("LinkTest").unwrap(); let contract = compiled.find_first("LinkTest").unwrap();
let bytecode = &contract.bytecode.as_ref().unwrap().object; let bytecode = &contract.bytecode.as_ref().unwrap().object;
assert!(!bytecode.is_unlinked()); assert!(!bytecode.is_unlinked());
} }
@ -1223,12 +1223,12 @@ fn can_recompile_with_changes() {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("A").is_some()); assert!(compiled.find_first("A").is_some());
assert!(compiled.find("B").is_some()); assert!(compiled.find_first("B").is_some());
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(compiled.find("A").is_some()); assert!(compiled.find_first("A").is_some());
assert!(compiled.find("B").is_some()); assert!(compiled.find_first("B").is_some());
assert!(compiled.is_unchanged()); assert!(compiled.is_unchanged());
// modify A.sol // modify A.sol
@ -1236,8 +1236,8 @@ fn can_recompile_with_changes() {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
assert!(compiled.find("A").is_some()); assert!(compiled.find_first("A").is_some());
assert!(compiled.find("B").is_some()); assert!(compiled.find_first("B").is_some());
} }
#[test] #[test]
@ -1272,18 +1272,18 @@ fn can_recompile_with_lowercase_names() {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("DeployProxy").is_some()); assert!(compiled.find_first("DeployProxy").is_some());
assert!(compiled.find("UpgradeProxy").is_some()); assert!(compiled.find_first("UpgradeProxy").is_some());
assert!(compiled.find("ProxyAdmin").is_some()); assert!(compiled.find_first("ProxyAdmin").is_some());
let artifacts = tmp.artifacts_snapshot().unwrap(); let artifacts = tmp.artifacts_snapshot().unwrap();
assert_eq!(artifacts.artifacts.as_ref().len(), 3); assert_eq!(artifacts.artifacts.as_ref().len(), 3);
artifacts.assert_artifacts_essentials_present(); artifacts.assert_artifacts_essentials_present();
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(compiled.find("DeployProxy").is_some()); assert!(compiled.find_first("DeployProxy").is_some());
assert!(compiled.find("UpgradeProxy").is_some()); assert!(compiled.find_first("UpgradeProxy").is_some());
assert!(compiled.find("ProxyAdmin").is_some()); assert!(compiled.find_first("ProxyAdmin").is_some());
assert!(compiled.is_unchanged()); assert!(compiled.is_unchanged());
// modify upgradeProxy.sol // modify upgradeProxy.sol
@ -1291,9 +1291,9 @@ fn can_recompile_with_lowercase_names() {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
assert!(compiled.find("DeployProxy").is_some()); assert!(compiled.find_first("DeployProxy").is_some());
assert!(compiled.find("UpgradeProxy").is_some()); assert!(compiled.find_first("UpgradeProxy").is_some());
assert!(compiled.find("ProxyAdmin").is_some()); assert!(compiled.find_first("ProxyAdmin").is_some());
let artifacts = tmp.artifacts_snapshot().unwrap(); let artifacts = tmp.artifacts_snapshot().unwrap();
assert_eq!(artifacts.artifacts.as_ref().len(), 3); assert_eq!(artifacts.artifacts.as_ref().len(), 3);
@ -1331,12 +1331,12 @@ fn can_recompile_unchanged_with_empty_files() {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("A").is_some()); assert!(compiled.find_first("A").is_some());
assert!(compiled.find("C").is_some()); assert!(compiled.find_first("C").is_some());
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(compiled.find("A").is_some()); assert!(compiled.find_first("A").is_some());
assert!(compiled.find("C").is_some()); assert!(compiled.find_first("C").is_some());
assert!(compiled.is_unchanged()); assert!(compiled.is_unchanged());
// modify C.sol // modify C.sol
@ -1344,8 +1344,8 @@ fn can_recompile_unchanged_with_empty_files() {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
assert!(compiled.find("A").is_some()); assert!(compiled.find_first("A").is_some());
assert!(compiled.find("C").is_some()); assert!(compiled.find_first("C").is_some());
} }
#[test] #[test]
@ -1380,8 +1380,8 @@ contract Contract {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("Contract").is_some()); assert!(compiled.find_first("Contract").is_some());
assert!(compiled.find("top_level").is_some()); assert!(compiled.find_first("top_level").is_some());
let mut artifacts = tmp.artifacts_snapshot().unwrap(); let mut artifacts = tmp.artifacts_snapshot().unwrap();
assert_eq!(artifacts.artifacts.as_ref().len(), 2); assert_eq!(artifacts.artifacts.as_ref().len(), 2);
@ -1536,11 +1536,11 @@ fn can_compile_sparse_with_link_references() {
let mut output = compiled.clone().output(); let mut output = compiled.clone().output();
assert!(compiled.find("ATest").is_some()); assert!(compiled.find_first("ATest").is_some());
assert!(compiled.find("MyLib").is_some()); assert!(compiled.find_first("MyLib").is_some());
let lib = compiled.remove("MyLib").unwrap(); let lib = compiled.remove_first("MyLib").unwrap();
assert!(lib.bytecode.is_some()); assert!(lib.bytecode.is_some());
let lib = compiled.remove("MyLib"); let lib = compiled.remove_first("MyLib");
assert!(lib.is_none()); assert!(lib.is_none());
let mut dup = output.clone(); let mut dup = output.clone();
@ -1578,7 +1578,7 @@ fn can_sanitize_bytecode_hash() {
let compiled = tmp.compile().unwrap(); let compiled = tmp.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.find("A").is_some()); assert!(compiled.find_first("A").is_some());
} }
#[test] #[test]
@ -1614,7 +1614,7 @@ fn can_compile_model_checker_sample() {
}); });
let compiled = project.compile().unwrap(); let compiled = project.compile().unwrap();
assert!(compiled.find("Assert").is_some()); assert!(compiled.find_first("Assert").is_some());
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(compiled.has_compiler_warnings()); assert!(compiled.has_compiler_warnings());
} }
@ -1735,8 +1735,8 @@ fn can_parse_notice() {
let mut compiled = project.compile().unwrap(); let mut compiled = project.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
assert!(compiled.find("Contract").is_some()); assert!(compiled.find_first("Contract").is_some());
let userdoc = compiled.remove("Contract").unwrap().userdoc; let userdoc = compiled.remove_first("Contract").unwrap().userdoc;
assert_eq!( assert_eq!(
userdoc, userdoc,
@ -1759,8 +1759,8 @@ fn can_parse_notice() {
let mut compiled = project.compile().unwrap(); let mut compiled = project.compile().unwrap();
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
assert!(compiled.find("Contract").is_some()); assert!(compiled.find_first("Contract").is_some());
let userdoc = compiled.remove("Contract").unwrap().userdoc; let userdoc = compiled.remove_first("Contract").unwrap().userdoc;
assert_eq!( assert_eq!(
userdoc, userdoc,
@ -1830,8 +1830,8 @@ contract NotERC20 is INotERC20 {
assert!(!compiled.has_compiler_errors()); assert!(!compiled.has_compiler_errors());
assert!(!compiled.is_unchanged()); assert!(!compiled.is_unchanged());
assert!(compiled.find("INotERC20").is_some()); assert!(compiled.find_first("INotERC20").is_some());
let contract = compiled.remove("INotERC20").unwrap(); let contract = compiled.remove_first("INotERC20").unwrap();
assert_eq!( assert_eq!(
contract.userdoc, contract.userdoc,
Some(UserDoc { Some(UserDoc {
@ -1901,8 +1901,8 @@ contract NotERC20 is INotERC20 {
}) })
); );
assert!(compiled.find("NotERC20").is_some()); assert!(compiled.find_first("NotERC20").is_some());
let contract = compiled.remove("NotERC20").unwrap(); let contract = compiled.remove_first("NotERC20").unwrap();
assert_eq!( assert_eq!(
contract.userdoc, contract.userdoc,
Some(UserDoc { Some(UserDoc {

View File

@ -30,7 +30,7 @@ async fn main() -> Result<()> {
let project = Project::builder().paths(paths).ephemeral().no_artifacts().build().unwrap(); let project = Project::builder().paths(paths).ephemeral().no_artifacts().build().unwrap();
// compile the project and get the artifacts // compile the project and get the artifacts
let output = project.compile().unwrap(); let output = project.compile().unwrap();
let contract = output.find("SimpleStorage").expect("could not find contract").clone(); let contract = output.find_first("SimpleStorage").expect("could not find contract").clone();
let (abi, bytecode, _) = contract.into_parts(); let (abi, bytecode, _) = contract.into_parts();
// 2. instantiate our wallet & anvil // 2. instantiate our wallet & anvil