1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use crate::{
error::{Error, ErrorKind},
repository::{git::Repository, signature::Signature},
};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
const STALE_AFTER: Duration = Duration::from_secs(90 * 86400);
#[cfg_attr(docsrs, doc(cfg(feature = "git")))]
#[derive(Debug)]
pub struct Commit {
pub commit_id: String,
pub author: String,
pub summary: String,
pub timestamp: SystemTime,
pub signature: Option<Signature>,
signed_data: Option<Vec<u8>>,
}
impl Commit {
pub(crate) fn from_repo_head(repo: &Repository) -> Result<Self, Error> {
let head = repo.repo.head()?;
let oid = head.target().ok_or_else(|| {
format_err!(
ErrorKind::Repo,
"no ref target for: {}",
repo.path.display()
)
})?;
let commit_id = oid.to_string();
let commit_object = repo.repo.find_object(oid, Some(git2::ObjectType::Commit))?;
let commit = commit_object.as_commit().unwrap();
let author = commit.author().to_string();
let summary = commit
.summary()
.ok_or_else(|| format_err!(ErrorKind::Repo, "no commit summary for {}", commit_id))?
.to_owned();
let (signature, signed_data) = match repo.repo.extract_signature(&oid, None) {
Ok((ref sig, ref data)) => (
Some(Signature::from_bytes(sig)?),
Some(data.to_vec()),
),
_ => (None, None),
};
let time = UNIX_EPOCH + Duration::from_secs(commit.time().seconds() as u64);
Ok(Commit {
commit_id,
author,
summary,
timestamp: time,
signature,
signed_data,
})
}
pub fn is_fresh(&self) -> bool {
self.timestamp > SystemTime::now().checked_sub(STALE_AFTER).unwrap()
}
pub fn raw_signed_bytes(&self) -> Option<&[u8]> {
self.signed_data.as_ref().map(|bytes| bytes.as_ref())
}
pub(crate) fn reset(&self, repo: &Repository) -> Result<(), Error> {
let commit_object = repo.repo.find_object(
git2::Oid::from_str(&self.commit_id).unwrap(),
Some(git2::ObjectType::Commit),
)?;
repo.repo
.reset(&commit_object, git2::ResetType::Hard, None)?;
Ok(())
}
}