Skip to main content

thin_fetch/object/
commit.rs

1use std::ops::Deref;
2
3use ring::digest::Digest;
4
5use crate::utils::{as_hex, get_hash};
6use crate::{Error, HashKind, error};
7
8#[derive(Debug)]
9pub struct Commit {
10    pub hash: Digest,
11    pub commit: gix_object::Commit,
12}
13
14impl Commit {
15    /// Parse commit from raw data.
16    ///
17    /// # Errors
18    ///
19    /// Returns an error when the commit could not be parsed.
20    pub fn parse(raw: &[u8], hash_kind: HashKind) -> Result<Self, Error> {
21        let hash = get_hash("commit", raw, hash_kind);
22
23        let cref = gix_object::CommitRef::from_bytes(raw, hash_kind.into())
24            .map_err(|err| error!("could not parse commit: {err}"))?;
25
26        let commit = cref
27            .to_owned()
28            .map_err(|err| error!("could not convert commit ref to owned: {err}"))?;
29
30        Ok(Self { hash, commit })
31    }
32
33    /// Get the commit header as [`std::fmt::Display`].
34    #[must_use]
35    pub fn header(&self) -> CommitHeader<'_> {
36        CommitHeader { commit: self }
37    }
38}
39
40impl Deref for Commit {
41    type Target = gix_object::Commit;
42
43    fn deref(&self) -> &Self::Target {
44        &self.commit
45    }
46}
47
48pub struct CommitHeader<'a> {
49    commit: &'a Commit,
50}
51
52impl std::fmt::Display for CommitHeader<'_> {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        let hash = as_hex(self.commit.hash.as_ref());
55
56        writeln!(f, "commit {hash}").unwrap();
57
58        let author = &self.commit.author;
59        writeln!(f, "Author: {} <{}>", author.name, author.email)?;
60
61        let zoned = author.time.to_zoned().unwrap();
62        let date = jiff::fmt::rfc2822::to_string(&zoned).unwrap();
63        writeln!(f, "Date:   {date}")?;
64        writeln!(f)?;
65
66        let msg = String::from_utf8_lossy(&self.commit.message);
67        let message = msg.trim_end_matches('\n');
68
69        for line in message.split('\n') {
70            writeln!(f, "    {line}")?;
71        }
72
73        Ok(())
74    }
75}