diff --git a/Cargo.lock b/Cargo.lock index 567472bd..9d75602d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -435,6 +435,17 @@ dependencies = [ "generic-array 0.14.4", ] +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + [[package]] name = "cmac" version = "0.6.0" @@ -536,6 +547,34 @@ dependencies = [ "winapi", ] +[[package]] +name = "console" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "regex", + "terminal_size", + "unicode-width", + "winapi", +] + +[[package]] +name = "console" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "terminal_size", + "winapi", +] + [[package]] name = "const-oid" version = "0.6.1" @@ -676,6 +715,18 @@ dependencies = [ "const-oid", ] +[[package]] +name = "dialoguer" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9dd058f8b65922819fabb4a41e7d1964e56344042c26efbccd465202c23fa0c" +dependencies = [ + "console 0.14.1", + "lazy_static", + "tempfile", + "zeroize", +] + [[package]] name = "digest" version = "0.8.1" @@ -772,6 +823,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.28" @@ -1078,12 +1135,14 @@ dependencies = [ "ethers-core", "futures-util", "hex", + "home", "md-5", "once_cell", "regex", "semver 1.0.4", "serde", "serde_json", + "svm-rs", "tempdir", "thiserror", "tokio", @@ -1352,6 +1411,15 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1394,6 +1462,15 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "home" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" +dependencies = [ + "winapi", +] + [[package]] name = "http" version = "0.2.5" @@ -1539,6 +1616,18 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" +dependencies = [ + "console 0.15.0", + "lazy_static", + "number_prefix", + "regex", +] + [[package]] name = "instant" version = "0.1.12" @@ -1557,6 +1646,15 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" +[[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -1763,6 +1861,12 @@ dependencies = [ "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.26.2" @@ -2797,12 +2901,61 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "structopt" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "subtle" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +[[package]] +name = "svm-rs" +version = "0.1.2" +source = "git+https://github.com/roynalnaruto/svm-rs#5d353ec236a596dbfd2b37878ee5aee53ab6eadf" +dependencies = [ + "anyhow", + "cfg-if 1.0.0", + "console 0.14.1", + "dialoguer", + "home", + "indicatif", + "itertools", + "once_cell", + "rand 0.8.4", + "reqwest", + "semver 1.0.4", + "serde", + "serde_json", + "structopt", + "tempfile", + "thiserror", + "tokio", + "url", +] + [[package]] name = "syn" version = "1.0.81" @@ -2856,6 +3009,25 @@ dependencies = [ "winapi", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.30" @@ -3154,6 +3326,18 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/ethers-solc/Cargo.toml b/ethers-solc/Cargo.toml index 57cca929..f9ade2b2 100644 --- a/ethers-solc/Cargo.toml +++ b/ethers-solc/Cargo.toml @@ -27,6 +27,10 @@ md-5 = "0.9.1" thiserror = "1.0.30" hex = "0.4.3" colored = "2.0.0" +svm = { package = "svm-rs", git = "https://github.com/roynalnaruto/svm-rs", optional = true } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +home = "0.5.3" [dev-dependencies] tokio = { version = "1.12.0", features = ["full"] } @@ -34,3 +38,4 @@ tempdir = "0.3.7" [features] async = ["tokio", "futures-util"] +full = ["async", "svm"] diff --git a/ethers-solc/src/compile.rs b/ethers-solc/src/compile.rs index 3e007274..76de8870 100644 --- a/ethers-solc/src/compile.rs +++ b/ethers-solc/src/compile.rs @@ -52,6 +52,63 @@ impl Solc { Solc(path.into()) } + /// Returns the directory in which [svm](https://github.com/roynalnaruto/svm-rs) stores all versions + /// + /// This will be `~/.svm` on unix + #[cfg(not(target_arch = "wasm32"))] + pub fn svm_home() -> Option { + home::home_dir().map(|dir| dir.join(".svm")) + } + + /// Returns the path for a [svm](https://github.com/roynalnaruto/svm-rs) installed version. + /// + /// # Example + /// ```no_run + /// # fn main() -> Result<(), Box> { + /// use ethers_solc::Solc; + /// let solc = Solc::find_svm_installed_version("0.8.9").unwrap(); + /// assert_eq!(solc, Some(Solc::new("~/.svm/0.8.9/solc-0.8.9"))); + /// # Ok(()) + /// # } + /// ``` + #[cfg(not(target_arch = "wasm32"))] + pub fn find_svm_installed_version(version: impl AsRef) -> Result> { + let version = version.as_ref(); + let solc = walkdir::WalkDir::new( + Self::svm_home().ok_or_else(|| SolcError::solc("svm home dir not found"))?, + ) + .max_depth(1) + .into_iter() + .filter_map(std::result::Result::ok) + .filter(|e| e.file_type().is_dir()) + .find(|e| e.path().ends_with(version)) + .map(|e| e.path().join(format!("solc-{}", version))) + .map(Solc::new); + Ok(solc) + } + + /// Installs the provided version of Solc in the machine under the svm dir + /// # Example + /// ```no_run + /// # async fn run() -> Result<(), Box> { + /// use ethers_solc::{Solc, ISTANBUL_SOLC}; + /// Solc::install(&ISTANBUL_SOLC).await.unwrap(); + /// let solc = Solc::find_svm_installed_version(&ISTANBUL_SOLC.to_string()); + /// # Ok(()) + /// # } + /// ``` + #[cfg(feature = "svm")] + pub async fn install(version: &Version) -> std::result::Result<(), svm::SolcVmError> { + svm::install(version).await + } + + /// Blocking version of `Self::install` + #[cfg(all(feature = "svm", feature = "async"))] + pub fn blocking_install(version: &Version) -> std::result::Result<(), svm::SolcVmError> { + tokio::runtime::Runtime::new().unwrap().block_on(svm::install(version))?; + Ok(()) + } + /// Convenience function for compiling all sources under the given path pub fn compile_source(&self, path: impl AsRef) -> Result { self.compile(&CompilerInput::new(path)?) @@ -218,6 +275,12 @@ mod tests { let _version = Version::from_str("0.6.6+commit.6c089d02.Linux.gcc").unwrap(); } + #[test] + #[ignore] + fn can_find_solc() { + let _solc = Solc::find_svm_installed_version("0.8.9").unwrap(); + } + #[cfg(feature = "async")] #[tokio::test] async fn async_solc_version_works() { diff --git a/ethers-solc/src/lib.rs b/ethers-solc/src/lib.rs index 04ef525b..b9ad04e6 100644 --- a/ethers-solc/src/lib.rs +++ b/ethers-solc/src/lib.rs @@ -8,7 +8,7 @@ use std::collections::btree_map::Entry; pub mod cache; mod compile; -pub use compile::Solc; +pub use compile::*; mod config; pub use config::{ArtifactOutput, ProjectPathsConfig, SolcConfig};