refactor(solc): add new io error with path info (#680)

* refactor(solc): add new io error with path info

* chore: rustfmt
This commit is contained in:
Matthias Seitz 2021-12-12 18:10:40 +01:00 committed by GitHub
parent ab8b5233d2
commit 5dec757493
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 134 additions and 66 deletions

View File

@ -6,12 +6,12 @@ use md5::Digest;
use semver::Version; use semver::Version;
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
fmt, fs, io, fmt, fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
str::FromStr, str::FromStr,
}; };
use crate::{compile::*, remappings::Remapping, utils}; use crate::{compile::*, error::SolcIoError, remappings::Remapping, utils};
use ethers_core::abi::Address; use ethers_core::abi::Address;
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
@ -30,7 +30,7 @@ pub struct CompilerInput {
impl CompilerInput { impl CompilerInput {
/// Reads all contracts found under the path /// Reads all contracts found under the path
pub fn new(path: impl AsRef<Path>) -> io::Result<Self> { pub fn new(path: impl AsRef<Path>) -> Result<Self, SolcIoError> {
Source::read_all_from(path.as_ref()).map(Self::with_sources) Source::read_all_from(path.as_ref()).map(Self::with_sources)
} }
@ -382,17 +382,18 @@ pub struct Source {
impl Source { impl Source {
/// Reads the file content /// Reads the file content
pub fn read(file: impl AsRef<Path>) -> io::Result<Self> { pub fn read(file: impl AsRef<Path>) -> Result<Self, SolcIoError> {
Ok(Self { content: fs::read_to_string(file.as_ref())? }) let file = file.as_ref();
Ok(Self { content: fs::read_to_string(file).map_err(|err| SolcIoError::new(err, file))? })
} }
/// Finds all source files under the given dir path and reads them all /// Finds all source files under the given dir path and reads them all
pub fn read_all_from(dir: impl AsRef<Path>) -> io::Result<Sources> { pub fn read_all_from(dir: impl AsRef<Path>) -> Result<Sources, SolcIoError> {
Self::read_all(utils::source_files(dir)?) Self::read_all(utils::source_files(dir))
} }
/// Reads all files /// Reads all files
pub fn read_all<T, I>(files: I) -> io::Result<Sources> pub fn read_all<T, I>(files: I) -> Result<Sources, SolcIoError>
where where
I: IntoIterator<Item = T>, I: IntoIterator<Item = T>,
T: Into<PathBuf>, T: Into<PathBuf>,
@ -421,17 +422,22 @@ impl Source {
#[cfg(feature = "async")] #[cfg(feature = "async")]
impl Source { impl Source {
/// async version of `Self::read` /// async version of `Self::read`
pub async fn async_read(file: impl AsRef<Path>) -> io::Result<Self> { pub async fn async_read(file: impl AsRef<Path>) -> Result<Self, SolcIoError> {
Ok(Self { content: tokio::fs::read_to_string(file.as_ref()).await? }) let file = file.as_ref();
Ok(Self {
content: tokio::fs::read_to_string(file)
.await
.map_err(|err| SolcIoError::new(err, file))?,
})
} }
/// Finds all source files under the given dir path and reads them all /// Finds all source files under the given dir path and reads them all
pub async fn async_read_all_from(dir: impl AsRef<Path>) -> io::Result<Sources> { pub async fn async_read_all_from(dir: impl AsRef<Path>) -> Result<Sources, SolcIoError> {
Self::async_read_all(utils::source_files(dir.as_ref())?).await Self::async_read_all(utils::source_files(dir.as_ref())).await
} }
/// async version of `Self::read_all` /// async version of `Self::read_all`
pub async fn async_read_all<T, I>(files: I) -> io::Result<Sources> pub async fn async_read_all<T, I>(files: I) -> Result<Sources, SolcIoError>
where where
I: IntoIterator<Item = T>, I: IntoIterator<Item = T>,
T: Into<PathBuf>, T: Into<PathBuf>,

View File

@ -64,7 +64,7 @@ impl SolFilesCache {
pub fn read(path: impl AsRef<Path>) -> Result<Self> { pub fn read(path: impl AsRef<Path>) -> Result<Self> {
let path = path.as_ref(); let path = path.as_ref();
tracing::trace!("reading solfiles cache at {}", path.display()); tracing::trace!("reading solfiles cache at {}", path.display());
let file = fs::File::open(path)?; let file = fs::File::open(path).map_err(|err| SolcError::io(err, path))?;
let file = std::io::BufReader::new(file); let file = std::io::BufReader::new(file);
let cache = serde_json::from_reader(file)?; let cache = serde_json::from_reader(file)?;
tracing::trace!("done"); tracing::trace!("done");
@ -74,7 +74,7 @@ impl SolFilesCache {
/// Write the cache to json file /// Write the cache to json file
pub fn write(&self, path: impl AsRef<Path>) -> Result<()> { pub fn write(&self, path: impl AsRef<Path>) -> Result<()> {
let path = path.as_ref(); let path = path.as_ref();
let file = fs::File::create(path)?; let file = fs::File::create(path).map_err(|err| SolcError::io(err, path))?;
tracing::trace!("writing cache to json file"); tracing::trace!("writing cache to json file");
serde_json::to_writer_pretty(file, self)?; serde_json::to_writer_pretty(file, self)?;
tracing::trace!("cache file located: {}", path.display()); tracing::trace!("cache file located: {}", path.display());
@ -198,13 +198,16 @@ impl SolFilesCache {
#[cfg(feature = "async")] #[cfg(feature = "async")]
impl SolFilesCache { impl SolFilesCache {
pub async fn async_read(path: impl AsRef<Path>) -> Result<Self> { pub async fn async_read(path: impl AsRef<Path>) -> Result<Self> {
let content = tokio::fs::read_to_string(path.as_ref()).await?; let path = path.as_ref();
let content =
tokio::fs::read_to_string(path).await.map_err(|err| SolcError::io(err, path))?;
Ok(serde_json::from_str(&content)?) Ok(serde_json::from_str(&content)?)
} }
pub async fn async_write(&self, path: impl AsRef<Path>) -> Result<()> { pub async fn async_write(&self, path: impl AsRef<Path>) -> Result<()> {
let path = path.as_ref();
let content = serde_json::to_vec_pretty(self)?; let content = serde_json::to_vec_pretty(self)?;
Ok(tokio::fs::write(path.as_ref(), content).await?) Ok(tokio::fs::write(path, content).await.map_err(|err| SolcError::io(err, path))?)
} }
} }
@ -236,12 +239,18 @@ impl SolFilesCacheBuilder {
let solc_config = let solc_config =
self.solc_config.map(Ok).unwrap_or_else(|| SolcConfig::builder().build())?; self.solc_config.map(Ok).unwrap_or_else(|| SolcConfig::builder().build())?;
let root = self.root.map(Ok).unwrap_or_else(std::env::current_dir)?; let root = self
.root
.map(Ok)
.unwrap_or_else(std::env::current_dir)
.map_err(|err| SolcError::io(err, "."))?;
let mut files = BTreeMap::new(); let mut files = BTreeMap::new();
for (file, source) in sources { for (file, source) in sources {
let last_modification_date = fs::metadata(&file)? let last_modification_date = fs::metadata(&file)
.modified()? .map_err(|err| SolcError::io(err, file.clone()))?
.modified()
.map_err(|err| SolcError::io(err, file.clone()))?
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.map_err(|err| SolcError::solc(err.to_string()))? .map_err(|err| SolcError::solc(err.to_string()))?
.as_millis() as u64; .as_millis() as u64;
@ -268,7 +277,9 @@ impl SolFilesCacheBuilder {
if dest.exists() { if dest.exists() {
// read the existing cache and extend it by the files that changed // read the existing cache and extend it by the files that changed
// (if we just wrote to the cache file, we'd overwrite the existing data) // (if we just wrote to the cache file, we'd overwrite the existing data)
let reader = std::io::BufReader::new(File::open(dest)?); let reader = std::io::BufReader::new(
File::open(dest).map_err(|err| SolcError::io(err, dest))?,
);
let mut cache: SolFilesCache = serde_json::from_reader(reader)?; let mut cache: SolFilesCache = serde_json::from_reader(reader)?;
assert_eq!(cache.format, format); assert_eq!(cache.format, format);
cache.files.extend(files); cache.files.extend(files);

View File

@ -247,7 +247,8 @@ impl Solc {
let version = self.version_short()?; let version = self.version_short()?;
let mut version_path = svm::version_path(version.to_string().as_str()); let mut version_path = svm::version_path(version.to_string().as_str());
version_path.push(format!("solc-{}", version.to_string().as_str())); version_path.push(format!("solc-{}", version.to_string().as_str()));
let content = std::fs::read(version_path)?; let content =
std::fs::read(&version_path).map_err(|err| SolcError::io(err, version_path))?;
use sha2::Digest; use sha2::Digest;
let mut hasher = sha2::Sha256::new(); let mut hasher = sha2::Sha256::new();
@ -265,6 +266,7 @@ impl Solc {
/// Convenience function for compiling all sources under the given path /// Convenience function for compiling all sources under the given path
pub fn compile_source(&self, path: impl AsRef<Path>) -> Result<CompilerOutput> { pub fn compile_source(&self, path: impl AsRef<Path>) -> Result<CompilerOutput> {
let path = path.as_ref();
self.compile(&CompilerInput::new(path)?) self.compile(&CompilerInput::new(path)?)
} }
@ -302,11 +304,12 @@ impl Solc {
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn()?; .spawn()
.map_err(|err| SolcError::io(err, &self.solc))?;
let stdin = child.stdin.take().unwrap(); let stdin = child.stdin.take().unwrap();
serde_json::to_writer(stdin, input)?; serde_json::to_writer(stdin, input)?;
compile_output(child.wait_with_output()?) compile_output(child.wait_with_output().map_err(|err| SolcError::io(err, &self.solc))?)
} }
pub fn version_short(&self) -> Result<Version> { pub fn version_short(&self) -> Result<Version> {
@ -322,7 +325,8 @@ impl Solc {
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.output()?, .output()
.map_err(|err| SolcError::io(err, &self.solc))?,
) )
} }
} }
@ -363,11 +367,14 @@ impl Solc {
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn()?; .spawn()
.map_err(|err| SolcError::io(err, &self.solc))?;
let stdin = child.stdin.as_mut().unwrap(); let stdin = child.stdin.as_mut().unwrap();
stdin.write_all(&content).await?; stdin.write_all(&content).await.map_err(|err| SolcError::io(err, &self.solc))?;
stdin.flush().await?; stdin.flush().await.map_err(|err| SolcError::io(err, &self.solc))?;
compile_output(child.wait_with_output().await?) compile_output(
child.wait_with_output().await.map_err(|err| SolcError::io(err, &self.solc))?,
)
} }
pub async fn async_version(&self) -> Result<Version> { pub async fn async_version(&self) -> Result<Version> {
@ -377,9 +384,11 @@ impl Solc {
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn()? .spawn()
.map_err(|err| SolcError::io(err, &self.solc))?
.wait_with_output() .wait_with_output()
.await?, .await
.map_err(|err| SolcError::io(err, &self.solc))?,
) )
} }
@ -470,7 +479,8 @@ fn version_from_output(output: Output) -> Result<Version> {
.stdout .stdout
.lines() .lines()
.last() .last()
.ok_or_else(|| SolcError::solc("version not found in solc output"))??; .ok_or_else(|| SolcError::solc("version not found in solc output"))?
.map_err(|err| SolcError::msg(format!("Failed to read output: {}", err)))?;
// NOTE: semver doesn't like `+` in g++ in build metadata which is invalid semver // NOTE: semver doesn't like `+` in g++ in build metadata which is invalid semver
Ok(Version::from_str(&version.trim_start_matches("Version: ").replace(".g++", ".gcc"))?) Ok(Version::from_str(&version.trim_start_matches("Version: ").replace(".g++", ".gcc"))?)
} else { } else {

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
artifacts::{CompactContract, CompactContractRef, Contract, Settings}, artifacts::{CompactContract, CompactContractRef, Contract, Settings},
cache::SOLIDITY_FILES_CACHE_FILENAME, cache::SOLIDITY_FILES_CACHE_FILENAME,
error::{Result, SolcError}, error::{Result, SolcError, SolcIoError},
hh::HardhatArtifact, hh::HardhatArtifact,
remappings::Remapping, remappings::Remapping,
CompilerOutput, CompilerOutput,
@ -51,12 +51,12 @@ impl ProjectPathsConfig {
/// Creates a new config with the current directory as the root /// Creates a new config with the current directory as the root
pub fn current_hardhat() -> Result<Self> { pub fn current_hardhat() -> Result<Self> {
Self::hardhat(std::env::current_dir()?) Self::hardhat(std::env::current_dir().map_err(|err| SolcError::io(err, "."))?)
} }
/// Creates a new config with the current directory as the root /// Creates a new config with the current directory as the root
pub fn current_dapptools() -> Result<Self> { pub fn current_dapptools() -> Result<Self> {
Self::dapptools(std::env::current_dir()?) Self::dapptools(std::env::current_dir().map_err(|err| SolcError::io(err, "."))?)
} }
} }
@ -68,7 +68,8 @@ pub enum PathStyle {
impl PathStyle { impl PathStyle {
pub fn paths(&self, root: impl AsRef<Path>) -> Result<ProjectPathsConfig> { pub fn paths(&self, root: impl AsRef<Path>) -> Result<ProjectPathsConfig> {
let root = std::fs::canonicalize(root)?; let root = root.as_ref();
let root = std::fs::canonicalize(root).map_err(|err| SolcError::io(err, root))?;
Ok(match self { Ok(match self {
PathStyle::Dapptools => ProjectPathsConfig::builder() PathStyle::Dapptools => ProjectPathsConfig::builder()
@ -157,9 +158,13 @@ impl ProjectPathsConfigBuilder {
self self
} }
pub fn build(self) -> io::Result<ProjectPathsConfig> { pub fn build(self) -> std::result::Result<ProjectPathsConfig, SolcIoError> {
let root = self.root.map(Ok).unwrap_or_else(std::env::current_dir)?; let root = self
let root = std::fs::canonicalize(root)?; .root
.map(Ok)
.unwrap_or_else(std::env::current_dir)
.map_err(|err| SolcIoError::new(err, "."))?;
let root = std::fs::canonicalize(&root).map_err(|err| SolcIoError::new(err, root))?;
Ok(ProjectPathsConfig { Ok(ProjectPathsConfig {
cache: self cache: self
@ -287,7 +292,8 @@ pub trait ArtifactOutput {
} }
fn read_cached_artifact(path: impl AsRef<Path>) -> Result<Self::Artifact> { fn read_cached_artifact(path: impl AsRef<Path>) -> Result<Self::Artifact> {
let file = fs::File::open(path.as_ref())?; let path = path.as_ref();
let file = fs::File::open(path).map_err(|err| SolcError::io(err, path))?;
let file = io::BufReader::new(file); let file = io::BufReader::new(file);
Ok(serde_json::from_reader(file)?) Ok(serde_json::from_reader(file)?)
} }
@ -362,7 +368,8 @@ impl ArtifactOutput for MinimalCombinedArtifacts {
})?; })?;
} }
let min = CompactContractRef::from(contract); let min = CompactContractRef::from(contract);
fs::write(&file, serde_json::to_vec_pretty(&min)?)? fs::write(&file, serde_json::to_vec_pretty(&min)?)
.map_err(|err| SolcError::io(err, file))?
} }
} }
Ok(()) Ok(())
@ -386,7 +393,8 @@ impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback {
} }
fn read_cached_artifact(path: impl AsRef<Path>) -> Result<Self::Artifact> { fn read_cached_artifact(path: impl AsRef<Path>) -> Result<Self::Artifact> {
let content = fs::read_to_string(path)?; let path = path.as_ref();
let content = fs::read_to_string(path).map_err(|err| SolcError::io(err, path))?;
if let Ok(a) = serde_json::from_str(&content) { if let Ok(a) = serde_json::from_str(&content) {
Ok(a) Ok(a)
} else { } else {
@ -429,17 +437,18 @@ impl fmt::Display for AllowedLibPaths {
} }
impl<T: Into<PathBuf>> TryFrom<Vec<T>> for AllowedLibPaths { impl<T: Into<PathBuf>> TryFrom<Vec<T>> for AllowedLibPaths {
type Error = std::io::Error; type Error = SolcIoError;
fn try_from(libs: Vec<T>) -> std::result::Result<Self, Self::Error> { fn try_from(libs: Vec<T>) -> std::result::Result<Self, Self::Error> {
let libs = libs let libs = libs
.into_iter() .into_iter()
.map(|lib| { .map(|lib| {
let path: PathBuf = lib.into(); let path: PathBuf = lib.into();
let lib = std::fs::canonicalize(path)?; let lib =
std::fs::canonicalize(&path).map_err(|err| SolcIoError::new(err, path))?;
Ok(lib) Ok(lib)
}) })
.collect::<std::result::Result<Vec<_>, std::io::Error>>()?; .collect::<std::result::Result<Vec<_>, _>>()?;
Ok(AllowedLibPaths(libs)) Ok(AllowedLibPaths(libs))
} }
} }

View File

@ -1,3 +1,4 @@
use std::{io, path::PathBuf};
use thiserror::Error; use thiserror::Error;
pub type Result<T> = std::result::Result<T, SolcError>; pub type Result<T> = std::result::Result<T, SolcError>;
@ -21,7 +22,7 @@ pub enum SolcError {
SerdeJson(#[from] serde_json::Error), SerdeJson(#[from] serde_json::Error),
/// Filesystem IO error /// Filesystem IO error
#[error(transparent)] #[error(transparent)]
Io(#[from] std::io::Error), Io(#[from] SolcIoError),
#[cfg(feature = "svm")] #[cfg(feature = "svm")]
#[error(transparent)] #[error(transparent)]
SvmError(#[from] svm::SolcVmError), SvmError(#[from] svm::SolcVmError),
@ -35,6 +36,9 @@ pub enum SolcError {
} }
impl SolcError { impl SolcError {
pub(crate) fn io(err: io::Error, path: impl Into<PathBuf>) -> Self {
SolcIoError::new(err, path).into()
}
pub(crate) fn solc(msg: impl Into<String>) -> Self { pub(crate) fn solc(msg: impl Into<String>) -> Self {
SolcError::SolcError(msg.into()) SolcError::SolcError(msg.into())
} }
@ -42,3 +46,22 @@ impl SolcError {
SolcError::Message(msg.into()) SolcError::Message(msg.into())
} }
} }
#[derive(Debug, Error)]
#[error("\"{}\": {io}", self.path.display())]
pub struct SolcIoError {
io: io::Error,
path: PathBuf,
}
impl SolcIoError {
pub fn new(io: io::Error, path: impl Into<PathBuf>) -> Self {
Self { io, path: path.into() }
}
}
impl From<SolcIoError> for io::Error {
fn from(err: SolcIoError) -> Self {
err.io
}
}

View File

@ -73,7 +73,8 @@ impl ArtifactOutput for HardhatArtifacts {
})?; })?;
} }
let artifact = Self::contract_to_artifact(file, name, contract.clone()); let artifact = Self::contract_to_artifact(file, name, contract.clone());
fs::write(&artifact_file, serde_json::to_vec_pretty(&artifact)?)? fs::write(&artifact_file, serde_json::to_vec_pretty(&artifact)?)
.map_err(|err| SolcError::io(err, artifact_file))?
} }
} }
Ok(()) Ok(())

View File

@ -26,10 +26,14 @@ use crate::{artifacts::Source, cache::SolFilesCache};
pub mod error; pub mod error;
pub mod utils; pub mod utils;
use crate::{artifacts::Sources, cache::PathMap}; use crate::{
artifacts::Sources,
cache::PathMap,
error::{SolcError, SolcIoError},
};
use error::Result; use error::Result;
use std::{ use std::{
borrow::Cow, collections::BTreeMap, convert::TryInto, fmt, fs, io, marker::PhantomData, borrow::Cow, collections::BTreeMap, convert::TryInto, fmt, fs, marker::PhantomData,
path::PathBuf, path::PathBuf,
}; };
@ -117,7 +121,7 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
if let Some(cache_dir) = self.paths.cache.parent() { if let Some(cache_dir) = self.paths.cache.parent() {
tracing::trace!("creating cache file parent directory \"{}\"", cache_dir.display()); tracing::trace!("creating cache file parent directory \"{}\"", cache_dir.display());
fs::create_dir_all(cache_dir)? fs::create_dir_all(cache_dir).map_err(|err| SolcError::io(err, cache_dir))?
} }
tracing::trace!("writing cache file to \"{}\"", self.paths.cache.display()); tracing::trace!("writing cache file to \"{}\"", self.paths.cache.display());
@ -128,9 +132,9 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
/// Returns all sources found under the project's configured sources path /// Returns all sources found under the project's configured sources path
#[tracing::instrument(skip_all, fields(name = "sources"))] #[tracing::instrument(skip_all, fields(name = "sources"))]
pub fn sources(&self) -> io::Result<Sources> { pub fn sources(&self) -> Result<Sources> {
tracing::trace!("reading all sources from \"{}\"", self.paths.sources.display()); tracing::trace!("reading all sources from \"{}\"", self.paths.sources.display());
Source::read_all_from(&self.paths.sources) Ok(Source::read_all_from(&self.paths.sources)?)
} }
/// This emits the cargo [`rerun-if-changed`](https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorerun-if-changedpath) instruction. /// This emits the cargo [`rerun-if-changed`](https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorerun-if-changedpath) instruction.
@ -161,7 +165,7 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
fn resolved_libraries( fn resolved_libraries(
&self, &self,
sources: &Sources, sources: &Sources,
) -> io::Result<BTreeMap<PathBuf, (Source, PathBuf)>> { ) -> Result<BTreeMap<PathBuf, (Source, PathBuf)>> {
let mut libs = BTreeMap::default(); let mut libs = BTreeMap::default();
for source in sources.values() { for source in sources.values() {
for import in source.parse_imports() { for import in source.parse_imports() {
@ -462,14 +466,16 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
} }
/// Removes the project's artifacts and cache file /// Removes the project's artifacts and cache file
pub fn cleanup(&self) -> Result<()> { pub fn cleanup(&self) -> std::result::Result<(), SolcIoError> {
tracing::trace!("clean up project"); tracing::trace!("clean up project");
if self.paths.cache.exists() { if self.paths.cache.exists() {
std::fs::remove_file(&self.paths.cache)?; std::fs::remove_file(&self.paths.cache)
.map_err(|err| SolcIoError::new(err, self.paths.cache.clone()))?;
tracing::trace!("removed cache file \"{}\"", self.paths.cache.display()); tracing::trace!("removed cache file \"{}\"", self.paths.cache.display());
} }
if self.paths.artifacts.exists() { if self.paths.artifacts.exists() {
std::fs::remove_dir_all(&self.paths.artifacts)?; std::fs::remove_dir_all(&self.paths.artifacts)
.map_err(|err| SolcIoError::new(err, self.paths.artifacts.clone()))?;
tracing::trace!("removed artifacts dir \"{}\"", self.paths.artifacts.display()); tracing::trace!("removed artifacts dir \"{}\"", self.paths.artifacts.display());
} }
Ok(()) Ok(())

View File

@ -132,16 +132,19 @@ impl Remapping {
// nothing to find // nothing to find
return Ok(Vec::new()) return Ok(Vec::new())
} }
let mut paths = std::fs::read_dir(path)?.into_iter().collect::<Vec<_>>(); let mut paths = std::fs::read_dir(path)
.map_err(|err| SolcError::io(err, path))?
.into_iter()
.collect::<Vec<_>>();
let mut remappings = Vec::new(); let mut remappings = Vec::new();
while let Some(path) = paths.pop() { while let Some(p) = paths.pop() {
let path = path?.path(); let path = p.map_err(|err| SolcError::io(err, path))?.path();
// get all the directories inside a file if it's a valid dir // get all the directories inside a file if it's a valid dir
if let Ok(dir) = std::fs::read_dir(&path) { if let Ok(dir) = std::fs::read_dir(&path) {
for inner in dir { for inner in dir {
let inner = inner?; let inner = inner.map_err(|err| SolcError::io(err, &path))?;
let path = inner.path().display().to_string(); let path = inner.path().display().to_string();
let path = path.rsplit('/').next().unwrap().to_string(); let path = path.rsplit('/').next().unwrap().to_string();
if path != DAPPTOOLS_CONTRACTS_DIR && path != JS_CONTRACTS_DIR { if path != DAPPTOOLS_CONTRACTS_DIR && path != JS_CONTRACTS_DIR {

View File

@ -49,17 +49,16 @@ pub fn find_version_pragma(contract: &str) -> Option<&str> {
/// ///
/// ```no_run /// ```no_run
/// use ethers_solc::utils; /// use ethers_solc::utils;
/// let sources = utils::source_files("./contracts").unwrap(); /// let sources = utils::source_files("./contracts");
/// ``` /// ```
pub fn source_files(root: impl AsRef<Path>) -> walkdir::Result<Vec<PathBuf>> { pub fn source_files(root: impl AsRef<Path>) -> Vec<PathBuf> {
let files = WalkDir::new(root) WalkDir::new(root)
.into_iter() .into_iter()
.filter_map(Result::ok) .filter_map(Result::ok)
.filter(|e| e.file_type().is_file()) .filter(|e| e.file_type().is_file())
.filter(|e| e.path().extension().map(|ext| ext == "sol").unwrap_or_default()) .filter(|e| e.path().extension().map(|ext| ext == "sol").unwrap_or_default())
.map(|e| e.path().into()) .map(|e| e.path().into())
.collect(); .collect()
Ok(files)
} }
/// Returns the source name for the given source path, the ancestors of the root path /// Returns the source name for the given source path, the ancestors of the root path
@ -192,7 +191,7 @@ mod tests {
File::create(&file_c).unwrap(); File::create(&file_c).unwrap();
File::create(&file_d).unwrap(); File::create(&file_d).unwrap();
let files: HashSet<_> = source_files(tmp_dir.path()).unwrap().into_iter().collect(); let files: HashSet<_> = source_files(tmp_dir.path()).into_iter().collect();
let expected: HashSet<_> = [file_a, file_b, file_c, file_d].into(); let expected: HashSet<_> = [file_a, file_b, file_c, file_d].into();
assert_eq!(files, expected); assert_eq!(files, expected);
} }