diff --git a/CHANGELOG.md b/CHANGELOG.md index 28a1c459..63ff4482 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,6 +95,8 @@ ### Unreleased +- Save cache entry objects with relative paths + [#1307](https://github.com/gakonst/ethers-rs/pull/1307) - Bundle svm, svm-builds and sha2 dependencies in new `svm-solc` feature [#1071](https://github.com/gakonst/ethers-rs/pull/1071) - Emit artifact files for source files without any ContractDefinition diff --git a/ethers-solc/src/cache.rs b/ethers-solc/src/cache.rs index f9af00e3..087c38de 100644 --- a/ethers-solc/src/cache.rs +++ b/ethers-solc/src/cache.rs @@ -104,7 +104,12 @@ impl SolFilesCache { Ok(cache) } - /// Reads the cache json file from the given path and returns the cache with modified paths + /// Reads the cache json file from the given path and returns the cache with paths adjoined to + /// the `ProjectPathsConfig`. + /// + /// This expects the `artifact` files to be relative to the artifacts dir of the `paths` and the + /// `CachEntry` paths to be relative to the root dir of the `paths` + /// /// /// /// # Example @@ -120,7 +125,7 @@ impl SolFilesCache { /// ``` pub fn read_joined(paths: &ProjectPathsConfig) -> Result { let mut cache = SolFilesCache::read(&paths.cache)?; - cache.join_artifacts_files(&paths.artifacts); + cache.join_entries(&paths.root).join_artifacts_files(&paths.artifacts); Ok(cache) } @@ -139,6 +144,26 @@ impl SolFilesCache { Ok(()) } + /// Sets the `CacheEntry`'s file paths to `root` adjoined to `self.file`. + pub fn join_entries(&mut self, root: impl AsRef) -> &mut Self { + let root = root.as_ref(); + self.files = std::mem::take(&mut self.files) + .into_iter() + .map(|(path, entry)| (root.join(path), entry)) + .collect(); + self + } + + /// Removes `base` from all `CacheEntry` paths + pub fn strip_entries_prefix(&mut self, base: impl AsRef) -> &mut Self { + let base = base.as_ref(); + self.files = std::mem::take(&mut self.files) + .into_iter() + .map(|(path, entry)| (path.strip_prefix(base).map(Into::into).unwrap_or(path), entry)) + .collect(); + self + } + /// Sets the artifact files location to `base` adjoined to the `CachEntries` artifacts. pub fn join_artifacts_files(&mut self, base: impl AsRef) -> &mut Self { let base = base.as_ref(); @@ -182,7 +207,7 @@ impl SolFilesCache { /// # Example /// /// ``` - /// fn t() { + /// # fn t() { /// use ethers_solc::artifacts::contract::CompactContract; /// use ethers_solc::cache::SolFilesCache; /// use ethers_solc::Project; @@ -934,10 +959,13 @@ impl<'a, T: ArtifactOutput> ArtifactsCache<'a, T> { cache .extend(dirty_source_files.into_iter().map(|(file, (entry, _))| (file, entry))); - cache.strip_artifact_files_prefixes(project.artifacts_path()); - // write to disk if write_to_disk { + // make all `CacheEntry` paths relative to the project root and all artifact + // paths relative to the artifact's directory + cache + .strip_entries_prefix(project.root()) + .strip_artifact_files_prefixes(project.artifacts_path()); cache.write(project.cache_path())?; } diff --git a/ethers-solc/tests/project.rs b/ethers-solc/tests/project.rs index 3a3ee65b..8da70148 100644 --- a/ethers-solc/tests/project.rs +++ b/ethers-solc/tests/project.rs @@ -1708,3 +1708,65 @@ fn can_parse_notice() { }) ); } + +#[test] +fn test_relative_cache_entries() { + let project = TempProject::dapptools().unwrap(); + let _a = project + .add_source( + "A", + r#" +pragma solidity ^0.8.10; +contract A { } +"#, + ) + .unwrap(); + let _b = project + .add_source( + "B", + r#" +pragma solidity ^0.8.10; +contract B { } +"#, + ) + .unwrap(); + let _c = project + .add_source( + "C", + r#" +pragma solidity ^0.8.10; +contract C { } +"#, + ) + .unwrap(); + let _d = project + .add_source( + "D", + r#" +pragma solidity ^0.8.10; +contract D { } +"#, + ) + .unwrap(); + + let compiled = project.compile().unwrap(); + println!("{}", compiled); + assert!(!compiled.has_compiler_errors()); + + let cache = SolFilesCache::read(project.cache_path()).unwrap(); + + let entries = vec![ + PathBuf::from("src/A.sol"), + PathBuf::from("src/B.sol"), + PathBuf::from("src/C.sol"), + PathBuf::from("src/D.sol"), + ]; + assert_eq!(entries, cache.files.keys().cloned().collect::>()); + + let cache = SolFilesCache::read_joined(project.paths()).unwrap(); + + assert_eq!( + entries.into_iter().map(|p| project.root().join(p)).collect::>(), + cache.files.keys().cloned().collect::>() + ); +}