]> git.proxmox.com Git - rustc.git/blob - vendor/gix/src/object/commit.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / gix / src / object / commit.rs
1 use crate::{bstr, bstr::BStr, Commit, ObjectDetached, Tree};
2
3 mod error {
4 use crate::object;
5
6 #[derive(Debug, thiserror::Error)]
7 #[allow(missing_docs)]
8 pub enum Error {
9 #[error(transparent)]
10 FindExistingObject(#[from] object::find::existing::Error),
11 #[error("The commit could not be decoded fully or partially")]
12 Decode(#[from] gix_object::decode::Error),
13 #[error("Expected object of type {}, but got {}", .expected, .actual)]
14 ObjectKind {
15 expected: gix_object::Kind,
16 actual: gix_object::Kind,
17 },
18 }
19 }
20
21 pub use error::Error;
22
23 impl<'repo> Commit<'repo> {
24 /// Create an owned instance of this object, copying our data in the process.
25 pub fn detached(&self) -> ObjectDetached {
26 ObjectDetached {
27 id: self.id,
28 kind: gix_object::Kind::Commit,
29 data: self.data.clone(),
30 }
31 }
32
33 /// Sever the connection to the `Repository` and turn this instance into a standalone object.
34 pub fn detach(self) -> ObjectDetached {
35 self.into()
36 }
37 }
38
39 impl<'repo> Commit<'repo> {
40 /// Turn this objects id into a shortened id with a length in hex as configured by `core.abbrev`.
41 pub fn short_id(&self) -> Result<gix_hash::Prefix, crate::id::shorten::Error> {
42 use crate::ext::ObjectIdExt;
43 self.id.attach(self.repo).shorten()
44 }
45
46 /// Parse the commits message into a [`MessageRef`][gix_object::commit::MessageRef]
47 pub fn message(&self) -> Result<gix_object::commit::MessageRef<'_>, gix_object::decode::Error> {
48 Ok(gix_object::commit::MessageRef::from_bytes(self.message_raw()?))
49 }
50 /// Decode the commit object until the message and return it.
51 pub fn message_raw(&self) -> Result<&'_ BStr, gix_object::decode::Error> {
52 gix_object::CommitRefIter::from_bytes(&self.data).message()
53 }
54 /// Obtain the message by using intricate knowledge about the encoding, which is fastest and
55 /// can't fail at the expense of error handling.
56 pub fn message_raw_sloppy(&self) -> &BStr {
57 use bstr::ByteSlice;
58 self.data
59 .find(b"\n\n")
60 .map(|pos| &self.data[pos + 2..])
61 .unwrap_or_default()
62 .as_bstr()
63 }
64
65 /// Decode the commit and obtain the time at which the commit was created.
66 ///
67 /// For the time at which it was authored, refer to `.decode()?.author.time`.
68 pub fn time(&self) -> Result<gix_date::Time, Error> {
69 Ok(self.committer()?.time)
70 }
71
72 /// Decode the entire commit object and return it for accessing all commit information.
73 ///
74 /// It will allocate only if there are more than 2 parents.
75 ///
76 /// Note that the returned commit object does make lookup easy and should be
77 /// used for successive calls to string-ish information to avoid decoding the object
78 /// more than once.
79 pub fn decode(&self) -> Result<gix_object::CommitRef<'_>, gix_object::decode::Error> {
80 gix_object::CommitRef::from_bytes(&self.data)
81 }
82
83 /// Return an iterator over tokens, representing this commit piece by piece.
84 pub fn iter(&self) -> gix_object::CommitRefIter<'_> {
85 gix_object::CommitRefIter::from_bytes(&self.data)
86 }
87
88 /// Return the commits author, with surrounding whitespace trimmed.
89 pub fn author(&self) -> Result<gix_actor::SignatureRef<'_>, gix_object::decode::Error> {
90 gix_object::CommitRefIter::from_bytes(&self.data)
91 .author()
92 .map(|s| s.trim())
93 }
94
95 /// Return the commits committer. with surrounding whitespace trimmed.
96 pub fn committer(&self) -> Result<gix_actor::SignatureRef<'_>, gix_object::decode::Error> {
97 gix_object::CommitRefIter::from_bytes(&self.data)
98 .committer()
99 .map(|s| s.trim())
100 }
101
102 /// Decode this commits parent ids on the fly without allocating.
103 // TODO: tests
104 pub fn parent_ids(&self) -> impl Iterator<Item = crate::Id<'repo>> + '_ {
105 use crate::ext::ObjectIdExt;
106 let repo = self.repo;
107 gix_object::CommitRefIter::from_bytes(&self.data)
108 .parent_ids()
109 .map(move |id| id.attach(repo))
110 }
111
112 /// Parse the commit and return the tree object it points to.
113 pub fn tree(&self) -> Result<Tree<'repo>, Error> {
114 match self.tree_id()?.object()?.try_into_tree() {
115 Ok(tree) => Ok(tree),
116 Err(crate::object::try_into::Error { actual, expected, .. }) => Err(Error::ObjectKind { actual, expected }),
117 }
118 }
119
120 /// Parse the commit and return the tree id it points to.
121 pub fn tree_id(&self) -> Result<crate::Id<'repo>, gix_object::decode::Error> {
122 gix_object::CommitRefIter::from_bytes(&self.data)
123 .tree_id()
124 .map(|id| crate::Id::from_id(id, self.repo))
125 }
126
127 /// Return our id own id with connection to this repository.
128 pub fn id(&self) -> crate::Id<'repo> {
129 use crate::ext::ObjectIdExt;
130 self.id.attach(self.repo)
131 }
132
133 /// Obtain a platform for traversing ancestors of this commit.
134 pub fn ancestors(&self) -> crate::revision::walk::Platform<'repo> {
135 self.id().ancestors()
136 }
137
138 /// Create a platform to further configure a `git describe` operation to find a name for this commit by looking
139 /// at the closest annotated tags (by default) in its past.
140 #[cfg(feature = "revision")]
141 pub fn describe(&self) -> crate::commit::describe::Platform<'repo> {
142 crate::commit::describe::Platform {
143 id: self.id,
144 repo: self.repo,
145 select: Default::default(),
146 first_parent: false,
147 id_as_fallback: false,
148 max_candidates: 10,
149 }
150 }
151
152 /// Extracts the PGP signature and the data that was used to create the signature, or `None` if it wasn't signed.
153 // TODO: make it possible to verify the signature, probably by wrapping `SignedData`. It's quite some work to do it properly.
154 pub fn signature(
155 &self,
156 ) -> Result<Option<(std::borrow::Cow<'_, BStr>, gix_object::commit::SignedData<'_>)>, gix_object::decode::Error>
157 {
158 gix_object::CommitRefIter::signature(&self.data)
159 }
160 }
161
162 impl<'r> std::fmt::Debug for Commit<'r> {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 write!(f, "Commit({})", self.id)
165 }
166 }