2021-10-26 11:28:10 +00:00
|
|
|
pub mod artifacts;
|
2022-01-06 11:54:46 +00:00
|
|
|
pub mod sourcemap;
|
2021-10-26 11:28:10 +00:00
|
|
|
|
|
|
|
pub use artifacts::{CompilerInput, CompilerOutput, EvmVersion};
|
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
mod artifact_output;
|
2021-10-26 11:28:10 +00:00
|
|
|
pub mod cache;
|
2021-12-11 17:39:39 +00:00
|
|
|
pub mod hh;
|
2022-02-04 16:20:24 +00:00
|
|
|
pub use artifact_output::*;
|
|
|
|
|
2022-01-05 21:46:57 +00:00
|
|
|
mod resolver;
|
2021-12-12 23:39:28 +00:00
|
|
|
pub use hh::{HardhatArtifact, HardhatArtifacts};
|
2022-01-05 21:46:57 +00:00
|
|
|
pub use resolver::Graph;
|
2021-10-26 11:28:10 +00:00
|
|
|
|
|
|
|
mod compile;
|
2022-02-04 16:20:24 +00:00
|
|
|
pub use compile::{
|
|
|
|
output::{AggregatedCompilerOutput, ProjectCompileOutput},
|
|
|
|
*,
|
|
|
|
};
|
2021-10-26 11:28:10 +00:00
|
|
|
|
|
|
|
mod config;
|
2022-02-04 16:20:24 +00:00
|
|
|
pub use config::{AllowedLibPaths, PathStyle, ProjectPathsConfig, SolcConfig};
|
2021-10-30 17:59:44 +00:00
|
|
|
|
2021-11-13 19:31:55 +00:00
|
|
|
pub mod remappings;
|
2022-02-04 16:20:24 +00:00
|
|
|
use crate::artifacts::Source;
|
2021-10-26 11:28:10 +00:00
|
|
|
|
|
|
|
pub mod error;
|
|
|
|
pub mod utils;
|
2021-11-26 16:49:19 +00:00
|
|
|
|
2021-12-12 17:10:40 +00:00
|
|
|
use crate::{
|
2022-02-04 16:20:24 +00:00
|
|
|
artifacts::{Contract, Sources},
|
2021-12-12 17:10:40 +00:00
|
|
|
error::{SolcError, SolcIoError},
|
|
|
|
};
|
2021-10-26 11:28:10 +00:00
|
|
|
use error::Result;
|
2021-10-30 17:59:44 +00:00
|
|
|
use std::{
|
2022-01-17 12:27:40 +00:00
|
|
|
marker::PhantomData,
|
|
|
|
path::{Path, PathBuf},
|
2021-10-30 17:59:44 +00:00
|
|
|
};
|
2021-10-26 11:28:10 +00:00
|
|
|
|
2021-12-12 23:39:28 +00:00
|
|
|
/// Utilities for creating, mocking and testing of (temporary) projects
|
|
|
|
#[cfg(feature = "project-util")]
|
|
|
|
pub mod project_util;
|
|
|
|
|
2021-12-06 23:02:13 +00:00
|
|
|
/// Represents a project workspace and handles `solc` compiling of all contracts in that workspace.
|
2021-10-26 11:28:10 +00:00
|
|
|
#[derive(Debug)]
|
2021-11-15 23:29:06 +00:00
|
|
|
pub struct Project<Artifacts: ArtifactOutput = MinimalCombinedArtifacts> {
|
2021-10-26 11:28:10 +00:00
|
|
|
/// The layout of the
|
2021-10-30 17:59:44 +00:00
|
|
|
pub paths: ProjectPathsConfig,
|
2021-10-26 11:28:10 +00:00
|
|
|
/// Where to find solc
|
|
|
|
pub solc: Solc,
|
2021-10-30 17:59:44 +00:00
|
|
|
/// How solc invocation should be configured.
|
|
|
|
pub solc_config: SolcConfig,
|
2021-10-26 11:28:10 +00:00
|
|
|
/// Whether caching is enabled
|
|
|
|
pub cached: bool,
|
2021-11-15 23:29:06 +00:00
|
|
|
/// Whether writing artifacts to disk is enabled
|
|
|
|
pub no_artifacts: bool,
|
2021-11-18 13:10:41 +00:00
|
|
|
/// Whether writing artifacts to disk is enabled
|
|
|
|
pub auto_detect: bool,
|
2021-10-26 11:28:10 +00:00
|
|
|
/// How to handle compiler output
|
2021-11-15 23:29:06 +00:00
|
|
|
pub artifacts: PhantomData<Artifacts>,
|
2021-10-30 17:59:44 +00:00
|
|
|
/// Errors/Warnings which match these error codes are not going to be logged
|
|
|
|
pub ignored_error_codes: Vec<u64>,
|
2021-11-08 20:11:45 +00:00
|
|
|
/// The paths which will be allowed for library inclusion
|
|
|
|
pub allowed_lib_paths: AllowedLibPaths,
|
2021-12-06 23:02:13 +00:00
|
|
|
/// Maximum number of `solc` processes to run simultaneously.
|
|
|
|
solc_jobs: usize,
|
2022-02-04 16:20:24 +00:00
|
|
|
/// Offline mode, if set, network access (download solc) is disallowed
|
|
|
|
pub offline: bool,
|
2021-10-26 11:28:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Project {
|
2021-11-15 23:29:06 +00:00
|
|
|
/// Convenience function to call `ProjectBuilder::default()`
|
2021-10-30 17:59:44 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
2021-11-15 23:29:06 +00:00
|
|
|
/// Configure with `MinimalCombinedArtifacts` artifacts output
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use ethers_solc::Project;
|
|
|
|
/// let config = Project::builder().build().unwrap();
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// To configure any a project with any `ArtifactOutput` use either
|
|
|
|
///
|
2021-10-30 17:59:44 +00:00
|
|
|
/// ```rust
|
|
|
|
/// use ethers_solc::Project;
|
|
|
|
/// let config = Project::builder().build().unwrap();
|
|
|
|
/// ```
|
2021-11-15 23:29:06 +00:00
|
|
|
///
|
|
|
|
/// or use the builder directly
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use ethers_solc::{MinimalCombinedArtifacts, ProjectBuilder};
|
|
|
|
/// let config = ProjectBuilder::<MinimalCombinedArtifacts>::default().build().unwrap();
|
|
|
|
/// ```
|
2021-10-30 17:59:44 +00:00
|
|
|
pub fn builder() -> ProjectBuilder {
|
|
|
|
ProjectBuilder::default()
|
2021-10-26 11:28:10 +00:00
|
|
|
}
|
2021-11-15 23:29:06 +00:00
|
|
|
}
|
2021-10-26 11:28:10 +00:00
|
|
|
|
2021-11-15 23:29:06 +00:00
|
|
|
impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
2021-12-12 23:39:28 +00:00
|
|
|
/// Returns the path to the artifacts directory
|
|
|
|
pub fn artifacts_path(&self) -> &PathBuf {
|
|
|
|
&self.paths.artifacts
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the path to the sources directory
|
|
|
|
pub fn sources_path(&self) -> &PathBuf {
|
|
|
|
&self.paths.sources
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the path to the cache file
|
|
|
|
pub fn cache_path(&self) -> &PathBuf {
|
|
|
|
&self.paths.cache
|
|
|
|
}
|
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
/// Returns the root directory of the project
|
|
|
|
pub fn root(&self) -> &PathBuf {
|
|
|
|
&self.paths.root
|
2021-12-06 23:02:13 +00:00
|
|
|
}
|
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
/// Applies the configured settings to the given `Solc`
|
|
|
|
fn configure_solc(&self, mut solc: Solc) -> Solc {
|
|
|
|
if self.allowed_lib_paths.0.is_empty() {
|
|
|
|
solc = solc.arg("--allow-paths").arg(self.allowed_lib_paths.to_string());
|
2021-10-30 17:59:44 +00:00
|
|
|
}
|
2022-02-04 16:20:24 +00:00
|
|
|
solc
|
|
|
|
}
|
2021-12-05 13:27:37 +00:00
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
/// Sets the maximum number of parallel `solc` processes to run simultaneously.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// if `jobs == 0`
|
|
|
|
pub fn set_solc_jobs(&mut self, jobs: usize) {
|
|
|
|
assert!(jobs > 0);
|
|
|
|
self.solc_jobs = jobs;
|
2021-10-30 17:59:44 +00:00
|
|
|
}
|
|
|
|
|
2021-12-06 23:02:13 +00:00
|
|
|
/// Returns all sources found under the project's configured sources path
|
2021-11-28 17:14:34 +00:00
|
|
|
#[tracing::instrument(skip_all, fields(name = "sources"))]
|
2021-12-12 17:10:40 +00:00
|
|
|
pub fn sources(&self) -> Result<Sources> {
|
2022-01-05 21:46:57 +00:00
|
|
|
self.paths.read_sources()
|
2021-10-30 17:59:44 +00:00
|
|
|
}
|
|
|
|
|
2021-11-20 14:47:36 +00:00
|
|
|
/// This emits the cargo [`rerun-if-changed`](https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorerun-if-changedpath) instruction.
|
|
|
|
/// Which tells Cargo to re-run the build script if a file inside the project's sources
|
|
|
|
/// directory has changed.
|
|
|
|
///
|
|
|
|
/// Use this if you compile a project in a `build.rs` file.
|
|
|
|
///
|
|
|
|
/// # Example `build.rs` file
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// use ethers_solc::{Project, ProjectPathsConfig};
|
2021-12-06 23:02:13 +00:00
|
|
|
/// // configure the project with all its paths, solc, cache etc. where the root dir is the current rust project.
|
2021-11-20 14:47:36 +00:00
|
|
|
/// let project = Project::builder()
|
|
|
|
/// .paths(ProjectPathsConfig::hardhat(env!("CARGO_MANIFEST_DIR")).unwrap())
|
|
|
|
/// .build()
|
|
|
|
/// .unwrap();
|
|
|
|
/// let output = project.compile().unwrap();
|
|
|
|
/// // Tell Cargo that if a source file changes, to rerun this build script.
|
|
|
|
/// project.rerun_if_sources_changed();
|
|
|
|
/// ```
|
|
|
|
pub fn rerun_if_sources_changed(&self) {
|
|
|
|
println!("cargo:rerun-if-changed={}", self.paths.sources.display())
|
|
|
|
}
|
|
|
|
|
2022-01-05 21:46:57 +00:00
|
|
|
/// Attempts to compile the contracts found at the configured source location, see
|
|
|
|
/// `ProjectPathsConfig::sources`.
|
2021-10-30 17:59:44 +00:00
|
|
|
///
|
|
|
|
/// NOTE: this does not check if the contracts were successfully compiled, see
|
|
|
|
/// `CompilerOutput::has_error` instead.
|
2022-02-04 16:20:24 +00:00
|
|
|
///
|
2021-11-03 08:05:09 +00:00
|
|
|
/// NB: If the `svm` feature is enabled, this function will automatically detect
|
2022-02-04 16:20:24 +00:00
|
|
|
/// solc versions across files, see [`Self::svm_compile()`]
|
2022-01-11 10:02:57 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use ethers_solc::Project;
|
|
|
|
/// # fn demo(project: Project) {
|
|
|
|
/// let project = Project::builder().build().unwrap();
|
|
|
|
/// let output = project.compile().unwrap();
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-11-28 17:14:34 +00:00
|
|
|
#[tracing::instrument(skip_all, name = "compile")]
|
2021-11-15 23:29:06 +00:00
|
|
|
pub fn compile(&self) -> Result<ProjectCompileOutput<Artifacts>> {
|
2022-01-05 21:46:57 +00:00
|
|
|
let sources = self.paths.read_input_files()?;
|
2021-12-25 16:18:57 +00:00
|
|
|
tracing::trace!("found {} sources to compile: {:?}", sources.len(), sources.keys());
|
2021-11-03 08:05:09 +00:00
|
|
|
|
|
|
|
#[cfg(all(feature = "svm", feature = "async"))]
|
2021-11-18 13:10:41 +00:00
|
|
|
if self.auto_detect {
|
2021-12-25 16:18:57 +00:00
|
|
|
tracing::trace!("using solc auto detection to compile sources");
|
2021-11-18 13:10:41 +00:00
|
|
|
return self.svm_compile(sources)
|
|
|
|
}
|
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
let solc = self.configure_solc(self.solc.clone());
|
2022-01-05 21:46:57 +00:00
|
|
|
|
2021-11-18 13:10:41 +00:00
|
|
|
self.compile_with_version(&solc, sources)
|
2021-11-03 08:05:09 +00:00
|
|
|
}
|
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
/// Compiles a set of contracts using `svm` managed solc installs
|
|
|
|
///
|
|
|
|
/// This will autodetect the appropriate `Solc` version(s) to use when compiling the provided
|
|
|
|
/// `Sources`. Solc auto-detection follows semver rules, see also
|
|
|
|
/// [`crate::resolver::Graph::get_input_node_versions()`]
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// This returns an error if contracts in the `Sources` set are incompatible (violate semver
|
|
|
|
/// rules) with their imports, for example source contract `A(=0.8.11)` imports dependency
|
|
|
|
/// `C(<0.8.0)`, which are incompatible.
|
|
|
|
///
|
|
|
|
/// # Example
|
2022-01-05 21:46:57 +00:00
|
|
|
///
|
2022-02-04 16:20:24 +00:00
|
|
|
/// ```
|
|
|
|
/// use ethers_solc::{artifacts::Source, Project, utils};
|
|
|
|
/// # fn demo(project: Project) {
|
|
|
|
/// let project = Project::builder().build().unwrap();
|
|
|
|
/// let files = utils::source_files("./src");
|
|
|
|
/// let sources = Source::read_all(files).unwrap();
|
|
|
|
/// let output = project.svm_compile(sources).unwrap();
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-12-06 23:02:13 +00:00
|
|
|
#[cfg(all(feature = "svm", feature = "async"))]
|
2022-02-04 16:20:24 +00:00
|
|
|
pub fn svm_compile(&self, sources: Sources) -> Result<ProjectCompileOutput<Artifacts>> {
|
|
|
|
project::ProjectCompiler::with_sources(self, sources)?.compile()
|
2021-11-03 08:05:09 +00:00
|
|
|
}
|
|
|
|
|
2021-12-05 13:27:37 +00:00
|
|
|
/// Compiles the given source files with the exact `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
|
|
|
|
/// sources and their existing artifacts are read instead. This will also update the cache
|
|
|
|
/// file and cleans up entries for files which may have been removed. Unchanged files that
|
|
|
|
/// for which an artifact exist, are not compiled again.
|
2022-01-11 10:02:57 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use ethers_solc::{Project, Solc};
|
|
|
|
/// # fn demo(project: Project) {
|
|
|
|
/// let project = Project::builder().build().unwrap();
|
|
|
|
/// let sources = project.paths.read_sources().unwrap();
|
|
|
|
/// project
|
|
|
|
/// .compile_with_version(
|
|
|
|
/// &Solc::find_svm_installed_version("0.8.11").unwrap().unwrap(),
|
|
|
|
/// sources,
|
|
|
|
/// )
|
|
|
|
/// .unwrap();
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-11-03 08:05:09 +00:00
|
|
|
pub fn compile_with_version(
|
|
|
|
&self,
|
|
|
|
solc: &Solc,
|
2021-12-06 23:02:13 +00:00
|
|
|
sources: Sources,
|
2021-11-15 23:29:06 +00:00
|
|
|
) -> Result<ProjectCompileOutput<Artifacts>> {
|
2022-02-04 16:20:24 +00:00
|
|
|
project::ProjectCompiler::with_sources_and_solc(
|
|
|
|
self,
|
|
|
|
sources,
|
|
|
|
self.configure_solc(solc.clone()),
|
|
|
|
)?
|
|
|
|
.compile()
|
2021-10-30 17:59:44 +00:00
|
|
|
}
|
2021-12-04 17:27:30 +00:00
|
|
|
|
|
|
|
/// Removes the project's artifacts and cache file
|
2022-01-21 01:51:41 +00:00
|
|
|
///
|
|
|
|
/// If the cache file was the only file in the folder, this also removes the empty folder.
|
2022-02-04 16:20:24 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use ethers_solc::Project;
|
|
|
|
/// # fn demo(project: Project) {
|
|
|
|
/// let project = Project::builder().build().unwrap();
|
|
|
|
/// let _ = project.compile().unwrap();
|
|
|
|
/// assert!(project.artifacts_path().exists());
|
|
|
|
/// assert!(project.cache_path().exists());
|
|
|
|
///
|
|
|
|
/// project.cleanup();
|
|
|
|
/// assert!(!project.artifacts_path().exists());
|
|
|
|
/// assert!(!project.cache_path().exists());
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-12-12 17:10:40 +00:00
|
|
|
pub fn cleanup(&self) -> std::result::Result<(), SolcIoError> {
|
2021-12-05 13:27:37 +00:00
|
|
|
tracing::trace!("clean up project");
|
2021-12-12 23:39:28 +00:00
|
|
|
if self.cache_path().exists() {
|
2022-01-20 13:49:59 +00:00
|
|
|
std::fs::remove_file(self.cache_path())
|
2021-12-12 23:39:28 +00:00
|
|
|
.map_err(|err| SolcIoError::new(err, self.cache_path()))?;
|
2022-01-21 01:51:41 +00:00
|
|
|
if let Some(cache_folder) = self.cache_path().parent() {
|
|
|
|
// remove the cache folder if the cache file was the only file
|
|
|
|
if cache_folder
|
|
|
|
.read_dir()
|
|
|
|
.map_err(|err| SolcIoError::new(err, cache_folder))?
|
|
|
|
.next()
|
|
|
|
.is_none()
|
|
|
|
{
|
|
|
|
std::fs::remove_dir(cache_folder)
|
|
|
|
.map_err(|err| SolcIoError::new(err, cache_folder))?;
|
|
|
|
}
|
|
|
|
}
|
2021-12-12 23:39:28 +00:00
|
|
|
tracing::trace!("removed cache file \"{}\"", self.cache_path().display());
|
2021-12-04 17:27:30 +00:00
|
|
|
}
|
|
|
|
if self.paths.artifacts.exists() {
|
2021-12-12 23:39:28 +00:00
|
|
|
std::fs::remove_dir_all(self.artifacts_path())
|
|
|
|
.map_err(|err| SolcIoError::new(err, self.artifacts_path().clone()))?;
|
|
|
|
tracing::trace!("removed artifacts dir \"{}\"", self.artifacts_path().display());
|
2021-12-04 17:27:30 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-01-17 12:27:40 +00:00
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
/// Flattens the target solidity file into a single string suitable for verification.
|
2022-01-17 12:27:40 +00:00
|
|
|
///
|
|
|
|
/// This method uses a dependency graph to resolve imported files and substitute
|
|
|
|
/// import directives with the contents of target files. It will strip the pragma
|
2022-02-04 16:20:24 +00:00
|
|
|
/// version directives and SDPX license identifiers from all imported files.
|
2022-01-17 12:27:40 +00:00
|
|
|
///
|
2022-02-04 16:20:24 +00:00
|
|
|
/// NB: the SDPX license identifier will be removed from the imported file
|
2022-01-17 12:27:40 +00:00
|
|
|
/// only if it is found at the beginning of the file.
|
|
|
|
pub fn flatten(&self, target: &Path) -> Result<String> {
|
|
|
|
self.paths.flatten(target)
|
|
|
|
}
|
2021-10-30 17:59:44 +00:00
|
|
|
}
|
|
|
|
|
2021-11-15 23:29:06 +00:00
|
|
|
pub struct ProjectBuilder<Artifacts: ArtifactOutput = MinimalCombinedArtifacts> {
|
2021-10-30 17:59:44 +00:00
|
|
|
/// The layout of the
|
|
|
|
paths: Option<ProjectPathsConfig>,
|
|
|
|
/// Where to find solc
|
|
|
|
solc: Option<Solc>,
|
|
|
|
/// How solc invocation should be configured.
|
|
|
|
solc_config: Option<SolcConfig>,
|
|
|
|
/// Whether caching is enabled, default is true.
|
|
|
|
cached: bool,
|
2021-11-15 23:29:06 +00:00
|
|
|
/// Whether writing artifacts to disk is enabled, default is true.
|
|
|
|
no_artifacts: bool,
|
2021-11-18 13:10:41 +00:00
|
|
|
/// Whether automatic solc version detection is enabled
|
|
|
|
auto_detect: bool,
|
2022-02-04 16:20:24 +00:00
|
|
|
/// Use offline mode
|
|
|
|
offline: bool,
|
2021-11-15 23:29:06 +00:00
|
|
|
artifacts: PhantomData<Artifacts>,
|
2021-10-30 17:59:44 +00:00
|
|
|
/// Which error codes to ignore
|
|
|
|
pub ignored_error_codes: Vec<u64>,
|
2021-11-08 20:11:45 +00:00
|
|
|
/// All allowed paths
|
|
|
|
pub allowed_paths: Vec<PathBuf>,
|
2021-12-06 23:02:13 +00:00
|
|
|
solc_jobs: Option<usize>,
|
2021-10-30 17:59:44 +00:00
|
|
|
}
|
|
|
|
|
2021-11-15 23:29:06 +00:00
|
|
|
impl<Artifacts: ArtifactOutput> ProjectBuilder<Artifacts> {
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2021-10-30 17:59:44 +00:00
|
|
|
pub fn paths(mut self, paths: ProjectPathsConfig) -> Self {
|
|
|
|
self.paths = Some(paths);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2021-10-30 17:59:44 +00:00
|
|
|
pub fn solc(mut self, solc: impl Into<Solc>) -> Self {
|
|
|
|
self.solc = Some(solc.into());
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2021-10-30 17:59:44 +00:00
|
|
|
pub fn solc_config(mut self, solc_config: SolcConfig) -> Self {
|
|
|
|
self.solc_config = Some(solc_config);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2021-10-30 17:59:44 +00:00
|
|
|
pub fn ignore_error_code(mut self, code: u64) -> Self {
|
|
|
|
self.ignored_error_codes.push(code);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-01-20 19:41:19 +00:00
|
|
|
#[must_use]
|
|
|
|
pub fn ignore_error_codes(mut self, codes: impl IntoIterator<Item = u64>) -> Self {
|
|
|
|
for code in codes {
|
|
|
|
self = self.ignore_error_code(code);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-10-30 17:59:44 +00:00
|
|
|
/// Disables cached builds
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2022-01-20 19:41:19 +00:00
|
|
|
pub fn ephemeral(self) -> Self {
|
|
|
|
self.set_cached(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the cache status
|
|
|
|
#[must_use]
|
|
|
|
pub fn set_cached(mut self, cached: bool) -> Self {
|
|
|
|
self.cached = cached;
|
2021-10-30 17:59:44 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
/// Activates offline mode
|
|
|
|
///
|
|
|
|
/// Prevents network possible access to download/check solc installs
|
|
|
|
#[must_use]
|
|
|
|
pub fn offline(self) -> Self {
|
|
|
|
self.set_offline(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the offline status
|
|
|
|
#[must_use]
|
|
|
|
pub fn set_offline(mut self, offline: bool) -> Self {
|
|
|
|
self.offline = offline;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-11-15 23:29:06 +00:00
|
|
|
/// Disables writing artifacts to disk
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2022-01-20 19:41:19 +00:00
|
|
|
pub fn no_artifacts(self) -> Self {
|
|
|
|
self.set_no_artifacts(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the no artifacts status
|
|
|
|
#[must_use]
|
|
|
|
pub fn set_no_artifacts(mut self, artifacts: bool) -> Self {
|
|
|
|
self.no_artifacts = artifacts;
|
2021-11-15 23:29:06 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-01-20 19:41:19 +00:00
|
|
|
/// Sets automatic solc version detection
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2022-01-20 19:41:19 +00:00
|
|
|
pub fn set_auto_detect(mut self, auto_detect: bool) -> Self {
|
|
|
|
self.auto_detect = auto_detect;
|
2021-11-18 13:10:41 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-01-20 19:41:19 +00:00
|
|
|
/// Disables automatic solc version detection
|
|
|
|
#[must_use]
|
|
|
|
pub fn no_auto_detect(self) -> Self {
|
|
|
|
self.set_auto_detect(false)
|
|
|
|
}
|
|
|
|
|
2021-12-06 23:02:13 +00:00
|
|
|
/// Sets the maximum number of parallel `solc` processes to run simultaneously.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// `jobs` must be at least 1
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2021-12-06 23:02:13 +00:00
|
|
|
pub fn solc_jobs(mut self, jobs: usize) -> Self {
|
|
|
|
assert!(jobs > 0);
|
|
|
|
self.solc_jobs = Some(jobs);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the number of parallel `solc` processes to `1`, no parallelization
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2021-12-06 23:02:13 +00:00
|
|
|
pub fn single_solc_jobs(self) -> Self {
|
|
|
|
self.solc_jobs(1)
|
|
|
|
}
|
|
|
|
|
2021-11-15 23:29:06 +00:00
|
|
|
/// Set arbitrary `ArtifactOutputHandler`
|
|
|
|
pub fn artifacts<A: ArtifactOutput>(self) -> ProjectBuilder<A> {
|
|
|
|
let ProjectBuilder {
|
|
|
|
paths,
|
|
|
|
solc,
|
|
|
|
solc_config,
|
|
|
|
cached,
|
|
|
|
no_artifacts,
|
2021-11-18 13:10:41 +00:00
|
|
|
auto_detect,
|
2021-11-15 23:29:06 +00:00
|
|
|
ignored_error_codes,
|
|
|
|
allowed_paths,
|
2021-12-06 23:02:13 +00:00
|
|
|
solc_jobs,
|
2022-02-04 16:20:24 +00:00
|
|
|
offline,
|
2021-11-15 23:29:06 +00:00
|
|
|
..
|
|
|
|
} = self;
|
|
|
|
ProjectBuilder {
|
|
|
|
paths,
|
|
|
|
solc,
|
|
|
|
solc_config,
|
|
|
|
cached,
|
|
|
|
no_artifacts,
|
2021-11-18 13:10:41 +00:00
|
|
|
auto_detect,
|
2022-02-04 16:20:24 +00:00
|
|
|
offline,
|
2021-11-15 23:29:06 +00:00
|
|
|
artifacts: PhantomData::default(),
|
|
|
|
ignored_error_codes,
|
|
|
|
allowed_paths,
|
2021-12-06 23:02:13 +00:00
|
|
|
solc_jobs,
|
2021-11-15 23:29:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-08 20:11:45 +00:00
|
|
|
/// Adds an allowed-path to the solc executable
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2021-11-08 20:11:45 +00:00
|
|
|
pub fn allowed_path<T: Into<PathBuf>>(mut self, path: T) -> Self {
|
|
|
|
self.allowed_paths.push(path.into());
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds multiple allowed-path to the solc executable
|
2021-12-19 04:28:38 +00:00
|
|
|
#[must_use]
|
2021-11-08 20:11:45 +00:00
|
|
|
pub fn allowed_paths<I, S>(mut self, args: I) -> Self
|
|
|
|
where
|
|
|
|
I: IntoIterator<Item = S>,
|
|
|
|
S: Into<PathBuf>,
|
|
|
|
{
|
|
|
|
for arg in args {
|
|
|
|
self = self.allowed_path(arg);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-11-15 23:29:06 +00:00
|
|
|
pub fn build(self) -> Result<Project<Artifacts>> {
|
2021-11-08 20:11:45 +00:00
|
|
|
let Self {
|
|
|
|
paths,
|
|
|
|
solc,
|
|
|
|
solc_config,
|
|
|
|
cached,
|
2021-11-15 23:29:06 +00:00
|
|
|
no_artifacts,
|
2021-11-18 13:10:41 +00:00
|
|
|
auto_detect,
|
2021-11-08 20:11:45 +00:00
|
|
|
artifacts,
|
|
|
|
ignored_error_codes,
|
|
|
|
mut allowed_paths,
|
2021-12-06 23:02:13 +00:00
|
|
|
solc_jobs,
|
2022-02-04 16:20:24 +00:00
|
|
|
offline,
|
2021-11-08 20:11:45 +00:00
|
|
|
} = self;
|
2021-10-30 17:59:44 +00:00
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
let paths = paths.map(Ok).unwrap_or_else(ProjectPathsConfig::current_hardhat)?;
|
|
|
|
|
2021-10-30 17:59:44 +00:00
|
|
|
let solc = solc.unwrap_or_default();
|
2022-01-20 19:41:19 +00:00
|
|
|
let solc_config = solc_config.unwrap_or_else(|| SolcConfig::builder().build());
|
2021-10-30 17:59:44 +00:00
|
|
|
|
2021-11-08 20:11:45 +00:00
|
|
|
if allowed_paths.is_empty() {
|
|
|
|
// allow every contract under root by default
|
|
|
|
allowed_paths.push(paths.root.clone())
|
|
|
|
}
|
|
|
|
|
2021-10-30 17:59:44 +00:00
|
|
|
Ok(Project {
|
2021-11-08 20:11:45 +00:00
|
|
|
paths,
|
2021-10-30 17:59:44 +00:00
|
|
|
solc,
|
|
|
|
solc_config,
|
|
|
|
cached,
|
2021-11-15 23:29:06 +00:00
|
|
|
no_artifacts,
|
2021-11-18 13:10:41 +00:00
|
|
|
auto_detect,
|
2021-11-15 23:29:06 +00:00
|
|
|
artifacts,
|
2021-10-30 17:59:44 +00:00
|
|
|
ignored_error_codes,
|
2022-02-04 16:20:24 +00:00
|
|
|
allowed_lib_paths: allowed_paths.into(),
|
2021-12-06 23:02:13 +00:00
|
|
|
solc_jobs: solc_jobs.unwrap_or_else(::num_cpus::get),
|
2022-02-04 16:20:24 +00:00
|
|
|
offline,
|
2021-10-30 17:59:44 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-15 23:29:06 +00:00
|
|
|
impl<Artifacts: ArtifactOutput> Default for ProjectBuilder<Artifacts> {
|
2021-10-30 17:59:44 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
paths: None,
|
|
|
|
solc: None,
|
|
|
|
solc_config: None,
|
|
|
|
cached: true,
|
2021-11-15 23:29:06 +00:00
|
|
|
no_artifacts: false,
|
2021-11-18 13:10:41 +00:00
|
|
|
auto_detect: true,
|
2022-02-04 16:20:24 +00:00
|
|
|
offline: false,
|
2021-11-15 23:29:06 +00:00
|
|
|
artifacts: PhantomData::default(),
|
2021-10-30 17:59:44 +00:00
|
|
|
ignored_error_codes: Vec::new(),
|
2021-11-08 20:11:45 +00:00
|
|
|
allowed_paths: vec![],
|
2021-12-06 23:02:13 +00:00
|
|
|
solc_jobs: None,
|
2021-10-26 11:28:10 +00:00
|
|
|
}
|
2021-10-30 17:59:44 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-26 11:28:10 +00:00
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
impl<Artifacts: ArtifactOutput> ArtifactOutput for Project<Artifacts> {
|
|
|
|
type Artifact = Artifacts::Artifact;
|
2021-11-15 23:29:06 +00:00
|
|
|
|
2022-02-04 16:20:24 +00:00
|
|
|
fn contract_to_artifact(file: &str, name: &str, contract: Contract) -> Self::Artifact {
|
|
|
|
Artifacts::contract_to_artifact(file, name, contract)
|
2021-11-15 23:29:06 +00:00
|
|
|
}
|
2021-10-26 11:28:10 +00:00
|
|
|
}
|
2021-11-03 08:05:09 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2022-02-04 16:20:24 +00:00
|
|
|
use crate::remappings::Remapping;
|
|
|
|
|
2021-11-03 08:05:09 +00:00
|
|
|
#[test]
|
|
|
|
#[cfg(all(feature = "svm", feature = "async"))]
|
|
|
|
fn test_build_all_versions() {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
let paths = ProjectPathsConfig::builder()
|
|
|
|
.root("./test-data/test-contract-versions")
|
|
|
|
.sources("./test-data/test-contract-versions")
|
|
|
|
.build()
|
|
|
|
.unwrap();
|
2021-11-15 23:29:06 +00:00
|
|
|
let project = Project::builder().paths(paths).no_artifacts().ephemeral().build().unwrap();
|
2021-11-03 08:05:09 +00:00
|
|
|
let compiled = project.compile().unwrap();
|
2021-11-15 23:29:06 +00:00
|
|
|
assert!(!compiled.has_compiler_errors());
|
|
|
|
let contracts = compiled.output().contracts;
|
2021-11-03 08:05:09 +00:00
|
|
|
// Contracts A to F
|
2022-02-04 16:20:24 +00:00
|
|
|
assert_eq!(contracts.contracts().count(), 5);
|
2021-11-03 08:05:09 +00:00
|
|
|
}
|
2021-11-08 20:11:45 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[cfg(all(feature = "svm", feature = "async"))]
|
|
|
|
fn test_build_many_libs() {
|
|
|
|
use super::*;
|
|
|
|
|
2022-01-05 21:46:57 +00:00
|
|
|
let root = utils::canonicalize("./test-data/test-contract-libs").unwrap();
|
2021-11-08 20:11:45 +00:00
|
|
|
|
|
|
|
let paths = ProjectPathsConfig::builder()
|
|
|
|
.root(&root)
|
|
|
|
.sources(root.join("src"))
|
|
|
|
.lib(root.join("lib1"))
|
|
|
|
.lib(root.join("lib2"))
|
2022-02-04 16:20:24 +00:00
|
|
|
.remappings(
|
|
|
|
Remapping::find_many(&root.join("lib1"))
|
|
|
|
.into_iter()
|
|
|
|
.chain(Remapping::find_many(&root.join("lib2"))),
|
|
|
|
)
|
2021-11-08 20:11:45 +00:00
|
|
|
.build()
|
|
|
|
.unwrap();
|
|
|
|
let project = Project::builder()
|
|
|
|
.paths(paths)
|
2021-11-15 23:29:06 +00:00
|
|
|
.no_artifacts()
|
2021-11-08 20:11:45 +00:00
|
|
|
.ephemeral()
|
2021-11-15 23:29:06 +00:00
|
|
|
.no_artifacts()
|
2021-11-08 20:11:45 +00:00
|
|
|
.build()
|
|
|
|
.unwrap();
|
|
|
|
let compiled = project.compile().unwrap();
|
2021-11-15 23:29:06 +00:00
|
|
|
assert!(!compiled.has_compiler_errors());
|
|
|
|
let contracts = compiled.output().contracts;
|
2022-02-04 16:20:24 +00:00
|
|
|
assert_eq!(contracts.contracts().count(), 3);
|
2021-11-08 20:11:45 +00:00
|
|
|
}
|
2021-11-13 19:31:55 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[cfg(all(feature = "svm", feature = "async"))]
|
|
|
|
fn test_build_remappings() {
|
|
|
|
use super::*;
|
|
|
|
|
2022-01-05 21:46:57 +00:00
|
|
|
let root = utils::canonicalize("./test-data/test-contract-remappings").unwrap();
|
2021-11-13 19:31:55 +00:00
|
|
|
let paths = ProjectPathsConfig::builder()
|
|
|
|
.root(&root)
|
|
|
|
.sources(root.join("src"))
|
|
|
|
.lib(root.join("lib"))
|
2022-02-04 16:20:24 +00:00
|
|
|
.remappings(Remapping::find_many(&root.join("lib")))
|
2021-11-13 19:31:55 +00:00
|
|
|
.build()
|
|
|
|
.unwrap();
|
2021-11-15 23:29:06 +00:00
|
|
|
let project = Project::builder().no_artifacts().paths(paths).ephemeral().build().unwrap();
|
2021-11-13 19:31:55 +00:00
|
|
|
let compiled = project.compile().unwrap();
|
2021-11-15 23:29:06 +00:00
|
|
|
assert!(!compiled.has_compiler_errors());
|
|
|
|
let contracts = compiled.output().contracts;
|
2022-02-04 16:20:24 +00:00
|
|
|
assert_eq!(contracts.contracts().count(), 2);
|
2021-11-13 19:31:55 +00:00
|
|
|
}
|
2021-11-03 08:05:09 +00:00
|
|
|
}
|