refactor: handle lock acquisition error, add type alias

This commit is contained in:
L Lllvvuu 2024-04-23 18:34:45 -07:00
parent 1cc6ca3b1d
commit 1e9ac5f591
No known key found for this signature in database
GPG key ID: CFAD5A25056DDD0F

View file

@ -103,6 +103,8 @@ impl FromIterator<PathBuf> for GitCache {
}
}
type SubmodulePaths = Result<Vec<PathBuf>, git2::Error>;
/// A **Git repository** is one weve discovered somewhere on the filesystem.
pub struct GitRepo {
/// All the interesting Git stuff goes through this.
@ -113,7 +115,7 @@ pub struct GitRepo {
/// Cached list of the relative paths of all submodules in this repository.
/// This is used to optionally ignore submodule contents when listing recursively.
relative_submodule_paths: RwLock<Option<Result<Vec<PathBuf>, git2::Error>>>,
relative_submodule_paths: RwLock<Option<SubmodulePaths>>,
/// The working directory of this repository.
/// This is used to check whether two repositories are the same.
@ -140,26 +142,46 @@ impl GitRepo {
/// “Prefix lookup” means that it should report an aggregate status of all
/// paths starting with the given prefix (in other words, a directory).
fn get_status(&self, index: &Path, prefix_lookup: bool) -> f::Git {
{
let statuses = self.statuses.read().unwrap();
if let Some(ref cached_statuses) = *statuses {
debug!("Git repo {:?} has been found in cache", &self.workdir);
return cached_statuses.status(index, prefix_lookup);
match self.statuses.read() {
Ok(statuses) => {
if let Some(ref cached_statuses) = *statuses {
debug!("Git repo {:?} has been found in cache", &self.workdir);
return cached_statuses.status(index, prefix_lookup);
}
}
Err(e) => {
error!("Failed to acquire read lock on git status cache: {:?}", e);
return f::Git::default();
}
}
let mut statuses = self.statuses.write().unwrap();
if let Some(ref cached_statuses) = *statuses {
debug!("Git repo {:?} has been found in cache", &self.workdir);
return cached_statuses.status(index, prefix_lookup);
}
match self.statuses.write() {
Ok(mut statuses) => {
if let Some(ref cached_statuses) = *statuses {
debug!("Git repo {:?} has been found in cache", &self.workdir);
return cached_statuses.status(index, prefix_lookup);
}
debug!("Querying Git repo {:?} for the first time", &self.workdir);
let repo = self.repo.lock().unwrap();
let new_statuses = repo_to_statuses(&repo, &self.workdir);
let result = new_statuses.status(index, prefix_lookup);
*statuses = Some(new_statuses);
result
debug!("Querying Git repo {:?} for the first time", &self.workdir);
match self.repo.lock() {
Ok(repo) => {
let new_statuses = repo_to_statuses(&repo, &self.workdir);
let result = new_statuses.status(index, prefix_lookup);
*statuses = Some(new_statuses);
result
}
Err(e) => {
error!("Failed to acquire lock on git2 repo: {:?}", e);
f::Git::default()
}
}
}
Err(e) => {
error!("Failed to acquire write lock on git status cache: {:?}", e);
f::Git::default()
}
}
}
/// Whether this repository has the given working directory.
@ -204,67 +226,65 @@ impl GitRepo {
}
fn has_in_submodule(&self, path: &Path) -> bool {
fn is_in_submodule(
relative_submodule_paths: &[PathBuf],
path: &Path,
extra_paths: &[PathBuf],
original_path: &Path,
) -> bool {
if let Ok(relative_path) = path.strip_prefix(original_path) {
if relative_submodule_paths
.iter()
.any(|p| relative_path.starts_with(p))
{
return true;
}
}
let path_is_in = |paths: &[PathBuf]| {
path.strip_prefix(&self.original_path)
.map(|relative_path| paths.iter().any(|p| relative_path.starts_with(p)))
.unwrap_or(false)
|| self.extra_paths.iter().any(|extra_path| {
path.strip_prefix(extra_path)
.map(|relative_path| paths.iter().any(|p| relative_path.starts_with(p)))
.unwrap_or(false)
})
};
extra_paths.iter().any(|extra_path| {
if let Ok(relative_path) = path.strip_prefix(extra_path) {
relative_submodule_paths
.iter()
.any(|p| relative_path.starts_with(p))
} else {
false
}
})
}
{
let relative_submodule_paths = self.relative_submodule_paths.read().unwrap();
match &*relative_submodule_paths {
Some(Ok(paths)) => {
return is_in_submodule(paths, path, &self.extra_paths, &self.original_path);
}
match self.relative_submodule_paths.read() {
Ok(guard) => match &*guard {
Some(Ok(paths)) => return path_is_in(paths),
Some(Err(_)) => return false,
None => {}
},
Err(e) => {
error!(
"Failed to acquire read lock for cached submodule paths: {:?}",
e
);
return false;
}
}
let mut relative_submodule_paths = self.relative_submodule_paths.write().unwrap();
match &*relative_submodule_paths {
Some(Ok(paths)) => is_in_submodule(paths, path, &self.extra_paths, &self.original_path),
Some(Err(_)) => false,
None => {
let repo = self.repo.lock().unwrap();
let paths_result = repo.submodules().map(|submodules| {
submodules
.iter()
.map(|submodule| submodule.path().to_path_buf())
.collect()
});
*relative_submodule_paths = Some(paths_result);
match &*relative_submodule_paths {
Some(Ok(paths)) => {
is_in_submodule(paths, path, &self.extra_paths, &self.original_path)
match self.relative_submodule_paths.write() {
Ok(mut guard) => match &*guard {
Some(Ok(paths)) => path_is_in(paths),
Some(Err(_)) => false,
None => match self.repo.lock() {
Ok(repo) => {
debug!("Querying Git repo {:?} for submodule paths", &self.workdir);
let relative_submodule_paths: SubmodulePaths =
repo.submodules().map(|submodules| {
submodules.iter().map(|s| s.path().to_path_buf()).collect()
});
let result = match &relative_submodule_paths {
Ok(paths) => path_is_in(paths),
Err(e) => {
error!("Error looking up Git submodules: {:?}", e);
false
}
};
*guard = Some(relative_submodule_paths);
result
}
Some(Err(e)) => {
error!("Error looking up Git submodules: {:?}", e);
Err(e) => {
error!("Failed to acquire lock on git2 repo: {:?}", e);
false
}
None => unreachable!(),
}
},
},
Err(e) => {
error!(
"Failed to acquire write lock for cached submodule paths: {:?}",
e
);
false
}
}
}