mirror of
https://github.com/kennethreitz-archive/gitx.git
synced 2026-06-05 15:30:18 +00:00
385 lines
10 KiB
Objective-C
385 lines
10 KiB
Objective-C
//
|
|
// PBGitTree.m
|
|
// GitTest
|
|
//
|
|
// Created by Pieter de Bie on 15-06-08.
|
|
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
|
//
|
|
|
|
#import "PBGitTree.h"
|
|
#import "PBGitCommit.h"
|
|
#import "NSFileHandleExt.h"
|
|
#import "PBEasyPipe.h"
|
|
#import "PBEasyFS.h"
|
|
|
|
@implementation PBGitTree
|
|
|
|
@synthesize sha, path, repository, leaf, parent;
|
|
@synthesize filterPredicate;
|
|
@synthesize filteredChildren;
|
|
|
|
#pragma mark -
|
|
#pragma mark get/set
|
|
|
|
- (NSArray *) filteredChildren {
|
|
if (!filteredChildren) {
|
|
filteredChildren = [[NSMutableArray alloc] init];
|
|
[filteredChildren addObjectsFromArray:self.children];
|
|
}
|
|
return filteredChildren;
|
|
}
|
|
|
|
- (void) setFilterPredicate:(NSPredicate *) newPredicate {
|
|
if (newPredicate != filterPredicate) {
|
|
[filterPredicate release];
|
|
filterPredicate = [newPredicate retain];
|
|
|
|
if (leaf) {
|
|
return;
|
|
}
|
|
|
|
// initiate filtering
|
|
[filteredChildren removeAllObjects];
|
|
filteredChildren = [[NSMutableArray alloc] init];
|
|
|
|
if (filterPredicate == nil) {
|
|
[filteredChildren addObjectsFromArray:self.children];
|
|
}
|
|
|
|
for (id item in self.children) {
|
|
[item setFilterPredicate:filterPredicate];
|
|
if (filterPredicate) {
|
|
if ([item leaf]) {
|
|
if ([filterPredicate evaluateWithObject:item]) {
|
|
[filteredChildren addObject:item];
|
|
}
|
|
} else {
|
|
if ([[item filteredChildren] count] > 0) {
|
|
[filteredChildren addObject:item];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
+ (PBGitTree*) rootForCommit:(id) commit
|
|
{
|
|
PBGitCommit* c = commit;
|
|
PBGitTree* tree = [[self alloc] init];
|
|
tree.parent = nil;
|
|
tree.leaf = NO;
|
|
tree.sha = [c realSha];
|
|
tree.repository = c.repository;
|
|
tree.path = @"";
|
|
return tree;
|
|
}
|
|
|
|
+ (PBGitTree*) treeForTree: (PBGitTree*) prev andPath: (NSString*) path;
|
|
{
|
|
PBGitTree* tree = [[self alloc] init];
|
|
tree.parent = prev;
|
|
tree.sha = prev.sha;
|
|
tree.repository = prev.repository;
|
|
tree.path = path;
|
|
return tree;
|
|
}
|
|
|
|
- init
|
|
{
|
|
filteredChildren = nil;
|
|
children = nil;
|
|
localFileName = nil;
|
|
leaf = YES;
|
|
return self;
|
|
}
|
|
|
|
- (NSString*) refSpec
|
|
{
|
|
return [NSString stringWithFormat:@"%@:%@", self.sha, self.fullPath];
|
|
}
|
|
|
|
- (BOOL) isLocallyCached
|
|
{
|
|
NSFileManager* fs = [NSFileManager defaultManager];
|
|
if (localFileName && [fs fileExistsAtPath:localFileName])
|
|
{
|
|
NSDate* mtime = [[fs attributesOfItemAtPath:localFileName error: nil] objectForKey:NSFileModificationDate];
|
|
if ([mtime compare:localMtime] == 0)
|
|
return YES;
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL)hasBinaryAttributes
|
|
{
|
|
// First ask git check-attr if the file has a binary attribute custom set
|
|
NSFileHandle *handle = [repository handleInWorkDirForArguments:[NSArray arrayWithObjects:@"check-attr", @"binary", [self fullPath], nil]];
|
|
NSData *data = [handle readDataToEndOfFile];
|
|
NSString *string = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding];
|
|
|
|
if (!string)
|
|
return NO;
|
|
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
|
|
|
|
if ([string hasSuffix:@"binary: set"])
|
|
return YES;
|
|
|
|
if ([string hasSuffix:@"binary: unset"])
|
|
return NO;
|
|
|
|
// Binary state unknown, do a check on common filename-extensions
|
|
for (NSString *extension in [NSArray arrayWithObjects:@".pdf", @".jpg", @".jpeg", @".png", @".bmp", @".gif", @".o", nil]) {
|
|
if ([[self fullPath] hasSuffix:extension])
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (NSString*) contents
|
|
{
|
|
if (!leaf)
|
|
return [NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]];
|
|
|
|
if ([self isLocallyCached]) {
|
|
NSData *data = [NSData dataWithContentsOfFile:localFileName];
|
|
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
if (!string)
|
|
string = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding];
|
|
return string;
|
|
}
|
|
|
|
return [repository outputForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]];
|
|
}
|
|
|
|
- (NSString *) blame:(NSError **)anError
|
|
{
|
|
NSString *error=nil;
|
|
NSString *res=nil;
|
|
if (!leaf)
|
|
error=[NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]];
|
|
|
|
if ([self hasBinaryAttributes])
|
|
error=[NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [self fileSize]];
|
|
|
|
if ([self fileSize] > 52428800) // ~50MB
|
|
error=[NSString stringWithFormat:@"%@ is too big to be displayed (%d bytes)", [self fullPath], [self fileSize]];
|
|
|
|
if(error==nil){
|
|
res=[repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"blame", @"-p", sha, @"--", [self fullPath], nil]];
|
|
}else{
|
|
if (anError != NULL) {
|
|
*anError = [NSError errorWithDomain:@"blame" code:1 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:error,NSLocalizedDescriptionKey,nil]];
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
- (NSString *) log:(NSString *)format error:(NSError **)anError
|
|
{
|
|
NSString *error=nil;
|
|
NSString *res=nil;
|
|
if (!leaf)
|
|
error=[NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]];
|
|
|
|
if(error==nil){
|
|
res=[repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"log", [NSString stringWithFormat:@"--pretty=format:%@",format], @"--", [self fullPath], nil]];
|
|
}else{
|
|
if (anError != NULL) {
|
|
*anError = [NSError errorWithDomain:@"log" code:1 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:error,NSLocalizedDescriptionKey,nil]];
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
- (NSString *) diff:(NSString *)format error:(NSError **)anError
|
|
{
|
|
NSString *error=nil;
|
|
NSString *res=nil;
|
|
if (!leaf)
|
|
error=[NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]];
|
|
|
|
if ([self hasBinaryAttributes])
|
|
error=[NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [self fileSize]];
|
|
|
|
if ([self fileSize] > 52428800) // ~50MB
|
|
error=[NSString stringWithFormat:@"%@ is too big to be displayed (%d bytes)", [self fullPath], [self fileSize]];
|
|
|
|
if(error==nil){
|
|
NSString *des=@"";
|
|
if(format==@"p") {
|
|
des=[NSString stringWithFormat:@"%@^",sha];
|
|
}else if(format==@"h") {
|
|
des=@"HEAD";
|
|
}else{
|
|
des=@"--";
|
|
}
|
|
res=[repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff", sha, des,[self fullPath], nil]];
|
|
if ([res length]==0) {
|
|
DLog(@"--%@",[res length]);
|
|
if (anError != NULL) {
|
|
*anError = [NSError errorWithDomain:@"diff" code:1 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"No Diff",NSLocalizedDescriptionKey,nil]];
|
|
}
|
|
}else{
|
|
DLog(@"--%@",[res substringToIndex:80]);
|
|
}
|
|
}else{
|
|
if (anError != NULL) {
|
|
*anError = [NSError errorWithDomain:@"diff" code:1 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:error,NSLocalizedDescriptionKey,nil]];
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
- (NSString *)textContents:(NSError **)anError
|
|
{
|
|
NSString *error=nil;
|
|
NSString *res=nil;
|
|
if (!leaf)
|
|
error=[NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]];
|
|
|
|
if ([self hasBinaryAttributes])
|
|
error=[NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [self fileSize]];
|
|
|
|
if ([self fileSize] > 52428800) // ~50MB
|
|
error=[NSString stringWithFormat:@"%@ is too big to be displayed (%d bytes)", [self fullPath], [self fileSize]];
|
|
|
|
if(error==nil){
|
|
res = [self contents];
|
|
}else{
|
|
if (anError != NULL) {
|
|
*anError = [NSError errorWithDomain:@"show" code:1 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:error,NSLocalizedDescriptionKey,nil]];
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
- (long long)fileSize
|
|
{
|
|
if (_fileSize)
|
|
return _fileSize;
|
|
|
|
NSFileHandle *handle = [repository handleForArguments:[NSArray arrayWithObjects:@"cat-file", @"-s", [self refSpec], nil]];
|
|
NSString *sizeString = [[NSString alloc] initWithData:[handle readDataToEndOfFile] encoding:NSISOLatin1StringEncoding];
|
|
|
|
if (!sizeString)
|
|
_fileSize = -1;
|
|
else
|
|
_fileSize = [sizeString longLongValue];
|
|
|
|
return _fileSize;
|
|
}
|
|
|
|
- (void) saveToFolder: (NSString *) dir
|
|
{
|
|
NSString* newName = [dir stringByAppendingPathComponent:path];
|
|
|
|
if (leaf) {
|
|
NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]];
|
|
NSData* data = [handle readDataToEndOfFile];
|
|
[data writeToFile:newName atomically:YES];
|
|
} else { // Directory
|
|
[[NSFileManager defaultManager] createDirectoryAtPath:newName withIntermediateDirectories:YES attributes:nil error:nil];
|
|
for (PBGitTree* child in [self children])
|
|
[child saveToFolder: newName];
|
|
}
|
|
}
|
|
|
|
- (NSString*) tmpDirWithContents
|
|
{
|
|
if (leaf)
|
|
return nil;
|
|
|
|
if (!localFileName)
|
|
localFileName = [PBEasyFS tmpDirWithPrefix: path];
|
|
|
|
for (PBGitTree* child in [self children]) {
|
|
[child saveToFolder: localFileName];
|
|
}
|
|
|
|
return localFileName;
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) tmpFileNameForContents
|
|
{
|
|
if (!leaf)
|
|
return [self tmpDirWithContents];
|
|
|
|
if ([self isLocallyCached])
|
|
return localFileName;
|
|
|
|
if (!localFileName)
|
|
localFileName = [[PBEasyFS tmpDirWithPrefix: sha] stringByAppendingPathComponent:path];
|
|
|
|
NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]];
|
|
NSData* data = [handle readDataToEndOfFile];
|
|
[data writeToFile:localFileName atomically:YES];
|
|
|
|
NSFileManager* fs = [NSFileManager defaultManager];
|
|
localMtime = [[fs attributesOfItemAtPath:localFileName error: nil] objectForKey:NSFileModificationDate];
|
|
|
|
return localFileName;
|
|
}
|
|
|
|
- (NSArray*) children
|
|
{
|
|
if (children != nil)
|
|
return children;
|
|
|
|
NSString* ref = [self refSpec];
|
|
|
|
NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", ref, nil]];
|
|
[handle readLine];
|
|
[handle readLine];
|
|
|
|
NSMutableArray* c = [NSMutableArray array];
|
|
|
|
NSString* p = [handle readLine];
|
|
while (p.length > 0) {
|
|
BOOL isLeaf = ([p characterAtIndex:p.length - 1] != '/');
|
|
if (!isLeaf)
|
|
p = [p substringToIndex:p.length -1];
|
|
|
|
PBGitTree* child = [PBGitTree treeForTree:self andPath:p];
|
|
child.leaf = isLeaf;
|
|
[c addObject: child];
|
|
|
|
p = [handle readLine];
|
|
}
|
|
children = c;
|
|
return c;
|
|
}
|
|
|
|
- (NSString*) fullPath
|
|
{
|
|
if (!parent)
|
|
return @"";
|
|
|
|
if ([parent.fullPath isEqualToString:@""])
|
|
return self.path;
|
|
|
|
return [parent.fullPath stringByAppendingPathComponent: self.path];
|
|
}
|
|
|
|
- (void) finalize
|
|
{
|
|
if (localFileName)
|
|
[[NSFileManager defaultManager] removeItemAtPath:localFileName error:nil];
|
|
[super finalize];
|
|
}
|
|
|
|
- (BOOL)isEqualTo:(PBGitTree *)object
|
|
{
|
|
return [sha isEqualTo:[object sha]] && [[self fullPath] isEqualTo:[object fullPath]];
|
|
}
|
|
@end
|