]> git.proxmox.com Git - rustc.git/blame - vendor/git2/src/reflog.rs
New upstream version 1.70.0+dfsg2
[rustc.git] / vendor / git2 / src / reflog.rs
CommitLineData
0a29b90c
FG
1use libc::size_t;
2use std::marker;
3use std::ops::Range;
4use std::str;
5
6use crate::util::Binding;
7use crate::{raw, signature, Error, Oid, Signature};
8
9/// A reference log of a git repository.
10pub struct Reflog {
11 raw: *mut raw::git_reflog,
12}
13
14/// An entry inside the reflog of a repository
15pub struct ReflogEntry<'reflog> {
16 raw: *const raw::git_reflog_entry,
17 _marker: marker::PhantomData<&'reflog Reflog>,
18}
19
20/// An iterator over the entries inside of a reflog.
21pub struct ReflogIter<'reflog> {
22 range: Range<usize>,
23 reflog: &'reflog Reflog,
24}
25
26impl Reflog {
27 /// Add a new entry to the in-memory reflog.
28 pub fn append(
29 &mut self,
30 new_oid: Oid,
31 committer: &Signature<'_>,
32 msg: Option<&str>,
33 ) -> Result<(), Error> {
34 let msg = crate::opt_cstr(msg)?;
35 unsafe {
36 try_call!(raw::git_reflog_append(
37 self.raw,
38 new_oid.raw(),
39 committer.raw(),
40 msg
41 ));
42 }
43 Ok(())
44 }
45
46 /// Remove an entry from the reflog by its index
47 ///
48 /// To ensure there's no gap in the log history, set rewrite_previous_entry
49 /// param value to `true`. When deleting entry n, member old_oid of entry
50 /// n-1 (if any) will be updated with the value of member new_oid of entry
51 /// n+1.
52 pub fn remove(&mut self, i: usize, rewrite_previous_entry: bool) -> Result<(), Error> {
53 unsafe {
54 try_call!(raw::git_reflog_drop(
55 self.raw,
56 i as size_t,
57 rewrite_previous_entry
58 ));
59 }
60 Ok(())
61 }
62
63 /// Lookup an entry by its index
64 ///
65 /// Requesting the reflog entry with an index of 0 (zero) will return the
66 /// most recently created entry.
67 pub fn get(&self, i: usize) -> Option<ReflogEntry<'_>> {
68 unsafe {
69 let ptr = raw::git_reflog_entry_byindex(self.raw, i as size_t);
70 Binding::from_raw_opt(ptr)
71 }
72 }
73
74 /// Get the number of log entries in a reflog
75 pub fn len(&self) -> usize {
76 unsafe { raw::git_reflog_entrycount(self.raw) as usize }
77 }
78
79 /// Return `true ` is there is no log entry in a reflog
80 pub fn is_empty(&self) -> bool {
81 self.len() == 0
82 }
83
84 /// Get an iterator to all entries inside of this reflog
85 pub fn iter(&self) -> ReflogIter<'_> {
86 ReflogIter {
87 range: 0..self.len(),
88 reflog: self,
89 }
90 }
91
92 /// Write an existing in-memory reflog object back to disk using an atomic
93 /// file lock.
94 pub fn write(&mut self) -> Result<(), Error> {
95 unsafe {
96 try_call!(raw::git_reflog_write(self.raw));
97 }
98 Ok(())
99 }
100}
101
102impl Binding for Reflog {
103 type Raw = *mut raw::git_reflog;
104
105 unsafe fn from_raw(raw: *mut raw::git_reflog) -> Reflog {
106 Reflog { raw }
107 }
108 fn raw(&self) -> *mut raw::git_reflog {
109 self.raw
110 }
111}
112
113impl Drop for Reflog {
114 fn drop(&mut self) {
115 unsafe { raw::git_reflog_free(self.raw) }
116 }
117}
118
119impl<'reflog> ReflogEntry<'reflog> {
120 /// Get the committer of this entry
121 pub fn committer(&self) -> Signature<'_> {
122 unsafe {
123 let ptr = raw::git_reflog_entry_committer(self.raw);
124 signature::from_raw_const(self, ptr)
125 }
126 }
127
128 /// Get the new oid
129 pub fn id_new(&self) -> Oid {
130 unsafe { Binding::from_raw(raw::git_reflog_entry_id_new(self.raw)) }
131 }
132
133 /// Get the old oid
134 pub fn id_old(&self) -> Oid {
135 unsafe { Binding::from_raw(raw::git_reflog_entry_id_old(self.raw)) }
136 }
137
138 /// Get the log message, returning `None` on invalid UTF-8.
139 pub fn message(&self) -> Option<&str> {
140 self.message_bytes().and_then(|s| str::from_utf8(s).ok())
141 }
142
143 /// Get the log message as a byte array.
144 pub fn message_bytes(&self) -> Option<&[u8]> {
145 unsafe { crate::opt_bytes(self, raw::git_reflog_entry_message(self.raw)) }
146 }
147}
148
149impl<'reflog> Binding for ReflogEntry<'reflog> {
150 type Raw = *const raw::git_reflog_entry;
151
152 unsafe fn from_raw(raw: *const raw::git_reflog_entry) -> ReflogEntry<'reflog> {
153 ReflogEntry {
154 raw,
155 _marker: marker::PhantomData,
156 }
157 }
158 fn raw(&self) -> *const raw::git_reflog_entry {
159 self.raw
160 }
161}
162
163impl<'reflog> Iterator for ReflogIter<'reflog> {
164 type Item = ReflogEntry<'reflog>;
165 fn next(&mut self) -> Option<ReflogEntry<'reflog>> {
166 self.range.next().and_then(|i| self.reflog.get(i))
167 }
168 fn size_hint(&self) -> (usize, Option<usize>) {
169 self.range.size_hint()
170 }
171}
172impl<'reflog> DoubleEndedIterator for ReflogIter<'reflog> {
173 fn next_back(&mut self) -> Option<ReflogEntry<'reflog>> {
174 self.range.next_back().and_then(|i| self.reflog.get(i))
175 }
176}
177impl<'reflog> ExactSizeIterator for ReflogIter<'reflog> {}
178
179#[cfg(test)]
180mod tests {
181 #[test]
182 fn smoke() {
183 let (_td, repo) = crate::test::repo_init();
184 let mut reflog = repo.reflog("HEAD").unwrap();
185 assert_eq!(reflog.iter().len(), 1);
186 reflog.write().unwrap();
187
188 let entry = reflog.iter().next().unwrap();
189 assert!(entry.message().is_some());
190
191 repo.reflog_rename("HEAD", "refs/heads/foo").unwrap();
192 repo.reflog_delete("refs/heads/foo").unwrap();
193 }
194}