Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

download a fresh list of compiler binaries if out of date #686

Merged
merged 3 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ solidity_testing_utils = { path = "crates/solidity/testing/utils" }
#
# External
#
anyhow = { version = "1.0.70", features = ["backtrace", "std"] }
anyhow = { version = "1.0.75", features = ["backtrace", "std"] }
ariadne = { version = "0.2.0" }
bson = { version = "2.6.1" }
cargo-emit = { version = "0.2.1" }
Expand Down
9 changes: 6 additions & 3 deletions crates/solidity/testing/solc/src/keywords/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::utils::{ApiInput, Binary, InputSource};
use anyhow::Result;
use codegen_language_definition::model::{Item, KeywordDefinition, KeywordItem, Language};
use indicatif::{ProgressBar, ProgressStyle};
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use semver::Version;
use solidity_language::SolidityDefinition;
use std::collections::HashSet;

pub fn check_solidity_keywords() {
pub fn check_solidity_keywords() -> Result<()> {
println!();
println!(" > Checking Solidity keywords:");
println!();
Expand All @@ -18,7 +19,7 @@ pub fn check_solidity_keywords() {
println!(" > Downloading solc binaries:");
println!();

let binaries = Binary::fetch_all(&language);
let binaries = Binary::fetch_all(&language)?;

println!();
println!(" > Testing all variations:");
Expand All @@ -27,7 +28,7 @@ pub fn check_solidity_keywords() {
let progress_bar = ProgressBar::new(test_cases.len() as u64);

let style = "[{elapsed_precise}] [{bar:80.cyan/blue}] {pos}/{len} │ ETA: {eta_precise}";
progress_bar.set_style(ProgressStyle::with_template(style).unwrap());
progress_bar.set_style(ProgressStyle::with_template(style)?);

test_cases.par_iter().for_each(|test_case| {
let result = test_case.execute(&binaries);
Expand Down Expand Up @@ -55,6 +56,8 @@ pub fn check_solidity_keywords() {

progress_bar.finish();
println!();

Ok(())
}

fn generate_test_cases(language: &Language) -> Vec<TestCase> {
Expand Down
9 changes: 4 additions & 5 deletions crates/solidity/testing/solc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod keywords;
mod utils;

use crate::keywords::check_solidity_keywords;
use anyhow::Result;
use clap::{Parser, Subcommand};

#[derive(Debug, Parser)]
Expand All @@ -16,12 +17,10 @@ enum AppCommand {
CheckSolidityKeywords,
}

fn main() {
fn main() -> Result<()> {
match CLI::parse().command {
AppCommand::CheckSolidityKeywords => {
check_solidity_keywords();
}
};
AppCommand::CheckSolidityKeywords => check_solidity_keywords(),
}
}

#[test]
Expand Down
93 changes: 52 additions & 41 deletions crates/solidity/testing/solc/src/utils/binaries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ use crate::utils::{ApiInput, ApiOutput};
use anyhow::Result;
use codegen_language_definition::model::Language;
use indicatif::{ProgressBar, ProgressStyle};
use infra_utils::{cargo::CargoWorkspace, commands::Command};
use infra_utils::{cargo::CargoWorkspace, commands::Command, paths::PathExtensions};
use rayon::prelude::{ParallelBridge, ParallelIterator};
use semver::Version;
use serde::Deserialize;
use std::{collections::HashMap, os::unix::prelude::PermissionsExt, path::Path, path::PathBuf};
use std::{
collections::HashMap, os::unix::prelude::PermissionsExt, path::Path, path::PathBuf,
time::Duration,
};
use url::Url;

#[derive(Debug)]
Expand All @@ -17,93 +20,103 @@ pub struct Binary {
}

impl Binary {
pub fn fetch_all(language: &Language) -> Vec<Self> {
let binaries_dir = get_binaries_dir();
let mirror_url = get_mirror_url();
let releases = fetch_releases(&mirror_url, &binaries_dir);
pub fn fetch_all(language: &Language) -> Result<Vec<Self>> {
let binaries_dir = get_binaries_dir()?;
let mirror_url = get_mirror_url()?;
let releases = fetch_releases(&mirror_url, &binaries_dir)?;

let progress_bar = ProgressBar::new(language.versions.len() as u64);

let style = "[{elapsed_precise}] [{bar:80.cyan/blue}] {pos}/{len} │ ETA: {eta_precise}";
progress_bar.set_style(ProgressStyle::with_template(style).unwrap());
progress_bar.set_style(ProgressStyle::with_template(style)?);

let mut binaries: Vec<_> = language
let mut binaries = language
.versions
.iter()
.par_bridge()
.map(|version| {
let local_path = binaries_dir.join(version.to_string());
if !local_path.exists() {
let remote_url = mirror_url.join(&releases[version]).unwrap();
download_file(remote_url, &local_path);
make_file_executable(&local_path);
let release = releases.get(version).unwrap_or_else(|| {
panic!("Expected release '{version}' to exist at: {mirror_url}")
});

let remote_url = mirror_url.join(release)?;
download_file(remote_url, &local_path)?;
make_file_executable(&local_path)?;
}

progress_bar.inc(1);

Self {
Ok(Self {
version: version.to_owned(),
local_path,
}
})
})
.collect();
.collect::<Result<Vec<_>>>()?;

progress_bar.finish();
println!();

binaries.sort_by_key(|binary| binary.version.to_owned());

binaries
Ok(binaries)
}

pub fn run(&self, input: &ApiInput) -> Result<ApiOutput> {
let input = serde_json::to_string(input).unwrap();
let input = serde_json::to_string(input)?;

let output = Command::new(self.local_path.to_str().unwrap())
let output = Command::new(self.local_path.unwrap_str())
.flag("--standard-json")
.evaluate_with_input(input)?;

Ok(serde_json::from_str(&output).unwrap())
Ok(serde_json::from_str(&output)?)
}
}

fn fetch_releases(mirror_url: &Url, binaries_dir: &Path) -> HashMap<Version, String> {
fn fetch_releases(mirror_url: &Url, binaries_dir: &Path) -> Result<HashMap<Version, String>> {
#[derive(Deserialize)]
struct MirrorList {
releases: HashMap<Version, String>,
}

let list_path = binaries_dir.join("list.json");
if !list_path.exists() {
let list_url = mirror_url.join("list.json").unwrap();
download_file(list_url, &list_path);

OmarTawfik marked this conversation as resolved.
Show resolved Hide resolved
let should_download_list = match list_path.metadata() {
Err(err) if err.kind() == std::io::ErrorKind::NotFound => true,
Err(err) => return Err(err)?,
Ok(metadata) => metadata.created()?.elapsed()? > Duration::from_secs(60 * 60 * 24),
};

if should_download_list {
let list_url = mirror_url.join("list.json")?;
download_file(list_url, &list_path)?;
}

let list_file = std::fs::read_to_string(list_path).unwrap();
let list: MirrorList = serde_json::from_str(&list_file).unwrap();
list.releases
let list_file = std::fs::read_to_string(list_path)?;
let list: MirrorList = serde_json::from_str(&list_file)?;
Ok(list.releases)
}

fn download_file(url: Url, path: &Path) {
let bytes = reqwest::blocking::get(url).unwrap().bytes().unwrap();

std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(path, bytes).unwrap();
fn download_file(url: Url, path: &Path) -> Result<()> {
let bytes = reqwest::blocking::get(url)?.bytes()?;
std::fs::create_dir_all(path.unwrap_parent())?;
std::fs::write(path, bytes)?;
Ok(())
}

fn make_file_executable(local_path: &PathBuf) {
let mut permissions = local_path.metadata().unwrap().permissions();
fn make_file_executable(local_path: &PathBuf) -> Result<()> {
let mut permissions = local_path.metadata()?.permissions();
permissions.set_mode(0o744);
std::fs::set_permissions(local_path, permissions).unwrap();
std::fs::set_permissions(local_path, permissions)?;
Ok(())
}

fn get_binaries_dir() -> PathBuf {
CargoWorkspace::locate_source_crate("solidity_testing_solc")
.unwrap()
.join("target/binaries")
fn get_binaries_dir() -> Result<PathBuf> {
Ok(CargoWorkspace::locate_source_crate("solidity_testing_solc")?.join("target/binaries"))
}

fn get_mirror_url() -> Url {
fn get_mirror_url() -> Result<Url> {
let platform_dir = if cfg!(target_os = "macos") {
"macosx-amd64"
} else {
Expand All @@ -113,7 +126,5 @@ fn get_mirror_url() -> Url {
);
};

format!("https://binaries.soliditylang.org/{platform_dir}/")
.parse()
.unwrap()
Ok(format!("https://binaries.soliditylang.org/{platform_dir}/").parse()?)
}