Files
gitx/PBGitRevList.m
T
Pieter de Bie 1f7d745bb9 RevList: Decorate commits in the same thread
This simplifies matters greatly, and shouldn't be a huge performance
decrease (unless you have > 2 cores, but even then). This also
fixes a bug with the new --early-output, where commits would show
multiple times because they were outputted twice.
2008-09-28 12:14:13 +02:00

162 lines
4.9 KiB
Objective-C

//
// PBGitRevList.m
// GitX
//
// Created by Pieter de Bie on 17-06-08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "PBGitRevList.h"
#import "PBGitRepository.h"
#import "PBGitCommit.h"
#import "PBGitGrapher.h"
#import "PBGitRevSpecifier.h"
@implementation PBGitRevList
@synthesize commits;
- initWithRepository: (id) repo
{
repository = repo;
[repository addObserver:self forKeyPath:@"currentBranch" options:0 context:nil];
return self;
}
- (void) reload
{
[self readCommitsForce: YES];
}
- (void) readCommitsForce: (BOOL) force
{
// We use refparse to get the commit sha that we will parse. That way,
// we can check if the current branch is the same as the previous one
// and in that case we don't have to reload the revision list.
// If no branch is selected, don't do anything
if (![repository currentBranch] || [[repository currentBranch] count] == 0)
return;
NSArray* selectedBranches = [[repository branches] objectsAtIndexes: [repository currentBranch]];
// Apparently, The selected index does not exist.. don't do anything
if ([selectedBranches count] == 0)
return;
PBGitRevSpecifier* newRev = [selectedBranches objectAtIndex:0];
NSString* newSha = nil;
if (!force && newRev && [newRev isSimpleRef]) {
newSha = [repository parseReference:[newRev simpleRef]];
if ([newSha isEqualToString:lastSha])
return;
}
lastSha = newSha;
NSThread * commitThread = [[NSThread alloc] initWithTarget: self selector: @selector(walkRevisionListWithSpecifier:) object:newRev];
[commitThread start];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
if (object == repository)
[self readCommitsForce: NO];
}
- (void) walkRevisionListWithSpecifier: (PBGitRevSpecifier*) rev
{
NSMutableArray* revisions = [NSMutableArray array];
PBGitGrapher* g = [[PBGitGrapher alloc] initWithRepository: repository];
NSDictionary* refs = [repository refs];
NSMutableArray* arguments;
BOOL showSign = [rev hasLeftRight];
if (showSign)
arguments = [NSMutableArray arrayWithObjects:@"log", @"--early-output", @"--topo-order", @"--pretty=format:%H\01%an\01%s\01%P\01%at\01%m", nil];
else
arguments = [NSMutableArray arrayWithObjects:@"log", @"--early-output", @"--topo-order", @"--pretty=format:%H\01%an\01%s\01%P\01%at", nil];
if (!rev)
[arguments addObject:@"HEAD"];
else
[arguments addObjectsFromArray:[rev parameters]];
if ([rev hasPathLimiter])
[arguments insertObject:@"--children" atIndex:1];
NSFileHandle* handle = [repository handleForArguments: arguments];
int fd = [handle fileDescriptor];
FILE* f = fdopen(fd, "r");
int BUFFERSIZE = 2048;
char buffer[BUFFERSIZE];
buffer[BUFFERSIZE - 2] = 0;
char* l;
int num = 0;
NSMutableString* currentLine = [NSMutableString string];
while (l = fgets(buffer, BUFFERSIZE, f)) {
NSString *s = [NSString stringWithCString:(const char *)l encoding:NSUTF8StringEncoding];
if ([s length] == 0)
s = [NSString stringWithCString:(const char *)l encoding:NSASCIIStringEncoding];
[currentLine appendString: s];
// If buffer is full, we go for another round
if (buffer[BUFFERSIZE - 2] != 0) {
//NSLog(@"Line too long!");
buffer[BUFFERSIZE - 2] = 0;
continue;
}
// We reached the end of some temporary output. Show what we have
// until now, and then start from the beginning.
if ([currentLine hasPrefix:@"Final output:"]) {
[self performSelectorOnMainThread:@selector(setCommits:) withObject:revisions waitUntilDone:NO];
g = [[PBGitGrapher alloc] initWithRepository: repository];
revisions = [NSMutableArray array];
currentLine = [NSMutableString string];
continue;
}
// If we are here, we currentLine is a full line.
NSArray* components = [currentLine componentsSeparatedByString:@"\01"];
if ([components count] < 5) {
NSLog(@"Can't split string: %@", currentLine);
currentLine = [NSMutableString string];
continue;
}
PBGitCommit* newCommit = [[PBGitCommit alloc] initWithRepository: repository andSha: [components objectAtIndex:0]];
NSArray* parents = [[components objectAtIndex:3] componentsSeparatedByString:@" "];
newCommit.parents = parents;
newCommit.subject = [components objectAtIndex:2];
newCommit.author = [components objectAtIndex:1];
newCommit.date = [NSDate dateWithTimeIntervalSince1970:[[components objectAtIndex:4] intValue]];
if (showSign)
newCommit.sign = [[components objectAtIndex:5] characterAtIndex:0];
[revisions addObject: newCommit];
[g decorateCommit: newCommit];
if (refs && [refs objectForKey:newCommit.sha])
newCommit.refs = [refs objectForKey:newCommit.sha];
if (++num % 1000 == 0)
[self performSelectorOnMainThread:@selector(setCommits:) withObject:revisions waitUntilDone:NO];
currentLine = [NSMutableString string];
}
// Make sure the commits are stored before exiting.
[self performSelectorOnMainThread:@selector(setCommits:) withObject:revisions waitUntilDone:YES];
[NSThread exit];
}
@end