PBGitRepository: Abstract revision walking to new class PBGitRevList

The revision walking code made the PBGitRepository unclean. Especially if
we want to keep multiple PBGitRepository objects around (e.g. persistent
data store), it needs to be more simple. This neatly extracts the revision
walking code from the repository code.
This commit is contained in:
Pieter de Bie
2008-06-17 19:32:38 +02:00
parent 447a8dc48c
commit ede8892dc9
7 changed files with 1131 additions and 1089 deletions
+997 -997
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -31,6 +31,7 @@
F5945E170E02B0C200706420 /* PBGitRepository.m in Sources */ = {isa = PBXBuildFile; fileRef = F5945E160E02B0C200706420 /* PBGitRepository.m */; };
F5B721C40E05CF7E00AF29DC /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F5B721C20E05CF7E00AF29DC /* MainMenu.xib */; };
F5DFFA6C0E075D8800617813 /* PBEasyFS.m in Sources */ = {isa = PBXBuildFile; fileRef = F5DFFA6B0E075D8800617813 /* PBEasyFS.m */; };
F5FF4E180E0829C20006317A /* PBGitRevList.m in Sources */ = {isa = PBXBuildFile; fileRef = F5FF4E170E0829C20006317A /* PBGitRevList.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -76,6 +77,8 @@
F5B721C30E05CF7E00AF29DC /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; };
F5DFFA6A0E075D8800617813 /* PBEasyFS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBEasyFS.h; sourceTree = "<group>"; };
F5DFFA6B0E075D8800617813 /* PBEasyFS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBEasyFS.m; sourceTree = "<group>"; };
F5FF4E160E0829C20006317A /* PBGitRevList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitRevList.h; sourceTree = "<group>"; };
F5FF4E170E0829C20006317A /* PBGitRevList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitRevList.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -188,6 +191,8 @@
F56524EF0E02D45200F03B52 /* PBGitCommit.m */,
F56174550E058893001DCD79 /* PBGitTree.h */,
F56174560E058893001DCD79 /* PBGitTree.m */,
F5FF4E160E0829C20006317A /* PBGitRevList.h */,
F5FF4E170E0829C20006317A /* PBGitRevList.m */,
);
name = Git;
sourceTree = "<group>";
@@ -311,6 +316,7 @@
F513085B0E0740F2000C8BCD /* PBQLOutlineView.m in Sources */,
F5DFFA6C0E075D8800617813 /* PBEasyFS.m in Sources */,
F50FE0E30E07BE9600854FCD /* PBGitRevisionCell.m in Sources */,
F5FF4E180E0829C20006317A /* PBGitRevList.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+3 -2
View File
@@ -7,10 +7,11 @@
//
#import <Cocoa/Cocoa.h>
#import "PBGitRevList.h"
@interface PBGitRepository : NSObject {
NSString* path;
NSArray* commits;
PBGitRevList* revisionList;
}
+ (void) setGitPath;
@@ -24,6 +25,6 @@
- (void) addCommit: (id)obj;
@property (copy) NSString* path;
@property (retain) NSArray* commits;
@property (readonly) PBGitRevList* revisionList;
@end
+22 -89
View File
@@ -14,12 +14,30 @@
@implementation PBGitRepository
@synthesize path, commits;
static NSString* gitPath = @"/usr/bin/env";
@synthesize path;
static NSString* gitPath;
+ (void) initialize
{
// Try to find the path of the Git binary
char* path = getenv("GIT_PATH");
if (path != nil) {
gitPath = [NSString stringWithCString:path];
return;
}
// No explicit path. Try it with "which"
gitPath = [PBEasyPipe outputForCommand:@"/usr/bin/which" withArgs:[NSArray arrayWithObject:@"git"]];
if (gitPath.length == 0) {
NSLog(@"Git path not found. Defaulting to /opt/pieter/bin/git");
gitPath = @"/opt/pieter/bin/git";
}
}
+ (PBGitRepository*) repositoryWithPath:(NSString*) path
{
[self setGitPath];
PBGitRepository* repo = [[PBGitRepository alloc] initWithPath: path];
return repo;
}
@@ -37,96 +55,11 @@ static NSString* gitPath = @"/usr/bin/env";
}
NSLog(@"Git path is: %@", self.path);
NSThread * commitThread = [[NSThread alloc] initWithTarget: self selector: @selector(initializeCommits) object:nil];
[commitThread start];
revisionList = [[PBGitRevList alloc] initWithRepository:self andRevListParameters:[NSArray array]];
return self;
}
+ (void) setGitPath
{
char* path = getenv("GIT_PATH");
if (path != nil) {
gitPath = [NSString stringWithCString:path];
return;
}
// No explicit path. Try it with "which"
gitPath = [PBEasyPipe outputForCommand:@"/usr/bin/which" withArgs:[NSArray arrayWithObject:@"git"]];
if (gitPath.length == 0) {
NSLog(@"Git path not found. Defaulting to /opt/pieter/bin/git");
gitPath = @"/opt/pieter/bin/git";
}
}
- (void) addCommit: (id) obj
{
self.commits = [self.commits arrayByAddingObject:obj];
}
- (void) setCommits:(NSArray*) obj
{
commits = obj;
}
- (void) initializeCommits
{
NSMutableArray * newArray = [NSMutableArray array];
NSDate* start = [NSDate date];
NSFileHandle* handle = [self handleForCommand:@"log --pretty=format:%H\01%an\01%s\01%P\01%at HEAD"];
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;
}
// 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);
continue;
}
PBGitCommit* newCommit = [[PBGitCommit alloc] initWithRepository: self 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:3] intValue]];
[newArray addObject: newCommit];
num++;
if (num % 10000 == 0)
[self performSelectorOnMainThread:@selector(setCommits:) withObject:newArray waitUntilDone:NO];
currentLine = [NSMutableString string];
}
[self performSelectorOnMainThread:@selector(setCommits:) withObject:newArray waitUntilDone:YES];
NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:start];
NSLog(@"Loaded %i commits in %f seconds", num, duration);
[NSThread exit];
}
- (NSFileHandle*) handleForArguments:(NSArray *)args
{
NSString* gitDirArg = [@"--git-dir=" stringByAppendingString:path];
+21
View File
@@ -0,0 +1,21 @@
//
// PBGitRevList.h
// GitX
//
// Created by Pieter de Bie on 17-06-08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface PBGitRevList : NSObject {
NSArray* commits;
NSArray* parameters;
id repository;
}
- initWithRepository:(id)repo andRevListParameters:(NSArray*) params;
@property(retain) NSArray* commits;
@end
+81
View File
@@ -0,0 +1,81 @@
//
// 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"
@implementation PBGitRevList
@synthesize commits;
- initWithRepository: (id) repo andRevListParameters: (NSArray*) params
{
parameters = params;
repository = repo;
NSThread * commitThread = [[NSThread alloc] initWithTarget: self selector: @selector(walkRevisionList) object:nil];
[commitThread start];
return self;
}
- (void) walkRevisionList
{
NSMutableArray * newArray = [NSMutableArray array];
NSDate* start = [NSDate date];
NSFileHandle* handle = [repository handleForCommand:@"log --pretty=format:%H\01%an\01%s\01%P\01%at HEAD"];
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;
}
// 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);
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:3] intValue]];
[newArray addObject: newCommit];
num++;
if (num % 10000 == 0)
[self performSelectorOnMainThread:@selector(setCommits:) withObject:newArray waitUntilDone:NO];
currentLine = [NSMutableString string];
}
[self performSelectorOnMainThread:@selector(setCommits:) withObject:newArray waitUntilDone:YES];
NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:start];
NSLog(@"Loaded %i commits in %f seconds", num, duration);
[NSThread exit];
}
@end
+1 -1
View File
@@ -65,7 +65,7 @@
- (void) selectCommit: (NSString*) sha
{
NSPredicate* selection = [NSPredicate predicateWithFormat:@"sha == %@", sha];
NSArray* selectedCommits = [controller.repository.commits filteredArrayUsingPredicate:selection];
NSArray* selectedCommits = [controller.repository.revisionList.commits filteredArrayUsingPredicate:selection];
// TODO: reimplement this. How can we set the new commit? Our detailscontroller is read-only
}