Skip to content

Commit fe68065

Browse files
author
Ben Chatelain
committed
API changes for push in libgit2 0.22
1 parent 2f9a457 commit fe68065

File tree

4 files changed

+356
-0
lines changed

4 files changed

+356
-0
lines changed

ObjectiveGit/GTRepository+RemoteOperations.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,34 @@ extern NSString *const GTRepositoryRemoteOptionsCredentialProvider;
4545
/// Retruns an array with GTFetchHeadEntry objects
4646
- (NSArray *)fetchHeadEntriesWithError:(NSError **)error;
4747

48+
#pragma mark - Push
49+
50+
/// Push a single branch to a remote.
51+
///
52+
/// branch - The branch to push.
53+
/// remote - The remote to push to.
54+
/// options - Options applied to the push operation.
55+
/// Recognized options are:
56+
/// `GTRepositoryRemoteOptionsCredentialProvider`
57+
/// error - The error if one occurred. Can be NULL.
58+
/// progressBlock - An optional callback for monitoring progress.
59+
///
60+
/// Returns YES if the push was successful, NO otherwise (and `error`, if provided,
61+
/// will point to an error describing what happened).
62+
- (BOOL)pushBranch:(GTBranch *)branch toRemote:(GTRemote *)remote withOptions:(NSDictionary *)options error:(NSError **)error progress:(void (^)(unsigned int current, unsigned int total, size_t bytes, BOOL *stop))progressBlock;
63+
64+
/// Push an array of branches to a remote.
65+
///
66+
/// branches - An array of branches to push.
67+
/// remote - The remote to push to.
68+
/// options - Options applied to the push operation.
69+
/// Recognized options are:
70+
/// `GTRepositoryRemoteOptionsCredentialProvider`
71+
/// error - The error if one occurred. Can be NULL.
72+
/// progressBlock - An optional callback for monitoring progress.
73+
///
74+
/// Returns YES if the push was successful, NO otherwise (and `error`, if provided,
75+
/// will point to an error describing what happened).
76+
- (BOOL)pushBranches:(NSArray *)branches toRemote:(GTRemote *)remote withOptions:(NSDictionary *)options error:(NSError **)error progress:(void (^)(unsigned int current, unsigned int total, size_t bytes, BOOL *stop))progressBlock;
77+
4878
@end

ObjectiveGit/GTRepository+RemoteOperations.m

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#import "GTOID.h"
1616
#import "GTRemote.h"
1717
#import "GTSignature.h"
18+
#import "NSArray+StringArray.h"
1819
#import "NSError+Git.h"
1920

2021
#import "git2/errors.h"
@@ -159,4 +160,99 @@ - (NSArray *)fetchHeadEntriesWithError:(NSError **)error {
159160
return entries;
160161
}
161162

163+
#pragma mark - Push (Public)
164+
165+
- (BOOL)pushBranch:(GTBranch *)branch toRemote:(GTRemote *)remote withOptions:(NSDictionary *)options error:(NSError **)error progress:(GTRemotePushTransferProgressBlock)progressBlock {
166+
NSParameterAssert(branch != nil);
167+
NSParameterAssert(remote != nil);
168+
169+
return [self pushBranches:@[ branch ] toRemote:remote withOptions:options error:error progress:progressBlock];
170+
}
171+
172+
- (BOOL)pushBranches:(NSArray *)branches toRemote:(GTRemote *)remote withOptions:(NSDictionary *)options error:(NSError **)error progress:(GTRemotePushTransferProgressBlock)progressBlock {
173+
NSParameterAssert(branches != nil);
174+
NSParameterAssert(branches.count != 0);
175+
NSParameterAssert(remote != nil);
176+
177+
NSMutableArray *refspecs = nil;
178+
// Build refspecs for the passed in branches
179+
refspecs = [NSMutableArray arrayWithCapacity:branches.count];
180+
for (GTBranch *branch in branches) {
181+
// Default remote reference for when branch doesn't exist on remote - create with same short name
182+
NSString *remoteBranchReference = [NSString stringWithFormat:@"refs/heads/%@", branch.shortName];
183+
184+
BOOL success = NO;
185+
GTBranch *trackingBranch = [branch trackingBranchWithError:error success:&success];
186+
187+
if (success && trackingBranch) {
188+
// Use remote branch short name from trackingBranch, which could be different
189+
// (e.g. refs/heads/master:refs/heads/my_master)
190+
remoteBranchReference = [NSString stringWithFormat:@"refs/heads/%@", trackingBranch.shortName];
191+
}
192+
193+
[refspecs addObject:[NSString stringWithFormat:@"refs/heads/%@:%@", branch.shortName, remoteBranchReference]];
194+
}
195+
196+
return [self pushRefspecs:refspecs toRemote:remote withOptions:options error:error progress:progressBlock];
197+
}
198+
199+
#pragma mark - Push (Private)
200+
201+
- (BOOL)pushRefspecs:(NSArray *)refspecs toRemote:(GTRemote *)remote withOptions:(NSDictionary *)options error:(NSError **)error progress:(GTRemotePushTransferProgressBlock)progressBlock {
202+
int gitError;
203+
GTCredentialProvider *credProvider = options[GTRepositoryRemoteOptionsCredentialProvider];
204+
205+
GTRemoteConnectionInfo connectionInfo = {
206+
.credProvider = { .credProvider = credProvider },
207+
.direction = GIT_DIRECTION_PUSH,
208+
.pushProgressBlock = progressBlock,
209+
};
210+
211+
git_remote_callbacks remote_callbacks = GIT_REMOTE_CALLBACKS_INIT;
212+
remote_callbacks.credentials = (credProvider != nil ? GTCredentialAcquireCallback : NULL),
213+
remote_callbacks.transfer_progress = GTRemoteFetchTransferProgressCallback,
214+
remote_callbacks.payload = &connectionInfo,
215+
216+
gitError = git_remote_set_callbacks(remote.git_remote, &remote_callbacks);
217+
if (gitError != GIT_OK) {
218+
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to set callbacks on remote"];
219+
return NO;
220+
}
221+
222+
gitError = git_remote_connect(remote.git_remote, GIT_DIRECTION_PUSH);
223+
if (gitError != GIT_OK) {
224+
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to connect remote"];
225+
return NO;
226+
}
227+
@onExit {
228+
git_remote_disconnect(remote.git_remote);
229+
// Clear out callbacks by overwriting with an effectively empty git_remote_callbacks struct
230+
git_remote_set_callbacks(remote.git_remote, &((git_remote_callbacks)GIT_REMOTE_CALLBACKS_INIT));
231+
};
232+
233+
git_push_options push_options = GIT_PUSH_OPTIONS_INIT;
234+
235+
gitError = git_push_init_options(&push_options, GIT_PUSH_OPTIONS_VERSION);
236+
if (gitError != GIT_OK) {
237+
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to init push options"];
238+
return NO;
239+
}
240+
241+
const git_strarray git_refspecs = refspecs.git_strarray;
242+
243+
gitError = git_remote_upload(remote.git_remote, &git_refspecs, &push_options);
244+
if (gitError != GIT_OK) {
245+
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Push upload to remote failed"];
246+
return NO;
247+
}
248+
249+
gitError = git_remote_update_tips(remote.git_remote, self.userSignatureForNow.git_signature, NULL);
250+
if (gitError != GIT_OK) {
251+
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Update tips failed"];
252+
return NO;
253+
}
254+
255+
return YES;
256+
}
257+
162258
@end

ObjectiveGitFramework.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@
307307
DD3D9513182A81E1004AF532 /* GTBlame.m in Sources */ = {isa = PBXBuildFile; fileRef = DD3D9511182A81E1004AF532 /* GTBlame.m */; };
308308
DD3D951C182AB25C004AF532 /* GTBlameHunk.h in Headers */ = {isa = PBXBuildFile; fileRef = DD3D951A182AB25C004AF532 /* GTBlameHunk.h */; settings = {ATTRIBUTES = (Public, ); }; };
309309
DD3D951D182AB25C004AF532 /* GTBlameHunk.m in Sources */ = {isa = PBXBuildFile; fileRef = DD3D951B182AB25C004AF532 /* GTBlameHunk.m */; };
310+
F8E4A2911A170CA6006485A8 /* GTRemotePushSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E4A2901A170CA6006485A8 /* GTRemotePushSpec.m */; };
310311
/* End PBXBuildFile section */
311312

312313
/* Begin PBXContainerItemProxy section */
@@ -567,6 +568,7 @@
567568
DD3D951B182AB25C004AF532 /* GTBlameHunk.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTBlameHunk.m; sourceTree = "<group>"; };
568569
E46931A7172740D300F2077D /* update_libgit2 */ = {isa = PBXFileReference; lastKnownFileType = text; name = update_libgit2; path = script/update_libgit2; sourceTree = "<group>"; };
569570
E46931A8172740D300F2077D /* update_libgit2_ios */ = {isa = PBXFileReference; lastKnownFileType = text; name = update_libgit2_ios; path = script/update_libgit2_ios; sourceTree = "<group>"; };
571+
F8E4A2901A170CA6006485A8 /* GTRemotePushSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTRemotePushSpec.m; sourceTree = "<group>"; };
570572
/* End PBXFileReference section */
571573

572574
/* Begin PBXFrameworksBuildPhase section */
@@ -717,6 +719,7 @@
717719
88F05AA816011FFD00B7AD1D /* GTObjectSpec.m */,
718720
D00F6815175D373C004DB9D6 /* GTReferenceSpec.m */,
719721
88215482171499BE00D76B76 /* GTReflogSpec.m */,
722+
F8E4A2901A170CA6006485A8 /* GTRemotePushSpec.m */,
720723
4DBA4A3117DA73CE006CD5F5 /* GTRemoteSpec.m */,
721724
200578C418932A82001C06C3 /* GTBlameSpec.m */,
722725
D0AC906B172F941F00347DC4 /* GTRepositorySpec.m */,
@@ -1265,6 +1268,7 @@
12651268
88E353061982EA6B0051001F /* GTRepositoryAttributesSpec.m in Sources */,
12661269
88234B2618F2FE260039972E /* GTRepositoryResetSpec.m in Sources */,
12671270
5BE612931745EEBC00266D8C /* GTTreeBuilderSpec.m in Sources */,
1271+
F8E4A2911A170CA6006485A8 /* GTRemotePushSpec.m in Sources */,
12681272
D06D9E011755D10000558C17 /* GTEnumeratorSpec.m in Sources */,
12691273
D03B7C411756AB370034A610 /* GTSubmoduleSpec.m in Sources */,
12701274
D00F6816175D373C004DB9D6 /* GTReferenceSpec.m in Sources */,

0 commit comments

Comments
 (0)