Skip to content

Commit 584ff60

Browse files
committed
Merge branch 'master' into purgatory
Conflicts: Classes/GTRepository.m Classes/GTSubmodule.m
2 parents c13b9b9 + 392eff9 commit 584ff60

24 files changed

+801
-700
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ External/libgit2-ios
2121

2222
project.xcworkspace
2323
*/xcuserdata/
24+
*.xccheckout
2425

2526
ObjectiveGitTests/fixtures/Fixtures/*
2627

Classes/GTDiff.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,11 @@ typedef enum {
185185
//
186186
// The 2 trees must be from the same repository, or an exception will be thrown.
187187
//
188-
// oldTree - The "left" side of the diff. May be nil to represent an empty tree.
188+
// oldTree - The "left" side of the diff. May be nil to represent an empty
189+
// tree.
189190
// newTree - The "right" side of the diff. May be nil to represent an empty
190191
// tree.
191-
// repository - The repository to be used for the diff.
192+
// repository - The repository to be used for the diff. Cannot be nil.
192193
// options - A dictionary containing any of the above options key constants, or
193194
// nil to use the defaults.
194195
// error - Populated with an `NSError` object on error, if information is
@@ -257,7 +258,12 @@ typedef enum {
257258
+ (GTDiff *)diffWorkingDirectoryToHEADInRepository:(GTRepository *)repository options:(NSDictionary *)options error:(NSError **)error;
258259

259260
// Designated initialiser.
260-
- (instancetype)initWithGitDiff:(git_diff *)diff;
261+
//
262+
// diff - The diff to represent. Cannot be NULL.
263+
// repository - The repository in which the diff lives. Cannot be nil.
264+
//
265+
// Returns the initialized object.
266+
- (instancetype)initWithGitDiff:(git_diff *)diff repository:(GTRepository *)repository;
261267

262268
// The libgit2 diff object.
263269
- (git_diff *)git_diff __attribute__((objc_returns_inner_pointer));

Classes/GTDiff.m

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ @interface GTDiff ()
3636

3737
@property (nonatomic, assign, readonly) git_diff *git_diff;
3838

39-
// A cache of the deltas for the diff. Will be populated only after the first
40-
// call of -enumerateDeltasUsingBlock:.
41-
@property (atomic, copy) NSArray *cachedDeltas;
39+
@property (nonatomic, strong, readonly) GTRepository *repository;
4240

4341
@end
4442

@@ -82,20 +80,17 @@ + (int)handleParsedOptionsDictionary:(NSDictionary *)dictionary usingBlock:(int
8280

8381
+ (GTDiff *)diffOldTree:(GTTree *)oldTree withNewTree:(GTTree *)newTree inRepository:(GTRepository *)repository options:(NSDictionary *)options error:(NSError **)error {
8482
NSParameterAssert(repository != nil);
85-
NSParameterAssert(newTree == nil || [newTree.repository isEqual:repository]);
86-
NSParameterAssert(oldTree == nil || [oldTree.repository isEqual:repository]);
8783

8884
__block git_diff *diff;
89-
int returnValue = [self handleParsedOptionsDictionary:options usingBlock:^(git_diff_options *optionsStruct) {
85+
int status = [self handleParsedOptionsDictionary:options usingBlock:^(git_diff_options *optionsStruct) {
9086
return git_diff_tree_to_tree(&diff, repository.git_repository, oldTree.git_tree, newTree.git_tree, optionsStruct);
9187
}];
92-
if (returnValue != GIT_OK) {
93-
if (error != NULL) *error = [NSError git_errorFor:returnValue description:@"Failed to create diff between %@ and %@", oldTree.SHA, newTree.SHA];
88+
if (status != GIT_OK) {
89+
if (error != NULL) *error = [NSError git_errorFor:status description:@"Failed to create diff between %@ and %@", oldTree.SHA, newTree.SHA];
9490
return nil;
9591
}
9692

97-
GTDiff *newDiff = [[GTDiff alloc] initWithGitDiff:diff];
98-
return newDiff;
93+
return [[GTDiff alloc] initWithGitDiff:diff repository:repository];
9994
}
10095

10196
+ (GTDiff *)diffIndexFromTree:(GTTree *)tree inRepository:(GTRepository *)repository options:(NSDictionary *)options error:(NSError **)error {
@@ -111,8 +106,7 @@ + (GTDiff *)diffIndexFromTree:(GTTree *)tree inRepository:(GTRepository *)reposi
111106
return nil;
112107
}
113108

114-
GTDiff *newDiff = [[GTDiff alloc] initWithGitDiff:diff];
115-
return newDiff;
109+
return [[GTDiff alloc] initWithGitDiff:diff repository:repository];
116110
}
117111

118112
+ (GTDiff *)diffIndexToWorkingDirectoryInRepository:(GTRepository *)repository options:(NSDictionary *)options error:(NSError **)error {
@@ -127,8 +121,7 @@ + (GTDiff *)diffIndexToWorkingDirectoryInRepository:(GTRepository *)repository o
127121
return nil;
128122
}
129123

130-
GTDiff *newDiff = [[GTDiff alloc] initWithGitDiff:diff];
131-
return newDiff;
124+
return [[GTDiff alloc] initWithGitDiff:diff repository:repository];
132125
}
133126

134127
+ (GTDiff *)diffWorkingDirectoryFromTree:(GTTree *)tree inRepository:(GTRepository *)repository options:(NSDictionary *)options error:(NSError **)error {
@@ -144,8 +137,7 @@ + (GTDiff *)diffWorkingDirectoryFromTree:(GTTree *)tree inRepository:(GTReposito
144137
return nil;
145138
}
146139

147-
GTDiff *newDiff = [[GTDiff alloc] initWithGitDiff:diff];
148-
return newDiff;
140+
return [[GTDiff alloc] initWithGitDiff:diff repository:repository];
149141
}
150142

151143
+ (GTDiff *)diffWorkingDirectoryToHEADInRepository:(GTRepository *)repository options:(NSDictionary *)options error:(NSError **)error {
@@ -163,13 +155,15 @@ + (GTDiff *)diffWorkingDirectoryToHEADInRepository:(GTRepository *)repository op
163155
return HEADIndexDiff;
164156
}
165157

166-
- (instancetype)initWithGitDiff:(git_diff *)diff {
158+
- (instancetype)initWithGitDiff:(git_diff *)diff repository:(GTRepository *)repository {
167159
NSParameterAssert(diff != NULL);
160+
NSParameterAssert(repository != nil);
168161

169162
self = [super init];
170163
if (self == nil) return nil;
171164

172165
_git_diff = diff;
166+
_repository = repository;
173167

174168
return self;
175169
}
@@ -188,25 +182,14 @@ - (NSString *)debugDescription {
188182
- (void)enumerateDeltasUsingBlock:(void (^)(GTDiffDelta *delta, BOOL *stop))block {
189183
NSParameterAssert(block != nil);
190184

191-
if (self.cachedDeltas == nil) {
192-
NSMutableArray *deltas = [NSMutableArray arrayWithCapacity:self.deltaCount];
193-
for (NSUInteger idx = 0; idx < self.deltaCount; idx ++) {
194-
git_patch *patch;
195-
int result = git_patch_from_diff(&patch, self.git_diff, idx);
196-
if (result != GIT_OK) continue;
197-
198-
GTDiffDelta *delta = [[GTDiffDelta alloc] initWithGitPatch:patch];
199-
if (delta == nil) continue;
185+
for (NSUInteger idx = 0; idx < self.deltaCount; idx ++) {
186+
GTDiffDelta *delta = [[GTDiffDelta alloc] initWithDiff:self deltaIndex:idx];
187+
if (delta == nil) continue;
200188

201-
[deltas addObject:delta];
202-
}
203-
204-
self.cachedDeltas = deltas;
189+
BOOL stop = NO;
190+
block(delta, &stop);
191+
if (stop) break;
205192
}
206-
207-
[self.cachedDeltas enumerateObjectsUsingBlock:^(GTDiffDelta *delta, NSUInteger idx, BOOL *stop) {
208-
block(delta, stop);
209-
}];
210193
}
211194

212195
- (NSUInteger)deltaCount {
@@ -253,8 +236,7 @@ - (BOOL)mergeDiffWithDiff:(GTDiff *)diff error:(NSError **)error {
253236
if (error) *error = [NSError git_errorFor:gitError description:@"Merging diffs failed"];
254237
return NO;
255238
}
256-
// Clear our cache of deltas
257-
self.cachedDeltas = nil;
239+
258240
return YES;
259241
}
260242

Classes/GTDiffDelta.h

Lines changed: 21 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
//
88

99
#import "git2.h"
10+
#import "GTDiffFile.h"
1011

11-
@class GTDiffFile;
12+
@class GTDiff;
1213
@class GTDiffHunk;
14+
@class GTDiffPatch;
1315

1416
// The type of change that this delta represents.
1517
//
@@ -43,11 +45,18 @@ typedef enum {
4345
// for the types of change represented.
4446
@interface GTDiffDelta : NSObject
4547

46-
// The underlying libgit2 `git_patch` object.
47-
@property (nonatomic, assign, readonly) git_patch *git_patch;
48+
// The `git_diff_delta` represented by the receiver.
49+
@property (nonatomic, assign, readonly) git_diff_delta git_diff_delta;
4850

49-
// Whether the file(s) are to be treated as binary.
50-
@property (nonatomic, readonly, getter = isBinary) BOOL binary;
51+
// The diff in which this delta is contained.
52+
@property (nonatomic, strong, readonly) GTDiff *diff;
53+
54+
// Any flags set on the delta. See `GTDiffFileFlag` for more info.
55+
//
56+
// Note that this may not include `GTDiffFileFlagBinary` _or_
57+
// `GTDiffFileFlagNotBinary` until the content is loaded for this delta (e.g.,
58+
// through a call to -generatePatch:).
59+
@property (nonatomic, assign, readonly) GTDiffFileFlag flags;
5160

5261
// The file to the "left" of the diff.
5362
@property (nonatomic, readonly, copy) GTDiffFile *oldFile;
@@ -60,46 +69,16 @@ typedef enum {
6069
// Think "status" as in `git status`.
6170
@property (nonatomic, readonly) GTDiffDeltaType type;
6271

63-
// The number of hunks represented by this delta.
64-
@property (nonatomic, readonly) NSUInteger hunkCount;
65-
66-
// The number of added lines in this delta.
67-
//
68-
// Undefined if this delta is binary.
69-
@property (nonatomic, readonly) NSUInteger addedLinesCount;
70-
71-
// The number of deleted lines in this delta.
72-
//
73-
// Undefined if this delta is binary.
74-
@property (nonatomic, readonly) NSUInteger deletedLinesCount;
75-
76-
// The number of context lines in this delta.
77-
//
78-
// Undefined if this delta is binary.
79-
@property (nonatomic, readonly) NSUInteger contextLinesCount;
80-
81-
// Designated initialiser.
82-
- (instancetype)initWithGitPatch:(git_patch *)patch;
72+
// Initializes the receiver to wrap the delta at the given index.
73+
- (instancetype)initWithDiff:(GTDiff *)diff deltaIndex:(NSUInteger)deltaIndex;
8374

84-
// A convenience accessor to fetch the `git_diff_delta` represented by the
85-
// object.
86-
- (const git_diff_delta *)git_diff_delta __attribute__((objc_returns_inner_pointer));
87-
88-
// Get the delta size.
89-
//
90-
// includeContext - Include the context lines in the size. Defaults to NO.
91-
// includeHunkHeaders - Include the hunk header lines in the size. Defaults to NO.
92-
// includeFileHeaders - Include the file header lines in the size. Defaults to NO.
75+
// Creates a patch from a text delta.
9376
//
94-
// Returns the raw size in bytes of the delta.
95-
- (NSUInteger)sizeWithContext:(BOOL)includeContext hunkHeaders:(BOOL)includeHunkHeaders fileHeaders:(BOOL)includeFileHeaders;
96-
97-
// Enumerate the hunks contained in the delta.
77+
// If the receiver represents a binary delta, this method will return an error.
9878
//
99-
// Blocks during enumeration.
79+
// error - If not NULL, set to any error that occurs.
10080
//
101-
// block - A block to be executed for each hunk. Setting `stop` to `YES`
102-
// immediately stops the enumeration.
103-
- (void)enumerateHunksUsingBlock:(void (^)(GTDiffHunk *hunk, BOOL *stop))block;
81+
// Returns a new patch, or nil if an error occurs.
82+
- (GTDiffPatch *)generatePatch:(NSError **)error;
10483

10584
@end

Classes/GTDiffDelta.m

Lines changed: 40 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,87 +8,71 @@
88

99
#import "GTDiffDelta.h"
1010

11-
#import "GTDiffFile.h"
12-
#import "GTDiffHunk.h"
1311
#import "GTDiff.h"
12+
#import "GTDiffFile.h"
13+
#import "GTDiffPatch.h"
14+
#import "NSError+Git.h"
1415

15-
@implementation GTDiffDelta
16-
17-
- (instancetype)initWithGitPatch:(git_patch *)patch {
18-
NSParameterAssert(patch != NULL);
19-
20-
self = [super init];
21-
if (self == nil) return nil;
22-
23-
_git_patch = patch;
24-
25-
size_t adds = 0;
26-
size_t deletes = 0;
27-
size_t contexts = 0;
28-
git_patch_line_stats(&contexts, &adds, &deletes, _git_patch);
29-
30-
_addedLinesCount = adds;
31-
_deletedLinesCount = deletes;
32-
_contextLinesCount = contexts;
16+
@interface GTDiffDelta ()
3317

34-
return self;
35-
}
18+
// The index of this delta within its parent `diff`.
19+
@property (nonatomic, assign, readonly) NSUInteger deltaIndex;
3620

37-
- (NSString *)debugDescription {
38-
return [NSString stringWithFormat:@"%@ flags: %u, oldFile: %@, newFile: %@", super.debugDescription, self.git_diff_delta->flags, self.oldFile, self.newFile];
39-
}
21+
@end
4022

41-
- (void)dealloc {
42-
if (_git_patch) {
43-
git_patch_free(_git_patch);
44-
_git_patch = NULL;
45-
}
46-
}
23+
@implementation GTDiffDelta
4724

48-
#pragma mark - Properties
25+
#pragma mark Properties
4926

50-
- (const git_diff_delta *)git_diff_delta {
51-
return git_patch_get_delta(self.git_patch);
27+
- (git_diff_delta)git_diff_delta {
28+
return *(git_diff_get_delta(self.diff.git_diff, self.deltaIndex));
5229
}
5330

54-
- (BOOL)isBinary {
55-
return (self.git_diff_delta->flags & GIT_DIFF_FLAG_BINARY) != 0;
31+
- (GTDiffFileFlag)flags {
32+
return (GTDiffFileFlag)self.git_diff_delta.flags;
5633
}
5734

5835
- (GTDiffFile *)oldFile {
59-
return [[GTDiffFile alloc] initWithGitDiffFile:self.git_diff_delta->old_file];
36+
return [[GTDiffFile alloc] initWithGitDiffFile:self.git_diff_delta.old_file];
6037
}
6138

6239
- (GTDiffFile *)newFile {
63-
return [[GTDiffFile alloc] initWithGitDiffFile:self.git_diff_delta->new_file];
40+
return [[GTDiffFile alloc] initWithGitDiffFile:self.git_diff_delta.new_file];
6441
}
6542

6643
- (GTDiffDeltaType)type {
67-
return (GTDiffDeltaType)self.git_diff_delta->status;
44+
return (GTDiffDeltaType)self.git_diff_delta.status;
6845
}
6946

70-
- (NSUInteger)hunkCount {
71-
return git_patch_num_hunks(self.git_patch);
72-
}
47+
#pragma mark Lifecycle
7348

74-
- (NSUInteger)sizeWithContext:(BOOL)includeContext hunkHeaders:(BOOL)includeHunkHeaders fileHeaders:(BOOL)includeFileHeaders {
75-
int shouldIncludeContext = (includeContext == YES ? 1 : 0);
76-
int shouldIncludeHunkHeaders = (includeHunkHeaders == YES ? 1 : 0);
77-
int shouldIncludeFileHeaders = (includeFileHeaders == YES ? 1 : 0);
78-
return git_patch_size(self.git_patch, shouldIncludeContext, shouldIncludeHunkHeaders, shouldIncludeFileHeaders);
79-
}
49+
- (instancetype)initWithDiff:(GTDiff *)diff deltaIndex:(NSUInteger)deltaIndex {
50+
self = [super init];
51+
if (self == nil) return nil;
8052

81-
- (void)enumerateHunksUsingBlock:(void (^)(GTDiffHunk *hunk, BOOL *stop))block {
82-
NSParameterAssert(block != nil);
53+
_diff = diff;
54+
_deltaIndex = deltaIndex;
8355

84-
for (NSUInteger idx = 0; idx < self.hunkCount; idx ++) {
85-
GTDiffHunk *hunk = [[GTDiffHunk alloc] initWithDelta:self hunkIndex:idx];
86-
if (hunk == nil) return;
56+
return self;
57+
}
58+
59+
#pragma mark Patch Generation
8760

88-
BOOL shouldStop = NO;
89-
block(hunk, &shouldStop);
90-
if (shouldStop) return;
61+
- (GTDiffPatch *)generatePatch:(NSError **)error {
62+
git_patch *patch = NULL;
63+
int gitError = git_patch_from_diff(&patch, self.diff.git_diff, self.deltaIndex);
64+
if (gitError != GIT_OK) {
65+
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Patch generation failed for delta %@", self];
66+
return nil;
9167
}
68+
69+
return [[GTDiffPatch alloc] initWithGitPatch:patch delta:self];
70+
}
71+
72+
#pragma mark NSObject
73+
74+
- (NSString *)description {
75+
return [NSString stringWithFormat:@"<%@: %p>{ flags: %u, oldFile: %@, newFile: %@ }", self.class, self, (unsigned)self.git_diff_delta.flags, self.oldFile, self.newFile];
9276
}
9377

9478
@end

Classes/GTDiffFile.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@
1010

1111
// Flags which may be set on the file.
1212
//
13-
// See diff.h for individual documentation.
13+
// GTDiffFileFlagBinaryMask - A mask to just retrieve the binary/not binary
14+
// information from a set of flags.
15+
//
16+
// See diff.h for further documentation.
1417
typedef enum {
1518
GTDiffFileFlagValidID = GIT_DIFF_FLAG_VALID_ID,
1619
GTDiffFileFlagBinary = GIT_DIFF_FLAG_BINARY,
1720
GTDiffFileFlagNotBinary = GIT_DIFF_FLAG_NOT_BINARY,
21+
22+
GTDiffFileFlagBinaryMask = GTDiffFileFlagBinary | GTDiffFileFlagNotBinary,
1823
} GTDiffFileFlag;
1924

2025
@class GTOID;

0 commit comments

Comments
 (0)