async_git/plumbing/
commit.rs1use std::io::Error as IOError;
2use std::str::FromStr;
3
4use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncWrite, BufReader};
5
6use crate::errors::{Result, Error};
7use crate::plumbing::Oid;
8
9#[derive(Clone, Debug)]
10pub struct Commit {
11 tree: Oid,
12 parents: Vec<Oid>,
13 author: String,
14 committer: String,
15 gpgsig: Option<String>,
16 message: String,
17}
18
19impl Commit {
20 pub async fn parse<R: AsyncRead + Unpin>(r: R) -> Result<Self> {
21 let mut r = BufReader::new(r);
22 let size = {
23 let mut size_buf = Vec::new();
24 r.read_until(0, &mut size_buf).await?;
25 size_buf.truncate(size_buf.len() - 1);
27 String::from_utf8(size_buf)?.parse::<usize>()?
28 };
29
30 let mut tree = None;
31 let mut parents = Vec::new();
32 let mut author = None;
33 let mut committer = None;
34 let mut gpgsig = None;
35
36 let mut process_header = |line: &str| -> Result<()> {
37 let mut parts = line.split(" ");
38 let key = parts.next().unwrap();
39 let value = parts.collect::<Vec<_>>().join(" ");
40 let value = value.trim();
41 match key {
42 "tree" => tree = Some(Oid::from_str(&value)?),
43 "parent" => parents.push(Oid::from_str(&value)?),
44 "author" => author = Some(value.to_string()),
45 "committer" => committer = Some(value.to_string()),
46 "gpgsig" => gpgsig = Some(value.to_string()),
47 _ => return Err(Error::InvalidCommitHeader(key.to_string())),
48 }
49 Ok(())
50 };
51
52 let mut prev_line = String::new();
53 r.read_line(&mut prev_line).await?;
54 loop {
55 let mut this_line = String::new();
56 r.read_line(&mut this_line).await?;
57
58 if this_line.starts_with(" ") {
59 prev_line += &this_line[1..];
60 } else {
61 if this_line.len() == 1 && this_line.as_bytes()[0] == b'\n' {
63 break;
64 }
65 process_header(&prev_line)?;
66 prev_line = this_line;
67 }
68 }
69 process_header(&prev_line)?;
70
71 let mut message = String::new();
72 r.read_to_string(&mut message).await?;
73 message = message.trim().to_string();
74
75 Ok(Commit {
76 tree: tree.unwrap(),
77 parents,
78 author: author.unwrap(),
79 committer: committer.unwrap(),
80 gpgsig,
81 message,
82 })
83 }
84
85 pub async fn write<W: AsyncWrite + Unpin>(self, w: W) -> Result<(), IOError> {
86 Ok(())
87 }
88}