the solc download per target helper

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
Cyrill Leutwiler
2025-03-24 22:33:37 +01:00
parent 97156ed21e
commit c69a87238d
16 changed files with 272 additions and 96 deletions
+67
View File
@@ -0,0 +1,67 @@
//! Helper for caching the solc binaries.
use std::{
cell::OnceCell,
collections::HashSet,
fs::{File, create_dir_all},
io::Write,
path::{Path, PathBuf},
sync::Mutex,
};
use crate::download::GHDownloader;
pub const SOLC_CACHE_DIRECTORY: &str = "solc";
pub const SOLC_CACHER: OnceCell<Mutex<SolcCacher>> = OnceCell::new();
pub fn get_or_download(
working_directory: &Path,
downloader: &GHDownloader,
) -> anyhow::Result<PathBuf> {
SOLC_CACHER
.get_or_init(|| {
Mutex::new(SolcCacher::new(
working_directory.join(SOLC_CACHE_DIRECTORY),
))
})
.lock()
.unwrap()
.get_or_download(downloader)
}
pub struct SolcCacher {
cache_directory: PathBuf,
cached_binaries: HashSet<PathBuf>,
}
impl SolcCacher {
fn new(cache_directory: PathBuf) -> Self {
Self {
cache_directory,
cached_binaries: Default::default(),
}
}
fn get_or_download(&mut self, downloader: &GHDownloader) -> anyhow::Result<PathBuf> {
let directory = self.cache_directory.join(downloader.version.to_string());
let file_path = directory.join(downloader.target);
if self.cached_binaries.contains(&file_path) {
return Ok(file_path);
}
if file_path.exists() {
self.cached_binaries.insert(file_path.clone());
return Ok(file_path);
}
create_dir_all(directory)?;
let buf = downloader.download()?;
File::create_new(&file_path)
.expect("should not exist because of above early return")
.write_all(&buf)?;
Ok(file_path)
}
}
+19 -23
View File
@@ -35,9 +35,9 @@ impl List {
/// Download solc binaries from GitHub releases (IPFS links aren't reliable).
pub struct GHDownloader {
version: Version,
target: &'static str,
list: &'static str,
pub version: Version,
pub target: &'static str,
pub list: &'static str,
}
impl GHDownloader {
@@ -48,36 +48,33 @@ impl GHDownloader {
pub const WINDOWS_NAME: &str = "solc-windows.exe";
pub const WASM_NAME: &str = "soljson.js";
pub fn linux(version: Version) -> Self {
fn new(version: Version, target: &'static str, list: &'static str) -> Self {
Self {
version,
target: Self::LINUX_NAME,
list: List::LINUX_URL,
target,
list,
}
}
pub fn linux(version: Version) -> Self {
Self::new(version, Self::LINUX_NAME, List::LINUX_URL)
}
pub fn macosx(version: Version) -> Self {
Self {
version,
target: Self::MACOSX_NAME,
list: List::MACOSX_URL,
}
Self::new(version, Self::MACOSX_NAME, List::MACOSX_URL)
}
pub fn windows(version: Version) -> Self {
Self {
version,
target: Self::WINDOWS_NAME,
list: List::WINDOWS_URL,
}
Self::new(version, Self::WINDOWS_NAME, List::WINDOWS_URL)
}
pub fn wasm(version: Version) -> Self {
Self {
version,
target: Self::WASM_NAME,
list: List::WASM_URL,
}
Self::new(version, Self::WASM_NAME, List::WASM_URL)
}
/// Returns the download link.
pub fn url(&self) -> String {
format!("{}/v{}/{}", Self::BASE_URL, &self.version, &self.target)
}
/// Download the solc binary.
@@ -92,8 +89,7 @@ impl GHDownloader {
.ok_or_else(|| anyhow::anyhow!("solc v{} not found builds", self.version))
.map(|b| b.sha256.strip_prefix("0x").unwrap_or(&b.sha256).to_string())?;
let url = format!("{}/v{}/{}", Self::BASE_URL, self.version, self.target);
let file = reqwest::blocking::get(&url)?.bytes()?.to_vec();
let file = reqwest::blocking::get(self.url())?.bytes()?.to_vec();
if hex::encode(Sha256::digest(&file)) != expected_digest {
anyhow::bail!("sha256 mismatch for solc version {}", self.version);
+34 -3
View File
@@ -1,8 +1,39 @@
//! This crates provides serializable Rust type definitions for the [solc binary lists][0].
//! The `download` feature enables helpers to download and cache solc binaries.
//! This crates provides serializable Rust type definitions for the [solc binary lists][0]
//! and download helpers.
//!
//! [0]: https://binaries.soliditylang.org
#[cfg(feature = "download")]
use std::path::{Path, PathBuf};
use cache::get_or_download;
use download::GHDownloader;
use semver::Version;
pub mod cache;
pub mod download;
pub mod list;
/// Downloads the solc binary for Wasm is `wasm` is set, otherwise for
/// the target platform.
///
/// Subsequent calls for the same version will use a cached artifact
/// and not download it again.
pub fn download_solc(
working_directory: &Path,
version: Version,
wasm: bool,
) -> anyhow::Result<PathBuf> {
let downloader = if wasm {
GHDownloader::wasm(version)
} else if cfg!(target_os = "linux") {
GHDownloader::linux(version)
} else if cfg!(target_os = "macos") {
GHDownloader::macosx(version)
} else if cfg!(target_os = "windows") {
GHDownloader::windows(version)
} else {
unimplemented!()
};
get_or_download(working_directory, &downloader)
}