diff --git a/asyncgit/src/error.rs b/asyncgit/src/error.rs index 1578ed1e50..9513ab48ab 100644 --- a/asyncgit/src/error.rs +++ b/asyncgit/src/error.rs @@ -123,6 +123,20 @@ pub enum Error { #[from] gix::object::find::existing::with_conversion::Error, ), + /// + #[error("gix::reference::iter::Error error: {0}")] + GixReferenceIter(#[from] gix::reference::iter::Error), + + /// + #[error("gix::reference::iter::init::Error error: {0}")] + GixReferenceIterInit(#[from] gix::reference::iter::init::Error), + + /// + #[error("gix::reference::peel::to_kind::Error error: {0}")] + GixReferencePeelToKind( + #[from] gix::reference::peel::to_kind::Error, + ), + /// #[error("amend error: config commit.gpgsign=true detected.\ngpg signing is not supported for amending non-last commits")] SignAmendNonLastCommit, diff --git a/asyncgit/src/sync/commits_info.rs b/asyncgit/src/sync/commits_info.rs index c00ddcba64..349123a58f 100644 --- a/asyncgit/src/sync/commits_info.rs +++ b/asyncgit/src/sync/commits_info.rs @@ -93,6 +93,15 @@ impl From for CommitId { } } +impl From> for CommitId { + fn from(commit: gix::Commit<'_>) -> Self { + #[allow(clippy::expect_used)] + let oid = Oid::from_bytes(commit.id().as_bytes()).expect("`Oid::from_bytes(commit.id().as_bytes())` is expected to never fail"); + + Self::new(oid) + } +} + impl From for gix::ObjectId { fn from(id: CommitId) -> Self { Self::from_bytes_or_panic(id.0.as_bytes()) diff --git a/asyncgit/src/sync/tags.rs b/asyncgit/src/sync/tags.rs index fe7071db84..f2193b2193 100644 --- a/asyncgit/src/sync/tags.rs +++ b/asyncgit/src/sync/tags.rs @@ -1,13 +1,7 @@ use super::{get_commits_info, CommitId, RepoPath}; -use crate::{ - error::Result, - sync::{repository::repo, utils::bytes2string}, -}; +use crate::{error::Result, sync::repository::repo}; use scopetime::scope_time; -use std::{ - collections::{BTreeMap, HashMap, HashSet}, - ops::Not, -}; +use std::collections::{BTreeMap, HashMap, HashSet}; /// #[derive(Clone, Hash, PartialEq, Eq, Debug)] @@ -64,52 +58,29 @@ pub fn get_tags(repo_path: &RepoPath) -> Result { } }; - let repo = repo(repo_path)?; - - repo.tag_foreach(|id, name| { - if let Ok(name) = - // skip the `refs/tags/` part - String::from_utf8(name[10..name.len()].into()) - { - //NOTE: find_tag (using underlying git_tag_lookup) only - // works on annotated tags lightweight tags `id` already - // points to the target commit - // see https://github.com/libgit2/libgit2/issues/5586 - let commit = repo - .find_tag(id) - .and_then(|tag| tag.target()) - .and_then(|target| target.peel_to_commit()) - .map_or_else( - |_| { - if repo.find_commit(id).is_ok() { - Some(CommitId::new(id)) - } else { - None - } - }, - |commit| Some(CommitId::new(commit.id())), - ); - - let annotation = repo - .find_tag(id) - .ok() - .as_ref() - .and_then(git2::Tag::message_bytes) - .and_then(|msg| { - msg.is_empty() - .not() - .then(|| bytes2string(msg).ok()) - .flatten() - }); - - if let Some(commit) = commit { - adder(commit, Tag { name, annotation }); - } - - return true; + let gix_repo: gix::Repository = + gix::ThreadSafeRepository::discover_with_environment_overrides(repo_path.gitpath()) + .map(Into::into)?; + let platform = gix_repo.references()?; + for mut reference in (platform.tags()?).flatten() { + let commit = reference.peel_to_commit(); + let tag = reference.peel_to_tag(); + + if let Ok(commit) = commit { + let tag_ref = tag.as_ref().map(gix::Tag::decode); + + let name = match tag_ref { + Ok(Ok(tag)) => tag.name.to_string(), + _ => reference.name().shorten().to_string(), + }; + let annotation = match tag_ref { + Ok(Ok(tag)) => Some(tag.message.to_string()), + _ => None, + }; + + adder(commit.into(), Tag { name, annotation }); } - false - })?; + } Ok(res) }