diff options
Diffstat (limited to 'vendor/gix/src/object/commit.rs')
-rw-r--r-- | vendor/gix/src/object/commit.rs | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/vendor/gix/src/object/commit.rs b/vendor/gix/src/object/commit.rs new file mode 100644 index 000000000..e28a12955 --- /dev/null +++ b/vendor/gix/src/object/commit.rs @@ -0,0 +1,156 @@ +use crate::{bstr, bstr::BStr, revision, Commit, ObjectDetached, Tree}; + +mod error { + use crate::object; + + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error(transparent)] + FindExistingObject(#[from] object::find::existing::Error), + #[error("The commit could not be decoded fully or partially")] + Decode(#[from] gix_object::decode::Error), + #[error("Expected object of type {}, but got {}", .expected, .actual)] + ObjectKind { + expected: gix_object::Kind, + actual: gix_object::Kind, + }, + } +} + +pub use error::Error; + +impl<'repo> Commit<'repo> { + /// Create an owned instance of this object, copying our data in the process. + pub fn detached(&self) -> ObjectDetached { + ObjectDetached { + id: self.id, + kind: gix_object::Kind::Commit, + data: self.data.clone(), + } + } + + /// Sever the connection to the `Repository` and turn this instance into a standalone object. + pub fn detach(self) -> ObjectDetached { + self.into() + } +} + +impl<'repo> Commit<'repo> { + /// Turn this objects id into a shortened id with a length in hex as configured by `core.abbrev`. + pub fn short_id(&self) -> Result<gix_hash::Prefix, crate::id::shorten::Error> { + use crate::ext::ObjectIdExt; + self.id.attach(self.repo).shorten() + } + + /// Parse the commits message into a [`MessageRef`][gix_object::commit::MessageRef] + pub fn message(&self) -> Result<gix_object::commit::MessageRef<'_>, gix_object::decode::Error> { + Ok(gix_object::commit::MessageRef::from_bytes(self.message_raw()?)) + } + /// Decode the commit object until the message and return it. + pub fn message_raw(&self) -> Result<&'_ BStr, gix_object::decode::Error> { + gix_object::CommitRefIter::from_bytes(&self.data).message() + } + /// Obtain the message by using intricate knowledge about the encoding, which is fastest and + /// can't fail at the expense of error handling. + pub fn message_raw_sloppy(&self) -> &BStr { + use bstr::ByteSlice; + self.data + .find(b"\n\n") + .map(|pos| &self.data[pos + 2..]) + .unwrap_or_default() + .as_bstr() + } + + /// Decode the commit and obtain the time at which the commit was created. + /// + /// For the time at which it was authored, refer to `.decode()?.author.time`. + pub fn time(&self) -> Result<gix_actor::Time, Error> { + Ok(self.committer()?.time) + } + + /// Decode the entire commit object and return it for accessing all commit information. + /// + /// It will allocate only if there are more than 2 parents. + /// + /// Note that the returned commit object does make lookup easy and should be + /// used for successive calls to string-ish information to avoid decoding the object + /// more than once. + pub fn decode(&self) -> Result<gix_object::CommitRef<'_>, gix_object::decode::Error> { + gix_object::CommitRef::from_bytes(&self.data) + } + + /// Return an iterator over tokens, representing this commit piece by piece. + pub fn iter(&self) -> gix_object::CommitRefIter<'_> { + gix_object::CommitRefIter::from_bytes(&self.data) + } + + /// Return the commits author, with surrounding whitespace trimmed. + pub fn author(&self) -> Result<gix_actor::SignatureRef<'_>, gix_object::decode::Error> { + gix_object::CommitRefIter::from_bytes(&self.data) + .author() + .map(|s| s.trim()) + } + + /// Return the commits committer. with surrounding whitespace trimmed. + pub fn committer(&self) -> Result<gix_actor::SignatureRef<'_>, gix_object::decode::Error> { + gix_object::CommitRefIter::from_bytes(&self.data) + .committer() + .map(|s| s.trim()) + } + + /// Decode this commits parent ids on the fly without allocating. + // TODO: tests + pub fn parent_ids(&self) -> impl Iterator<Item = crate::Id<'repo>> + '_ { + use crate::ext::ObjectIdExt; + let repo = self.repo; + gix_object::CommitRefIter::from_bytes(&self.data) + .parent_ids() + .map(move |id| id.attach(repo)) + } + + /// Parse the commit and return the the tree object it points to. + pub fn tree(&self) -> Result<Tree<'repo>, Error> { + match self.tree_id()?.object()?.try_into_tree() { + Ok(tree) => Ok(tree), + Err(crate::object::try_into::Error { actual, expected, .. }) => Err(Error::ObjectKind { actual, expected }), + } + } + + /// Parse the commit and return the the tree id it points to. + pub fn tree_id(&self) -> Result<crate::Id<'repo>, gix_object::decode::Error> { + gix_object::CommitRefIter::from_bytes(&self.data) + .tree_id() + .map(|id| crate::Id::from_id(id, self.repo)) + } + + /// Return our id own id with connection to this repository. + pub fn id(&self) -> crate::Id<'repo> { + use crate::ext::ObjectIdExt; + self.id.attach(self.repo) + } + + /// Obtain a platform for traversing ancestors of this commit. + pub fn ancestors(&self) -> revision::walk::Platform<'repo> { + self.id().ancestors() + } + + /// Create a platform to further configure a `git describe` operation to find a name for this commit by looking + /// at the closest annotated tags (by default) in its past. + pub fn describe(&self) -> crate::commit::describe::Platform<'repo> { + crate::commit::describe::Platform { + id: self.id, + repo: self.repo, + select: Default::default(), + first_parent: false, + id_as_fallback: false, + max_candidates: 10, + } + } +} + +impl<'r> std::fmt::Debug for Commit<'r> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Commit({})", self.id) + } +} |