-
Notifications
You must be signed in to change notification settings - Fork 280
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
629 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// | ||
// GTRepository+GTRepository_Worktree.h | ||
// ObjectiveGitFramework | ||
// | ||
// Created by Etienne on 25/07/2017. | ||
// Copyright © 2017 GitHub, Inc. All rights reserved. | ||
// | ||
|
||
#import <ObjectiveGit/ObjectiveGit.h> | ||
|
||
@class GTWorktree; | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
@interface GTRepository (Worktree) | ||
|
||
/// Is this the worktree of another repository ? | ||
@property (nonatomic, readonly, getter = isWorktree) BOOL worktree; | ||
|
||
/// The URL for the underlying repository's git directory. | ||
/// Returns the same as -gitDirectoryURL if this is not a worktree. | ||
@property (nonatomic, readonly, strong) NSURL *commonGitDirectoryURL; | ||
|
||
+ (instancetype _Nullable)repositoryWithWorktree:(GTWorktree *)worktree error:(NSError **)error; | ||
|
||
- (instancetype _Nullable)initWithWorktree:(GTWorktree *)worktree error:(NSError **)error; | ||
|
||
- (GTReference * _Nullable)HEADReferenceInWorktreeWithName:(NSString *)name error:(NSError **)error; | ||
|
||
- (BOOL)isHEADDetached:(BOOL *)detached inWorktreeWithName:(NSString *)name error:(NSError **)error; | ||
|
||
- (BOOL)setWorkingDirectoryURL:(NSURL *)URL updateGitLink:(BOOL)update error:(NSError **)error; | ||
|
||
- (NSArray <NSString *> * _Nullable)worktreeNamesWithError:(NSError **)error; | ||
|
||
- (GTWorktree * _Nullable)lookupWorktreeWithName:(NSString *)name error:(NSError **)error; | ||
|
||
- (GTWorktree * _Nullable)openWorktree:(NSError **)error; | ||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// | ||
// GTRepository+Worktree.m | ||
// ObjectiveGitFramework | ||
// | ||
// Created by Etienne on 25/07/2017. | ||
// Copyright © 2017 GitHub, Inc. All rights reserved. | ||
// | ||
|
||
#import "GTRepository+Worktree.h" | ||
|
||
@implementation GTRepository (Worktree) | ||
|
||
+ (instancetype)repositoryWithWorktree:(GTWorktree *)worktree error:(NSError **)error { | ||
return [[self alloc] initWithWorktree:worktree error:error]; | ||
} | ||
|
||
- (instancetype)initWithWorktree:(GTWorktree *)worktree error:(NSError **)error { | ||
NSParameterAssert(worktree != nil); | ||
|
||
git_repository *repo; | ||
int gitError = git_repository_open_from_worktree(&repo, worktree.git_worktree); | ||
if (gitError != GIT_OK) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to open worktree"]; | ||
return nil; | ||
} | ||
return [self initWithGitRepository:repo]; | ||
} | ||
|
||
- (BOOL)isWorktree { | ||
return (BOOL)git_repository_is_worktree(self.git_repository); | ||
} | ||
|
||
- (NSURL *)commonGitDirectoryURL { | ||
return [NSURL fileURLWithPath:@(git_repository_commondir(self.git_repository)) isDirectory:YES]; | ||
} | ||
|
||
- (GTReference *)HEADReferenceInWorktreeWithName:(NSString *)name error:(NSError **)error { | ||
NSParameterAssert(name != nil); | ||
|
||
git_reference *ref; | ||
int gitError = git_repository_head_for_worktree(&ref, self.git_repository, name.UTF8String); | ||
if (gitError != GIT_OK) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to resolve HEAD in worktree"]; | ||
return nil; | ||
} | ||
|
||
return [[GTReference alloc] initWithGitReference:ref repository:self]; | ||
} | ||
|
||
- (BOOL)isHEADDetached:(BOOL *)detached inWorktreeWithName:(NSString *)name error:(NSError **)error { | ||
NSParameterAssert(detached != nil); | ||
NSParameterAssert(name != nil); | ||
|
||
int gitError = git_repository_head_detached_for_worktree(self.git_repository, name.UTF8String); | ||
if (gitError < 0) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to resolve HEAD in worktree"]; | ||
return NO; | ||
} | ||
|
||
*detached = (gitError == 1); | ||
|
||
return YES; | ||
} | ||
|
||
- (BOOL)setWorkingDirectoryURL:(NSURL *)URL updateGitLink:(BOOL)update error:(NSError **)error { | ||
NSParameterAssert(URL != nil); | ||
|
||
int gitError = git_repository_set_workdir(self.git_repository, URL.fileSystemRepresentation, update); | ||
if (gitError != GIT_OK) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to set workdir"]; | ||
return NO; | ||
} | ||
|
||
return YES; | ||
} | ||
|
||
- (NSArray<NSString *> *)worktreeNamesWithError:(NSError **)error { | ||
git_strarray names; | ||
int gitError = git_worktree_list(&names, self.git_repository); | ||
if (gitError != GIT_OK) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to load worktree names"]; | ||
return nil; | ||
} | ||
|
||
return [NSArray git_arrayWithStrarray:names]; | ||
} | ||
|
||
- (GTWorktree *)lookupWorktreeWithName:(NSString *)name error:(NSError **)error { | ||
NSParameterAssert(name != nil); | ||
|
||
git_worktree *worktree; | ||
int gitError = git_worktree_lookup(&worktree, self.git_repository, name.UTF8String); | ||
if (gitError != GIT_OK) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to lookup worktree"]; | ||
return nil; | ||
} | ||
|
||
return [[GTWorktree alloc] initWithGitWorktree:worktree]; | ||
} | ||
|
||
- (GTWorktree *)openWorktree:(NSError **)error { | ||
git_worktree *worktree; | ||
int gitError = git_worktree_open_from_repository(&worktree, self.git_repository); | ||
if (gitError != GIT_OK) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to open worktree"]; | ||
return nil; | ||
} | ||
|
||
return [[GTWorktree alloc] initWithGitWorktree:worktree]; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// | ||
// GTWorktree.h | ||
// ObjectiveGitFramework | ||
// | ||
// Created by Etienne on 25/07/2017. | ||
// Copyright © 2017 GitHub, Inc. All rights reserved. | ||
// | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
#import "GTRepository.h" | ||
|
||
#import "git2/worktree.h" | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
/// Add a worktree and keep it locked | ||
/// A boolean, defaults to NO. | ||
extern NSString *GTWorktreeAddOptionsLocked; | ||
|
||
@interface GTWorktree : NSObject | ||
|
||
/// Add a new worktree to a repository. | ||
/// | ||
/// @param name The name of the worktree. | ||
/// @param worktreeURL The location of the worktree. | ||
/// @param repository The repository the worktree should be added to. | ||
/// @param options The options to use when adding the worktree. | ||
/// | ||
/// @return the newly created worktree object. | ||
+ (instancetype _Nullable)addWorktreeWithName:(NSString *)name URL:(NSURL *)worktreeURL forRepository:(GTRepository *)repository options:(NSDictionary * _Nullable)options error:(NSError **)error; | ||
|
||
/// Initialize a worktree from a git_worktree. | ||
- (instancetype _Nullable)initWithGitWorktree:(git_worktree *)worktree; | ||
|
||
/// The underlying `git_worktree` object. | ||
- (git_worktree *)git_worktree __attribute__((objc_returns_inner_pointer)); | ||
|
||
/// Check the worktree validity | ||
/// | ||
/// @param error An explanation if the worktree is not valid. nil otherwise | ||
/// | ||
/// @return YES if the worktree is valid, NO otherwise (and error will be set). | ||
- (BOOL)isValid:(NSError **)error; | ||
|
||
/// Lock the worktree. | ||
/// | ||
/// This will prevent the worktree from being prunable. | ||
/// | ||
/// @param reason An optional reason for the lock. | ||
/// @param error The error if the worktree couldn't be locked. | ||
/// | ||
/// @return YES if the lock was successful, NO otherwise (and error will be set). | ||
- (BOOL)lockWithReason:(NSString * _Nullable)reason error:(NSError **)error; | ||
|
||
/// Unlock a worktree. | ||
/// | ||
/// @param wasLocked On return, NO if the worktree wasn't locked, YES otherwise. | ||
/// @param error The error if the worktree couldn't be unlocked. | ||
/// | ||
/// @return YES if the unlock succeeded, NO otherwise (and error will be set). | ||
- (BOOL)unlock:(BOOL *)wasLocked error:(NSError **)error; | ||
|
||
/// Check a worktree's lock state. | ||
/// | ||
/// @param locked On return, YES if the worktree is locked, NO otherwise. | ||
/// @param reason On return, the lock reason, if the worktree is locked. nil otherwise. | ||
/// @param error The error if the lock state couldn't be determined. | ||
/// | ||
/// @return YES if the check succeeded, NO otherwise (and error will be set). | ||
- (BOOL)isLocked:(BOOL *)locked reason:(NSString ** _Nullable)reason error:(NSError **)error; | ||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// | ||
// GTWorktree.m | ||
// ObjectiveGitFramework | ||
// | ||
// Created by Etienne on 25/07/2017. | ||
// Copyright © 2017 GitHub, Inc. All rights reserved. | ||
// | ||
|
||
#import "NSError+Git.h" | ||
#import "GTWorktree.h" | ||
#import "NSData+Git.h" | ||
|
||
#import "git2/errors.h" | ||
#import "git2/buffer.h" | ||
|
||
NSString *GTWorktreeAddOptionsLocked = @"GTWorktreeAddOptionsLocked"; | ||
|
||
@interface GTWorktree () | ||
@property (nonatomic, assign, readonly) git_worktree *git_worktree; | ||
@end | ||
|
||
@implementation GTWorktree | ||
|
||
+ (instancetype)addWorktreeWithName:(NSString *)name URL:(NSURL *)worktreeURL forRepository:(GTRepository *)repository options:(NSDictionary *)options error:(NSError **)error { | ||
git_worktree *worktree; | ||
git_worktree_add_options git_options = GIT_WORKTREE_ADD_OPTIONS_INIT; | ||
|
||
if (options) { | ||
git_options.lock = [options[GTWorktreeAddOptionsLocked] boolValue]; | ||
} | ||
|
||
int gitError = git_worktree_add(&worktree, repository.git_repository, name.UTF8String, worktreeURL.fileSystemRepresentation, &git_options); | ||
if (gitError != GIT_OK) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to add worktree"]; | ||
return nil; | ||
} | ||
|
||
return [[self alloc] initWithGitWorktree:worktree]; | ||
} | ||
|
||
- (instancetype)initWithGitWorktree:(git_worktree *)worktree { | ||
self = [super init]; | ||
if (!self) return nil; | ||
|
||
_git_worktree = worktree; | ||
|
||
return self; | ||
} | ||
|
||
- (void)dealloc { | ||
git_worktree_free(_git_worktree); | ||
} | ||
|
||
- (BOOL)isValid:(NSError **)error { | ||
int gitError = git_worktree_validate(self.git_worktree); | ||
if (gitError < 0) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to validate worktree"]; | ||
return NO; | ||
} | ||
|
||
return YES; | ||
} | ||
|
||
- (BOOL)lockWithReason:(NSString *)reason error:(NSError **)error { | ||
int gitError = git_worktree_lock(self.git_worktree, reason.UTF8String); | ||
if (gitError != GIT_OK) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to lock worktree"]; | ||
return NO; | ||
} | ||
|
||
return YES; | ||
} | ||
|
||
- (BOOL)unlock:(BOOL *)wasLocked error:(NSError **)error { | ||
int gitError = git_worktree_unlock(self.git_worktree); | ||
if (gitError < 0) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to unlock worktree"]; | ||
return NO; | ||
} | ||
|
||
if (wasLocked) { | ||
// unlock returns 1 if there was no lock. | ||
*wasLocked = (gitError == 0); | ||
} | ||
|
||
return YES; | ||
} | ||
|
||
- (BOOL)isLocked:(BOOL *)locked reason:(NSString **)reason error:(NSError **)error { | ||
git_buf reasonBuf = GIT_BUF_INIT_CONST("", 0); | ||
int gitError = git_worktree_is_locked(&reasonBuf, self.git_worktree); | ||
if (gitError < 0) { | ||
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to check lock state of worktree"]; | ||
return NO; | ||
} | ||
|
||
if (locked) *locked = (gitError > 0); | ||
if (reason) { | ||
if (gitError > 0 && reasonBuf.size > 0) { | ||
*reason = [[NSString alloc] initWithData:[NSData git_dataWithBuffer:&reasonBuf] | ||
encoding:NSUTF8StringEncoding]; | ||
} else { | ||
*reason = nil; | ||
} | ||
} | ||
|
||
return YES; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.