diff --git a/git-commit/Cargo.toml b/git-commit/Cargo.toml index ae4d0ac..8afd078 100644 --- a/git-commit/Cargo.toml +++ b/git-commit/Cargo.toml @@ -16,3 +16,7 @@ thiserror = "1" version = "0.15.0" default-features = false features = ["vendored-libgit2"] + +[dependencies.git-trailers] +version = "0.1.0" +path = "../git-trailers" diff --git a/git-commit/src/lib.rs b/git-commit/src/lib.rs index f3b0b04..4f675fc 100644 --- a/git-commit/src/lib.rs +++ b/git-commit/src/lib.rs @@ -12,17 +12,20 @@ //! [git-commit]: https://git-scm.com/book/en/v2/Git-Internals-Git-Objects use std::{ + borrow::Cow, fmt::Write as _, str::{self, FromStr}, }; use git2::{ObjectType, Oid}; +use git_trailers::{self as trailers, OwnedTrailer}; pub mod author; pub use author::Author; pub mod headers; pub use headers::{Headers, Signature}; +use trailers::Trailer; /// A git commit in its object description form, i.e. the output of /// `git cat-file` for a commit object. @@ -34,17 +37,22 @@ pub struct Commit { committer: Author, headers: Headers, message: String, + trailers: Vec, } impl Commit { - pub fn new( + pub fn new( tree: Oid, parents: Vec, author: Author, committer: Author, headers: Headers, message: String, - ) -> Self { + trailers: T, + ) -> Self + where + T: IntoIterator, + { Self { tree, parents, @@ -52,6 +60,7 @@ impl Commit { committer, headers, message, + trailers: trailers.into_iter().collect(), } } @@ -118,6 +127,10 @@ impl Commit { pub fn push_header(&mut self, name: &str, value: &str) { self.headers.push(name, value.trim()); } + + pub fn trailers(&self) -> impl Iterator { + self.trailers.iter() + } } pub mod error { @@ -137,6 +150,8 @@ pub mod error { #[derive(Debug, Error)] pub enum Parse { + #[error(transparent)] + Author(#[from] author::ParseError), #[error("invalid '{header}'")] InvalidHeader { header: &'static str, @@ -148,7 +163,9 @@ pub mod error { #[error("missing '{0}' while parsing commit")] Missing(&'static str), #[error(transparent)] - Author(#[from] author::ParseError), + Token(#[from] git_trailers::InvalidToken), + #[error("error occurred while checking for git-trailers: {0}")] + Trailers(#[source] git2::Error), #[error(transparent)] Utf8(#[from] str::Utf8Error), } @@ -226,6 +243,17 @@ impl FromStr for Commit { } } + // FIXME: would be nice if git-trailers could parse a message + // looking for the trailers, instead of going through git2 + // here. + let trailers = git2::message_trailers_strs(message).map_err(error::Parse::Trailers)?; + let trailers = trailers + .iter() + .map(|(token, values)| { + let values = values.split_whitespace().map(Cow::Borrowed).collect(); + trailers::Token::try_from(token).map(|token| Trailer { token, values }.to_owned()) + }) + .collect::, _>>()?; Ok(Self { tree, parents, @@ -233,6 +261,7 @@ impl FromStr for Commit { committer: committer.ok_or(error::Parse::Missing("committer"))?, headers, message: message.to_owned(), + trailers, }) } } @@ -255,6 +284,7 @@ impl ToString for Commit { } writeln!(buf).ok(); write!(buf, "{}", self.message).ok(); + buf } } diff --git a/git-commit/t/src/commit.rs b/git-commit/t/src/commit.rs index a766a17..a5c8f24 100644 --- a/git-commit/t/src/commit.rs +++ b/git-commit/t/src/commit.rs @@ -11,6 +11,8 @@ committer Alexis Sellier 1664786099 -0200 Add SSH functionality with new `radicle-ssh` We borrow code from `thrussh`, refactored to be runtime-less. + +X-Signed-Off-By: Alex Sellier "; const SSH_SIGNATURE: &str = "\ @@ -69,6 +71,8 @@ gpgsig -----BEGIN PGP SIGNATURE----- Add SSH functionality with new `radicle-ssh` We borrow code from `thrussh`, refactored to be runtime-less. + +X-Signed-Off-By: Alex Sellier "; #[test]