diff options
Diffstat (limited to 'helix-vcs/src/git.rs')
-rw-r--r-- | helix-vcs/src/git.rs | 55 |
1 files changed, 34 insertions, 21 deletions
diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs index 1732bdd0..00a2c596 100644 --- a/helix-vcs/src/git.rs +++ b/helix-vcs/src/git.rs @@ -1,3 +1,4 @@ +use anyhow::{bail, Context, Result}; use arc_swap::ArcSwap; use std::path::Path; use std::sync::Arc; @@ -14,7 +15,7 @@ mod test; pub struct Git; impl Git { - fn open_repo(path: &Path, ceiling_dir: Option<&Path>) -> Option<ThreadSafeRepository> { + fn open_repo(path: &Path, ceiling_dir: Option<&Path>) -> Result<ThreadSafeRepository> { // custom open options let mut git_open_opts_map = gix::sec::trust::Mapping::<gix::open::Options>::default(); @@ -45,26 +46,31 @@ impl Git { open_options.ceiling_dirs = vec![ceiling_dir.to_owned()]; } - ThreadSafeRepository::discover_with_environment_overrides_opts( + let res = ThreadSafeRepository::discover_with_environment_overrides_opts( path, open_options, git_open_opts_map, - ) - .ok() + )?; + + Ok(res) } } impl DiffProvider for Git { - fn get_diff_base(&self, file: &Path) -> Option<Vec<u8>> { + fn get_diff_base(&self, file: &Path) -> Result<Vec<u8>> { debug_assert!(!file.exists() || file.is_file()); debug_assert!(file.is_absolute()); // TODO cache repository lookup - let repo = Git::open_repo(file.parent()?, None)?.to_thread_local(); - let head = repo.head_commit().ok()?; + + let repo_dir = file.parent().context("file has no parent directory")?; + let repo = Git::open_repo(repo_dir, None) + .context("failed to open git repo")? + .to_thread_local(); + let head = repo.head_commit()?; let file_oid = find_file_in_commit(&repo, &head, file)?; - let file_object = repo.find_object(file_oid).ok()?; + let file_object = repo.find_object(file_oid)?; let mut data = file_object.detach().data; // convert LF to CRLF if configured to avoid showing every line as changed if repo @@ -87,35 +93,42 @@ impl DiffProvider for Git { } data = normalized_file } - Some(data) + Ok(data) } - fn get_current_head_name(&self, file: &Path) -> Option<Arc<ArcSwap<Box<str>>>> { + fn get_current_head_name(&self, file: &Path) -> Result<Arc<ArcSwap<Box<str>>>> { debug_assert!(!file.exists() || file.is_file()); debug_assert!(file.is_absolute()); - let repo = Git::open_repo(file.parent()?, None)?.to_thread_local(); - let head_ref = repo.head_ref().ok()?; - let head_commit = repo.head_commit().ok()?; + let repo_dir = file.parent().context("file has no parent directory")?; + let repo = Git::open_repo(repo_dir, None) + .context("failed to open git repo")? + .to_thread_local(); + let head_ref = repo.head_ref()?; + let head_commit = repo.head_commit()?; let name = match head_ref { Some(reference) => reference.name().shorten().to_string(), None => head_commit.id.to_hex_with_len(8).to_string(), }; - Some(Arc::new(ArcSwap::from_pointee(name.into_boxed_str()))) + Ok(Arc::new(ArcSwap::from_pointee(name.into_boxed_str()))) } } /// Finds the object that contains the contents of a file at a specific commit. -fn find_file_in_commit(repo: &Repository, commit: &Commit, file: &Path) -> Option<ObjectId> { - let repo_dir = repo.work_dir()?; - let rel_path = file.strip_prefix(repo_dir).ok()?; - let tree = commit.tree().ok()?; - let tree_entry = tree.lookup_entry_by_path(rel_path).ok()??; +fn find_file_in_commit(repo: &Repository, commit: &Commit, file: &Path) -> Result<ObjectId> { + let repo_dir = repo.work_dir().context("repo has no worktree")?; + let rel_path = file.strip_prefix(repo_dir)?; + let tree = commit.tree()?; + let tree_entry = tree + .lookup_entry_by_path(rel_path)? + .context("file is untracked")?; match tree_entry.mode() { // not a file, everything is new, do not show diff - EntryMode::Tree | EntryMode::Commit | EntryMode::Link => None, + mode @ (EntryMode::Tree | EntryMode::Commit | EntryMode::Link) => { + bail!("entry at {} is not a file but a {mode:?}", file.display()) + } // found a file - EntryMode::Blob | EntryMode::BlobExecutable => Some(tree_entry.object_id()), + EntryMode::Blob | EntryMode::BlobExecutable => Ok(tree_entry.object_id()), } } |