Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
chore: extract output module
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse committed Dec 6, 2021
1 parent 827cf54 commit 8b8fed7
Show file tree
Hide file tree
Showing 2 changed files with 196 additions and 190 deletions.
196 changes: 6 additions & 190 deletions ethers-solc/src/project/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
artifacts::{CompilerInput, CompilerOutput, Sources},
artifacts::{CompilerInput, Sources},
cache::PathMap,
compile::*,
config::{
Expand All @@ -9,16 +9,18 @@ use crate::{
utils,
};
use std::{
borrow::Cow,
collections::{btree_map::Entry, BTreeMap},
convert::TryInto,
fmt, fs, io,
fs, io,
marker::PhantomData,
path::PathBuf,
};

use crate::{artifacts::Source, cache::SolFilesCache};

mod output;
pub use output::ProjectCompileOutput;

/// Represents a project workspace and handles `solc` compiling of all contracts in that workspace.
#[derive(Debug)]
pub struct Project<Artifacts: ArtifactOutput = MinimalCombinedArtifacts> {
Expand Down Expand Up @@ -334,7 +336,7 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
Ok(compiled)
}

/// Compiles the given source files with the exact `Solc` executable
/// Compiles the given source files with the provided `Solc` executable
///
/// First all libraries for the sources are resolved by scanning all their imports.
/// If caching is enabled for the `Project`, then all unchanged files are filtered from the
Expand Down Expand Up @@ -644,192 +646,6 @@ impl<Artifacts: ArtifactOutput> Default for ProjectBuilder<Artifacts> {
}
}

/// The outcome of `Project::compile`
#[derive(Debug, Clone, PartialEq, Default)]
pub struct ProjectCompileOutput<T: ArtifactOutput> {
/// If solc was invoked multiple times in `Project::compile` then this contains a merged
/// version of all `CompilerOutput`s. If solc was called only once then `compiler_output`
/// holds the `CompilerOutput` of that call.
compiler_output: Option<CompilerOutput>,
/// All artifacts that were read from cache
artifacts: BTreeMap<PathBuf, T::Artifact>,
ignored_error_codes: Vec<u64>,
}

impl<T: ArtifactOutput> ProjectCompileOutput<T> {
pub fn with_ignored_errors(ignored_errors: Vec<u64>) -> Self {
Self {
compiler_output: None,
artifacts: Default::default(),
ignored_error_codes: ignored_errors,
}
}

pub fn from_unchanged(artifacts: BTreeMap<PathBuf, T::Artifact>) -> Self {
Self { compiler_output: None, artifacts, ignored_error_codes: vec![] }
}

pub fn from_compiler_output(
compiler_output: CompilerOutput,
ignored_error_codes: Vec<u64>,
) -> Self {
Self {
compiler_output: Some(compiler_output),
artifacts: Default::default(),
ignored_error_codes,
}
}

pub fn from_compiler_output_and_cache(
compiler_output: CompilerOutput,
cache: BTreeMap<PathBuf, T::Artifact>,
ignored_error_codes: Vec<u64>,
) -> Self {
Self { compiler_output: Some(compiler_output), artifacts: cache, ignored_error_codes }
}

/// Get the (merged) solc compiler output
/// ```no_run
/// use std::collections::BTreeMap;
/// use ethers_solc::artifacts::Contract;
/// use ethers_solc::Project;
///
/// let project = Project::builder().build().unwrap();
/// let contracts: BTreeMap<String, Contract> =
/// project.compile().unwrap().output().contracts_into_iter().collect();
/// ```
pub fn output(self) -> CompilerOutput {
self.compiler_output.unwrap_or_default()
}

/// Combine two outputs
pub fn extend(&mut self, compiled: ProjectCompileOutput<T>) {
let ProjectCompileOutput { compiler_output, artifacts, .. } = compiled;
self.artifacts.extend(artifacts);
if let Some(output) = compiler_output {
self.extend_output(output);
}
}

pub fn extend_output(&mut self, compiled: CompilerOutput) {
if let Some(output) = self.compiler_output.as_mut() {
output.errors.extend(compiled.errors);
output.sources.extend(compiled.sources);
output.contracts.extend(compiled.contracts);
} else {
self.compiler_output = Some(compiled);
}
}

pub fn extend_artifacts(&mut self, artifacts: BTreeMap<PathBuf, T::Artifact>) {
self.artifacts.extend(artifacts);
}

/// Whether this type does not contain compiled contracts
pub fn is_unchanged(&self) -> bool {
!self.has_compiled_contracts()
}

/// Whether this type has a compiler output
pub fn has_compiled_contracts(&self) -> bool {
if let Some(output) = self.compiler_output.as_ref() {
!output.contracts.is_empty()
} else {
false
}
}

/// Whether there were errors
pub fn has_compiler_errors(&self) -> bool {
if let Some(output) = self.compiler_output.as_ref() {
output.has_error()
} else {
false
}
}

/// Finds the first contract with the given name and removes it from the set
pub fn remove(&mut self, contract: impl AsRef<str>) -> Option<T::Artifact> {
let contract = contract.as_ref();
if let Some(output) = self.compiler_output.as_mut() {
if let contract @ Some(_) = output
.contracts
.values_mut()
.find_map(|c| c.remove(contract).map(T::contract_to_artifact))
{
return contract
}
}
let key = self
.artifacts
.iter()
.find_map(|(path, _)| {
T::contract_name(path).filter(|name| name == contract).map(|_| path)
})?
.clone();
self.artifacts.remove(&key)
}
}

impl<T: ArtifactOutput> ProjectCompileOutput<T>
where
T::Artifact: Clone,
{
/// Finds the first contract with the given name
pub fn find(&self, contract: impl AsRef<str>) -> Option<Cow<T::Artifact>> {
let contract = contract.as_ref();
if let Some(output) = self.compiler_output.as_ref() {
if let contract @ Some(_) = output.contracts.values().find_map(|c| {
c.get(contract).map(|c| T::contract_to_artifact(c.clone())).map(Cow::Owned)
}) {
return contract
}
}
self.artifacts.iter().find_map(|(path, art)| {
T::contract_name(path).filter(|name| name == contract).map(|_| Cow::Borrowed(art))
})
}
}

impl<T: ArtifactOutput + 'static> ProjectCompileOutput<T> {
/// All artifacts together with their contract name
///
/// # Example
///
/// ```no_run
/// use std::collections::BTreeMap;
/// use ethers_solc::artifacts::CompactContract;
/// use ethers_solc::Project;
///
/// let project = Project::builder().build().unwrap();
/// let contracts: BTreeMap<String, CompactContract> = project.compile().unwrap().into_artifacts().collect();
/// ```
pub fn into_artifacts(mut self) -> Box<dyn Iterator<Item = (String, T::Artifact)>> {
let artifacts = self.artifacts.into_iter().filter_map(|(path, art)| {
T::contract_name(&path)
.map(|name| (format!("{:?}:{}", path.file_name().unwrap(), name), art))
});

let artifacts: Box<dyn Iterator<Item = (String, T::Artifact)>> =
if let Some(output) = self.compiler_output.take() {
Box::new(artifacts.chain(T::output_to_artifacts(output).into_values().flatten()))
} else {
Box::new(artifacts)
};
artifacts
}
}

impl<T: ArtifactOutput> fmt::Display for ProjectCompileOutput<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(output) = self.compiler_output.as_ref() {
output.diagnostics(&self.ignored_error_codes).fmt(f)
} else {
f.write_str("Nothing to compile")
}
}
}

#[cfg(test)]
mod tests {
#[test]
Expand Down
Loading

0 comments on commit 8b8fed7

Please sign in to comment.