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

feat: allow multiple compiler configs #170

Merged
merged 20 commits into from
Nov 15, 2024
2 changes: 1 addition & 1 deletion crates/artifacts/solc/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ pub struct CompactContractRefSome<'a> {
pub bin_runtime: &'a BytecodeObject,
}

impl<'a> CompactContractRefSome<'a> {
impl CompactContractRefSome<'_> {
/// Returns the individual parts of this contract.
///
/// If the values are `None`, then `Default` is returned.
Expand Down
2 changes: 1 addition & 1 deletion crates/artifacts/solc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1150,7 +1150,7 @@ impl<'de> Deserialize<'de> for LosslessMetadata {
{
struct LosslessMetadataVisitor;

impl<'de> Visitor<'de> for LosslessMetadataVisitor {
impl Visitor<'_> for LosslessMetadataVisitor {
type Value = LosslessMetadata;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down
6 changes: 3 additions & 3 deletions crates/artifacts/solc/src/sourcemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ enum Token<'a> {
Regular,
}

impl<'a> fmt::Debug for Token<'a> {
impl fmt::Debug for Token<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Token::Number(s) => write!(f, "NUMBER({s:?})"),
Expand All @@ -105,7 +105,7 @@ impl<'a> fmt::Debug for Token<'a> {
}
}

impl<'a> fmt::Display for Token<'a> {
impl fmt::Display for Token<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Token::Number(_) => write!(f, "number"),
Expand Down Expand Up @@ -531,7 +531,7 @@ impl<'input> Parser<'input> {
}
}

impl<'input> Iterator for Parser<'input> {
impl Iterator for Parser<'_> {
type Item = Result<SourceElement, SyntaxError>;

fn next(&mut self) -> Option<Self::Item> {
Expand Down
136 changes: 75 additions & 61 deletions crates/compilers/src/artifact_output/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ mod hh;
pub use hh::*;

use crate::{
cache::{CachedArtifact, CompilerCache},
cache::{CachedArtifacts, CompilerCache},
output::{
contracts::VersionedContracts,
sources::{VersionedSourceFile, VersionedSourceFiles},
Expand All @@ -52,6 +52,7 @@ pub struct ArtifactId {
pub version: Version,
/// `solc` build id
pub build_id: String,
pub profile: String,
}

impl ArtifactId {
Expand Down Expand Up @@ -119,6 +120,7 @@ pub struct ArtifactFile<T> {
/// `solc` version that produced this artifact
pub version: Version,
pub build_id: String,
pub profile: String,
}

impl<T: Serialize> ArtifactFile<T> {
Expand Down Expand Up @@ -298,6 +300,7 @@ impl<T> Artifacts<T> {
source: source.clone(),
version: artifact.version.clone(),
build_id: artifact.build_id.clone(),
profile: artifact.profile.clone(),
}
.with_slashed_paths(),
&artifact.artifact,
Expand All @@ -324,6 +327,7 @@ impl<T> Artifacts<T> {
source: source.clone(),
version: artifact.version,
build_id: artifact.build_id.clone(),
profile: artifact.profile.clone(),
}
.with_slashed_paths(),
artifact.artifact,
Expand Down Expand Up @@ -642,14 +646,22 @@ pub trait ArtifactOutput {

/// Returns the file name for the contract's artifact
/// `Greeter.json`
fn output_file_name(name: &str) -> PathBuf {
format!("{name}.json").into()
}

/// Returns the file name for the contract's artifact and the given version
/// `Greeter.0.8.11.json`
fn output_file_name_versioned(name: &str, version: &Version) -> PathBuf {
format!("{}.{}.{}.{}.json", name, version.major, version.minor, version.patch).into()
fn output_file_name(
name: &str,
version: &Version,
profile: &str,
with_version: bool,
with_profile: bool,
) -> PathBuf {
let mut name = name.to_string();
if with_version {
name.push_str(&format!(".{}.{}.{}", version.major, version.minor, version.patch));
}
if with_profile {
name.push_str(&format!(".{profile}"));
}
name.push_str(".json");
name.into()
}

/// Returns the appropriate file name for the conflicting file.
Expand Down Expand Up @@ -724,24 +736,23 @@ pub trait ArtifactOutput {
/// Returns the path to the contract's artifact location based on the contract's file and name
///
/// This returns `contract.sol/contract.json` by default
fn output_file(contract_file: &Path, name: &str) -> PathBuf {
contract_file
.file_name()
.map(Path::new)
.map(|p| p.join(Self::output_file_name(name)))
.unwrap_or_else(|| Self::output_file_name(name))
}

/// Returns the path to the contract's artifact location based on the contract's file, name and
/// version
///
/// This returns `contract.sol/contract.0.8.11.json` by default
fn output_file_versioned(contract_file: &Path, name: &str, version: &Version) -> PathBuf {
fn output_file(
contract_file: &Path,
name: &str,
version: &Version,
profile: &str,
with_version: bool,
with_profile: bool,
) -> PathBuf {
contract_file
.file_name()
.map(Path::new)
.map(|p| p.join(Self::output_file_name_versioned(name, version)))
.unwrap_or_else(|| Self::output_file_name_versioned(name, version))
.map(|p| {
p.join(Self::output_file_name(name, version, profile, with_version, with_profile))
})
.unwrap_or_else(|| {
Self::output_file_name(name, version, profile, with_version, with_profile)
})
}

/// The inverse of `contract_file_name`
Expand All @@ -752,11 +763,6 @@ pub trait ArtifactOutput {
file.file_stem().and_then(|s| s.to_str().map(|s| s.to_string()))
}

/// Whether the corresponding artifact of the given contract file and name exists
fn output_exists(contract_file: &Path, name: &str, root: &Path) -> bool {
root.join(Self::output_file(contract_file, name)).exists()
}

/// Read the artifact that's stored at the given path
///
/// # Errors
Expand Down Expand Up @@ -800,28 +806,27 @@ pub trait ArtifactOutput {

/// Generates a path for an artifact based on already taken paths by either cached or compiled
/// artifacts.
#[allow(clippy::too_many_arguments)]
fn get_artifact_path(
ctx: &OutputContext<'_>,
already_taken: &HashSet<String>,
file: &Path,
name: &str,
artifacts_folder: &Path,
version: &Version,
versioned: bool,
profile: &str,
with_version: bool,
with_profile: bool,
) -> PathBuf {
// if an artifact for the contract already exists (from a previous compile job)
// we reuse the path, this will make sure that even if there are conflicting
// files (files for witch `T::output_file()` would return the same path) we use
// consistent output paths
if let Some(existing_artifact) = ctx.existing_artifact(file, name, version) {
if let Some(existing_artifact) = ctx.existing_artifact(file, name, version, profile) {
trace!("use existing artifact file {:?}", existing_artifact,);
existing_artifact.to_path_buf()
} else {
let path = if versioned {
Self::output_file_versioned(file, name, version)
} else {
Self::output_file(file, name)
};
let path = Self::output_file(file, name, version, profile, with_version, with_profile);

let path = artifacts_folder.join(path);

Expand Down Expand Up @@ -854,7 +859,9 @@ pub trait ArtifactOutput {
let mut taken_paths_lowercase = ctx
.existing_artifacts
.values()
.flat_map(|artifacts| artifacts.values().flat_map(|artifacts| artifacts.values()))
.flat_map(|artifacts| artifacts.values())
.flat_map(|artifacts| artifacts.values())
.flat_map(|artifacts| artifacts.values())
.map(|a| a.path.to_slash_lossy().to_lowercase())
.collect::<HashSet<_>>();

Expand All @@ -865,22 +872,26 @@ pub trait ArtifactOutput {
});
for file in files {
for (name, versioned_contracts) in &contracts[file] {
let unique_versions =
versioned_contracts.iter().map(|c| &c.version).collect::<HashSet<_>>();
let unique_profiles =
versioned_contracts.iter().map(|c| &c.profile).collect::<HashSet<_>>();
for contract in versioned_contracts {
non_standalone_sources.insert(file);

// track `SourceFile`s that can be mapped to contracts
let source_file = sources.find_file_and_version(file, &contract.version);

if let Some(source) = source_file {
non_standalone_sources.insert((source.id, &contract.version));
}

let artifact_path = Self::get_artifact_path(
&ctx,
&taken_paths_lowercase,
file,
name,
layout.artifacts.as_path(),
&contract.version,
versioned_contracts.len() > 1,
&contract.profile,
unique_versions.len() > 1,
unique_profiles.len() > 1,
);

taken_paths_lowercase.insert(artifact_path.to_slash_lossy().to_lowercase());
Expand All @@ -904,6 +915,7 @@ pub trait ArtifactOutput {
file: artifact_path,
version: contract.version.clone(),
build_id: contract.build_id.clone(),
profile: contract.profile.clone(),
};

artifacts
Expand All @@ -921,8 +933,10 @@ pub trait ArtifactOutput {
// any contract definition, which are not included in the `CompilerOutput` but we want to
// create Artifacts for them regardless
for (file, sources) in sources.as_ref().iter() {
let unique_versions = sources.iter().map(|s| &s.version).collect::<HashSet<_>>();
let unique_profiles = sources.iter().map(|s| &s.profile).collect::<HashSet<_>>();
for source in sources {
if !non_standalone_sources.contains(&(source.source_file.id, &source.version)) {
if !non_standalone_sources.contains(file) {
// scan the ast as a safe measure to ensure this file does not include any
// source units
// there's also no need to create a standalone artifact for source files that
Expand All @@ -945,26 +959,26 @@ pub trait ArtifactOutput {
name,
&layout.artifacts,
&source.version,
sources.len() > 1,
&source.profile,
unique_versions.len() > 1,
unique_profiles.len() > 1,
);

let entries = artifacts
taken_paths_lowercase
.insert(artifact_path.to_slash_lossy().to_lowercase());

artifacts
.entry(file.clone())
.or_default()
.entry(name.to_string())
.or_default();

if entries.iter().all(|entry| entry.version != source.version) {
taken_paths_lowercase
.insert(artifact_path.to_slash_lossy().to_lowercase());

entries.push(ArtifactFile {
.or_default()
.push(ArtifactFile {
artifact,
file: artifact_path,
version: source.version.clone(),
build_id: source.build_id.clone(),
profile: source.profile.clone(),
});
}
}
}
}
Expand Down Expand Up @@ -1015,8 +1029,7 @@ pub struct OutputContext<'a> {
/// └── inner
/// └── a.sol
/// ```
pub existing_artifacts:
BTreeMap<&'a Path, &'a BTreeMap<String, BTreeMap<Version, CachedArtifact>>>,
pub existing_artifacts: BTreeMap<&'a Path, &'a CachedArtifacts>,
}

// === impl OutputContext
Expand All @@ -1042,13 +1055,14 @@ impl<'a> OutputContext<'a> {
file: &Path,
contract: &str,
version: &Version,
profile: &str,
) -> Option<&Path> {
self.existing_artifacts.get(file).and_then(|contracts| {
contracts
.get(contract)
.and_then(|versions| versions.get(version))
.map(|a| a.path.as_path())
})
self.existing_artifacts
.get(file)
.and_then(|contracts| contracts.get(contract))
.and_then(|versions| versions.get(version))
.and_then(|profiles| profiles.get(profile))
.map(|a| a.path.as_path())
}
}

Expand Down
Loading