Skip to content

Wrap all the various way of doing checkouts in GTCheckoutOptions #459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Feb 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions ObjectiveGit/GTCheckoutOptions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//
// GTCheckoutOptions.h
// ObjectiveGitFramework
//
// Created by Etienne on 10/04/2015.
// Copyright (c) 2015 GitHub, Inc. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "git2/checkout.h"

@class GTDiffFile;

NS_ASSUME_NONNULL_BEGIN

/// Checkout strategies used by the various -checkout... methods
/// See git_checkout_strategy_t
typedef NS_OPTIONS(NSInteger, GTCheckoutStrategyType) {
GTCheckoutStrategyNone = GIT_CHECKOUT_NONE,
GTCheckoutStrategySafe = GIT_CHECKOUT_SAFE,
GTCheckoutStrategyForce = GIT_CHECKOUT_FORCE,
GTCheckoutStrategyRecreateMissing = GIT_CHECKOUT_RECREATE_MISSING,
GTCheckoutStrategyAllowConflicts = GIT_CHECKOUT_ALLOW_CONFLICTS,
GTCheckoutStrategyRemoveUntracked = GIT_CHECKOUT_REMOVE_UNTRACKED,
GTCheckoutStrategyRemoveIgnored = GIT_CHECKOUT_REMOVE_IGNORED,
GTCheckoutStrategyUpdateOnly = GIT_CHECKOUT_UPDATE_ONLY,
GTCheckoutStrategyDontUpdateIndex = GIT_CHECKOUT_DONT_UPDATE_INDEX,
GTCheckoutStrategyNoRefresh = GIT_CHECKOUT_NO_REFRESH,
GTCheckoutStrategySkipUnmerged = GIT_CHECKOUT_SKIP_UNMERGED,
GTCheckoutStrategyUseOurs = GIT_CHECKOUT_USE_OURS,
GTCheckoutStrategyUseTheirs = GIT_CHECKOUT_USE_THEIRS,
GTCheckoutStrategyDisablePathspecMatch = GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH,
GTCheckoutStrategySkipLockedDirectories = GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES,
GTCheckoutStrategyDoNotOverwriteIgnored = GIT_CHECKOUT_DONT_OVERWRITE_IGNORED,
GTCheckoutStrategyConflictStyleMerge = GIT_CHECKOUT_CONFLICT_STYLE_MERGE,
GTCheckoutStrategyCoflictStyleDiff3 = GIT_CHECKOUT_CONFLICT_STYLE_DIFF3,
GTCheckoutStrategyDoNotRemoveExisting = GIT_CHECKOUT_DONT_REMOVE_EXISTING,
GTCheckoutStrategyDoNotWriteIndex = GIT_CHECKOUT_DONT_WRITE_INDEX,
};

/// Checkout notification flags used by the various -checkout... methods
/// See git_checkout_notify_t
typedef NS_OPTIONS(NSInteger, GTCheckoutNotifyFlags) {
GTCheckoutNotifyNone = GIT_CHECKOUT_NOTIFY_NONE,
GTCheckoutNotifyConflict = GIT_CHECKOUT_NOTIFY_CONFLICT,
GTCheckoutNotifyDirty = GIT_CHECKOUT_NOTIFY_DIRTY,
GTCheckoutNotifyUpdated = GIT_CHECKOUT_NOTIFY_UPDATED,
GTCheckoutNotifyUntracked = GIT_CHECKOUT_NOTIFY_UNTRACKED,
GTCheckoutNotifyIgnored = GIT_CHECKOUT_NOTIFY_IGNORED,

GTCheckoutNotifyAll = GIT_CHECKOUT_NOTIFY_ALL,
};

@interface GTCheckoutOptions : NSObject

/// Create a checkout options object.
///
/// Since there are many places where we can checkout data, this object allow us
/// to centralize all the various behaviors that checkout allow.
///
/// @param strategy The checkout strategy to use.
/// @param notifyFlags The checkout events that will be notified via `notifyBlock`.
/// @param progressBlock A block that will be called for each checkout step.
/// @param notifyBlock A block that will be called for each event, @see `notifyFlags`.
///
/// @return A newly-initialized GTCheckoutOptions object.
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags progressBlock:(nullable void (^)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps))progressBlock notifyBlock:(nullable int (^)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir))notifyBlock;

/// Create a checkout options object.
/// @see +checkoutOptionsWithStrategy:notifyFlags:progressBlock:notifyBlock:
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags notifyBlock:(int (^)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir))notifyBlock;

/// Create a checkout options object.
/// @see +checkoutOptionsWithStrategy:notifyFlags:progressBlock:notifyBlock:
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy progressBlock:(void (^)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps))progressBlock;

/// Create a checkout options object.
/// @see +checkoutOptionsWithStrategy:notifyFlags:progressBlock:notifyBlock:
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy;

/// Get the underlying git_checkout_options struct.
///
/// @return <#return value description#>
- (git_checkout_options *)git_checkoutOptions NS_RETURNS_INNER_POINTER;

/// The checkout strategy to use.
@property (assign) GTCheckoutStrategyType strategy;

/// The checkout progress block that was passed in.
@property (copy) void (^progressBlock)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps);

/// The notification flags currently enabled.
@property (assign) GTCheckoutNotifyFlags notifyFlags;

/// The checkout notification block that was passed in.
@property (copy) int (^notifyBlock)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the copy-ness here makes me twitchy.


/// An array of strings used to restrict what will be checked out.
@property (copy) NSArray <NSString *> *pathSpecs;

@end

NS_ASSUME_NONNULL_END
100 changes: 100 additions & 0 deletions ObjectiveGit/GTCheckoutOptions.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// GTCheckoutOptions.m
// ObjectiveGitFramework
//
// Created by Etienne on 10/04/2015.
// Copyright (c) 2015 GitHub, Inc. All rights reserved.
//

#import "GTCheckoutOptions.h"
#import "GTDiffFile.h"
#import "NSError+Git.h"
#import "NSArray+StringArray.h"
#import "git2.h"

// The type of block set in progressBlock for progress reporting
typedef void (^GTCheckoutProgressBlock)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps);

// The type of block set in notifyBlock for notification reporting
typedef int (^GTCheckoutNotifyBlock)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile * __nullable baseline, GTDiffFile * __nullable target, GTDiffFile * __nullable workdir);


@interface GTCheckoutOptions () {
git_checkout_options _git_checkoutOptions;
}
@end

@implementation GTCheckoutOptions

+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags progressBlock:(nullable GTCheckoutProgressBlock)progressBlock notifyBlock:(nullable GTCheckoutNotifyBlock)notifyBlock {
GTCheckoutOptions *options = [self checkoutOptionsWithStrategy:strategy];
options.notifyFlags = notifyFlags;
options.notifyBlock = notifyBlock;
options.progressBlock = progressBlock;
return options;
}

+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy progressBlock:(GTCheckoutProgressBlock)progressBlock {
NSParameterAssert(progressBlock != nil);
GTCheckoutOptions *options = [self checkoutOptionsWithStrategy:strategy];
options.progressBlock = progressBlock;
return options;
}

+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags notifyBlock:(GTCheckoutNotifyBlock)notifyBlock {
NSParameterAssert(notifyBlock != nil);
return [self checkoutOptionsWithStrategy:strategy notifyFlags:notifyFlags progressBlock:nil notifyBlock:notifyBlock];
}

+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy {
GTCheckoutOptions *options = [[self alloc] init];
options.strategy = strategy;
return options;
}

- (instancetype)init {
self = [super init];
if (self == nil) return nil;

_git_checkoutOptions.version = GIT_CHECKOUT_OPTIONS_VERSION;

return self;
}

static void GTCheckoutProgressCallback(const char *path, size_t completedSteps, size_t totalSteps, void *payload) {
if (payload == NULL) return;
void (^block)(NSString *, NSUInteger, NSUInteger) = (__bridge id)payload;
NSString *nsPath = (path != NULL ? @(path) : nil);
block(nsPath, completedSteps, totalSteps);
}

static int GTCheckoutNotifyCallback(git_checkout_notify_t why, const char *path, const git_diff_file *baseline, const git_diff_file *target, const git_diff_file *workdir, void *payload) {
if (payload == NULL) return 0;
GTCheckoutNotifyBlock block = (__bridge id)payload;
NSString *nsPath = (path != NULL ? @(path) : nil);
GTDiffFile *gtBaseline = (baseline != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*baseline] : nil);
GTDiffFile *gtTarget = (target != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*target] : nil);
GTDiffFile *gtWorkdir = (workdir != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*workdir] : nil);
return block((GTCheckoutNotifyFlags)why, nsPath, gtBaseline, gtTarget, gtWorkdir);
}

- (git_checkout_options *)git_checkoutOptions {
_git_checkoutOptions.checkout_strategy = self.strategy;

if (self.progressBlock != nil) {
_git_checkoutOptions.progress_cb = GTCheckoutProgressCallback;
_git_checkoutOptions.progress_payload = (__bridge void *)self.progressBlock;
}

if (self.notifyBlock != nil) {
_git_checkoutOptions.notify_cb = GTCheckoutNotifyCallback;
_git_checkoutOptions.notify_flags = self.notifyFlags;
_git_checkoutOptions.notify_payload = (__bridge void *)self.notifyBlock;
}

_git_checkoutOptions.paths = self.pathSpecs.git_strarray;

return &_git_checkoutOptions;
}

@end
5 changes: 2 additions & 3 deletions ObjectiveGit/GTRepository+Merging.m
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@ - (BOOL)mergeBranchIntoCurrentBranch:(GTBranch *)branch withError:(NSError **)er
// Fast-forward branch
NSString *message = [NSString stringWithFormat:@"merge %@: Fast-forward", branch.name];
GTReference *reference = [localBranch.reference referenceByUpdatingTarget:remoteCommit.SHA message:message error:error];
BOOL checkoutSuccess = [self checkoutReference:reference strategy:GTCheckoutStrategyForce error:error progressBlock:nil];

BOOL checkoutSuccess = [self checkoutReference:reference options:[GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategyForce] error:error];
return checkoutSuccess;
} else if (analysis & GTMergeAnalysisNormal) {
// Do normal merge
Expand Down Expand Up @@ -164,7 +163,7 @@ - (BOOL)mergeBranchIntoCurrentBranch:(GTBranch *)branch withError:(NSError **)er
return NO;
}

BOOL success = [self checkoutReference:localBranch.reference strategy:GTCheckoutStrategyForce error:error progressBlock:nil];
BOOL success = [self checkoutReference:localBranch.reference options:[GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategyForce] error:error];
return success;
}

Expand Down
20 changes: 12 additions & 8 deletions ObjectiveGit/GTRepository+Stashing.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,25 @@ NS_ASSUME_NONNULL_BEGIN

/// Apply stashed changes.
///
/// index - The index of the stash to apply. 0 is the latest one.
/// flags - The flags to use when applying the stash.
/// error - If not NULL, set to any error that occurred.
/// index - The index of the stash to apply. 0 is the latest one.
/// flags - The flags to use when applying the stash.
/// options - The options to use when checking out.
/// error - If not NULL, set to any error that occurred.
/// progressBlock - A block that will be executed on each step of the stash application.
///
/// Returns YES if the requested stash was successfully applied, NO otherwise.
- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock;
- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(nullable GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock;

/// Pop stashed changes.
///
/// index - The index of the stash to apply. 0 is the most recent stash.
/// flags - The flags to use when applying the stash.
/// error - If not NULL, set to any error that occurred.
/// index - The index of the stash to apply. 0 is the most recent stash.
/// flags - The flags to use when applying the stash.
/// options - The options to use when checking out.
/// error - If not NULL, set to any error that occurred.
/// progressBlock - A block that will be executed on each step of the stash application.
///
/// Returns YES if the requested stash was successfully applied, NO otherwise.
- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock;
- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(nullable GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock;

/// Drop a stash from the repository's list of stashes.
///
Expand Down
12 changes: 10 additions & 2 deletions ObjectiveGit/GTRepository+Stashing.m
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static int stashApplyProgressCallback(git_stash_apply_progress_t progress, void
return (stop ? GIT_EUSER : 0);
}

- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock {
- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock {
git_stash_apply_options stash_options = GIT_STASH_APPLY_OPTIONS_INIT;

stash_options.flags = (git_stash_apply_flags)flags;
Expand All @@ -68,6 +68,10 @@ - (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)fl
stash_options.progress_payload = (__bridge void *)progressBlock;
}

if (options != nil) {
stash_options.checkout_options = *options.git_checkoutOptions;
}

int gitError = git_stash_apply(self.git_repository, index, &stash_options);
if (gitError != GIT_OK) {
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Stash apply failed" failureReason:@"The stash at index %ld couldn't be applied.", (unsigned long)index];
Expand All @@ -76,7 +80,7 @@ - (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)fl
return YES;
}

- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock {
- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock{
git_stash_apply_options stash_options = GIT_STASH_APPLY_OPTIONS_INIT;

stash_options.flags = (git_stash_apply_flags)flags;
Expand All @@ -85,6 +89,10 @@ - (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flag
stash_options.progress_payload = (__bridge void *)progressBlock;
}

if (options != nil) {
stash_options.checkout_options = *options.git_checkoutOptions;
}

int gitError = git_stash_pop(self.git_repository, index, &stash_options);
if (gitError != GIT_OK) {
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Stash pop failed" failureReason:@"The stash at index %ld couldn't be applied.", (unsigned long)index];
Expand Down
Loading