From 8a685841d7a7187a7c9d489f4ce3f31377a09cea Mon Sep 17 00:00:00 2001 From: Slava Karpenko Date: Thu, 16 Mar 2017 16:55:37 +0300 Subject: [PATCH 1/3] Numerous GTIndex improvements - Added GTIndex.checksum accessor - Added addPathspecs/removePathspaces calls. - Fixed proper nullability for enumerateConflictedFiles --- ObjectiveGit/GTIndex.h | 53 +++++++++++++++++++++++++++++++++- ObjectiveGit/GTIndex.m | 64 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 112 insertions(+), 5 deletions(-) diff --git a/ObjectiveGit/GTIndex.h b/ObjectiveGit/GTIndex.h index ba57ac2f3..18f1dc174 100644 --- a/ObjectiveGit/GTIndex.h +++ b/ObjectiveGit/GTIndex.h @@ -29,7 +29,9 @@ #import #include "git2/types.h" +#include "git2/index.h" +@class GTOID; @class GTIndexEntry; @class GTRepository; @class GTTree; @@ -45,6 +47,9 @@ NS_ASSUME_NONNULL_BEGIN /// The file URL for the index if it exists on disk; nil otherwise. @property (nonatomic, readonly, copy) NSURL * _Nullable fileURL; +/// The index checksum +@property (nonatomic, readonly, strong) GTOID * _Nullable checksum; + /// The number of entries in the index. @property (nonatomic, readonly) NSUInteger entryCount; @@ -202,7 +207,53 @@ NS_ASSUME_NONNULL_BEGIN /// /// Returns `YES` in the event of successful enumeration or no conflicts in the /// index, `NO` in case of error. -- (BOOL)enumerateConflictedFilesWithError:(NSError **)error usingBlock:(void (^)(GTIndexEntry *ancestor, GTIndexEntry *ours, GTIndexEntry *theirs, BOOL *stop))block; +- (BOOL)enumerateConflictedFilesWithError:(NSError **)error usingBlock:(void (^)(GTIndexEntry * _Nullable ancestor, GTIndexEntry * _Nullable ours, GTIndexEntry * _Nullable theirs, BOOL *stop))block; + +/// An enum for use with addPathspecs:flags:error:passingTest: below +/// See index.h for documentation of each individual git_index_add_option_t flag. +typedef NS_OPTIONS(NSInteger, GTIndexAddOptionFlags) { + GTIndexAddOptionDefault = GIT_INDEX_ADD_DEFAULT, + GTIndexAddOptionForce = GIT_INDEX_ADD_FORCE, + GTIndexAddOptionDisablePathspecMatch = GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH, + GTIndexAddOptionCheckPathspec = GIT_INDEX_ADD_CHECK_PATHSPEC +}; + +/// Add or update index entries matching files in the working directory. +/// This method will immediately fail if the index's repo is bare. +/// +/// pathspecs - An `NSString` array of path patterns. (E.g: *.c) +/// If nil is passed in, all index entries will be updated. +/// flags - A combination of GTIndexAddOptionFlags flags +/// block - A block run each time a pathspec is matched; before the index is +/// added/updated. The `matchedPathspec` parameter is a string indicating +/// what the pathspec (from `pathspecs`) matched. If you pass in NULL +/// in to the `pathspecs` parameter this parameter will be nil. +/// The `path` parameter is a repository relative path to the file +/// about to be added/updated. +/// The `stop` parameter can be set to `YES` to abort the operation. +/// Return `YES` to update the given path, or `NO` to skip it. May be nil. +/// error - When something goes wrong, this parameter is set. Optional. +/// +/// Returns `YES` in the event that everything has gone smoothly. Otherwise, `NO`. +- (BOOL)addPathspecs:(NSArray * _Nullable)pathspecs flags:(GTIndexAddOptionFlags)flags error:(NSError **)error passingTest:(BOOL (^ _Nullable )(NSString * _Nullable matchedPathspec, NSString *path, BOOL *stop))block; + +/// Remove all matching index entries. +/// This method will immediately fail if the index's repo is bare. +/// +/// pathspecs - An `NSString` array of path patterns. (E.g: *.c) +/// If nil is passed in, all index entries will be updated. +/// block - A block run each time a pathspec is matched; before the index is +/// removed. The `matchedPathspec` parameter is a string indicating +/// what the pathspec (from `pathspecs`) matched. If you pass in NULL +/// in to the `pathspecs` parameter this parameter will be nil. +/// The `path` parameter is a repository relative path to the file +/// about to be updated. +/// The `stop` parameter can be set to `YES` to abort the operation. +/// Return `YES` to update the given path, or `NO` to skip it. May be nil. +/// error - When something goes wrong, this parameter is set. Optional. +/// +/// Returns `YES` in the event that everything has gone smoothly. Otherwise, `NO`. +- (BOOL)removePathspecs:(NSArray * _Nullable)pathspecs error:(NSError **)error passingTest:(BOOL (^ _Nullable)(NSString * _Nullable matchedPathspec, NSString *path, BOOL *stop))block; /// Update all index entries to match the working directory. /// This method will immediately fail if the index's repo is bare. diff --git a/ObjectiveGit/GTIndex.m b/ObjectiveGit/GTIndex.m index 863beb9cc..1ac8f853b 100644 --- a/ObjectiveGit/GTIndex.m +++ b/ObjectiveGit/GTIndex.m @@ -121,6 +121,14 @@ - (id)initWithGitIndex:(git_index *)index repository:(GTRepository *)repository #pragma mark Entries +- (GTOID *)checksum { + const git_oid *oid = git_index_checksum(self.git_index); + if (oid != NULL) + return [GTOID oidWithGitOid:oid]; + else + return nil; +} + - (NSUInteger)entryCount { return git_index_entrycount(self.git_index); } @@ -308,17 +316,17 @@ - (BOOL)enumerateConflictedFilesWithError:(NSError **)error usingBlock:(void (^) return NO; } - GTIndexEntry *blockAncestor; + GTIndexEntry *blockAncestor = nil; if (ancestor != NULL) { blockAncestor = [[GTIndexEntry alloc] initWithGitIndexEntry:ancestor]; } - GTIndexEntry *blockOurs; + GTIndexEntry *blockOurs = nil; if (ours != NULL) { blockOurs = [[GTIndexEntry alloc] initWithGitIndexEntry:ours]; } - GTIndexEntry *blockTheirs; + GTIndexEntry *blockTheirs = nil; if (theirs != NULL) { blockTheirs = [[GTIndexEntry alloc] initWithGitIndexEntry:theirs]; } @@ -336,10 +344,58 @@ - (BOOL)enumerateConflictedFilesWithError:(NSError **)error usingBlock:(void (^) BOOL shouldAbortImmediately; }; +- (BOOL)addPathspecs:(NSArray *)pathspecs flags:(GTIndexAddOptionFlags)flags error:(NSError **)error passingTest:(GTIndexPathspecMatchedBlock)block { + NSAssert(self.repository.isBare == NO, @"This method only works with non-bare repositories."); + + __block git_strarray strarray = pathspecs.git_strarray; + @onExit { + if (strarray.count > 0) git_strarray_free(&strarray); + }; + + struct GTIndexPathspecMatchedInfo payload = { + .block = block, + .shouldAbortImmediately = NO, + }; + + int returnCode = git_index_add_all(self.git_index, &strarray, (unsigned int)flags, (block != nil ? GTIndexPathspecMatchFound : NULL), &payload); + if (returnCode != GIT_OK && returnCode != GIT_EUSER) { + if (error != nil) *error = [NSError git_errorFor:returnCode description:NSLocalizedString(@"Could not add to index.", nil)]; + return NO; + } + + return YES; +} + +- (BOOL)removePathspecs:(NSArray *)pathspecs error:(NSError **)error passingTest:(GTIndexPathspecMatchedBlock)block { + NSAssert(self.repository.isBare == NO, @"This method only works with non-bare repositories."); + + __block git_strarray strarray = pathspecs.git_strarray; + @onExit { + if (strarray.count > 0) git_strarray_free(&strarray); + }; + + struct GTIndexPathspecMatchedInfo payload = { + .block = block, + .shouldAbortImmediately = NO, + }; + + int returnCode = git_index_remove_all(self.git_index, &strarray, (block != nil ? GTIndexPathspecMatchFound : NULL), &payload); + if (returnCode != GIT_OK && returnCode != GIT_EUSER) { + if (error != nil) *error = [NSError git_errorFor:returnCode description:NSLocalizedString(@"Could not remove from index.", nil)]; + return NO; + } + + return YES; +} + - (BOOL)updatePathspecs:(NSArray *)pathspecs error:(NSError **)error passingTest:(GTIndexPathspecMatchedBlock)block { NSAssert(self.repository.isBare == NO, @"This method only works with non-bare repositories."); - const git_strarray strarray = pathspecs.git_strarray; + __block git_strarray strarray = pathspecs.git_strarray; + @onExit { + if (strarray.count > 0) git_strarray_free(&strarray); + }; + struct GTIndexPathspecMatchedInfo payload = { .block = block, .shouldAbortImmediately = NO, From c7fcb6355f5a7466aee10f214b4e9621599a33f7 Mon Sep 17 00:00:00 2001 From: Slava Karpenko Date: Thu, 16 Mar 2017 16:56:37 +0300 Subject: [PATCH 2/3] GTRepository+Status improvements - Converted GTRepositoryStatusFlags into NS_OPTIONS for proper handling from Swift - Added missing flags for GTFileStatusFlags --- ObjectiveGit/GTRepository+Status.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ObjectiveGit/GTRepository+Status.h b/ObjectiveGit/GTRepository+Status.h index 86d4121ca..f5e222bae 100644 --- a/ObjectiveGit/GTRepository+Status.h +++ b/ObjectiveGit/GTRepository+Status.h @@ -30,8 +30,10 @@ typedef NS_OPTIONS(NSInteger, GTFileStatusFlags) { GTFileStatusDeletedInWorktree = GIT_STATUS_WT_DELETED, GTFileStatusTypeChangedInWorktree = GIT_STATUS_WT_TYPECHANGE, GTFileStatusRenamedInWorktree = GIT_STATUS_WT_RENAMED, + GTFileStatusUnreadableInWorktree = GIT_STATUS_WT_UNREADABLE, GTFileStatusIgnored = GIT_STATUS_IGNORED, + GTFileStatusConflicted = GIT_STATUS_CONFLICTED }; /// An `NSNumber` wrapped `GTRepositoryStatusOptionsShow` bitmask. @@ -57,8 +59,8 @@ extern NSString *const GTRepositoryStatusOptionsFlagsKey; /// An enum, for use as documented, with the `GTRepositoryStatusOptionsFlagsKey` /// key. /// -/// See status.h for documentation of each individual flag. -typedef enum { +/// See status.h for documentation of each individual git_status_opt_t flag. +typedef NS_OPTIONS(NSInteger, GTRepositoryStatusFlags) { GTRepositoryStatusFlagsIncludeUntracked = GIT_STATUS_OPT_INCLUDE_UNTRACKED, GTRepositoryStatusFlagsIncludeIgnored = GIT_STATUS_OPT_INCLUDE_IGNORED, GTRepositoryStatusFlagsIncludeUnmodified = GIT_STATUS_OPT_INCLUDE_UNMODIFIED, @@ -71,9 +73,11 @@ typedef enum { GTRepositoryStatusFlagsRenamesFromRewrites = GIT_STATUS_OPT_RENAMES_FROM_REWRITES, GTRepositoryStatusFlagsSortCaseSensitively = GIT_STATUS_OPT_SORT_CASE_SENSITIVELY, GTRepositoryStatusFlagsSortCaseInsensitively = GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY, + GTRepositoryStatusFlagsNoRefresh = GIT_STATUS_OPT_NO_REFRESH, + GTRepositoryStatusFlagsUpdateIndex = GIT_STATUS_OPT_UPDATE_INDEX, GTRepositoryStatusFlagsIncludeUnreadable = GIT_STATUS_OPT_INCLUDE_UNREADABLE, - GTRepositoryStatusFlagsIncludeUnreadableAsUntracked = GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED, -} GTRepositoryStatusFlags; + GTRepositoryStatusFlagsIncludeUnreadableAsUntracked = GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED +}; /// An `NSArray` of `NSStrings`s to limit the status to specific paths inside /// the repository. The entries in the array represent either single paths or From d49758613e38df7114e64a854c2fce4ed048fd78 Mon Sep 17 00:00:00 2001 From: Slava Karpenko Date: Wed, 29 Mar 2017 11:53:06 +0300 Subject: [PATCH 3/3] Code review feedback fixes for PR #622 --- ObjectiveGit/GTIndex.h | 28 ++++++++++++++-------------- ObjectiveGit/GTIndex.m | 29 ++++++++++++----------------- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/ObjectiveGit/GTIndex.h b/ObjectiveGit/GTIndex.h index 18f1dc174..c8f9b143d 100644 --- a/ObjectiveGit/GTIndex.h +++ b/ObjectiveGit/GTIndex.h @@ -209,13 +209,13 @@ NS_ASSUME_NONNULL_BEGIN /// index, `NO` in case of error. - (BOOL)enumerateConflictedFilesWithError:(NSError **)error usingBlock:(void (^)(GTIndexEntry * _Nullable ancestor, GTIndexEntry * _Nullable ours, GTIndexEntry * _Nullable theirs, BOOL *stop))block; -/// An enum for use with addPathspecs:flags:error:passingTest: below +/// Options for use with addPathspecs:flags:error:passingTest: below /// See index.h for documentation of each individual git_index_add_option_t flag. -typedef NS_OPTIONS(NSInteger, GTIndexAddOptionFlags) { - GTIndexAddOptionDefault = GIT_INDEX_ADD_DEFAULT, - GTIndexAddOptionForce = GIT_INDEX_ADD_FORCE, - GTIndexAddOptionDisablePathspecMatch = GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH, - GTIndexAddOptionCheckPathspec = GIT_INDEX_ADD_CHECK_PATHSPEC +typedef NS_OPTIONS(NSInteger, GTIndexAddOptions) { + GTIndexAddOptionsDefault = GIT_INDEX_ADD_DEFAULT, + GTIndexAddOptionsForce = GIT_INDEX_ADD_FORCE, + GTIndexAddOptionsDisablePathspecMatch = GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH, + GTIndexAddOptionsCheckPathspec = GIT_INDEX_ADD_CHECK_PATHSPEC }; /// Add or update index entries matching files in the working directory. @@ -223,10 +223,10 @@ typedef NS_OPTIONS(NSInteger, GTIndexAddOptionFlags) { /// /// pathspecs - An `NSString` array of path patterns. (E.g: *.c) /// If nil is passed in, all index entries will be updated. -/// flags - A combination of GTIndexAddOptionFlags flags -/// block - A block run each time a pathspec is matched; before the index is -/// added/updated. The `matchedPathspec` parameter is a string indicating -/// what the pathspec (from `pathspecs`) matched. If you pass in NULL +/// flags - A combination of GTIndexAddOptions flags +/// block - A block that will be called on each match, before the index is changed. +/// The `matchedPathspec` parameter is a string indicating +/// which pathspec (from `pathspecs`) matched. If you pass in nil /// in to the `pathspecs` parameter this parameter will be nil. /// The `path` parameter is a repository relative path to the file /// about to be added/updated. @@ -235,16 +235,16 @@ typedef NS_OPTIONS(NSInteger, GTIndexAddOptionFlags) { /// error - When something goes wrong, this parameter is set. Optional. /// /// Returns `YES` in the event that everything has gone smoothly. Otherwise, `NO`. -- (BOOL)addPathspecs:(NSArray * _Nullable)pathspecs flags:(GTIndexAddOptionFlags)flags error:(NSError **)error passingTest:(BOOL (^ _Nullable )(NSString * _Nullable matchedPathspec, NSString *path, BOOL *stop))block; +- (BOOL)addPathspecs:(NSArray * _Nullable)pathspecs flags:(GTIndexAddOptions)flags error:(NSError **)error passingTest:(BOOL (^ _Nullable )(NSString * _Nullable matchedPathspec, NSString *path, BOOL *stop))block; /// Remove all matching index entries. /// This method will immediately fail if the index's repo is bare. /// /// pathspecs - An `NSString` array of path patterns. (E.g: *.c) /// If nil is passed in, all index entries will be updated. -/// block - A block run each time a pathspec is matched; before the index is -/// removed. The `matchedPathspec` parameter is a string indicating -/// what the pathspec (from `pathspecs`) matched. If you pass in NULL +/// block - A block that will be called on each match, before the index is changed. +/// The `matchedPathspec` parameter is a string indicating +/// which pathspec (from `pathspecs`) matched. If you pass in nil /// in to the `pathspecs` parameter this parameter will be nil. /// The `path` parameter is a repository relative path to the file /// about to be updated. diff --git a/ObjectiveGit/GTIndex.m b/ObjectiveGit/GTIndex.m index 1ac8f853b..4885cff24 100644 --- a/ObjectiveGit/GTIndex.m +++ b/ObjectiveGit/GTIndex.m @@ -123,10 +123,11 @@ - (id)initWithGitIndex:(git_index *)index repository:(GTRepository *)repository - (GTOID *)checksum { const git_oid *oid = git_index_checksum(self.git_index); - if (oid != NULL) + if (oid != NULL) { return [GTOID oidWithGitOid:oid]; - else - return nil; + } + + return nil; } - (NSUInteger)entryCount { @@ -316,17 +317,17 @@ - (BOOL)enumerateConflictedFilesWithError:(NSError **)error usingBlock:(void (^) return NO; } - GTIndexEntry *blockAncestor = nil; + GTIndexEntry *blockAncestor; if (ancestor != NULL) { blockAncestor = [[GTIndexEntry alloc] initWithGitIndexEntry:ancestor]; } - GTIndexEntry *blockOurs = nil; + GTIndexEntry *blockOurs; if (ours != NULL) { blockOurs = [[GTIndexEntry alloc] initWithGitIndexEntry:ours]; } - GTIndexEntry *blockTheirs = nil; + GTIndexEntry *blockTheirs; if (theirs != NULL) { blockTheirs = [[GTIndexEntry alloc] initWithGitIndexEntry:theirs]; } @@ -344,9 +345,7 @@ - (BOOL)enumerateConflictedFilesWithError:(NSError **)error usingBlock:(void (^) BOOL shouldAbortImmediately; }; -- (BOOL)addPathspecs:(NSArray *)pathspecs flags:(GTIndexAddOptionFlags)flags error:(NSError **)error passingTest:(GTIndexPathspecMatchedBlock)block { - NSAssert(self.repository.isBare == NO, @"This method only works with non-bare repositories."); - +- (BOOL)addPathspecs:(NSArray *)pathspecs flags:(GTIndexAddOptions)flags error:(NSError **)error passingTest:(GTIndexPathspecMatchedBlock)block { __block git_strarray strarray = pathspecs.git_strarray; @onExit { if (strarray.count > 0) git_strarray_free(&strarray); @@ -357,7 +356,7 @@ - (BOOL)addPathspecs:(NSArray *)pathspecs flags:(GTIndexAddOptionFlags)flags err .shouldAbortImmediately = NO, }; - int returnCode = git_index_add_all(self.git_index, &strarray, (unsigned int)flags, (block != nil ? GTIndexPathspecMatchFound : NULL), &payload); + int returnCode = git_index_add_all(self.git_index, &strarray, (unsigned int)flags, (block != nil ? GTIndexPathspecMatchFoundCallback : NULL), &payload); if (returnCode != GIT_OK && returnCode != GIT_EUSER) { if (error != nil) *error = [NSError git_errorFor:returnCode description:NSLocalizedString(@"Could not add to index.", nil)]; return NO; @@ -367,8 +366,6 @@ - (BOOL)addPathspecs:(NSArray *)pathspecs flags:(GTIndexAddOptionFlags)flags err } - (BOOL)removePathspecs:(NSArray *)pathspecs error:(NSError **)error passingTest:(GTIndexPathspecMatchedBlock)block { - NSAssert(self.repository.isBare == NO, @"This method only works with non-bare repositories."); - __block git_strarray strarray = pathspecs.git_strarray; @onExit { if (strarray.count > 0) git_strarray_free(&strarray); @@ -379,7 +376,7 @@ - (BOOL)removePathspecs:(NSArray *)pathspecs error:(NSError **)error passingTest .shouldAbortImmediately = NO, }; - int returnCode = git_index_remove_all(self.git_index, &strarray, (block != nil ? GTIndexPathspecMatchFound : NULL), &payload); + int returnCode = git_index_remove_all(self.git_index, &strarray, (block != nil ? GTIndexPathspecMatchFoundCallback : NULL), &payload); if (returnCode != GIT_OK && returnCode != GIT_EUSER) { if (error != nil) *error = [NSError git_errorFor:returnCode description:NSLocalizedString(@"Could not remove from index.", nil)]; return NO; @@ -389,8 +386,6 @@ - (BOOL)removePathspecs:(NSArray *)pathspecs error:(NSError **)error passingTest } - (BOOL)updatePathspecs:(NSArray *)pathspecs error:(NSError **)error passingTest:(GTIndexPathspecMatchedBlock)block { - NSAssert(self.repository.isBare == NO, @"This method only works with non-bare repositories."); - __block git_strarray strarray = pathspecs.git_strarray; @onExit { if (strarray.count > 0) git_strarray_free(&strarray); @@ -401,7 +396,7 @@ - (BOOL)updatePathspecs:(NSArray *)pathspecs error:(NSError **)error passingTest .shouldAbortImmediately = NO, }; - int returnCode = git_index_update_all(self.git_index, &strarray, (block != nil ? GTIndexPathspecMatchFound : NULL), &payload); + int returnCode = git_index_update_all(self.git_index, &strarray, (block != nil ? GTIndexPathspecMatchFoundCallback : NULL), &payload); if (returnCode != GIT_OK && returnCode != GIT_EUSER) { if (error != nil) *error = [NSError git_errorFor:returnCode description:NSLocalizedString(@"Could not update index.", nil)]; return NO; @@ -410,7 +405,7 @@ - (BOOL)updatePathspecs:(NSArray *)pathspecs error:(NSError **)error passingTest return YES; } -int GTIndexPathspecMatchFound(const char *path, const char *matched_pathspec, void *payload) { +int GTIndexPathspecMatchFoundCallback(const char *path, const char *matched_pathspec, void *payload) { struct GTIndexPathspecMatchedInfo *info = payload; GTIndexPathspecMatchedBlock block = info->block; if (info->shouldAbortImmediately) {