mirror of
https://github.com/kennethreitz-archive/gitx.git
synced 2026-06-05 23:40:18 +00:00
238 lines
6.4 KiB
Plaintext
238 lines
6.4 KiB
Plaintext
//
|
|
// 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"
|
|
|
|
#include <ext/stdio_filebuf.h>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <map>
|
|
|
|
using namespace std;
|
|
|
|
|
|
@interface PBGitRevList ()
|
|
|
|
@property (assign) BOOL isParsing;
|
|
|
|
@end
|
|
|
|
|
|
#define kRevListThreadKey @"thread"
|
|
#define kRevListRevisionsKey @"revisions"
|
|
|
|
|
|
@implementation PBGitRevList
|
|
|
|
@synthesize commits;
|
|
@synthesize isParsing;
|
|
|
|
|
|
- (id) initWithRepository:(PBGitRepository *)repo rev:(PBGitRevSpecifier *)rev shouldGraph:(BOOL)graph
|
|
{
|
|
repository = repo;
|
|
isGraphing = graph;
|
|
currentRev = [rev copy];
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
- (void) loadRevisons
|
|
{
|
|
[parseThread cancel];
|
|
|
|
parseThread = [[NSThread alloc] initWithTarget:self selector:@selector(walkRevisionListWithSpecifier:) object:currentRev];
|
|
self.isParsing = YES;
|
|
resetCommits = YES;
|
|
[parseThread start];
|
|
}
|
|
|
|
|
|
- (void)cancel
|
|
{
|
|
[parseThread cancel];
|
|
}
|
|
|
|
|
|
- (void) finishedParsing
|
|
{
|
|
self.isParsing = NO;
|
|
}
|
|
|
|
|
|
- (void) updateCommits:(NSDictionary *)update
|
|
{
|
|
if ([update objectForKey:kRevListThreadKey] != parseThread)
|
|
return;
|
|
|
|
NSArray *revisions = [update objectForKey:kRevListRevisionsKey];
|
|
if (!revisions || [revisions count] == 0)
|
|
return;
|
|
|
|
if (resetCommits) {
|
|
self.commits = [NSMutableArray array];
|
|
resetCommits = NO;
|
|
}
|
|
|
|
NSRange range = NSMakeRange([commits count], [revisions count]);
|
|
NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:range];
|
|
|
|
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:@"commits"];
|
|
[commits addObjectsFromArray:revisions];
|
|
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:@"commits"];
|
|
}
|
|
|
|
|
|
- (void) walkRevisionListWithSpecifier:(PBGitRevSpecifier*)rev
|
|
{
|
|
NSDate *start = [NSDate date];
|
|
NSDate *lastUpdate = [NSDate date];
|
|
NSMutableArray *revisions = [NSMutableArray array];
|
|
PBGitGrapher *g = [[PBGitGrapher alloc] initWithRepository:repository];
|
|
std::map<string, NSStringEncoding> encodingMap;
|
|
NSThread *currentThread = [NSThread currentThread];
|
|
|
|
NSString *formatString = @"--pretty=format:%H\01%e\01%aN\01%cN\01%P\01%at\01%s";
|
|
BOOL showSign = [rev hasLeftRight];
|
|
|
|
if (showSign)
|
|
formatString = [@"%m\01" stringByAppendingString:formatString];
|
|
|
|
NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"log", @"-z", @"--topo-order", @"--children", formatString, nil];
|
|
|
|
if (!rev)
|
|
[arguments addObject:@"HEAD"];
|
|
else
|
|
[arguments addObjectsFromArray:[rev parameters]];
|
|
|
|
NSString *directory = rev.workingDirectory ? rev.workingDirectory.path : repository.fileURL.path;
|
|
NSTask *task = [PBEasyPipe taskForCommand:[PBGitBinary path] withArgs:arguments inDir:directory];
|
|
[task launch];
|
|
NSFileHandle *handle = [task.standardOutput fileHandleForReading];
|
|
|
|
int fd = [handle fileDescriptor];
|
|
__gnu_cxx::stdio_filebuf<char> buf(fd, std::ios::in);
|
|
std::istream stream(&buf);
|
|
|
|
int num = 0;
|
|
while (true) {
|
|
if ([currentThread isCancelled])
|
|
break;
|
|
|
|
char c;
|
|
char sign;
|
|
if (showSign)
|
|
{
|
|
stream >> sign;
|
|
stream >> c; // Remove separator
|
|
if (sign != '>' && sign != '<' && sign != '^' && sign != '-')
|
|
DLog(@"Error loading commits: sign not correct");
|
|
}
|
|
|
|
string sha;
|
|
if (!getline(stream, sha, '\1'))
|
|
break;
|
|
|
|
// From now on, 1.2 seconds
|
|
string encoding_str;
|
|
getline(stream, encoding_str, '\1');
|
|
NSStringEncoding encoding = NSUTF8StringEncoding;
|
|
if (encoding_str.length())
|
|
{
|
|
if (encodingMap.find(encoding_str) != encodingMap.end()) {
|
|
encoding = encodingMap[encoding_str];
|
|
} else {
|
|
encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)[NSString stringWithUTF8String:encoding_str.c_str()]));
|
|
encodingMap[encoding_str] = encoding;
|
|
}
|
|
}
|
|
|
|
NSString *oid=[NSString stringWithCString:sha.c_str() encoding:encoding];
|
|
if([oid length]!=40)
|
|
break;
|
|
|
|
PBGitCommit *newCommit = [PBGitCommit commitWithRepository:repository andSha:oid];
|
|
|
|
if (showSign)
|
|
[newCommit setSign: sign];
|
|
|
|
string author;
|
|
getline(stream, author, '\1');
|
|
|
|
string committer;
|
|
getline(stream, committer, '\1');
|
|
|
|
string parentString;
|
|
getline(stream, parentString, '\1');
|
|
|
|
if (parentString.size() != 0)
|
|
{
|
|
if (((parentString.size() + 1) % 41) != 0) {
|
|
DLog(@"invalid parents: %zu", parentString.size());
|
|
continue;
|
|
}
|
|
int nParents = (parentString.size() + 1) / 41;
|
|
NSMutableArray *parents = [NSMutableArray arrayWithCapacity:nParents];
|
|
int parentIndex;
|
|
for (parentIndex = 0; parentIndex < nParents; ++parentIndex) {
|
|
NSString *pOid=[NSString stringWithCString:parentString.substr(parentIndex * 41, 40).c_str() encoding:encoding];
|
|
[parents addObject:pOid];
|
|
}
|
|
[newCommit setParents:parents];
|
|
}
|
|
|
|
int time;
|
|
stream >> time;
|
|
|
|
string subject;
|
|
getline(stream, subject, '\0');
|
|
|
|
[newCommit setSubject:[NSString stringWithCString:subject.c_str() encoding:encoding]];
|
|
[newCommit setAuthor:[NSString stringWithCString:author.c_str() encoding:encoding]];
|
|
[newCommit setCommitter:[NSString stringWithCString:committer.c_str() encoding:encoding]];
|
|
[newCommit setTimestamp:time];
|
|
|
|
[revisions addObject: newCommit];
|
|
if (isGraphing)
|
|
[g decorateCommit:newCommit];
|
|
|
|
if (++num % 100 == 0) {
|
|
if ([[NSDate date] timeIntervalSinceDate:lastUpdate] > 0.1) {
|
|
NSDictionary *update = [NSDictionary dictionaryWithObjectsAndKeys:currentThread, kRevListThreadKey, revisions, kRevListRevisionsKey, nil];
|
|
[self performSelectorOnMainThread:@selector(updateCommits:) withObject:update waitUntilDone:NO];
|
|
revisions = [NSMutableArray array];
|
|
lastUpdate = [NSDate date];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (![currentThread isCancelled]) {
|
|
NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:start];
|
|
DLog(@"Loaded %i commits in %f seconds (%f/sec)", num, duration, num/duration);
|
|
|
|
// Make sure the commits are stored before exiting.
|
|
NSDictionary *update = [NSDictionary dictionaryWithObjectsAndKeys:currentThread, kRevListThreadKey, revisions, kRevListRevisionsKey, nil];
|
|
[self performSelectorOnMainThread:@selector(updateCommits:) withObject:update waitUntilDone:YES];
|
|
|
|
[self performSelectorOnMainThread:@selector(finishedParsing) withObject:nil waitUntilDone:NO];
|
|
}
|
|
else {
|
|
DLog(@"[%@ %@] thread has been canceled", [self class], NSStringFromSelector(_cmd));
|
|
}
|
|
|
|
[task terminate];
|
|
[task waitUntilExit];
|
|
}
|
|
|
|
@end
|