-
Notifications
You must be signed in to change notification settings - Fork 284
Expand file tree
/
Copy pathGTDiffDelta.m
More file actions
186 lines (142 loc) · 6.73 KB
/
GTDiffDelta.m
File metadata and controls
186 lines (142 loc) · 6.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//
// GTDiffDelta.m
// ObjectiveGitFramework
//
// Created by Danny Greg on 30/11/2012.
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "GTDiffDelta.h"
#import "GTBlob.h"
#import "GTDiff+Private.h"
#import "GTDiffFile.h"
#import "GTDiffPatch.h"
#import "NSError+Git.h"
#import "git2/errors.h"
@interface GTDiffDelta ()
/// Used to dynamically access the underlying `git_diff_delta`.
@property (nonatomic, copy, readonly) git_diff_delta (^deltaAccessor)(void);
/// Used to generate a patch from this delta.
@property (nonatomic, copy, readonly) int (^patchGenerator)(git_patch **patch);
/// Initializes the diff delta with blocks that will fulfill its contract.
///
/// deltaAccessor - A block that will return the `git_diff_delta` underlying
/// this object. Must not be nil.
/// patchGenerator - A block that will be used to lazily generate a patch for
/// the given diff delta. Must not be nil.
///
/// This is the designated initializer for this class.
- (instancetype)initWithGitDiffDeltaBlock:(git_diff_delta (^)(void))deltaAccessor patchGeneratorBlock:(int (^)(git_patch **patch))patchGenerator NS_DESIGNATED_INITIALIZER;
@end
@implementation GTDiffDelta
#pragma mark Properties
- (git_diff_delta)git_diff_delta {
return self.deltaAccessor();
}
- (GTDiffFileFlag)flags {
return (GTDiffFileFlag)self.git_diff_delta.flags;
}
- (GTDiffFile *)oldFile {
return [[GTDiffFile alloc] initWithGitDiffFile:self.git_diff_delta.old_file];
}
- (GTDiffFile *)newFile {
return [[GTDiffFile alloc] initWithGitDiffFile:self.git_diff_delta.new_file];
}
- (GTDeltaType)type {
return (GTDeltaType)self.git_diff_delta.status;
}
- (double)similarity {
return (double)(self.git_diff_delta.similarity / 100.0);
}
#pragma mark Lifecycle
static int GTDiffDeltaCallback(const git_diff_delta *delta, float progress, void *payload) {
git_diff_delta *storage = payload;
*storage = *delta;
return GIT_OK;
}
+ (instancetype)diffDeltaFromBlob:(GTBlob *)oldBlob forPath:(NSString *)oldBlobPath toBlob:(GTBlob *)newBlob forPath:(NSString *)newBlobPath options:(NSDictionary *)options error:(NSError **)error {
__block git_diff_delta diffDelta;
int returnValue = [GTDiff handleParsedOptionsDictionary:options usingBlock:^(git_diff_options *optionsStruct) {
return git_diff_blobs(oldBlob.git_blob, oldBlobPath.UTF8String, newBlob.git_blob, newBlobPath.UTF8String, optionsStruct, >DiffDeltaCallback, NULL, NULL, NULL, &diffDelta);
}];
if (returnValue != GIT_OK) {
if (error != NULL) *error = [NSError git_errorFor:returnValue description:@"Failed to create diff delta between blob %@ at path %@ and blob %@ at path %@", oldBlob.SHA, oldBlobPath, newBlob.SHA, newBlobPath];
return nil;
}
return [[self alloc] initWithGitDiffDeltaBlock:^{
return diffDelta;
} patchGeneratorBlock:^(git_patch **patch) {
return [GTDiff handleParsedOptionsDictionary:options usingBlock:^(git_diff_options *optionsStruct) {
return git_patch_from_blobs(patch, oldBlob.git_blob, oldBlobPath.UTF8String, newBlob.git_blob, newBlobPath.UTF8String, optionsStruct);
}];
}];
}
+ (instancetype)diffDeltaFromBlob:(GTBlob *)blob forPath:(NSString *)blobPath toData:(NSData *)data forPath:(NSString *)dataPath options:(NSDictionary *)options error:(NSError **)error {
__block git_diff_delta diffDelta;
int returnValue = [GTDiff handleParsedOptionsDictionary:options usingBlock:^(git_diff_options *optionsStruct) {
return git_diff_blob_to_buffer(blob.git_blob, blobPath.UTF8String, data.bytes, data.length, dataPath.UTF8String, optionsStruct, >DiffDeltaCallback, NULL, NULL, NULL, &diffDelta);
}];
if (returnValue != GIT_OK) {
if (error != NULL) *error = [NSError git_errorFor:returnValue description:@"Failed to create diff delta between blob %@ at path %@ and data at path %@", blob.SHA, blobPath, dataPath];
return nil;
}
return [[self alloc] initWithGitDiffDeltaBlock:^{
return diffDelta;
} patchGeneratorBlock:^(git_patch **patch) {
return [GTDiff handleParsedOptionsDictionary:options usingBlock:^(git_diff_options *optionsStruct) {
return git_patch_from_blob_and_buffer(patch, blob.git_blob, blobPath.UTF8String, data.bytes, data.length, dataPath.UTF8String, optionsStruct);
}];
}];
}
+ (instancetype)diffDeltaFromData:(NSData *)oldData forPath:(NSString *)oldDataPath toData:(NSData *)newData forPath:(NSString *)newDataPath options:(NSDictionary *)options error:(NSError **)error {
__block git_diff_delta diffDelta;
int returnValue = [GTDiff handleParsedOptionsDictionary:options usingBlock:^(git_diff_options *optionsStruct) {
return git_diff_buffers(oldData.bytes, oldData.length, oldDataPath.UTF8String, newData.bytes, newData.length, newDataPath.UTF8String, optionsStruct, >DiffDeltaCallback, NULL, NULL, NULL, &diffDelta);
}];
if (returnValue != GIT_OK) {
if (error != NULL) *error = [NSError git_errorFor:returnValue description:@"Failed to create diff delta between data at path %@ and data at path %@", oldDataPath, newDataPath];
return nil;
}
return [[self alloc] initWithGitDiffDeltaBlock:^{
return diffDelta;
} patchGeneratorBlock:^(git_patch **patch) {
return [GTDiff handleParsedOptionsDictionary:options usingBlock:^(git_diff_options *optionsStruct) {
return git_patch_from_buffers(patch, oldData.bytes, oldData.length, oldDataPath.UTF8String, newData.bytes, newData.length, newDataPath.UTF8String, optionsStruct);
}];
}];
}
- (instancetype)init {
NSAssert(NO, @"Call to an unavailable initializer.");
return nil;
}
- (instancetype)initWithDiff:(GTDiff *)diff deltaIndex:(NSUInteger)deltaIndex {
NSCParameterAssert(diff != nil);
return [self initWithGitDiffDeltaBlock:^{
return *(git_diff_get_delta(diff.git_diff, deltaIndex));
} patchGeneratorBlock:^(git_patch **patch) {
return git_patch_from_diff(patch, diff.git_diff, deltaIndex);
}];
}
- (instancetype)initWithGitDiffDeltaBlock:(git_diff_delta (^)(void))deltaAccessor patchGeneratorBlock:(int (^)(git_patch **patch))patchGenerator {
NSCParameterAssert(deltaAccessor != nil);
NSCParameterAssert(patchGenerator != nil);
self = [super init];
if (self == nil) return nil;
_deltaAccessor = [deltaAccessor copy];
_patchGenerator = [patchGenerator copy];
return self;
}
#pragma mark Patch Generation
- (GTDiffPatch *)generatePatch:(NSError **)error {
git_patch *patch = NULL;
int gitError = self.patchGenerator(&patch);
if (gitError != GIT_OK) {
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Patch generation failed for delta %@", self];
return nil;
}
return [[GTDiffPatch alloc] initWithGitPatch:patch delta:self];
}
#pragma mark NSObject
- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p>{ flags: %u, oldFile: %@, newFile: %@ }", self.class, self, (unsigned)self.git_diff_delta.flags, self.oldFile, self.newFile];
}
@end