Merge branch 'fix_interspacing'
[GitX.git] / PBGitRepository.m
blobfc7b66fb5c00a34d9d4c3d3e2759e7438d75918e
1 //
2 //  PBGitRepository.m
3 //  GitTest
4 //
5 //  Created by Pieter de Bie on 13-06-08.
6 //  Copyright 2008 __MyCompanyName__. All rights reserved.
7 //
9 #import "PBGitRepository.h"
10 #import "PBGitCommit.h"
11 #import "PBDetailController.h"
13 #import "NSFileHandleExt.h"
14 #import "PBEasyPipe.h"
16 NSString* PBGitRepositoryErrorDomain = @"GitXErrorDomain";
18 @implementation PBGitRepository
20 @synthesize revisionList, branches, currentBranch;
21 static NSString* gitPath;
23 + (void) initialize
25         // Try to find the path of the Git binary
26         char* path = getenv("GIT_PATH");
27         if (path != nil) {
28                 gitPath = [NSString stringWithCString:path];
29                 return;
30         }
31         
32         // No explicit path. Try it with "which"
33         gitPath = [PBEasyPipe outputForCommand:@"/usr/bin/which" withArgs:[NSArray arrayWithObject:@"git"]];
34         if (gitPath.length > 0)
35                 return;
36         
37         // Still no path. Let's try some default locations.
38         NSArray* locations = [NSArray arrayWithObjects:@"/opt/local/bin/git", @"/sw/bin/git", @"/opt/git/bin/git", nil];
39         for (NSString* location in locations) {
40                 if ([[NSFileManager defaultManager] fileExistsAtPath:location]) {
41                         gitPath = location;
42                         return;
43                 }
44         }
45         
46         NSLog(@"Could not find a git binary!");
49 - (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
51         if (outError) {
52                 *outError = [NSError errorWithDomain:PBGitRepositoryErrorDomain
53                                       code:0
54                                   userInfo:[NSDictionary dictionaryWithObject:@"Reading files is not supported." forKey:NSLocalizedFailureReasonErrorKey]];
55         }
56         return NO;
59 + (NSURL*)gitDirForURL:(NSURL*)repositoryURL;
61         NSString* repositoryPath = [repositoryURL path];
62         NSURL* gitDirURL         = nil;
64         if ([repositoryPath hasSuffix:@".git"]) {
65                 gitDirURL = [NSURL fileURLWithPath:repositoryPath];
66         } else {
67                 // Use rev-parse to find the .git dir for the repository being opened
68                 NSString* newPath = [PBEasyPipe outputForCommand:gitPath withArgs:[NSArray arrayWithObjects:@"rev-parse", @"--git-dir", nil] inDir:repositoryPath];
69                 if ([newPath isEqualToString:@".git"]) {
70                         gitDirURL = [NSURL fileURLWithPath:[repositoryPath stringByAppendingPathComponent:@".git"]];
71                 } else if ([newPath length] > 0) {
72                         gitDirURL = [NSURL fileURLWithPath:newPath];
73                 }
74         }
76         return gitDirURL;
79 // For a given path inside a repository, return either the .git dir
80 // (for a bare repo) or the directory above the .git dir otherwise
81 + (NSURL*)baseDirForURL:(NSURL*)repositoryURL;
83         NSURL* gitDirURL         = [self gitDirForURL:repositoryURL];
84         NSString* repositoryPath = [gitDirURL path];
86         if (![[PBEasyPipe outputForCommand:gitPath withArgs:[NSArray arrayWithObjects:@"rev-parse", @"--is-bare-repository", nil] inDir:repositoryPath] isEqualToString:@"true"]) {
87                 repositoryURL = [NSURL fileURLWithPath:[[repositoryURL path] stringByDeletingLastPathComponent]];
88         }
90         return repositoryURL;
93 - (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError **)outError
95         BOOL success = NO;
97         if (![fileWrapper isDirectory]) {
98                 if (outError) {
99                         NSDictionary* userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Reading files is not supported.", [fileWrapper filename]]
100                                                               forKey:NSLocalizedRecoverySuggestionErrorKey];
101                         *outError = [NSError errorWithDomain:PBGitRepositoryErrorDomain code:0 userInfo:userInfo];
102                 }
103         } else {
104                 NSURL* gitDirURL = [PBGitRepository gitDirForURL:[self fileURL]];
105                 if (gitDirURL) {
106                         [self setFileURL:gitDirURL];
107                         success = YES;
108                 } else if (outError) {
109                         NSDictionary* userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"%@ does not appear to be a git repository.", [fileWrapper filename]]
110                                                               forKey:NSLocalizedRecoverySuggestionErrorKey];
111                         *outError = [NSError errorWithDomain:PBGitRepositoryErrorDomain code:0 userInfo:userInfo];
112                 }
114                 if (success) {
115                         [self readBranches];
116                         [self readCurrentBranch];
117                         revisionList = [[PBGitRevList alloc] initWithRepository:self andRevListParameters:[NSArray array]];
118                 }
119         }
121         return success;
124 // The fileURL the document keeps is to the .git dir, but that’s pretty
125 // useless for display in the window title bar, so we show the directory above
126 - (NSString*)displayName
128         NSString* displayName = self.fileURL.path.lastPathComponent;
129         if ([displayName isEqualToString:@".git"])
130                 displayName = [self.fileURL.path stringByDeletingLastPathComponent].lastPathComponent;
131         return displayName;
134 // Overridden to create our custom window controller
135 - (void)makeWindowControllers
137         PBDetailController* controller = [[PBDetailController alloc] initWithRepository:self];
138         [self addWindowController:controller];
139         [controller release];
142 - (void) readBranches
144         NSString* output = [PBEasyPipe outputForCommand:gitPath withArgs:[NSArray arrayWithObjects:@"for-each-ref", @"refs/heads", nil] inDir: self.fileURL.path];
145         NSArray* lines = [output componentsSeparatedByString:@"\n"];
146         NSMutableArray* newBranches = [NSMutableArray array];
147         for (NSString* line in lines) {
148                 NSString* substr = [line substringWithRange: NSMakeRange(40,19)];
149                 if (![substr isEqualToString:@" commit\trefs/heads/"]) {
150                         NSLog(@"Cannot parse branch %@. (%@)", line, substr);
151                         continue;
152                 }
153                 NSString* branch = [line substringFromIndex:59];
154                 [newBranches addObject: branch];
155         }
156         self.branches = newBranches;
159 - (void) readCurrentBranch
161         NSString* branch = [self parseSymbolicReference: @"HEAD"];
162         if (branch && [branch hasPrefix:@"refs/heads/"])
163                 self.currentBranch = [branch substringFromIndex:11];
167 - (NSFileHandle*) handleForArguments:(NSArray *)args
169         NSString* gitDirArg = [@"--git-dir=" stringByAppendingString:self.fileURL.path];
170         NSMutableArray* arguments =  [NSMutableArray arrayWithObject: gitDirArg];
171         [arguments addObjectsFromArray: args];
172         return [PBEasyPipe handleForCommand:gitPath withArgs:arguments];
175 - (NSFileHandle*) handleForCommand:(NSString *)cmd
177         NSArray* arguments = [cmd componentsSeparatedByString:@" "];
178         return [self handleForArguments:arguments];
181 - (NSString*) outputForCommand:(NSString *)cmd
183         NSArray* arguments = [cmd componentsSeparatedByString:@" "];
184         return [self outputForArguments: arguments];
187 - (NSString*) outputForArguments:(NSArray*) arguments
189         return [PBEasyPipe outputForCommand:gitPath withArgs:arguments inDir: self.fileURL.path];
192 - (NSString*) parseReference:(NSString *)reference
194         return [self outputForArguments:[NSArray arrayWithObjects: @"rev-parse", reference, nil]];
197 - (NSString*) parseSymbolicReference:(NSString*) reference
199         NSString* ref = [self outputForArguments:[NSArray arrayWithObjects: @"symbolic-ref", reference, nil]];
200         if ([ref hasPrefix:@"refs/"])
201                 return ref;
203         return nil;
205 @end