5 // Created by Pieter de Bie on 15-06-08.
6 // Copyright 2008 __MyCompanyName__. All rights reserved.
10 #import "PBGitCommit.h"
11 #import "NSFileHandleExt.h"
12 #import "PBEasyPipe.h"
15 @implementation PBGitTree
17 @synthesize sha, path, repository, leaf, parent;
19 + (PBGitTree*) rootForCommit:(id) commit
21 PBGitCommit* c = commit;
22 PBGitTree* tree = [[self alloc] init];
25 tree.sha = [c realSha];
26 tree.repository = c.repository;
31 + (PBGitTree*) treeForTree: (PBGitTree*) prev andPath: (NSString*) path;
33 PBGitTree* tree = [[self alloc] init];
36 tree.repository = prev.repository;
51 return [NSString stringWithFormat:@"%@:%@", self.sha, self.fullPath];
54 - (BOOL) isLocallyCached
56 NSFileManager* fs = [NSFileManager defaultManager];
57 if (localFileName && [fs fileExistsAtPath:localFileName])
59 NSDate* mtime = [[fs attributesOfItemAtPath:localFileName error: nil] objectForKey:NSFileModificationDate];
60 if ([mtime compare:localMtime] == 0)
66 - (BOOL)hasBinaryHeader:(NSString*)contents
71 return [contents rangeOfString:@"\0" options:0 range:NSMakeRange(0, ([contents length] >= 8000) ? 7999 : [contents length])].location != NSNotFound;
74 - (BOOL)hasBinaryAttributes
76 // First ask git check-attr if the file has a binary attribute custom set
77 NSFileHandle *handle = [repository handleInWorkDirForArguments:[NSArray arrayWithObjects:@"check-attr", @"binary", [self fullPath], nil]];
78 NSData *data = [handle readDataToEndOfFile];
79 NSString *string = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding];
83 string = [string stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
85 if ([string hasSuffix:@"binary: set"])
88 if ([string hasSuffix:@"binary: unset"])
91 // Binary state unknown, do a check on common filename-extensions
92 for (NSString *extension in [NSArray arrayWithObjects:@".pdf", @".jpg", @".jpeg", @".png", @".bmp", @".gif", @".o", nil]) {
93 if ([[self fullPath] hasSuffix:extension])
100 - (NSString*) contents
103 return [NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]];
105 if ([self isLocallyCached]) {
106 NSData *data = [NSData dataWithContentsOfFile:localFileName];
107 NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
109 string = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding];
113 return [repository outputForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]];
116 - (long long)fileSize
121 NSFileHandle *handle = [repository handleForArguments:[NSArray arrayWithObjects:@"cat-file", @"-s", [self refSpec], nil]];
122 NSString *sizeString = [[NSString alloc] initWithData:[handle readDataToEndOfFile] encoding:NSISOLatin1StringEncoding];
127 _fileSize = [sizeString longLongValue];
132 - (NSString *)textContents
135 return [NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]];
137 if ([self hasBinaryAttributes])
138 return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [self fileSize]];
140 if ([self fileSize] > 52428800) // ~50MB
141 return [NSString stringWithFormat:@"%@ is too big to be displayed (%d bytes)", [self fullPath], [self fileSize]];
143 NSString* contents = [self contents];
145 if ([self hasBinaryHeader:contents])
146 return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [self fileSize]];
151 - (void) saveToFolder: (NSString *) dir
153 NSString* newName = [dir stringByAppendingPathComponent:path];
156 NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]];
157 NSData* data = [handle readDataToEndOfFile];
158 [data writeToFile:newName atomically:YES];
159 } else { // Directory
160 [[NSFileManager defaultManager] createDirectoryAtPath:newName attributes:nil];
161 for (PBGitTree* child in [self children])
162 [child saveToFolder: newName];
166 - (NSString*) tmpDirWithContents
172 localFileName = [PBEasyFS tmpDirWithPrefix: path];
174 for (PBGitTree* child in [self children]) {
175 [child saveToFolder: localFileName];
178 return localFileName;
183 - (NSString*) tmpFileNameForContents
186 return [self tmpDirWithContents];
188 if ([self isLocallyCached])
189 return localFileName;
192 localFileName = [[PBEasyFS tmpDirWithPrefix: sha] stringByAppendingPathComponent:path];
194 NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]];
195 NSData* data = [handle readDataToEndOfFile];
196 [data writeToFile:localFileName atomically:YES];
198 NSFileManager* fs = [NSFileManager defaultManager];
199 localMtime = [[fs attributesOfItemAtPath:localFileName error: nil] objectForKey:NSFileModificationDate];
201 return localFileName;
204 - (NSArray*) children
209 NSString* ref = [self refSpec];
211 NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", ref, nil]];
215 NSMutableArray* c = [NSMutableArray array];
217 NSString* p = [handle readLine];
218 while (p.length > 0) {
219 BOOL isLeaf = ([p characterAtIndex:p.length - 1] != '/');
221 p = [p substringToIndex:p.length -1];
223 PBGitTree* child = [PBGitTree treeForTree:self andPath:p];
225 [c addObject: child];
227 p = [handle readLine];
233 - (NSString*) fullPath
238 if ([parent.fullPath isEqualToString:@""])
241 return [parent.fullPath stringByAppendingPathComponent: self.path];
247 [[NSFileManager defaultManager] removeFileAtPath:localFileName handler:nil];