Release notes for 0.6.3
[GitX.git] / PBGitRevList.mm
blobba39a3a9aca772bd8c26ffa0f7990b36f3d4aea9
1 //
2 //  PBGitRevList.m
3 //  GitX
4 //
5 //  Created by Pieter de Bie on 17-06-08.
6 //  Copyright 2008 __MyCompanyName__. All rights reserved.
7 //
9 #import "PBGitRevList.h"
10 #import "PBGitRepository.h"
11 #import "PBGitCommit.h"
12 #import "PBGitGrapher.h"
13 #import "PBGitRevSpecifier.h"
15 #include "git/oid.h"
16 #include <ext/stdio_filebuf.h>
17 #include <iostream>
18 #include <string>
20 using namespace std;
22 @implementation PBGitRevList
24 @synthesize commits;
25 - initWithRepository: (id) repo
27         repository = repo;
28         [repository addObserver:self forKeyPath:@"currentBranch" options:0 context:nil];
30         return self;
33 - (void) reload
35         [self readCommitsForce: YES];
38 - (void) readCommitsForce: (BOOL) force
40         // We use refparse to get the commit sha that we will parse. That way,
41         // we can check if the current branch is the same as the previous one
42         // and in that case we don't have to reload the revision list.
44         // If no branch is selected, don't do anything
45         if (![repository currentBranch])
46                 return;
48         PBGitRevSpecifier* newRev = [repository currentBranch];
49         NSString* newSha = nil;
51         if (!force && newRev && [newRev isSimpleRef]) {
52                 newSha = [repository parseReference:[newRev simpleRef]];
53                 if ([newSha isEqualToString:lastSha])
54                         return;
55         }
56         lastSha = newSha;
58         NSThread * commitThread = [[NSThread alloc] initWithTarget: self selector: @selector(walkRevisionListWithSpecifier:) object:newRev];
59         [commitThread start];
62 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
63         change:(NSDictionary *)change context:(void *)context
65         if (object == repository)
66                 [self readCommitsForce: NO];
69 - (void) walkRevisionListWithSpecifier: (PBGitRevSpecifier*) rev
71         NSDate *start = [NSDate date];
72         NSMutableArray* revisions = [NSMutableArray array];
73         PBGitGrapher* g = [[PBGitGrapher alloc] initWithRepository: repository];
75         NSMutableArray* arguments;
76         BOOL showSign = [rev hasLeftRight];
78         if (showSign)
79                 arguments = [NSMutableArray arrayWithObjects:@"log", @"-z", @"--early-output", @"--topo-order", @"--pretty=format:%H\01%an\01%s\01%P\01%at\01%m", nil];
80         else
81                 arguments = [NSMutableArray arrayWithObjects:@"log", @"-z", @"--early-output", @"--topo-order", @"--pretty=format:%H\01%an\01%s\01%P\01%at", nil];
83         if (!rev)
84                 [arguments addObject:@"HEAD"];
85         else
86                 [arguments addObjectsFromArray:[rev parameters]];
88         if ([rev hasPathLimiter])
89                 [arguments insertObject:@"--children" atIndex:1];
91         NSTask *task = [PBEasyPipe taskForCommand:[PBGitBinary path] withArgs:arguments inDir:[repository fileURL].path];
92         [task launch];
93         NSFileHandle* handle = [task.standardOutput fileHandleForReading];
94         
95         int fd = [handle fileDescriptor];
96         __gnu_cxx::stdio_filebuf<char> buf(fd, std::ios::in);
97         std::istream stream(&buf);
99         int num = 0;
100         while (true) {
101                 string sha;
102                 if (!getline(stream, sha, '\1'))
103                         break;
105                 // We reached the end of some temporary output. Show what we have
106                 // until now, and then start again. The sha of the next thing is still
107                 // in this buffer. So, we use a substring of current input.
108                 if (sha[1] == 'i') // Matches 'Final output'
109                 {
110                         num = 0;
111                         [self performSelectorOnMainThread:@selector(setCommits:) withObject:revisions waitUntilDone:NO];
112                         g = [[PBGitGrapher alloc] initWithRepository: repository];
113                         revisions = [NSMutableArray array];
114                         
115                         sha = sha.substr(sha.length() - 40, 40);
116                 }
118                 // From now on, 1.2 seconds
119                 git_oid oid;
120                 git_oid_mkstr(&oid, sha.c_str());
121                 PBGitCommit* newCommit = [[PBGitCommit alloc] initWithRepository:repository andSha:oid];
123                 string author;
124                 getline(stream, author, '\1');
126                 string subject;
127                 getline(stream, subject, '\1');
129                 string parentString;
130                 getline(stream, parentString, '\1');
131                 if (parentString.size() != 0)
132                 {
133                         if (((parentString.size() + 1) % 41) != 0) {
134                                 NSLog(@"invalid parents: %i", parentString.size());
135                                 continue;
136                         }
137                         int nParents = (parentString.size() + 1) / 41;
138                         git_oid *parents = (git_oid *)malloc(sizeof(git_oid) * nParents);
139                         int parentIndex;
140                         for (parentIndex = 0; parentIndex < nParents; ++parentIndex)
141                                 git_oid_mkstr(parents + parentIndex, parentString.substr(parentIndex * 41, 40).c_str());
142                         
143                         newCommit.parentShas = parents;
144                         newCommit.nParents = nParents;
145                 }
147                 int time;
148                 stream >> time;
150                 
151                 [newCommit setSubject:[NSString stringWithUTF8String:subject.c_str()]];
152                 [newCommit setAuthor:[NSString stringWithUTF8String:author.c_str()]];
153                 [newCommit setTimestamp:time];
154                 
155                 if (showSign)
156                 {
157                         char c;
158                         stream >> c; // Remove separator
159                         stream >> c;
160                         if (c != '>' && c != '<' && c != '^' && c != '-')
161                                 NSLog(@"Error loading commits: sign not correct");
162                         [newCommit setSign: c];
163                 }
165                 char c;
166                 stream >> c;
167                 if (c != '\0')
168                         cout << "Error" << endl;
170                 [revisions addObject: newCommit];
171                 [g decorateCommit: newCommit];
173                 if (++num % 1000 == 0)
174                         [self performSelectorOnMainThread:@selector(setCommits:) withObject:revisions waitUntilDone:NO];
175         }
176         
177         NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:start];
178         NSLog(@"Loaded %i commits in %f seconds", num, duration);
179         // Make sure the commits are stored before exiting.
180         [self performSelectorOnMainThread:@selector(setCommits:) withObject:revisions waitUntilDone:YES];
181         [task waitUntilExit];
184 @end