diff --git a/crates/core/src/driver/mod.rs b/crates/core/src/driver/mod.rs index 11c16ae..efd99c4 100644 --- a/crates/core/src/driver/mod.rs +++ b/crates/core/src/driver/mod.rs @@ -101,30 +101,12 @@ where anyhow::bail!("unsupported solc version: {:?}", &mode.solc_version); }; - // Note: if the metadata is contained within a solidity file then this is the only file that - // we wish to compile since this is a self-contained test. Otherwise, if it's a JSON file - // then we need to compile all of the contracts that are in the directory since imports are - // allowed in there. - let Some(ref metadata_file_path) = metadata.file_path else { - anyhow::bail!("The metadata file path is not defined"); - }; - let mut files_to_compile = if metadata_file_path - .extension() - .is_some_and(|extension| extension.eq_ignore_ascii_case("sol")) - { - Box::new(std::iter::once(metadata_file_path.clone())) as Box> - } else { - Box::new( - FilesWithExtensionIterator::new(metadata.directory()?) - .with_allowed_extension("sol"), - ) - }; - let compiler = Compiler::::new() .allow_path(metadata.directory()?) .solc_optimizer(mode.solc_optimize()); - let mut compiler = - files_to_compile.try_fold(compiler, |compiler, path| compiler.with_source(&path))?; + let mut compiler = metadata + .files_to_compile()? + .try_fold(compiler, |compiler, path| compiler.with_source(&path))?; for (library_instance, (library_address, _)) in self.deployed_libraries.iter() { let library_ident = &metadata .contracts diff --git a/crates/format/src/metadata.rs b/crates/format/src/metadata.rs index fa61dc6..b72376b 100644 --- a/crates/format/src/metadata.rs +++ b/crates/format/src/metadata.rs @@ -9,7 +9,7 @@ use std::{ use serde::{Deserialize, Serialize}; -use revive_dt_common::macros::define_wrapper_type; +use revive_dt_common::{iterators::FilesWithExtensionIterator, macros::define_wrapper_type}; use crate::{ case::Case, @@ -212,6 +212,29 @@ impl Metadata { } } } + + /// Returns an iterator over all of the solidity files that needs to be compiled for this + /// [`Metadata`] object + /// + /// Note: if the metadata is contained within a solidity file then this is the only file that + /// we wish to compile since this is a self-contained test. Otherwise, if it's a JSON file + /// then we need to compile all of the contracts that are in the directory since imports are + /// allowed in there. + pub fn files_to_compile(&self) -> anyhow::Result>> { + let Some(ref metadata_file_path) = self.file_path else { + anyhow::bail!("The metadata file path is not defined"); + }; + if metadata_file_path + .extension() + .is_some_and(|extension| extension.eq_ignore_ascii_case("sol")) + { + Ok(Box::new(std::iter::once(metadata_file_path.clone()))) + } else { + Ok(Box::new( + FilesWithExtensionIterator::new(self.directory()?).with_allowed_extension("sol"), + )) + } + } } define_wrapper_type!( diff --git a/crates/solc-binaries/src/download.rs b/crates/solc-binaries/src/download.rs index c893e3a..8e637d2 100644 --- a/crates/solc-binaries/src/download.rs +++ b/crates/solc-binaries/src/download.rs @@ -5,7 +5,7 @@ use std::{ sync::{LazyLock, Mutex}, }; -use semver::Version; +use semver::{Version, VersionReq}; use sha2::{Digest, Sha256}; use crate::list::List; @@ -52,27 +52,50 @@ impl GHDownloader { pub const WINDOWS_NAME: &str = "solc-windows.exe"; pub const WASM_NAME: &str = "soljson.js"; - fn new(version: Version, target: &'static str, list: &'static str) -> Self { - Self { - version, - target, - list, + fn new( + version: impl Into, + target: &'static str, + list: &'static str, + ) -> anyhow::Result { + let version_or_requirement = version.into(); + match version_or_requirement { + VersionOrRequirement::Version(version) => Ok(Self { + version, + target, + list, + }), + VersionOrRequirement::Requirement(requirement) => { + let Some(version) = List::download(list)? + .builds + .into_iter() + .map(|build| build.version) + .filter(|version| requirement.matches(version)) + .max() + else { + anyhow::bail!("Failed to find a version that satisfies {requirement:?}"); + }; + Ok(Self { + version, + target, + list, + }) + } } } - pub fn linux(version: Version) -> Self { + pub fn linux(version: impl Into) -> anyhow::Result { Self::new(version, Self::LINUX_NAME, List::LINUX_URL) } - pub fn macosx(version: Version) -> Self { + pub fn macosx(version: impl Into) -> anyhow::Result { Self::new(version, Self::MACOSX_NAME, List::MACOSX_URL) } - pub fn windows(version: Version) -> Self { + pub fn windows(version: impl Into) -> anyhow::Result { Self::new(version, Self::WINDOWS_NAME, List::WINDOWS_URL) } - pub fn wasm(version: Version) -> Self { + pub fn wasm(version: impl Into) -> anyhow::Result { Self::new(version, Self::WASM_NAME, List::WASM_URL) } @@ -104,6 +127,24 @@ impl GHDownloader { } } +#[derive(Clone, Debug)] +pub enum VersionOrRequirement { + Version(Version), + Requirement(VersionReq), +} + +impl From for VersionOrRequirement { + fn from(value: Version) -> Self { + Self::Version(value) + } +} + +impl From for VersionOrRequirement { + fn from(value: VersionReq) -> Self { + Self::Requirement(value) + } +} + #[cfg(test)] mod tests { use crate::{download::GHDownloader, list::List}; @@ -111,24 +152,24 @@ mod tests { #[test] fn try_get_windows() { let version = List::download(List::WINDOWS_URL).unwrap().latest_release; - GHDownloader::windows(version).download().unwrap(); + GHDownloader::windows(version).unwrap().download().unwrap(); } #[test] fn try_get_macosx() { let version = List::download(List::MACOSX_URL).unwrap().latest_release; - GHDownloader::macosx(version).download().unwrap(); + GHDownloader::macosx(version).unwrap().download().unwrap(); } #[test] fn try_get_linux() { let version = List::download(List::LINUX_URL).unwrap().latest_release; - GHDownloader::linux(version).download().unwrap(); + GHDownloader::linux(version).unwrap().download().unwrap(); } #[test] fn try_get_wasm() { let version = List::download(List::WASM_URL).unwrap().latest_release; - GHDownloader::wasm(version).download().unwrap(); + GHDownloader::wasm(version).unwrap().download().unwrap(); } } diff --git a/crates/solc-binaries/src/lib.rs b/crates/solc-binaries/src/lib.rs index aabc86e..850fb43 100644 --- a/crates/solc-binaries/src/lib.rs +++ b/crates/solc-binaries/src/lib.rs @@ -7,7 +7,8 @@ use std::path::{Path, PathBuf}; use cache::get_or_download; use download::GHDownloader; -use semver::Version; + +use crate::download::VersionOrRequirement; pub mod cache; pub mod download; @@ -20,7 +21,7 @@ pub mod list; /// and not download it again. pub fn download_solc( cache_directory: &Path, - version: Version, + version: impl Into, wasm: bool, ) -> anyhow::Result { let downloader = if wasm { @@ -33,7 +34,7 @@ pub fn download_solc( GHDownloader::windows(version) } else { unimplemented!() - }; + }?; get_or_download(cache_directory, &downloader) }