mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-06-15 14:51:05 +00:00
Fix compilation errors related to paths
This commit is contained in:
@@ -44,6 +44,8 @@ pub trait SolidityCompiler {
|
|||||||
pub struct CompilerInput<T: PartialEq + Eq + Hash> {
|
pub struct CompilerInput<T: PartialEq + Eq + Hash> {
|
||||||
pub extra_options: T,
|
pub extra_options: T,
|
||||||
pub input: SolcStandardJsonInput,
|
pub input: SolcStandardJsonInput,
|
||||||
|
pub allow_paths: Vec<PathBuf>,
|
||||||
|
pub base_path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The generic compilation output configuration.
|
/// The generic compilation output configuration.
|
||||||
@@ -83,8 +85,8 @@ where
|
|||||||
pub struct Compiler<T: SolidityCompiler> {
|
pub struct Compiler<T: SolidityCompiler> {
|
||||||
input: SolcStandardJsonInput,
|
input: SolcStandardJsonInput,
|
||||||
extra_options: T::Options,
|
extra_options: T::Options,
|
||||||
allow_paths: Vec<String>,
|
allow_paths: Vec<PathBuf>,
|
||||||
base_path: Option<String>,
|
base_path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Compiler<solc::Solc> {
|
impl Default for Compiler<solc::Solc> {
|
||||||
@@ -145,12 +147,12 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allow_path(mut self, path: String) -> Self {
|
pub fn allow_path(mut self, path: PathBuf) -> Self {
|
||||||
self.allow_paths.push(path);
|
self.allow_paths.push(path);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn base_path(mut self, base_path: String) -> Self {
|
pub fn base_path(mut self, base_path: PathBuf) -> Self {
|
||||||
self.base_path = Some(base_path);
|
self.base_path = Some(base_path);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -159,6 +161,8 @@ where
|
|||||||
T::new(solc_path).build(CompilerInput {
|
T::new(solc_path).build(CompilerInput {
|
||||||
extra_options: self.extra_options,
|
extra_options: self.extra_options,
|
||||||
input: self.input,
|
input: self.input,
|
||||||
|
allow_paths: self.allow_paths,
|
||||||
|
base_path: self.base_path,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,13 +23,24 @@ impl SolidityCompiler for Resolc {
|
|||||||
&self,
|
&self,
|
||||||
input: CompilerInput<Self::Options>,
|
input: CompilerInput<Self::Options>,
|
||||||
) -> anyhow::Result<CompilerOutput<Self::Options>> {
|
) -> anyhow::Result<CompilerOutput<Self::Options>> {
|
||||||
let mut child = Command::new(&self.resolc_path)
|
let mut command = Command::new(&self.resolc_path);
|
||||||
.arg("--standard-json")
|
command
|
||||||
.args(&input.extra_options)
|
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()?;
|
.arg("--standard-json");
|
||||||
|
|
||||||
|
if !input.allow_paths.is_empty() {
|
||||||
|
command.arg("--allow-paths").arg(
|
||||||
|
input
|
||||||
|
.allow_paths
|
||||||
|
.iter()
|
||||||
|
.map(|path| path.display().to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(","),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut child = command.spawn()?;
|
||||||
|
|
||||||
let stdin_pipe = child.stdin.as_mut().expect("stdin must be piped");
|
let stdin_pipe = child.stdin.as_mut().expect("stdin must be piped");
|
||||||
serde_json::to_writer(stdin_pipe, &input.input)?;
|
serde_json::to_writer(stdin_pipe, &input.input)?;
|
||||||
@@ -55,13 +66,22 @@ impl SolidityCompiler for Resolc {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let parsed: SolcStandardJsonOutput = serde_json::from_slice(&stdout).map_err(|e| {
|
let parsed = serde_json::from_slice::<SolcStandardJsonOutput>(&stdout).map_err(|e| {
|
||||||
anyhow::anyhow!(
|
anyhow::anyhow!(
|
||||||
"failed to parse resolc JSON output: {e}\nstderr: {}",
|
"failed to parse resolc JSON output: {e}\nstderr: {}",
|
||||||
String::from_utf8_lossy(&stderr)
|
String::from_utf8_lossy(&stderr)
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// Detecting if the compiler output contained errors and reporting them through logs and
|
||||||
|
// errors instead of returning the compiler output that might contain errors.
|
||||||
|
for error in parsed.errors.iter().flatten() {
|
||||||
|
if error.severity == "error" {
|
||||||
|
tracing::error!(?error, ?input, "Encountered an error in the compilation");
|
||||||
|
anyhow::bail!("Encountered an error in the compilation: {error}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(CompilerOutput {
|
Ok(CompilerOutput {
|
||||||
input,
|
input,
|
||||||
output: parsed,
|
output: parsed,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use std::{
|
|||||||
use crate::{CompilerInput, CompilerOutput, SolidityCompiler};
|
use crate::{CompilerInput, CompilerOutput, SolidityCompiler};
|
||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use revive_dt_solc_binaries::download_solc;
|
use revive_dt_solc_binaries::download_solc;
|
||||||
|
use revive_solc_json_interface::SolcStandardJsonOutput;
|
||||||
|
|
||||||
pub struct Solc {
|
pub struct Solc {
|
||||||
solc_path: PathBuf,
|
solc_path: PathBuf,
|
||||||
@@ -21,12 +22,24 @@ impl SolidityCompiler for Solc {
|
|||||||
&self,
|
&self,
|
||||||
input: CompilerInput<Self::Options>,
|
input: CompilerInput<Self::Options>,
|
||||||
) -> anyhow::Result<CompilerOutput<Self::Options>> {
|
) -> anyhow::Result<CompilerOutput<Self::Options>> {
|
||||||
let mut child = Command::new(&self.solc_path)
|
let mut command = Command::new(&self.solc_path);
|
||||||
|
command
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.arg("--standard-json")
|
.arg("--standard-json");
|
||||||
.spawn()?;
|
|
||||||
|
if !input.allow_paths.is_empty() {
|
||||||
|
command.arg("--allow-paths").arg(
|
||||||
|
input
|
||||||
|
.allow_paths
|
||||||
|
.iter()
|
||||||
|
.map(|path| path.display().to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(","),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut child = command.spawn()?;
|
||||||
|
|
||||||
let stdin = child.stdin.as_mut().expect("should be piped");
|
let stdin = child.stdin.as_mut().expect("should be piped");
|
||||||
serde_json::to_writer(stdin, &input.input)?;
|
serde_json::to_writer(stdin, &input.input)?;
|
||||||
@@ -42,9 +55,26 @@ impl SolidityCompiler for Solc {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let parsed =
|
||||||
|
serde_json::from_slice::<SolcStandardJsonOutput>(&output.stdout).map_err(|e| {
|
||||||
|
anyhow::anyhow!(
|
||||||
|
"failed to parse resolc JSON output: {e}\nstderr: {}",
|
||||||
|
String::from_utf8_lossy(&output.stdout)
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Detecting if the compiler output contained errors and reporting them through logs and
|
||||||
|
// errors instead of returning the compiler output that might contain errors.
|
||||||
|
for error in parsed.errors.iter().flatten() {
|
||||||
|
if error.severity == "error" {
|
||||||
|
tracing::error!(?error, ?input, "Encountered an error in the compilation");
|
||||||
|
anyhow::bail!("Encountered an error in the compilation: {error}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(CompilerOutput {
|
Ok(CompilerOutput {
|
||||||
input,
|
input,
|
||||||
output: serde_json::from_slice(&output.stdout)?,
|
output: parsed,
|
||||||
error: None,
|
error: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,25 +70,12 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
let compiler = Compiler::<T::Compiler>::new()
|
let compiler = Compiler::<T::Compiler>::new()
|
||||||
.base_path(metadata.directory()?.display().to_string())
|
.base_path(metadata.directory()?)
|
||||||
.allow_path(metadata.directory()?.display().to_string())
|
.allow_path(metadata.directory()?)
|
||||||
.solc_optimizer(mode.solc_optimize());
|
.solc_optimizer(mode.solc_optimize());
|
||||||
|
|
||||||
let compiler = std::fs::read_dir(metadata.directory()?)?
|
let compiler = FilesWithExtensionIterator::new(metadata.directory()?)
|
||||||
.flat_map(|entry| match entry {
|
.with_allowed_extension("sol")
|
||||||
Ok(entry) => {
|
|
||||||
if entry
|
|
||||||
.path()
|
|
||||||
.extension()
|
|
||||||
.is_some_and(|ext| ext.eq_ignore_ascii_case("sol"))
|
|
||||||
{
|
|
||||||
Some(entry.path())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => None,
|
|
||||||
})
|
|
||||||
.try_fold(compiler, |compiler, path| compiler.with_source(&path))?;
|
.try_fold(compiler, |compiler, path| compiler.with_source(&path))?;
|
||||||
|
|
||||||
let mut task = CompilationTask {
|
let mut task = CompilationTask {
|
||||||
@@ -492,3 +479,77 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An iterator that finds files of a certain extension in the provided directory. You can think of
|
||||||
|
/// this a glob pattern similar to: `${path}/**/*.md`
|
||||||
|
struct FilesWithExtensionIterator {
|
||||||
|
/// The set of allowed extensions that that match the requirement and that should be returned
|
||||||
|
/// when found.
|
||||||
|
allowed_extensions: std::collections::HashSet<std::borrow::Cow<'static, str>>,
|
||||||
|
|
||||||
|
/// The set of directories to visit next. This iterator does BFS and so these directories will
|
||||||
|
/// only be visited if we can't find any files in our state.
|
||||||
|
directories_to_search: Vec<std::path::PathBuf>,
|
||||||
|
|
||||||
|
/// The set of files matching the allowed extensions that were found. If there are entries in
|
||||||
|
/// this vector then they will be returned when the [`Iterator::next`] method is called. If not
|
||||||
|
/// then we visit one of the next directories to visit.
|
||||||
|
///
|
||||||
|
/// [`Iterator`]: std::iter::Iterator
|
||||||
|
files_matching_allowed_extensions: Vec<std::path::PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FilesWithExtensionIterator {
|
||||||
|
fn new(root_directory: std::path::PathBuf) -> Self {
|
||||||
|
Self {
|
||||||
|
allowed_extensions: Default::default(),
|
||||||
|
directories_to_search: vec![root_directory],
|
||||||
|
files_matching_allowed_extensions: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_allowed_extension(
|
||||||
|
mut self,
|
||||||
|
allowed_extension: impl Into<std::borrow::Cow<'static, str>>,
|
||||||
|
) -> Self {
|
||||||
|
self.allowed_extensions.insert(allowed_extension.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for FilesWithExtensionIterator {
|
||||||
|
type Item = std::path::PathBuf;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if let Some(file_path) = self.files_matching_allowed_extensions.pop() {
|
||||||
|
return Some(file_path);
|
||||||
|
};
|
||||||
|
|
||||||
|
let directory_to_search = self.directories_to_search.pop()?;
|
||||||
|
|
||||||
|
// Read all of the entries in the directory. If we failed to read this dir's entires then we
|
||||||
|
// elect to just ignore it and look in the next directory, we do that by calling the next
|
||||||
|
// method again on the iterator, which is an intentional decision that we made here instead
|
||||||
|
// of panicking.
|
||||||
|
let Ok(dir_entries) = std::fs::read_dir(directory_to_search) else {
|
||||||
|
return self.next();
|
||||||
|
};
|
||||||
|
|
||||||
|
for entry in dir_entries.flatten() {
|
||||||
|
let entry_path = entry.path();
|
||||||
|
if entry_path.is_dir() {
|
||||||
|
self.directories_to_search.push(entry_path)
|
||||||
|
} else if entry_path.is_file()
|
||||||
|
&& entry_path.extension().is_some_and(|ext| {
|
||||||
|
self.allowed_extensions
|
||||||
|
.iter()
|
||||||
|
.any(|allowed| ext.eq_ignore_ascii_case(allowed.as_ref()))
|
||||||
|
})
|
||||||
|
{
|
||||||
|
self.files_matching_allowed_extensions.push(entry_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user