diff options
Diffstat (limited to 'extra/git2/src/worktree.rs')
-rw-r--r-- | extra/git2/src/worktree.rs | 331 |
1 files changed, 0 insertions, 331 deletions
diff --git a/extra/git2/src/worktree.rs b/extra/git2/src/worktree.rs deleted file mode 100644 index 569b639cf..000000000 --- a/extra/git2/src/worktree.rs +++ /dev/null @@ -1,331 +0,0 @@ -use crate::buf::Buf; -use crate::reference::Reference; -use crate::repo::Repository; -use crate::util::{self, Binding}; -use crate::{raw, Error}; -use std::os::raw::c_int; -use std::path::Path; -use std::ptr; -use std::str; -use std::{marker, mem}; - -/// An owned git worktree -/// -/// This structure corresponds to a `git_worktree` in libgit2. -// -pub struct Worktree { - raw: *mut raw::git_worktree, -} - -/// Options which can be used to configure how a worktree is initialized -pub struct WorktreeAddOptions<'a> { - raw: raw::git_worktree_add_options, - _marker: marker::PhantomData<Reference<'a>>, -} - -/// Options to configure how worktree pruning is performed -pub struct WorktreePruneOptions { - raw: raw::git_worktree_prune_options, -} - -/// Lock Status of a worktree -#[derive(PartialEq, Debug)] -pub enum WorktreeLockStatus { - /// Worktree is Unlocked - Unlocked, - /// Worktree is locked with the optional message - Locked(Option<String>), -} - -impl Worktree { - /// Open a worktree of a the repository - /// - /// If a repository is not the main tree but a worktree, this - /// function will look up the worktree inside the parent - /// repository and create a new `git_worktree` structure. - pub fn open_from_repository(repo: &Repository) -> Result<Worktree, Error> { - let mut raw = ptr::null_mut(); - unsafe { - try_call!(raw::git_worktree_open_from_repository(&mut raw, repo.raw())); - Ok(Binding::from_raw(raw)) - } - } - - /// Retrieves the name of the worktree - /// - /// This is the name that can be passed to repo::Repository::find_worktree - /// to reopen the worktree. This is also the name that would appear in the - /// list returned by repo::Repository::worktrees - pub fn name(&self) -> Option<&str> { - unsafe { - crate::opt_bytes(self, raw::git_worktree_name(self.raw)) - .and_then(|s| str::from_utf8(s).ok()) - } - } - - /// Retrieves the path to the worktree - /// - /// This is the path to the top-level of the source and not the path to the - /// .git file within the worktree. This path can be passed to - /// repo::Repository::open. - pub fn path(&self) -> &Path { - unsafe { - util::bytes2path(crate::opt_bytes(self, raw::git_worktree_path(self.raw)).unwrap()) - } - } - - /// Validates the worktree - /// - /// This checks that it still exists on the - /// filesystem and that the metadata is correct - pub fn validate(&self) -> Result<(), Error> { - unsafe { - try_call!(raw::git_worktree_validate(self.raw)); - } - Ok(()) - } - - /// Locks the worktree - pub fn lock(&self, reason: Option<&str>) -> Result<(), Error> { - let reason = crate::opt_cstr(reason)?; - unsafe { - try_call!(raw::git_worktree_lock(self.raw, reason)); - } - Ok(()) - } - - /// Unlocks the worktree - pub fn unlock(&self) -> Result<(), Error> { - unsafe { - try_call!(raw::git_worktree_unlock(self.raw)); - } - Ok(()) - } - - /// Checks if worktree is locked - pub fn is_locked(&self) -> Result<WorktreeLockStatus, Error> { - let buf = Buf::new(); - unsafe { - match try_call!(raw::git_worktree_is_locked(buf.raw(), self.raw)) { - 0 => Ok(WorktreeLockStatus::Unlocked), - _ => { - let v = buf.to_vec(); - Ok(WorktreeLockStatus::Locked(match v.len() { - 0 => None, - _ => Some(String::from_utf8(v).unwrap()), - })) - } - } - } - } - - /// Prunes the worktree - pub fn prune(&self, opts: Option<&mut WorktreePruneOptions>) -> Result<(), Error> { - // When successful the worktree should be removed however the backing structure - // of the git_worktree should still be valid. - unsafe { - try_call!(raw::git_worktree_prune(self.raw, opts.map(|o| o.raw()))); - } - Ok(()) - } - - /// Checks if the worktree is prunable - pub fn is_prunable(&self, opts: Option<&mut WorktreePruneOptions>) -> Result<bool, Error> { - unsafe { - let rv = try_call!(raw::git_worktree_is_prunable( - self.raw, - opts.map(|o| o.raw()) - )); - Ok(rv != 0) - } - } -} - -impl<'a> WorktreeAddOptions<'a> { - /// Creates a default set of add options. - /// - /// By default this will not lock the worktree - pub fn new() -> WorktreeAddOptions<'a> { - unsafe { - let mut raw = mem::zeroed(); - assert_eq!( - raw::git_worktree_add_options_init(&mut raw, raw::GIT_WORKTREE_ADD_OPTIONS_VERSION), - 0 - ); - WorktreeAddOptions { - raw, - _marker: marker::PhantomData, - } - } - } - - /// If enabled, this will cause the newly added worktree to be locked - pub fn lock(&mut self, enabled: bool) -> &mut WorktreeAddOptions<'a> { - self.raw.lock = enabled as c_int; - self - } - - /// reference to use for the new worktree HEAD - pub fn reference( - &mut self, - reference: Option<&'a Reference<'_>>, - ) -> &mut WorktreeAddOptions<'a> { - self.raw.reference = if let Some(reference) = reference { - reference.raw() - } else { - ptr::null_mut() - }; - self - } - - /// Get a set of raw add options to be used with `git_worktree_add` - pub fn raw(&self) -> *const raw::git_worktree_add_options { - &self.raw - } -} - -impl WorktreePruneOptions { - /// Creates a default set of pruning options - /// - /// By defaults this will prune only worktrees that are no longer valid - /// unlocked and not checked out - pub fn new() -> WorktreePruneOptions { - unsafe { - let mut raw = mem::zeroed(); - assert_eq!( - raw::git_worktree_prune_options_init( - &mut raw, - raw::GIT_WORKTREE_PRUNE_OPTIONS_VERSION - ), - 0 - ); - WorktreePruneOptions { raw } - } - } - - /// Controls whether valid (still existing on the filesystem) worktrees - /// will be pruned - /// - /// Defaults to false - pub fn valid(&mut self, valid: bool) -> &mut WorktreePruneOptions { - self.flag(raw::GIT_WORKTREE_PRUNE_VALID, valid) - } - - /// Controls whether locked worktrees will be pruned - /// - /// Defaults to false - pub fn locked(&mut self, locked: bool) -> &mut WorktreePruneOptions { - self.flag(raw::GIT_WORKTREE_PRUNE_LOCKED, locked) - } - - /// Controls whether the actual working tree on the filesystem is recursively removed - /// - /// Defaults to false - pub fn working_tree(&mut self, working_tree: bool) -> &mut WorktreePruneOptions { - self.flag(raw::GIT_WORKTREE_PRUNE_WORKING_TREE, working_tree) - } - - fn flag(&mut self, flag: raw::git_worktree_prune_t, on: bool) -> &mut WorktreePruneOptions { - if on { - self.raw.flags |= flag as u32; - } else { - self.raw.flags &= !(flag as u32); - } - self - } - - /// Get a set of raw prune options to be used with `git_worktree_prune` - pub fn raw(&mut self) -> *mut raw::git_worktree_prune_options { - &mut self.raw - } -} - -impl Binding for Worktree { - type Raw = *mut raw::git_worktree; - unsafe fn from_raw(ptr: *mut raw::git_worktree) -> Worktree { - Worktree { raw: ptr } - } - fn raw(&self) -> *mut raw::git_worktree { - self.raw - } -} - -impl Drop for Worktree { - fn drop(&mut self) { - unsafe { raw::git_worktree_free(self.raw) } - } -} - -#[cfg(test)] -mod tests { - use crate::WorktreeAddOptions; - use crate::WorktreeLockStatus; - - use tempfile::TempDir; - - #[test] - fn smoke_add_no_ref() { - let (_td, repo) = crate::test::repo_init(); - - let wtdir = TempDir::new().unwrap(); - let wt_path = wtdir.path().join("tree-no-ref-dir"); - let opts = WorktreeAddOptions::new(); - - let wt = repo.worktree("tree-no-ref", &wt_path, Some(&opts)).unwrap(); - assert_eq!(wt.name(), Some("tree-no-ref")); - assert_eq!( - wt.path().canonicalize().unwrap(), - wt_path.canonicalize().unwrap() - ); - let status = wt.is_locked().unwrap(); - assert_eq!(status, WorktreeLockStatus::Unlocked); - } - - #[test] - fn smoke_add_locked() { - let (_td, repo) = crate::test::repo_init(); - - let wtdir = TempDir::new().unwrap(); - let wt_path = wtdir.path().join("locked-tree"); - let mut opts = WorktreeAddOptions::new(); - opts.lock(true); - - let wt = repo.worktree("locked-tree", &wt_path, Some(&opts)).unwrap(); - // shouldn't be able to lock a worktree that was created locked - assert!(wt.lock(Some("my reason")).is_err()); - assert_eq!(wt.name(), Some("locked-tree")); - assert_eq!( - wt.path().canonicalize().unwrap(), - wt_path.canonicalize().unwrap() - ); - assert_eq!(wt.is_locked().unwrap(), WorktreeLockStatus::Locked(None)); - assert!(wt.unlock().is_ok()); - assert!(wt.lock(Some("my reason")).is_ok()); - assert_eq!( - wt.is_locked().unwrap(), - WorktreeLockStatus::Locked(Some("my reason".to_string())) - ); - } - - #[test] - fn smoke_add_from_branch() { - let (_td, repo) = crate::test::repo_init(); - - let (wt_top, branch) = crate::test::worktrees_env_init(&repo); - let wt_path = wt_top.path().join("test"); - let mut opts = WorktreeAddOptions::new(); - let reference = branch.into_reference(); - opts.reference(Some(&reference)); - - let wt = repo - .worktree("test-worktree", &wt_path, Some(&opts)) - .unwrap(); - assert_eq!(wt.name(), Some("test-worktree")); - assert_eq!( - wt.path().canonicalize().unwrap(), - wt_path.canonicalize().unwrap() - ); - let status = wt.is_locked().unwrap(); - assert_eq!(status, WorktreeLockStatus::Unlocked); - } -} |