diff --git a/gix-object/src/commit/mod.rs b/gix-object/src/commit/mod.rs index b55d0a17237..8cc49647158 100644 --- a/gix-object/src/commit/mod.rs +++ b/gix-object/src/commit/mod.rs @@ -5,6 +5,9 @@ use winnow::prelude::*; use crate::{Commit, CommitRef, TagRef}; +/// The well-known field name for gpg signatures. +pub const SIGNATURE_FIELD_NAME: &str = "gpgsig"; + mod decode; /// pub mod message; @@ -84,7 +87,7 @@ impl<'a> CommitRef<'a> { } /// Returns a convenient iterator over all extra headers. - pub fn extra_headers(&self) -> crate::commit::ExtraHeaders> { + pub fn extra_headers(&self) -> ExtraHeaders> { ExtraHeaders::new(self.extra_headers.iter().map(|(k, v)| (*k, v.as_ref()))) } @@ -147,16 +150,26 @@ where pub fn new(iter: I) -> Self { ExtraHeaders { inner: iter } } + /// Find the _value_ of the _first_ header with the given `name`. pub fn find(mut self, name: &str) -> Option<&'a BStr> { self.inner .find_map(move |(k, v)| if k == name.as_bytes().as_bstr() { Some(v) } else { None }) } + + /// Find the entry index with the given name, or return `None` if unavailable. + pub fn find_pos(self, name: &str) -> Option { + self.inner + .enumerate() + .find_map(|(pos, (field, _value))| (field == name).then_some(pos)) + } + /// Return an iterator over all _values_ of headers with the given `name`. pub fn find_all(self, name: &'a str) -> impl Iterator { self.inner .filter_map(move |(k, v)| if k == name.as_bytes().as_bstr() { Some(v) } else { None }) } + /// Return an iterator over all git mergetags. /// /// A merge tag is a tag object embedded within the respective header field of a commit, making @@ -167,6 +180,6 @@ where /// Return the cryptographic signature provided by gpg/pgp verbatim. pub fn pgp_signature(self) -> Option<&'a BStr> { - self.find("gpgsig") + self.find(SIGNATURE_FIELD_NAME) } } diff --git a/gix-object/tests/object/commit/from_bytes.rs b/gix-object/tests/object/commit/from_bytes.rs index bf61ade50cf..9a7e0f23842 100644 --- a/gix-object/tests/object/commit/from_bytes.rs +++ b/gix-object/tests/object/commit/from_bytes.rs @@ -1,12 +1,11 @@ -use gix_actor::SignatureRef; -use gix_date::{time::Sign, Time}; -use gix_object::{bstr::ByteSlice, commit::message::body::TrailerRef, CommitRef}; -use smallvec::SmallVec; - use crate::{ commit::{LONG_MESSAGE, MERGE_TAG, SIGNATURE}, fixture_name, linus_signature, signature, }; +use gix_actor::SignatureRef; +use gix_date::{time::Sign, Time}; +use gix_object::{bstr::ByteSlice, commit::message::body::TrailerRef, CommitRef}; +use smallvec::SmallVec; #[test] fn invalid_timestsamp() { @@ -354,7 +353,12 @@ fn newline_right_after_signature_multiline_header() -> crate::Result { let pgp_sig = crate::commit::OTHER_SIGNATURE.as_bstr(); assert_eq!(commit.extra_headers[0].1.as_ref(), pgp_sig); assert_eq!(commit.extra_headers().pgp_signature(), Some(pgp_sig)); - assert_eq!(commit.extra_headers().find("gpgsig"), Some(pgp_sig)); + assert_eq!( + commit.extra_headers().find(gix_object::commit::SIGNATURE_FIELD_NAME), + Some(pgp_sig) + ); + assert_eq!(commit.extra_headers().find_pos("gpgsig"), Some(0)); + assert_eq!(commit.extra_headers().find_pos("something else"), None); assert!(commit.message.starts_with(b"Rollup")); Ok(()) }