diff --git a/lib/src/bindings/worktree.dart b/lib/src/bindings/worktree.dart index d80e131..d1009ae 100644 --- a/lib/src/bindings/worktree.dart +++ b/lib/src/bindings/worktree.dart @@ -75,6 +75,27 @@ Pointer lookup({ } } +/// Check if the worktree prunable. +/// +/// A worktree is not prunable in the following scenarios: +/// - the worktree is linking to a valid on-disk worktree. +/// - the worktree is locked. +/// +/// Throws a [LibGit2Error] if error occured. +bool isPrunable(Pointer wt) { + final opts = calloc(); + final optsError = libgit2.git_worktree_prune_options_init( + opts, + GIT_WORKTREE_PRUNE_OPTIONS_VERSION, + ); + + if (optsError < 0) { + throw LibGit2Error(libgit2.git_error_last()); + } + + return libgit2.git_worktree_is_prunable(wt, opts) > 0 ? true : false; +} + /// Prune working tree. /// /// Prune the working tree, that is remove the git data structures on disk. @@ -118,5 +139,37 @@ String path(Pointer wt) { return libgit2.git_worktree_path(wt).cast().toDartString(); } +/// Check if worktree is locked. +/// +/// A worktree may be locked if the linked working tree is stored on a portable +/// device which is not available. +/// +/// Throws a [LibGit2Error] if error occured. +bool isLocked(Pointer wt) { + final result = libgit2.git_worktree_is_locked(nullptr, wt); + + if (result < 0) { + throw LibGit2Error(libgit2.git_error_last()); + } else if (result == 0) { + return false; + } else { + return true; + } +} + +/// Lock worktree if not already locked. +void lock(Pointer wt) => libgit2.git_worktree_lock(wt, nullptr); + +/// Unlock a locked worktree. +void unlock(Pointer wt) => libgit2.git_worktree_unlock(wt); + +/// Check if worktree is valid. +/// +/// A valid worktree requires both the git data structures inside the linked parent +/// repository and the linked working copy to be present. +bool isValid(Pointer wt) { + return libgit2.git_worktree_validate(wt) == 0 ? true : false; +} + /// Free a previously allocated worktree. void free(Pointer wt) => libgit2.git_worktree_free(wt); diff --git a/lib/src/worktree.dart b/lib/src/worktree.dart index 6788a9a..abbdfc0 100644 --- a/lib/src/worktree.dart +++ b/lib/src/worktree.dart @@ -52,6 +52,29 @@ class Worktree { /// Returns the filesystem path for the worktree. String get path => bindings.path(_worktreePointer); + /// Checks if worktree is locked. + /// + /// A worktree may be locked if the linked working tree is stored on a portable + /// device which is not available. + /// + /// Throws a [LibGit2Error] if error occured. + bool get isLocked => bindings.isLocked(_worktreePointer); + + /// Locks worktree if not already locked. + void lock() => bindings.lock(_worktreePointer); + + /// Unlocks a locked worktree. + void unlock() => bindings.unlock(_worktreePointer); + + /// Checks if the worktree prunable. + /// + /// A worktree is not prunable in the following scenarios: + /// - the worktree is linking to a valid on-disk worktree. + /// - the worktree is locked. + /// + /// Throws a [LibGit2Error] if error occured. + bool get isPrunable => bindings.isPrunable(_worktreePointer); + /// Prunes working tree. /// /// Prune the working tree, that is remove the git data structures on disk. @@ -59,6 +82,12 @@ class Worktree { /// Throws a [LibGit2Error] if error occured. void prune() => bindings.prune(_worktreePointer); + /// Checks if worktree is valid. + /// + /// A valid worktree requires both the git data structures inside the linked parent + /// repository and the linked working copy to be present. + bool get isValid => bindings.isValid(_worktreePointer); + /// Releases memory allocated for worktree object. void free() => bindings.free(_worktreePointer); diff --git a/test/worktree_test.dart b/test/worktree_test.dart index 1699466..f1e0da1 100644 --- a/test/worktree_test.dart +++ b/test/worktree_test.dart @@ -33,21 +33,18 @@ void main() { name: worktreeName, path: worktreeDir.path, ); - final lookedupWorktree = repo.lookupWorktree(worktreeName); final branches = repo.branches; expect(repo.worktrees, [worktreeName]); expect(branches.any((branch) => branch.name == worktreeName), true); expect(worktree.name, worktreeName); - expect(lookedupWorktree.name, worktreeName); expect(worktree.path, worktreeDir.path); - expect(lookedupWorktree.path, worktreeDir.path); + expect(worktree.isLocked, false); expect(File('${worktreeDir.path}/.git').existsSync(), true); for (final branch in branches) { branch.free(); } - lookedupWorktree.free(); worktree.free(); }); @@ -87,6 +84,37 @@ void main() { worktree.free(); }); + test('successfully lookups worktree', () { + final worktree = repo.createWorktree( + name: worktreeName, + path: worktreeDir.path, + ); + final lookedupWorktree = repo.lookupWorktree(worktreeName); + + expect(lookedupWorktree.name, worktreeName); + expect(lookedupWorktree.path, worktreeDir.path); + expect(lookedupWorktree.isLocked, false); + + lookedupWorktree.free(); + worktree.free(); + }); + + test('successfully locks and unlocks worktree', () { + final worktree = repo.createWorktree( + name: worktreeName, + path: worktreeDir.path, + ); + expect(worktree.isLocked, false); + + worktree.lock(); + expect(worktree.isLocked, true); + + worktree.unlock(); + expect(worktree.isLocked, false); + + worktree.free(); + }); + test('successfully prunes worktree', () { expect(repo.worktrees, []); @@ -95,8 +123,13 @@ void main() { path: worktreeDir.path, ); expect(repo.worktrees, [worktreeName]); + expect(worktree.isPrunable, false); + expect(worktree.isValid, true); worktreeDir.deleteSync(recursive: true); + expect(worktree.isPrunable, true); + expect(worktree.isValid, false); + worktree.prune(); expect(repo.worktrees, []);