Skip to content

Commit

Permalink
feat: add commit::ExtraHeaders::find_pos(), and expose "gpgsig" hea…
Browse files Browse the repository at this point in the history
…der name.

That way it it's easier to manipulate existing extra-header fields.
  • Loading branch information
Byron committed Feb 11, 2025
1 parent 5f0c124 commit 4ae5512
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 8 deletions.
17 changes: 15 additions & 2 deletions gix-object/src/commit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -84,7 +87,7 @@ impl<'a> CommitRef<'a> {
}

/// Returns a convenient iterator over all extra headers.
pub fn extra_headers(&self) -> crate::commit::ExtraHeaders<impl Iterator<Item = (&BStr, &BStr)>> {
pub fn extra_headers(&self) -> ExtraHeaders<impl Iterator<Item = (&BStr, &BStr)>> {
ExtraHeaders::new(self.extra_headers.iter().map(|(k, v)| (*k, v.as_ref())))
}

Expand Down Expand Up @@ -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<usize> {
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<Item = &'a BStr> {
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
Expand All @@ -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)
}
}
16 changes: 10 additions & 6 deletions gix-object/tests/object/commit/from_bytes.rs
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -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(())
}

0 comments on commit 4ae5512

Please sign in to comment.