feat(solc): include project paths in cache (#1097)
* feat: add project paths struct * feat: add project paths to cache file * chore: bump format version * update cache creation api * feat: add cache condition
This commit is contained in:
parent
842f4d260f
commit
26b6472f9b
|
@ -1,7 +1,7 @@
|
|||
//! Support for compiling contracts
|
||||
use crate::{
|
||||
artifacts::Sources,
|
||||
config::SolcConfig,
|
||||
config::{ProjectPaths, SolcConfig},
|
||||
error::{Result, SolcError},
|
||||
filter::{FilteredSource, FilteredSourceInfo, FilteredSources},
|
||||
resolver::GraphEdges,
|
||||
|
@ -25,7 +25,7 @@ use std::{
|
|||
/// `ethers-solc` uses a different format version id, but the actual format is consistent with
|
||||
/// hardhat This allows ethers-solc to detect if the cache file was written by hardhat or
|
||||
/// `ethers-solc`
|
||||
const ETHERS_FORMAT_VERSION: &str = "ethers-rs-sol-cache-2";
|
||||
const ETHERS_FORMAT_VERSION: &str = "ethers-rs-sol-cache-3";
|
||||
|
||||
/// The file name of the default cache file
|
||||
pub const SOLIDITY_FILES_CACHE_FILENAME: &str = "solidity-files-cache.json";
|
||||
|
@ -35,13 +35,15 @@ pub const SOLIDITY_FILES_CACHE_FILENAME: &str = "solidity-files-cache.json";
|
|||
pub struct SolFilesCache {
|
||||
#[serde(rename = "_format")]
|
||||
pub format: String,
|
||||
/// contains all directories used for the project
|
||||
pub paths: ProjectPaths,
|
||||
pub files: BTreeMap<PathBuf, CacheEntry>,
|
||||
}
|
||||
|
||||
impl SolFilesCache {
|
||||
/// Create a new cache instance with the given files
|
||||
pub fn new(files: BTreeMap<PathBuf, CacheEntry>) -> Self {
|
||||
Self { format: ETHERS_FORMAT_VERSION.to_string(), files }
|
||||
pub fn new(files: BTreeMap<PathBuf, CacheEntry>, paths: ProjectPaths) -> Self {
|
||||
Self { format: ETHERS_FORMAT_VERSION.to_string(), files, paths }
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
@ -348,7 +350,18 @@ impl SolFilesCache {
|
|||
|
||||
impl Default for SolFilesCache {
|
||||
fn default() -> Self {
|
||||
SolFilesCache { format: ETHERS_FORMAT_VERSION.to_string(), files: Default::default() }
|
||||
SolFilesCache {
|
||||
format: ETHERS_FORMAT_VERSION.to_string(),
|
||||
files: Default::default(),
|
||||
paths: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ProjectPathsConfig> for SolFilesCache {
|
||||
fn from(config: &'a ProjectPathsConfig) -> Self {
|
||||
let paths = config.paths_relative();
|
||||
SolFilesCache::new(Default::default(), paths)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -741,13 +754,26 @@ pub(crate) enum ArtifactsCache<'a, T: ArtifactOutput> {
|
|||
|
||||
impl<'a, T: ArtifactOutput> ArtifactsCache<'a, T> {
|
||||
pub fn new(project: &'a Project<T>, edges: GraphEdges) -> Result<Self> {
|
||||
/// returns the [SolFilesCache] to use
|
||||
fn get_cache<T: ArtifactOutput>(project: &Project<T>) -> SolFilesCache {
|
||||
// the currently configured paths
|
||||
let paths = project.paths.paths_relative();
|
||||
|
||||
if project.cache_path().exists() {
|
||||
if let Ok(cache) = SolFilesCache::read_joined(&project.paths) {
|
||||
if cache.paths == paths {
|
||||
// unchanged project paths
|
||||
return cache
|
||||
}
|
||||
}
|
||||
}
|
||||
// new empty cache
|
||||
SolFilesCache::new(Default::default(), paths)
|
||||
}
|
||||
|
||||
let cache = if project.cached {
|
||||
// read the cache file if it already exists
|
||||
let mut cache = if project.cache_path().exists() {
|
||||
SolFilesCache::read_joined(&project.paths).unwrap_or_default()
|
||||
} else {
|
||||
SolFilesCache::default()
|
||||
};
|
||||
let mut cache = get_cache(project);
|
||||
|
||||
cache.remove_missing_files();
|
||||
|
||||
|
|
|
@ -10,14 +10,14 @@ use crate::{
|
|||
use crate::artifacts::output_selection::ContractOutputSelection;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
collections::{BTreeSet, HashSet},
|
||||
fmt::{self, Formatter},
|
||||
fs,
|
||||
path::{Component, Path, PathBuf},
|
||||
};
|
||||
|
||||
/// Where to find all files or where to write them
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ProjectPathsConfig {
|
||||
/// Project root
|
||||
pub root: PathBuf,
|
||||
|
@ -60,6 +60,25 @@ impl ProjectPathsConfig {
|
|||
Self::dapptools(std::env::current_dir().map_err(|err| SolcError::io(err, "."))?)
|
||||
}
|
||||
|
||||
/// Returns a new [ProjectPaths] instance that contains all directories configured for this
|
||||
/// project
|
||||
pub fn paths(&self) -> ProjectPaths {
|
||||
ProjectPaths {
|
||||
artifacts: self.artifacts.clone(),
|
||||
sources: self.sources.clone(),
|
||||
tests: self.tests.clone(),
|
||||
libraries: self.libraries.iter().cloned().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as [Self::paths()] but strips the `root` form all paths,
|
||||
/// [ProjectPaths::strip_prefix_all()]
|
||||
pub fn paths_relative(&self) -> ProjectPaths {
|
||||
let mut paths = self.paths();
|
||||
paths.strip_prefix_all(&self.root);
|
||||
paths
|
||||
}
|
||||
|
||||
/// Creates all configured dirs and files
|
||||
pub fn create_all(&self) -> std::result::Result<(), SolcIoError> {
|
||||
if let Some(parent) = self.cache.parent() {
|
||||
|
@ -316,6 +335,61 @@ impl fmt::Display for ProjectPathsConfig {
|
|||
}
|
||||
}
|
||||
|
||||
/// This is a subset of [ProjectPathsConfig] that contains all relevant folders in the project
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ProjectPaths {
|
||||
pub artifacts: PathBuf,
|
||||
pub sources: PathBuf,
|
||||
pub tests: PathBuf,
|
||||
pub libraries: BTreeSet<PathBuf>,
|
||||
}
|
||||
|
||||
impl ProjectPaths {
|
||||
/// Joins the folders' location with `root`
|
||||
pub fn join_all(&mut self, root: impl AsRef<Path>) -> &mut Self {
|
||||
let root = root.as_ref();
|
||||
self.artifacts = root.join(&self.artifacts);
|
||||
self.sources = root.join(&self.sources);
|
||||
self.tests = root.join(&self.tests);
|
||||
let libraries = std::mem::take(&mut self.libraries);
|
||||
self.libraries.extend(libraries.into_iter().map(|p| root.join(p)));
|
||||
self
|
||||
}
|
||||
|
||||
/// Removes `base` from all folders
|
||||
pub fn strip_prefix_all(&mut self, base: impl AsRef<Path>) -> &mut Self {
|
||||
let base = base.as_ref();
|
||||
|
||||
if let Ok(prefix) = self.artifacts.strip_prefix(base) {
|
||||
self.artifacts = prefix.to_path_buf();
|
||||
}
|
||||
if let Ok(prefix) = self.sources.strip_prefix(base) {
|
||||
self.sources = prefix.to_path_buf();
|
||||
}
|
||||
if let Ok(prefix) = self.tests.strip_prefix(base) {
|
||||
self.tests = prefix.to_path_buf();
|
||||
}
|
||||
let libraries = std::mem::take(&mut self.libraries);
|
||||
self.libraries.extend(
|
||||
libraries
|
||||
.into_iter()
|
||||
.map(|p| p.strip_prefix(base).map(|p| p.to_path_buf()).unwrap_or(p)),
|
||||
);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ProjectPaths {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
artifacts: "out".into(),
|
||||
sources: "src".into(),
|
||||
tests: "tests".into(),
|
||||
libraries: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum PathStyle {
|
||||
HardHat,
|
||||
|
|
Loading…
Reference in New Issue