Repository: gakonst/ethers-rs
Pull request #1581 (2022-08-09 14:21:31)

feat(solc): add helper to checkout temp projects
<!--
Thank you for your Pull Request. Please provide a description above and review
the requirements below.

Bug fixes and new features should include tests.

Contributors guide: https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md

The contributors guide includes instructions for running rustfmt and building the
documentation.
-->

## Motivation
make it easy to checkout and compile a repo via `TempProject`
useful for writing tests for https://github.com/gakonst/ethers-rs/pull/1567
cc @onbjerg 
<!--
Explain the context and why you're making that change. What is the problem
you're trying to solve? In some cases there is not a problem and this can be
thought of as being the motivation for your change.
-->

## Solution

<!--
Summarize the solution and provide any necessary context needed to understand
the code change.
-->

## PR Checklist

- [x] Added Tests
- [x] Added Documentation
- [ ] Updated the changelog



Patch:
diff --git a/ethers-solc/src/project_util/mod.rs b/ethers-solc/src/project_util/mod.rs
index 107dc360..5b2b95d8 100644
--- a/ethers-solc/src/project_util/mod.rs
+++ b/ethers-solc/src/project_util/mod.rs
@@ -16,6 +16,8 @@ use fs_extra::{dir, file};
 use std::{
     fmt,
     path::{Path, PathBuf},
+    process,
+    process::Command,
 };
 use tempfile::TempDir;
 
@@ -407,6 +409,26 @@ impl TempProject<ConfigurableArtifacts> {
         Ok(project)
     }
 
+    /// Clones the given repo into a temp dir, initializes it recursively and configures it.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use ethers_solc::project_util::TempProject;
+    /// # fn t() {
+    /// let project = TempProject::checkout("transmissions11/solmate").unwrap();
+    /// # }
+    /// ```
+    pub fn checkout(repo: impl AsRef<str>) -> Result<Self> {
+        let tmp_dir = tempdir("tmp_checkout")?;
+        clone_remote(&format!("https://github.com/{}", repo.as_ref()), tmp_dir.path())
+            .map_err(|err| SolcIoError::new(err, tmp_dir.path()))?;
+        let paths = ProjectPathsConfig::dapptools(tmp_dir.path())?;
+
+        let inner = Project::builder().paths(paths).build()?;
+        Ok(Self::create_new(tmp_dir, inner)?)
+    }
+
     /// Create a new temporary project and populate it with mock files
     ///
     /// ```no_run
@@ -507,6 +529,17 @@ pub fn copy_dir(source: impl AsRef<Path>, target_dir: impl AsRef<Path>) -> Resul
     Ok(())
 }
 
+/// Clones a remote repository into the specified directory.
+pub fn clone_remote(
+    repo_url: &str,
+    target_dir: impl AsRef<Path>,
+) -> std::io::Result<process::Output> {
+    Command::new("git")
+        .args(["clone", "--depth", "1", "--recursive", repo_url])
+        .arg(target_dir.as_ref())
+        .output()
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;


Test patch:
diff --git a/ethers-solc/tests/project.rs b/ethers-solc/tests/project.rs
index a468c43c..cb3cbdfd 100644
--- a/ethers-solc/tests/project.rs
+++ b/ethers-solc/tests/project.rs
@@ -2129,6 +2129,15 @@ fn can_handle_conflicting_files() {
     );
 }
 
+#[test]
+fn can_checkout_repo() {
+    let project = TempProject::checkout("transmissions11/solmate").unwrap();
+
+    let compiled = project.compile().unwrap();
+    assert!(!compiled.has_compiler_errors());
+    let _artifacts = project.artifacts_snapshot().unwrap();
+}
+
 #[test]
 fn can_add_basic_contract_and_library() {
     let mut project = TempProject::<ConfigurableArtifacts>::dapptools().unwrap();