mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-29 14:47:56 +00:00
multiple resolc fixes and improvements (#151)
- Error out early on compiler invocations with invalid base path or include path flags. - Do not error out if no files and no errors were produced. This aligns resolc closer to sloc. - Add a CLI test with an involved fixture containing multiple contract remappings to properly testing the standard JSON path. - Fixes input normalization in the Wasm version. Co-authored-by: Cyrill Leutwiler <cyrill@parity.io>
This commit is contained in:
committed by
GitHub
parent
b78b2b2af9
commit
06f43083c3
@@ -9,6 +9,8 @@ pub mod soljson_compiler;
|
||||
pub mod standard_json;
|
||||
pub mod version;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use semver::VersionReq;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -29,6 +31,13 @@ pub const FIRST_VIA_IR_VERSION: semver::Version = semver::Version::new(0, 8, 13)
|
||||
|
||||
/// The last supported version of `solc`.
|
||||
pub const LAST_SUPPORTED_VERSION: semver::Version = semver::Version::new(0, 8, 28);
|
||||
/// `--base-path` was introduced in 0.6.9 <https://github.com/ethereum/solidity/releases/tag/v0.6.9>
|
||||
pub static FIRST_SUPPORTS_BASE_PATH: Lazy<VersionReq> =
|
||||
Lazy::new(|| VersionReq::parse(">=0.6.9").unwrap());
|
||||
|
||||
/// `--include-path` was introduced in 0.8.8 <https://github.com/ethereum/solidity/releases/tag/v0.8.8>
|
||||
pub static FIRST_SUPPORTS_INCLUDE_PATH: Lazy<VersionReq> =
|
||||
Lazy::new(|| VersionReq::parse(">=0.8.8").unwrap());
|
||||
|
||||
/// The Solidity compiler.
|
||||
pub trait Compiler {
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::solc::standard_json::output::Output as StandardJsonOutput;
|
||||
use crate::solc::version::Version;
|
||||
|
||||
use super::Compiler;
|
||||
use crate::solc::{FIRST_SUPPORTS_BASE_PATH, FIRST_SUPPORTS_INCLUDE_PATH};
|
||||
|
||||
/// The Solidity compiler.
|
||||
pub struct SolcCompiler {
|
||||
@@ -58,10 +59,23 @@ impl Compiler for SolcCompiler {
|
||||
command.stdout(std::process::Stdio::piped());
|
||||
command.arg("--standard-json");
|
||||
|
||||
if let Some(base_path) = base_path {
|
||||
command.arg("--base-path");
|
||||
command.arg(base_path);
|
||||
if let Some(base_path) = &base_path {
|
||||
if !FIRST_SUPPORTS_BASE_PATH.matches(&version.default) {
|
||||
anyhow::bail!(
|
||||
"--base-path not supported this version {} of solc",
|
||||
&version.default
|
||||
);
|
||||
}
|
||||
command.arg("--base-path").arg(base_path);
|
||||
}
|
||||
|
||||
if !include_paths.is_empty() && !FIRST_SUPPORTS_INCLUDE_PATH.matches(&version.default) {
|
||||
anyhow::bail!(
|
||||
"--include-path not supported this version {} of solc",
|
||||
&version.default
|
||||
);
|
||||
}
|
||||
|
||||
for include_path in include_paths.into_iter() {
|
||||
command.arg("--include-path");
|
||||
command.arg(include_path);
|
||||
|
||||
@@ -35,6 +35,7 @@ impl Compiler for SoljsonCompiler {
|
||||
_allow_paths: Option<String>,
|
||||
) -> anyhow::Result<StandardJsonOutput> {
|
||||
let version = self.version()?;
|
||||
input.normalize(&version.default);
|
||||
let suppressed_warnings = input.suppressed_warnings.take().unwrap_or_default();
|
||||
|
||||
let input_json = serde_json::to_string(&input).expect("Always valid");
|
||||
|
||||
@@ -24,9 +24,8 @@ use crate::yul::parser::statement::object::Object;
|
||||
use self::contract::Contract;
|
||||
use self::error::Error as SolcStandardJsonOutputError;
|
||||
use self::source::Source;
|
||||
|
||||
/// The `solc --standard-json` output.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||
pub struct Output {
|
||||
/// The file-contract hashmap.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@@ -64,15 +63,12 @@ impl Output {
|
||||
|
||||
let files = match self.contracts.as_ref() {
|
||||
Some(files) => files,
|
||||
None => {
|
||||
anyhow::bail!(
|
||||
"{}",
|
||||
self.errors
|
||||
.as_ref()
|
||||
.map(|errors| serde_json::to_string_pretty(errors).expect("Always valid"))
|
||||
.unwrap_or_else(|| "Unknown project assembling error".to_owned())
|
||||
);
|
||||
}
|
||||
None => match &self.errors {
|
||||
Some(errors) if errors.iter().any(|e| e.severity == "error") => {
|
||||
anyhow::bail!(serde_json::to_string_pretty(errors).expect("Always valid"));
|
||||
}
|
||||
_ => &BTreeMap::new(),
|
||||
},
|
||||
};
|
||||
let mut project_contracts = BTreeMap::new();
|
||||
|
||||
@@ -159,7 +155,6 @@ impl Output {
|
||||
messages.extend(polkavm_messages);
|
||||
}
|
||||
}
|
||||
|
||||
self.errors = match self.errors.take() {
|
||||
Some(mut errors) => {
|
||||
errors.extend(messages);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,29 +1,44 @@
|
||||
import * as shell from 'shelljs';
|
||||
import * as fs from 'fs';
|
||||
import { spawnSync } from 'child_process';
|
||||
|
||||
interface CommandResult {
|
||||
output: string;
|
||||
exitCode: number;
|
||||
}
|
||||
|
||||
export const executeCommand = (command: string): CommandResult => {
|
||||
const result = shell.exec(command, {async: false});
|
||||
export const executeCommand = (command: string, stdin?: string): CommandResult => {
|
||||
if (stdin) {
|
||||
const process = spawnSync(command, [], {
|
||||
input: stdin,
|
||||
shell: true,
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 30 * 1024 * 1024
|
||||
});
|
||||
|
||||
return {
|
||||
exitCode: process.status || 0,
|
||||
output: (process.stdout || process.stderr || '').toString()
|
||||
};
|
||||
}
|
||||
|
||||
const result = shell.exec(command, { silent: true, async: false });
|
||||
return {
|
||||
exitCode: result.code,
|
||||
output: result.stdout.trim() || result.stderr.trim(),
|
||||
output: result.stdout || result.stderr || ''
|
||||
};
|
||||
};
|
||||
|
||||
export const isFolderExist = (folder: string): boolean => {
|
||||
export const isFolderExist = (folder: string): boolean => {
|
||||
return shell.test('-d', folder);
|
||||
};
|
||||
|
||||
export const isFileExist = (pathToFileDir: string, fileName: string, fileExtension:string): boolean => {
|
||||
return shell.ls(pathToFileDir).stdout.includes(fileName + fileExtension);
|
||||
export const isFileExist = (pathToFileDir: string, fileName: string, fileExtension: string): boolean => {
|
||||
return shell.ls(pathToFileDir).stdout.includes(fileName + fileExtension);
|
||||
};
|
||||
|
||||
export const isFileEmpty = (file: string): boolean => {
|
||||
export const isFileEmpty = (file: string): boolean => {
|
||||
if (fs.existsSync(file)) {
|
||||
return (fs.readFileSync(file).length === 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { executeCommand, isFolderExist, isFileExist, isFileEmpty } from "../src/helper";
|
||||
import { paths } from '../src/entities';
|
||||
import * as shell from 'shelljs';
|
||||
import * as path from 'path';
|
||||
|
||||
|
||||
//id1762
|
||||
@@ -142,3 +144,48 @@ describe("Run resolc with source debug information, check LLVM debug-info", () =
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
describe("Standard JSON compilation with path options", () => {
|
||||
const contractsDir = path.join(shell.tempdir(), 'contracts-test');
|
||||
const inputFile = path.join(__dirname, '..', 'src/contracts/compiled/1.json');
|
||||
|
||||
beforeAll(() => {
|
||||
shell.mkdir('-p', contractsDir);
|
||||
|
||||
const input = JSON.parse(shell.cat(inputFile).toString());
|
||||
|
||||
Object.entries(input.sources).forEach(([sourcePath, source]: [string, any]) => {
|
||||
const filePath = path.join(contractsDir, sourcePath);
|
||||
shell.mkdir('-p', path.dirname(filePath));
|
||||
shell.ShellString(source.content).to(filePath);
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
shell.rm('-rf', contractsDir);
|
||||
});
|
||||
|
||||
describe("Output with all path options", () => {
|
||||
let result: { exitCode: number; output: string };
|
||||
|
||||
beforeAll(() => {
|
||||
const tempInputFile = path.join(contractsDir, 'temp-input.json');
|
||||
shell.cp(inputFile, tempInputFile);
|
||||
const inputContent = shell.cat(inputFile).toString();
|
||||
|
||||
const command = `resolc --standard-json --base-path "${contractsDir}" --include-path "${contractsDir}" --allow-paths "${contractsDir}"`;
|
||||
|
||||
result = executeCommand(command, inputContent);
|
||||
|
||||
shell.rm(tempInputFile);
|
||||
|
||||
});
|
||||
|
||||
it("Compiler run successful without emiting warnings", () => {
|
||||
const parsedResults = JSON.parse(result.output)
|
||||
expect(parsedResults.errors.filter((error: { type: string; }) => error.type != 'Warning')).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user