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:
parent
ab8b5233d2
commit
5dec757493
|
@ -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>,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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(())
|
||||||
|
|
|
@ -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(())
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue