Skip to content

Added Pushing to and Pulling from a repository #329

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

Closed
wants to merge 4 commits into from
Closed
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
2 changes: 2 additions & 0 deletions Classes/GTRemote.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
// remote - The underlying `git_remote` object.
- (id)initWithGitRemote:(git_remote *)remote;

- (id)initWithGitRepository:(git_repository *)repository name:(NSString *)name url:(NSString *)url error:(NSError **)error;
Copy link
Member

Choose a reason for hiding this comment

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

Why does this take a git_repository instead of a GTRepository?

Copy link
Member

Choose a reason for hiding this comment

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

Style: needs documentation; URL should be capitalized and probably be URLString since it's not an actual NSURL.


// The underlying `git_remote` object.
- (git_remote *)git_remote __attribute__((objc_returns_inner_pointer));

Expand Down
12 changes: 12 additions & 0 deletions Classes/GTRemote.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ - (id)initWithGitRemote:(git_remote *)remote {
return self;
}

- (id)initWithGitRepository:(git_repository *)repository name:(NSString *)name url:(NSString *)url error:(NSError **)error {

Copy link
Member

Choose a reason for hiding this comment

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

Style: no newline.

git_remote *remote;
int gitError = git_remote_create(&remote, repository, [name UTF8String], [url UTF8String]);
Copy link
Member

Choose a reason for hiding this comment

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

Style: dot syntax for -UTF8String.

Copy link
Member

Choose a reason for hiding this comment

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

It's odd, I think, for an initializer like this to be side-effecting (adding a remote to a repository). IMHO, that should be a method on GTRepository.

if (gitError != GIT_OK || repository == NULL) {
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to create remote named %@ at %@", name, url];
return nil;
}

return [[GTRemote alloc] initWithGitRemote:remote];
}

- (void)dealloc {
if (_git_remote != NULL) git_remote_free(_git_remote);
}
Expand Down
15 changes: 15 additions & 0 deletions Classes/GTRepository+Pulling.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// GTRepository+Pulling.h
// ObjectiveGitFramework
//
// Created by John Beatty on 1/13/14.
// Copyright (c) 2014 Objective Products LLC. All rights reserved.
//

#import <ObjectiveGit/ObjectiveGit.h>

@interface GTRepository (Pulling)

- (void)pullBranch:(GTBranch *)branch fromRemote:(GTRemote *)_remote options:(NSDictionary *)pullOptions;
Copy link
Member

Choose a reason for hiding this comment

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

Documentation needed.


@end
112 changes: 112 additions & 0 deletions Classes/GTRepository+Pulling.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//
// GTRepository+Pulling.m
// ObjectiveGitFramework
//
// Created by John Beatty on 1/13/14.
// Copyright (c) 2014 Objective Products LLC. All rights reserved.
//

#import "GTRepository+Pulling.h"
#import "NSError+Git.h"
#import "GTCredential+Private.h"

NSString *const GTRepositoryPullingOptionsCredentialProvider = @"GTRepositoryPullingOptionsCredentialProvider";

@implementation GTRepository (Pulling)

typedef void(^GTTransferProgressBlock)(const git_transfer_progress *progress);

struct GTPullPayload {
// credProvider must be first for compatibility with GTCredentialAcquireCallbackInfo
__unsafe_unretained GTCredentialProvider *credProvider;
__unsafe_unretained GTTransferProgressBlock transferProgressBlock;
};

static int pullTransferProgressCallback(const git_transfer_progress *progress, void *payload) {
if (payload == NULL) return 0;
struct GTPullPayload *pld = payload;
if (pld->transferProgressBlock == NULL) return 0;
pld->transferProgressBlock(progress);
return GIT_OK;
}

static int pullCompletionCallback(git_remote_completion_type type, void *data) {
NSLog(@"%s", __PRETTY_FUNCTION__);
return GIT_OK;
}

- (void)pullBranch:(GTBranch *)branch fromRemote:(GTRemote *)_remote options:(NSDictionary *)pullOptions {
NSLog(@"%s %@", __PRETTY_FUNCTION__, [[branch reference] name]);
NSError *error;
git_remote* remote;

GTCredentialProvider *credentialProvider = pullOptions[GTRepositoryPullingOptionsCredentialProvider];

git_remote_callbacks remote_callbacks = GIT_REMOTE_CALLBACKS_INIT;
struct GTPullPayload payload;
payload.credProvider = credentialProvider;
remote_callbacks.version = GIT_REMOTE_CALLBACKS_VERSION;
remote_callbacks.credentials = GTCredentialAcquireCallback;

payload.transferProgressBlock = ^(const git_transfer_progress *progress) {
NSLog(@"%s %d %d %d", __PRETTY_FUNCTION__, progress->total_objects, progress->received_objects, progress->local_objects );
};
remote_callbacks.transfer_progress = pullTransferProgressCallback;
remote_callbacks.completion = pullCompletionCallback;
remote_callbacks.payload = &payload;

int gitError = git_remote_load(&remote, self.git_repository, [[_remote name] UTF8String]);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to load remote"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}

git_remote_check_cert(remote, 0);
gitError = git_remote_set_callbacks(remote, &remote_callbacks);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to add remote callbacks"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}

const git_transfer_progress *stats = git_remote_stats(remote);

gitError = git_remote_connect(remote, GIT_DIRECTION_FETCH);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to open remote connection."];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}
gitError = git_remote_add_fetch(remote, [[NSString stringWithFormat:@"%@:%@", [[branch reference] name], [[branch reference] name]] UTF8String]);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to add refspec"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);

}

NSLog(@"%s %s", __PRETTY_FUNCTION__, git_remote_url(remote));
NSLog(@"%s connected? %d", __PRETTY_FUNCTION__, git_remote_connected(remote));
GTSignature *signature = [self userSignatureForNow];
gitError = git_remote_fetch(remote, signature.git_signature, NULL);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to download data."];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}

if (stats->local_objects > 0) {
printf("\rReceived %d/%d objects in %zu bytes (used %d local objects)\n",
stats->indexed_objects, stats->total_objects, stats->received_bytes, stats->local_objects);
} else{
printf("\rReceived %d/%d objects in %zu bytes\n",
stats->indexed_objects, stats->total_objects, stats->received_bytes);
}

git_remote_disconnect(remote);
gitError = git_remote_update_tips(remote, signature.git_signature, NULL);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to update tips."];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}

git_remote_free(remote);
}

@end
21 changes: 21 additions & 0 deletions Classes/GTRepository+Pushing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// GTRepository+Pushing.h
// ObjectiveGitFramework
//
// Created by John Beatty on 1/12/14.
// Copyright (c) 2014 Objective Products LLC. All rights reserved.
//

#import "GTRepository.h"

@class GTRemote;
@class GTBranch;

// A `GTCredentialProvider`, that will be used to authenticate against the remote.
extern NSString *const GTRepositoryPushingOptionsCredentialProvider;

@interface GTRepository (Pushing)

- (void)pushBranch:(GTBranch *)branch toRemote:(GTRemote *)_remote options:(NSDictionary *)pushOptions;

@end
127 changes: 127 additions & 0 deletions Classes/GTRepository+Pushing.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//
// GTRepository+Pushing.m
// ObjectiveGitFramework
//
// Created by John Beatty on 1/12/14.
// Copyright (c) 2014 Objective Products LLC All rights reserved.
//

#import "NSError+Git.h"
#import "GTRepository+Pushing.h"
#import "GTConfiguration.h"
#import "GTRemote.h"
#import "GTCredential.h"
#import "GTCredential+Private.h"
#import "GTBranch.h"
#import "GTSignature.h"

NSString *const GTRepositoryPushingOptionsCredentialProvider = @"GTRepositoryPushingOptionsCredentialProvider";

@implementation GTRepository (Pushing)

typedef void(^GTTransferProgressBlock)(const git_transfer_progress *progress);

struct GTPushPayload {
// credProvider must be first for compatibility with GTCredentialAcquireCallbackInfo
__unsafe_unretained GTCredentialProvider *credProvider;
__unsafe_unretained GTTransferProgressBlock transferProgressBlock;
};

static int pushTransferProgressCallback(const git_transfer_progress *progress, void *payload) {
if (payload == NULL) return 0;
struct GTPushPayload *pld = payload;
if (pld->transferProgressBlock == NULL) return 0;
pld->transferProgressBlock(progress);
return GIT_OK;
}

static int pushRefspecCallback(const char *ref, const char *msg, void *data) {
NSLog(@"%s %s %s", __PRETTY_FUNCTION__, ref, msg);
return GIT_OK;
}

static int pushCompletionCallback(git_remote_completion_type type, void *data) {
NSLog(@"%s", __PRETTY_FUNCTION__);
return GIT_OK;
}

- (void)pushBranch:(GTBranch *)branch toRemote:(GTRemote *)_remote options:(NSDictionary *)pushOptions {
NSLog(@"%s %@", __PRETTY_FUNCTION__, [[branch reference] name]);
NSError *error;
git_remote* remote;
git_push *push;
git_push_options options = GIT_PUSH_OPTIONS_INIT;

GTCredentialProvider *credentialProvider = pushOptions[GTRepositoryPushingOptionsCredentialProvider];

git_remote_callbacks remote_callbacks = GIT_REMOTE_CALLBACKS_INIT;
struct GTPushPayload payload;
payload.credProvider = credentialProvider;
remote_callbacks.version = GIT_REMOTE_CALLBACKS_VERSION;
remote_callbacks.credentials = GTCredentialAcquireCallback;

payload.transferProgressBlock = ^(const git_transfer_progress *progress) {
NSLog(@"%s %d %d %d", __PRETTY_FUNCTION__, progress->total_objects, progress->received_objects, progress->local_objects );
};
remote_callbacks.transfer_progress = pushTransferProgressCallback;
remote_callbacks.completion = pushCompletionCallback;
remote_callbacks.payload = &payload;

int gitError = git_remote_load(&remote, self.git_repository, [[_remote name] UTF8String]);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to load remote"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}
git_remote_check_cert(remote, 0);
gitError = git_remote_set_callbacks(remote, &remote_callbacks);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to add remote callbacks"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}
gitError = git_remote_connect(remote, GIT_DIRECTION_PUSH);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to open remote connection."];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}
gitError = git_push_new(&push, remote);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to create git_push object"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}
gitError = git_push_set_options(push, &options);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to add options"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}
gitError = git_push_add_refspec(push, [[NSString stringWithFormat:@"%@:%@", [[branch reference] name], [[branch reference] name]] UTF8String]);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to add refspec"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);

}
gitError = git_push_finish(push);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to finish push"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}
gitError = git_push_unpack_ok(push);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to unpack push"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}
GTSignature *signature = [self userSignatureForNow];
gitError = git_push_update_tips(push, signature.git_signature, NULL);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to update tips"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}
gitError = git_push_status_foreach(push, pushRefspecCallback, NULL);
if (gitError != GIT_OK) {
error = [NSError git_errorFor:gitError description:@"Failed to loop through refs"];
NSLog(@"%s %@", __PRETTY_FUNCTION__, error);
}
git_push_free(push);

}

@end
2 changes: 2 additions & 0 deletions Classes/ObjectiveGit.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#import <ObjectiveGit/GTRepository+Stashing.h>
#import <ObjectiveGit/GTRepository+Committing.h>
#import <ObjectiveGit/GTRepository+Status.h>
#import <ObjectiveGit/GTRepository+Pushing.h>
#import <ObjectiveGit/GTRepository+Pulling.h>
#import <ObjectiveGit/GTEnumerator.h>
#import <ObjectiveGit/GTCommit.h>
#import <ObjectiveGit/GTCredential.h>
Expand Down
Loading