solc: add tracing (#628)
* feat(solc): add tracing * chore: apply suggestions from code review Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> * chore: fix compilation error * chore: adjust log Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
parent
41f8e295a0
commit
d06bfdc15c
|
@ -43,15 +43,25 @@ impl SolFilesCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the cache json file from the given path
|
/// Reads the cache json file from the given path
|
||||||
|
#[tracing::instrument(skip_all, name = "sol-files-cache::read")]
|
||||||
pub fn read(path: impl AsRef<Path>) -> Result<Self> {
|
pub fn read(path: impl AsRef<Path>) -> Result<Self> {
|
||||||
let file = fs::File::open(path.as_ref())?;
|
let path = path.as_ref();
|
||||||
Ok(serde_json::from_reader(file)?)
|
tracing::trace!("reading solfiles cache at {}", path.display());
|
||||||
|
let file = fs::File::open(path)?;
|
||||||
|
let file = std::io::BufReader::new(file);
|
||||||
|
let cache = serde_json::from_reader(file)?;
|
||||||
|
tracing::trace!("done");
|
||||||
|
Ok(cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 file = fs::File::create(path.as_ref())?;
|
let path = path.as_ref();
|
||||||
Ok(serde_json::to_writer_pretty(file, self)?)
|
let file = fs::File::create(path)?;
|
||||||
|
tracing::trace!("writing cache to json file");
|
||||||
|
serde_json::to_writer_pretty(file, self)?;
|
||||||
|
tracing::trace!("cache file located: {}", path.display());
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_missing_files(&mut self) {
|
pub fn remove_missing_files(&mut self) {
|
||||||
|
|
|
@ -90,15 +90,18 @@ impl Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
||||||
|
#[tracing::instrument(skip_all, name = "Project::write_cache_file")]
|
||||||
fn write_cache_file(
|
fn write_cache_file(
|
||||||
&self,
|
&self,
|
||||||
sources: Sources,
|
sources: Sources,
|
||||||
artifacts: Vec<(PathBuf, Vec<String>)>,
|
artifacts: Vec<(PathBuf, Vec<String>)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
tracing::trace!("inserting files to cache");
|
||||||
let mut cache = SolFilesCache::builder()
|
let mut cache = SolFilesCache::builder()
|
||||||
.root(&self.paths.root)
|
.root(&self.paths.root)
|
||||||
.solc_config(self.solc_config.clone())
|
.solc_config(self.solc_config.clone())
|
||||||
.insert_files(sources, Some(self.paths.cache.clone()))?;
|
.insert_files(sources, Some(self.paths.cache.clone()))?;
|
||||||
|
tracing::trace!("files inserted");
|
||||||
|
|
||||||
// add the artifacts for each file to the cache entry
|
// add the artifacts for each file to the cache entry
|
||||||
for (file, artifacts) in artifacts {
|
for (file, artifacts) in artifacts {
|
||||||
|
@ -110,10 +113,13 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
||||||
if let Some(cache_dir) = self.paths.cache.parent() {
|
if let Some(cache_dir) = self.paths.cache.parent() {
|
||||||
fs::create_dir_all(cache_dir)?
|
fs::create_dir_all(cache_dir)?
|
||||||
}
|
}
|
||||||
cache.write(&self.paths.cache)
|
cache.write(&self.paths.cache)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all sources found under the project's sources path
|
/// Returns all sources found under the project's sources path
|
||||||
|
#[tracing::instrument(skip_all, fields(name = "sources"))]
|
||||||
pub fn sources(&self) -> io::Result<Sources> {
|
pub fn sources(&self) -> io::Result<Sources> {
|
||||||
Source::read_all_from(self.paths.sources.as_path())
|
Source::read_all_from(self.paths.sources.as_path())
|
||||||
}
|
}
|
||||||
|
@ -167,11 +173,15 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
||||||
|
|
||||||
/// NB: If the `svm` feature is enabled, this function will automatically detect
|
/// NB: If the `svm` feature is enabled, this function will automatically detect
|
||||||
/// solc versions across files.
|
/// solc versions across files.
|
||||||
|
#[tracing::instrument(skip_all, name = "compile")]
|
||||||
pub fn compile(&self) -> Result<ProjectCompileOutput<Artifacts>> {
|
pub fn compile(&self) -> Result<ProjectCompileOutput<Artifacts>> {
|
||||||
|
tracing::trace!("sources");
|
||||||
let sources = self.sources()?;
|
let sources = self.sources()?;
|
||||||
|
tracing::trace!("done");
|
||||||
|
|
||||||
#[cfg(all(feature = "svm", feature = "async"))]
|
#[cfg(all(feature = "svm", feature = "async"))]
|
||||||
if self.auto_detect {
|
if self.auto_detect {
|
||||||
|
tracing::trace!("auto-compile");
|
||||||
return self.svm_compile(sources)
|
return self.svm_compile(sources)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,15 +193,20 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "svm", feature = "async"))]
|
#[cfg(all(feature = "svm", feature = "async"))]
|
||||||
|
#[tracing::instrument(skip(self, sources))]
|
||||||
fn svm_compile(&self, sources: Sources) -> Result<ProjectCompileOutput<Artifacts>> {
|
fn svm_compile(&self, sources: Sources) -> Result<ProjectCompileOutput<Artifacts>> {
|
||||||
// split them by version
|
// split them by version
|
||||||
let mut sources_by_version = BTreeMap::new();
|
let mut sources_by_version = BTreeMap::new();
|
||||||
// we store the solc versions by path, in case there exists a corrupt solc binary
|
// we store the solc versions by path, in case there exists a corrupt solc binary
|
||||||
let mut solc_versions = HashMap::new();
|
let mut solc_versions = HashMap::new();
|
||||||
|
|
||||||
|
// TODO: Rayon
|
||||||
|
// tracing::trace!("parsing sources");
|
||||||
for (path, source) in sources.into_iter() {
|
for (path, source) in sources.into_iter() {
|
||||||
// will detect and install the solc version
|
// will detect and install the solc version
|
||||||
|
// tracing::trace!("finding version {}", path.display());
|
||||||
let version = Solc::detect_version(&source)?;
|
let version = Solc::detect_version(&source)?;
|
||||||
|
// tracing::trace!("found {}", version);
|
||||||
// gets the solc binary for that version, it is expected tha this will succeed
|
// gets the solc binary for that version, it is expected tha this will succeed
|
||||||
// AND find the solc since it was installed right above
|
// AND find the solc since it was installed right above
|
||||||
let mut solc = Solc::find_svm_installed_version(version.to_string())?
|
let mut solc = Solc::find_svm_installed_version(version.to_string())?
|
||||||
|
@ -204,21 +219,31 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
||||||
let entry = sources_by_version.entry(solc).or_insert_with(BTreeMap::new);
|
let entry = sources_by_version.entry(solc).or_insert_with(BTreeMap::new);
|
||||||
entry.insert(path.clone(), source);
|
entry.insert(path.clone(), source);
|
||||||
}
|
}
|
||||||
|
// tracing::trace!("done");
|
||||||
|
|
||||||
let mut compiled =
|
let mut compiled =
|
||||||
ProjectCompileOutput::with_ignored_errors(self.ignored_error_codes.clone());
|
ProjectCompileOutput::with_ignored_errors(self.ignored_error_codes.clone());
|
||||||
|
|
||||||
// run the compilation step for each version
|
// run the compilation step for each version
|
||||||
|
tracing::trace!("compiling sources with viable solc versions");
|
||||||
for (solc, sources) in sources_by_version {
|
for (solc, sources) in sources_by_version {
|
||||||
|
let span = tracing::trace_span!("solc", "{}", solc.version_short()?);
|
||||||
|
let _enter = span.enter();
|
||||||
|
|
||||||
// verify that this solc version's checksum matches the checksum found remotely. If
|
// verify that this solc version's checksum matches the checksum found remotely. If
|
||||||
// not, re-install the same version.
|
// not, re-install the same version.
|
||||||
let version = solc_versions.get(&solc.solc).unwrap();
|
let version = solc_versions.get(&solc.solc).unwrap();
|
||||||
if let Err(_e) = solc.verify_checksum() {
|
if let Err(_e) = solc.verify_checksum() {
|
||||||
|
tracing::trace!("corrupted solc version, redownloading...");
|
||||||
Solc::blocking_install(version)?;
|
Solc::blocking_install(version)?;
|
||||||
|
tracing::trace!("done.");
|
||||||
}
|
}
|
||||||
// once matched, proceed to compile with it
|
// once matched, proceed to compile with it
|
||||||
|
tracing::trace!("compiling_with_version");
|
||||||
compiled.extend(self.compile_with_version(&solc, sources)?);
|
compiled.extend(self.compile_with_version(&solc, sources)?);
|
||||||
|
tracing::trace!("done compiling_with_version");
|
||||||
}
|
}
|
||||||
|
tracing::trace!("compiled sources with viable solc versions");
|
||||||
|
|
||||||
Ok(compiled)
|
Ok(compiled)
|
||||||
}
|
}
|
||||||
|
@ -228,6 +253,8 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
||||||
solc: &Solc,
|
solc: &Solc,
|
||||||
mut sources: Sources,
|
mut sources: Sources,
|
||||||
) -> Result<ProjectCompileOutput<Artifacts>> {
|
) -> Result<ProjectCompileOutput<Artifacts>> {
|
||||||
|
let span = tracing::trace_span!("compiling");
|
||||||
|
let _enter = span.enter();
|
||||||
// add all libraries to the source set while keeping track of their actual disk path
|
// add all libraries to the source set while keeping track of their actual disk path
|
||||||
// (`contracts/contract.sol` -> `/Users/.../contracts.sol`)
|
// (`contracts/contract.sol` -> `/Users/.../contracts.sol`)
|
||||||
let mut source_name_to_path = HashMap::new();
|
let mut source_name_to_path = HashMap::new();
|
||||||
|
@ -235,17 +262,21 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
||||||
// `contracts/contract.sol`)
|
// `contracts/contract.sol`)
|
||||||
let mut path_to_source_name = HashMap::new();
|
let mut path_to_source_name = HashMap::new();
|
||||||
|
|
||||||
|
tracing::trace!("resolving libraries");
|
||||||
for (import, (source, path)) in self.resolved_libraries(&sources)? {
|
for (import, (source, path)) in self.resolved_libraries(&sources)? {
|
||||||
// inserting with absolute path here and keep track of the source name <-> path mappings
|
// inserting with absolute path here and keep track of the source name <-> path mappings
|
||||||
sources.insert(path.clone(), source);
|
sources.insert(path.clone(), source);
|
||||||
path_to_source_name.insert(path.clone(), import.clone());
|
path_to_source_name.insert(path.clone(), import.clone());
|
||||||
source_name_to_path.insert(import, path);
|
source_name_to_path.insert(import, path);
|
||||||
}
|
}
|
||||||
|
tracing::trace!("resolved libraries");
|
||||||
|
|
||||||
// If there's a cache set, filter to only re-compile the files which were changed
|
// If there's a cache set, filter to only re-compile the files which were changed
|
||||||
let (sources, cached_artifacts) = if self.cached && self.paths.cache.exists() {
|
let (sources, cached_artifacts) = if self.cached && self.paths.cache.exists() {
|
||||||
|
tracing::trace!("reading solfiles cache for incremental compilation");
|
||||||
let mut cache = SolFilesCache::read(&self.paths.cache)?;
|
let mut cache = SolFilesCache::read(&self.paths.cache)?;
|
||||||
cache.remove_missing_files();
|
cache.remove_missing_files();
|
||||||
|
tracing::trace!("done reading solfiles cache for incremental compilation");
|
||||||
let changed_files = cache.get_changed_or_missing_artifacts_files::<Artifacts>(
|
let changed_files = cache.get_changed_or_missing_artifacts_files::<Artifacts>(
|
||||||
sources,
|
sources,
|
||||||
Some(&self.solc_config),
|
Some(&self.solc_config),
|
||||||
|
@ -254,12 +285,17 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
||||||
cache.remove_changed_files(&changed_files);
|
cache.remove_changed_files(&changed_files);
|
||||||
|
|
||||||
let cached_artifacts = if self.paths.artifacts.exists() {
|
let cached_artifacts = if self.paths.artifacts.exists() {
|
||||||
cache.read_artifacts::<Artifacts>(&self.paths.artifacts)?
|
tracing::trace!("reading artifacts from cache..");
|
||||||
|
let artifacts = cache.read_artifacts::<Artifacts>(&self.paths.artifacts)?;
|
||||||
|
tracing::trace!("done reading artifacts from cache");
|
||||||
|
artifacts
|
||||||
} else {
|
} else {
|
||||||
BTreeMap::default()
|
BTreeMap::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
// if nothing changed and all artifacts still exist
|
// if nothing changed and all artifacts still exist
|
||||||
if changed_files.is_empty() {
|
if changed_files.is_empty() {
|
||||||
|
tracing::trace!("no change");
|
||||||
return Ok(ProjectCompileOutput::from_unchanged(cached_artifacts))
|
return Ok(ProjectCompileOutput::from_unchanged(cached_artifacts))
|
||||||
}
|
}
|
||||||
// There are changed files and maybe some cached files
|
// There are changed files and maybe some cached files
|
||||||
|
@ -274,7 +310,9 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
||||||
let input = CompilerInput::with_sources(sources)
|
let input = CompilerInput::with_sources(sources)
|
||||||
.normalize_evm_version(&solc.version()?)
|
.normalize_evm_version(&solc.version()?)
|
||||||
.with_remappings(self.paths.remappings.clone());
|
.with_remappings(self.paths.remappings.clone());
|
||||||
|
tracing::trace!("calling solc");
|
||||||
let output = solc.compile(&input)?;
|
let output = solc.compile(&input)?;
|
||||||
|
tracing::trace!("compiled input, output has error: {}", output.has_error());
|
||||||
if output.has_error() {
|
if output.has_error() {
|
||||||
return Ok(ProjectCompileOutput::from_compiler_output(
|
return Ok(ProjectCompileOutput::from_compiler_output(
|
||||||
output,
|
output,
|
||||||
|
@ -305,6 +343,7 @@ impl<Artifacts: ArtifactOutput> Project<Artifacts> {
|
||||||
if !self.no_artifacts {
|
if !self.no_artifacts {
|
||||||
Artifacts::on_output(&output, &self.paths)?;
|
Artifacts::on_output(&output, &self.paths)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ProjectCompileOutput::from_compiler_output_and_cache(
|
Ok(ProjectCompileOutput::from_compiler_output_and_cache(
|
||||||
output,
|
output,
|
||||||
cached_artifacts,
|
cached_artifacts,
|
||||||
|
|
Loading…
Reference in New Issue