diff options
Diffstat (limited to 'extra/git2/src/treebuilder.rs')
-rw-r--r-- | extra/git2/src/treebuilder.rs | 234 |
1 files changed, 0 insertions, 234 deletions
diff --git a/extra/git2/src/treebuilder.rs b/extra/git2/src/treebuilder.rs deleted file mode 100644 index 1548a048c..000000000 --- a/extra/git2/src/treebuilder.rs +++ /dev/null @@ -1,234 +0,0 @@ -use std::marker; -use std::ptr; - -use libc::{c_int, c_void}; - -use crate::util::{Binding, IntoCString}; -use crate::{panic, raw, tree, Error, Oid, Repository, TreeEntry}; - -/// Constructor for in-memory trees (low-level) -/// -/// You probably want to use [`build::TreeUpdateBuilder`] instead. -/// -/// This is the more raw of the two tree update facilities. It -/// handles only one level of a nested tree structure at a time. Each -/// path passed to `insert` etc. must be a single component. -/// -/// [`build::TreeUpdateBuilder`]: crate::build::TreeUpdateBuilder -pub struct TreeBuilder<'repo> { - raw: *mut raw::git_treebuilder, - _marker: marker::PhantomData<&'repo Repository>, -} - -impl<'repo> TreeBuilder<'repo> { - /// Clear all the entries in the builder - pub fn clear(&mut self) -> Result<(), Error> { - unsafe { - try_call!(raw::git_treebuilder_clear(self.raw)); - } - Ok(()) - } - - /// Get the number of entries - pub fn len(&self) -> usize { - unsafe { raw::git_treebuilder_entrycount(self.raw) as usize } - } - - /// Return `true` if there is no entry - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Get en entry from the builder from its filename - pub fn get<P>(&self, filename: P) -> Result<Option<TreeEntry<'_>>, Error> - where - P: IntoCString, - { - let filename = filename.into_c_string()?; - unsafe { - let ret = raw::git_treebuilder_get(self.raw, filename.as_ptr()); - if ret.is_null() { - Ok(None) - } else { - Ok(Some(tree::entry_from_raw_const(ret))) - } - } - } - - /// Add or update an entry in the builder - /// - /// No attempt is made to ensure that the provided Oid points to - /// an object of a reasonable type (or any object at all). - /// - /// The mode given must be one of 0o040000, 0o100644, 0o100755, 0o120000 or - /// 0o160000 currently. - pub fn insert<P: IntoCString>( - &mut self, - filename: P, - oid: Oid, - filemode: i32, - ) -> Result<TreeEntry<'_>, Error> { - let filename = filename.into_c_string()?; - let filemode = filemode as raw::git_filemode_t; - - let mut ret = ptr::null(); - unsafe { - try_call!(raw::git_treebuilder_insert( - &mut ret, - self.raw, - filename, - oid.raw(), - filemode - )); - Ok(tree::entry_from_raw_const(ret)) - } - } - - /// Remove an entry from the builder by its filename - pub fn remove<P: IntoCString>(&mut self, filename: P) -> Result<(), Error> { - let filename = filename.into_c_string()?; - unsafe { - try_call!(raw::git_treebuilder_remove(self.raw, filename)); - } - Ok(()) - } - - /// Selectively remove entries from the tree - /// - /// Values for which the filter returns `true` will be kept. Note - /// that this behavior is different from the libgit2 C interface. - pub fn filter<F>(&mut self, mut filter: F) -> Result<(), Error> - where - F: FnMut(&TreeEntry<'_>) -> bool, - { - let mut cb: &mut FilterCb<'_> = &mut filter; - let ptr = &mut cb as *mut _; - let cb: raw::git_treebuilder_filter_cb = Some(filter_cb); - unsafe { - try_call!(raw::git_treebuilder_filter(self.raw, cb, ptr as *mut _)); - panic::check(); - } - Ok(()) - } - - /// Write the contents of the TreeBuilder as a Tree object and - /// return its Oid - pub fn write(&self) -> Result<Oid, Error> { - let mut raw = raw::git_oid { - id: [0; raw::GIT_OID_RAWSZ], - }; - unsafe { - try_call!(raw::git_treebuilder_write(&mut raw, self.raw())); - Ok(Binding::from_raw(&raw as *const _)) - } - } -} - -type FilterCb<'a> = dyn FnMut(&TreeEntry<'_>) -> bool + 'a; - -extern "C" fn filter_cb(entry: *const raw::git_tree_entry, payload: *mut c_void) -> c_int { - let ret = panic::wrap(|| unsafe { - // There's no way to return early from git_treebuilder_filter. - if panic::panicked() { - true - } else { - let entry = tree::entry_from_raw_const(entry); - let payload = payload as *mut &mut FilterCb<'_>; - (*payload)(&entry) - } - }); - if ret == Some(false) { - 1 - } else { - 0 - } -} - -impl<'repo> Binding for TreeBuilder<'repo> { - type Raw = *mut raw::git_treebuilder; - - unsafe fn from_raw(raw: *mut raw::git_treebuilder) -> TreeBuilder<'repo> { - TreeBuilder { - raw, - _marker: marker::PhantomData, - } - } - fn raw(&self) -> *mut raw::git_treebuilder { - self.raw - } -} - -impl<'repo> Drop for TreeBuilder<'repo> { - fn drop(&mut self) { - unsafe { raw::git_treebuilder_free(self.raw) } - } -} - -#[cfg(test)] -mod tests { - use crate::ObjectType; - - #[test] - fn smoke() { - let (_td, repo) = crate::test::repo_init(); - - let mut builder = repo.treebuilder(None).unwrap(); - assert_eq!(builder.len(), 0); - let blob = repo.blob(b"data").unwrap(); - { - let entry = builder.insert("a", blob, 0o100644).unwrap(); - assert_eq!(entry.kind(), Some(ObjectType::Blob)); - } - builder.insert("b", blob, 0o100644).unwrap(); - assert_eq!(builder.len(), 2); - builder.remove("a").unwrap(); - assert_eq!(builder.len(), 1); - assert_eq!(builder.get("b").unwrap().unwrap().id(), blob); - builder.clear().unwrap(); - assert_eq!(builder.len(), 0); - } - - #[test] - fn write() { - let (_td, repo) = crate::test::repo_init(); - - let mut builder = repo.treebuilder(None).unwrap(); - let data = repo.blob(b"data").unwrap(); - builder.insert("name", data, 0o100644).unwrap(); - let tree = builder.write().unwrap(); - let tree = repo.find_tree(tree).unwrap(); - let entry = tree.get(0).unwrap(); - assert_eq!(entry.name(), Some("name")); - let blob = entry.to_object(&repo).unwrap(); - let blob = blob.as_blob().unwrap(); - assert_eq!(blob.content(), b"data"); - - let builder = repo.treebuilder(Some(&tree)).unwrap(); - assert_eq!(builder.len(), 1); - } - - #[test] - fn filter() { - let (_td, repo) = crate::test::repo_init(); - - let mut builder = repo.treebuilder(None).unwrap(); - let blob = repo.blob(b"data").unwrap(); - let tree = { - let head = repo.head().unwrap().peel(ObjectType::Commit).unwrap(); - let head = head.as_commit().unwrap(); - head.tree_id() - }; - builder.insert("blob", blob, 0o100644).unwrap(); - builder.insert("dir", tree, 0o040000).unwrap(); - builder.insert("dir2", tree, 0o040000).unwrap(); - - builder.filter(|_| true).unwrap(); - assert_eq!(builder.len(), 3); - builder - .filter(|e| e.kind().unwrap() != ObjectType::Blob) - .unwrap(); - assert_eq!(builder.len(), 2); - builder.filter(|_| false).unwrap(); - assert_eq!(builder.len(), 0); - } -} |