summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Worthe <justin@jemstep.com>2020-03-25 11:45:22 +0200
committerJustin Worthe <justin@jemstep.com>2020-03-25 11:45:22 +0200
commita5eacee3a6c293a5d15c0b31a728ec43b6d2e6f8 (patch)
treedbaa7ca963a858db6165f3281a42ea99d2fb94e4
parenta1437e90a3735b6ad9d3e16edb99e28b1b8cab74 (diff)
Added caching of the temp repo
Now that we need to clone the whole repo, it makes more sense to clone it once (lazily) and use that one clone of the repo for any subsequent checks that need it.
-rw-r--r--src/git.rs75
1 files changed, 48 insertions, 27 deletions
diff --git a/src/git.rs b/src/git.rs
index fda6f9e..b9ac418 100644
--- a/src/git.rs
+++ b/src/git.rs
@@ -10,6 +10,7 @@ use std::io::prelude::*;
use std::path::Path;
use std::process::*;
use std::str;
+use uuid::Uuid;
use crate::config::*;
use log::*;
@@ -78,8 +79,9 @@ pub trait Git: Sized {
pub struct LiveGit {
repo: Repository,
- tag_cache: RefCell<HashMap<Option<String>, HashMap<Oid, Vec<Tag>>>>,
config: GitConfig,
+ tag_cache: RefCell<HashMap<Option<String>, HashMap<Oid, Vec<Tag>>>>,
+ temp_repo_clone: RefCell<Option<TempRepo>>,
}
impl Git for LiveGit {
@@ -336,27 +338,28 @@ impl Git for LiveGit {
verification_commit: &Commit,
) -> Result<bool, Box<dyn Error>> {
use git2::MergeOptions;
- let temp_repo = TempRepo::new(&self.repo, verification_commit.id)?;
- let commit = temp_repo.repo.find_commit(verification_commit.id)?;
- let parents = commit.parents().collect::<Vec<_>>();
-
- match &parents[..] {
- [a, b] => {
- let expected_tree_id = commit.tree_id();
- let reproduced_tree_id = temp_repo
- .repo
- .merge_commits(&a, &b, Some(MergeOptions::new().fail_on_conflict(true)))
- .and_then(|mut index| index.write_tree_to(&temp_repo.repo));
- trace!("Checking for a trivial merge commit, expecting tree_id of {}, result of reproducing tree is {:?}", expected_tree_id, reproduced_tree_id);
- let matches = reproduced_tree_id
- .as_ref()
- .map(|id| *id == expected_tree_id)
- .unwrap_or(false);
-
- Ok(matches)
+
+ self.with_temp_repo_clone(|temp_repo| {
+ let commit = temp_repo.repo.find_commit(verification_commit.id)?;
+ let parents = commit.parents().collect::<Vec<_>>();
+ match &parents[..] {
+ [a, b] => {
+ let expected_tree_id = commit.tree_id();
+ let reproduced_tree_id = temp_repo
+ .repo
+ .merge_commits(&a, &b, Some(MergeOptions::new().fail_on_conflict(true)))
+ .and_then(|mut index| index.write_tree_to(&temp_repo.repo));
+ trace!("Checking for a trivial merge commit, expecting tree_id of {}, result of reproducing tree is {:?}", expected_tree_id, reproduced_tree_id);
+ let matches = reproduced_tree_id
+ .as_ref()
+ .map(|id| *id == expected_tree_id)
+ .unwrap_or(false);
+
+ Ok(matches)
+ }
+ _ => Ok(false),
}
- _ => Ok(false),
- }
+ })
}
fn is_mainline(&self, ref_name: &str) -> Result<bool, Box<dyn Error>> {
@@ -409,8 +412,9 @@ impl LiveGit {
let repo = Repository::discover(path)?;
Ok(LiveGit {
repo,
- tag_cache: RefCell::new(HashMap::new()),
config: GitConfig::default(),
+ tag_cache: RefCell::new(HashMap::new()),
+ temp_repo_clone: RefCell::new(None),
})
}
@@ -418,8 +422,9 @@ impl LiveGit {
let repo = Repository::discover(path)?;
Ok(LiveGit {
repo,
- tag_cache: RefCell::new(HashMap::new()),
config,
+ tag_cache: RefCell::new(HashMap::new()),
+ temp_repo_clone: RefCell::new(None),
})
}
@@ -463,6 +468,21 @@ impl LiveGit {
.cloned()
.unwrap_or(Vec::new())
}
+
+ fn with_temp_repo_clone<T>(
+ &self,
+ f: impl Fn(&TempRepo) -> Result<T, Box<dyn Error>>,
+ ) -> Result<T, Box<dyn Error>> {
+ let mut cache = self.temp_repo_clone.borrow_mut();
+ if let Some(temp_repo) = cache.as_ref() {
+ return f(temp_repo);
+ } else {
+ let temp_repo = TempRepo::new(&self.repo)?;
+ let result = f(&temp_repo);
+ *cache = Some(temp_repo);
+ result
+ }
+ }
}
struct TempRepo {
@@ -470,18 +490,19 @@ struct TempRepo {
}
impl TempRepo {
- fn new(src_repo: &Repository, commit_id: Oid) -> Result<TempRepo, Box<dyn Error>> {
+ fn new(src_repo: &Repository) -> Result<TempRepo, Box<dyn Error>> {
let max_attempts = 20;
let tmp_dir = std::env::temp_dir();
- for suffix in 0..max_attempts {
- let tmp_repo_path = tmp_dir.join(format!("capn_tmp_{}_{}.git", commit_id, suffix));
+ for attempt in 1..=max_attempts {
+ let tmp_repo_path = tmp_dir.join(format!("capn_tmp_{}.git", Uuid::new_v4()));
match std::fs::create_dir(&tmp_repo_path) {
Err(ref e) if e.kind() == std::io::ErrorKind::AlreadyExists => continue,
Err(e) => return Err(Box::new(e)),
Ok(_) => {
trace!(
- "Created temp repo for verification: {}",
+ "Created temp repo for verification after {} attempts: {}",
+ attempt,
tmp_repo_path.display()
);
let src_path = src_repo.path().to_str().ok_or(Box::new(CapnError::new(