diff options
author | Justin Worthe <justin@jemstep.com> | 2020-03-25 11:45:22 +0200 |
---|---|---|
committer | Justin Worthe <justin@jemstep.com> | 2020-03-25 11:45:22 +0200 |
commit | a5eacee3a6c293a5d15c0b31a728ec43b6d2e6f8 (patch) | |
tree | dbaa7ca963a858db6165f3281a42ea99d2fb94e4 | |
parent | a1437e90a3735b6ad9d3e16edb99e28b1b8cab74 (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.rs | 75 |
1 files changed, 48 insertions, 27 deletions
@@ -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( |