diff options
Diffstat (limited to '')
-rw-r--r-- | vendor/git2/src/reflog.rs | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/vendor/git2/src/reflog.rs b/vendor/git2/src/reflog.rs new file mode 100644 index 0000000..bbd2140 --- /dev/null +++ b/vendor/git2/src/reflog.rs @@ -0,0 +1,196 @@ +use libc::size_t; +use std::iter::FusedIterator; +use std::marker; +use std::ops::Range; +use std::str; + +use crate::util::Binding; +use crate::{raw, signature, Error, Oid, Signature}; + +/// A reference log of a git repository. +pub struct Reflog { + raw: *mut raw::git_reflog, +} + +/// An entry inside the reflog of a repository +pub struct ReflogEntry<'reflog> { + raw: *const raw::git_reflog_entry, + _marker: marker::PhantomData<&'reflog Reflog>, +} + +/// An iterator over the entries inside of a reflog. +pub struct ReflogIter<'reflog> { + range: Range<usize>, + reflog: &'reflog Reflog, +} + +impl Reflog { + /// Add a new entry to the in-memory reflog. + pub fn append( + &mut self, + new_oid: Oid, + committer: &Signature<'_>, + msg: Option<&str>, + ) -> Result<(), Error> { + let msg = crate::opt_cstr(msg)?; + unsafe { + try_call!(raw::git_reflog_append( + self.raw, + new_oid.raw(), + committer.raw(), + msg + )); + } + Ok(()) + } + + /// Remove an entry from the reflog by its index + /// + /// To ensure there's no gap in the log history, set rewrite_previous_entry + /// param value to `true`. When deleting entry n, member old_oid of entry + /// n-1 (if any) will be updated with the value of member new_oid of entry + /// n+1. + pub fn remove(&mut self, i: usize, rewrite_previous_entry: bool) -> Result<(), Error> { + unsafe { + try_call!(raw::git_reflog_drop( + self.raw, + i as size_t, + rewrite_previous_entry + )); + } + Ok(()) + } + + /// Lookup an entry by its index + /// + /// Requesting the reflog entry with an index of 0 (zero) will return the + /// most recently created entry. + pub fn get(&self, i: usize) -> Option<ReflogEntry<'_>> { + unsafe { + let ptr = raw::git_reflog_entry_byindex(self.raw, i as size_t); + Binding::from_raw_opt(ptr) + } + } + + /// Get the number of log entries in a reflog + pub fn len(&self) -> usize { + unsafe { raw::git_reflog_entrycount(self.raw) as usize } + } + + /// Return `true ` is there is no log entry in a reflog + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get an iterator to all entries inside of this reflog + pub fn iter(&self) -> ReflogIter<'_> { + ReflogIter { + range: 0..self.len(), + reflog: self, + } + } + + /// Write an existing in-memory reflog object back to disk using an atomic + /// file lock. + pub fn write(&mut self) -> Result<(), Error> { + unsafe { + try_call!(raw::git_reflog_write(self.raw)); + } + Ok(()) + } +} + +impl Binding for Reflog { + type Raw = *mut raw::git_reflog; + + unsafe fn from_raw(raw: *mut raw::git_reflog) -> Reflog { + Reflog { raw } + } + fn raw(&self) -> *mut raw::git_reflog { + self.raw + } +} + +impl Drop for Reflog { + fn drop(&mut self) { + unsafe { raw::git_reflog_free(self.raw) } + } +} + +impl<'reflog> ReflogEntry<'reflog> { + /// Get the committer of this entry + pub fn committer(&self) -> Signature<'_> { + unsafe { + let ptr = raw::git_reflog_entry_committer(self.raw); + signature::from_raw_const(self, ptr) + } + } + + /// Get the new oid + pub fn id_new(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_reflog_entry_id_new(self.raw)) } + } + + /// Get the old oid + pub fn id_old(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_reflog_entry_id_old(self.raw)) } + } + + /// Get the log message, returning `None` on invalid UTF-8. + pub fn message(&self) -> Option<&str> { + self.message_bytes().and_then(|s| str::from_utf8(s).ok()) + } + + /// Get the log message as a byte array. + pub fn message_bytes(&self) -> Option<&[u8]> { + unsafe { crate::opt_bytes(self, raw::git_reflog_entry_message(self.raw)) } + } +} + +impl<'reflog> Binding for ReflogEntry<'reflog> { + type Raw = *const raw::git_reflog_entry; + + unsafe fn from_raw(raw: *const raw::git_reflog_entry) -> ReflogEntry<'reflog> { + ReflogEntry { + raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *const raw::git_reflog_entry { + self.raw + } +} + +impl<'reflog> Iterator for ReflogIter<'reflog> { + type Item = ReflogEntry<'reflog>; + fn next(&mut self) -> Option<ReflogEntry<'reflog>> { + self.range.next().and_then(|i| self.reflog.get(i)) + } + fn size_hint(&self) -> (usize, Option<usize>) { + self.range.size_hint() + } +} +impl<'reflog> DoubleEndedIterator for ReflogIter<'reflog> { + fn next_back(&mut self) -> Option<ReflogEntry<'reflog>> { + self.range.next_back().and_then(|i| self.reflog.get(i)) + } +} +impl<'reflog> FusedIterator for ReflogIter<'reflog> {} +impl<'reflog> ExactSizeIterator for ReflogIter<'reflog> {} + +#[cfg(test)] +mod tests { + #[test] + fn smoke() { + let (_td, repo) = crate::test::repo_init(); + let mut reflog = repo.reflog("HEAD").unwrap(); + assert_eq!(reflog.iter().len(), 1); + reflog.write().unwrap(); + + let entry = reflog.iter().next().unwrap(); + assert!(entry.message().is_some()); + + repo.reflog_rename("HEAD", "refs/heads/foo").unwrap(); + repo.reflog_delete("refs/heads/foo").unwrap(); + } +} |