From 6531cfce3bc6b4bd55607304169809e2c3defcc8 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 01:59:28 +0200 Subject: [PATCH 01/24] Add a new class, PBGitIndex, which integrates functionality from both indexcontrollers --- GitX.xcodeproj/project.pbxproj | 18 +- PBGitIndex.h | 52 +++++ PBGitIndex.m | 345 +++++++++++++++++++++++++++++++++ 3 files changed, 413 insertions(+), 2 deletions(-) create mode 100644 PBGitIndex.h create mode 100644 PBGitIndex.m diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj index be97512..d091d92 100644 --- a/GitX.xcodeproj/project.pbxproj +++ b/GitX.xcodeproj/project.pbxproj @@ -97,6 +97,7 @@ F59116E90E843BCB0072CCB1 /* PBGitCommitController.m in Sources */ = {isa = PBXBuildFile; fileRef = F59116E80E843BCB0072CCB1 /* PBGitCommitController.m */; }; F593DF780E9E636C003A8559 /* PBFileChangesTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = F593DF770E9E636C003A8559 /* PBFileChangesTableView.m */; }; F5945E170E02B0C200706420 /* PBGitRepository.m in Sources */ = {isa = PBXBuildFile; fileRef = F5945E160E02B0C200706420 /* PBGitRepository.m */; }; + F59F1DD5105C4FF300115F88 /* PBGitIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = F59F1DD4105C4FF300115F88 /* PBGitIndex.m */; }; F5AD56790E79B78100EDAAFE /* PBCommitList.m in Sources */ = {isa = PBXBuildFile; fileRef = F5AD56780E79B78100EDAAFE /* PBCommitList.m */; }; F5B721C40E05CF7E00AF29DC /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F5B721C20E05CF7E00AF29DC /* MainMenu.xib */; }; F5C007750E731B48007B84B2 /* PBGitRef.m in Sources */ = {isa = PBXBuildFile; fileRef = F5C007740E731B48007B84B2 /* PBGitRef.m */; }; @@ -250,6 +251,8 @@ F593DF770E9E636C003A8559 /* PBFileChangesTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBFileChangesTableView.m; sourceTree = ""; }; F5945E150E02B0C200706420 /* PBGitRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitRepository.h; sourceTree = ""; }; F5945E160E02B0C200706420 /* PBGitRepository.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitRepository.m; sourceTree = ""; }; + F59F1DD3105C4FF300115F88 /* PBGitIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitIndex.h; sourceTree = ""; }; + F59F1DD4105C4FF300115F88 /* PBGitIndex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitIndex.m; sourceTree = ""; }; F5AD56770E79B78100EDAAFE /* PBCommitList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBCommitList.h; sourceTree = ""; }; F5AD56780E79B78100EDAAFE /* PBCommitList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBCommitList.m; sourceTree = ""; }; F5B721C30E05CF7E00AF29DC /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; @@ -467,6 +470,7 @@ F56174540E05887E001DCD79 /* Git */ = { isa = PBXGroup; children = ( + F59F1DD2105C4FDE00115F88 /* Index */, F5E927E30E883D6800056E75 /* Commit */, F5E927E10E883D2E00056E75 /* History */, F5945E150E02B0C200706420 /* PBGitRepository.h */, @@ -549,6 +553,17 @@ name = SpeedTest; sourceTree = ""; }; + F59F1DD2105C4FDE00115F88 /* Index */ = { + isa = PBXGroup; + children = ( + F5E927F60E883E7200056E75 /* PBChangedFile.h */, + F5E927F70E883E7200056E75 /* PBChangedFile.m */, + F59F1DD3105C4FF300115F88 /* PBGitIndex.h */, + F59F1DD4105C4FF300115F88 /* PBGitIndex.m */, + ); + name = Index; + sourceTree = ""; + }; F5B161BB0EAB6E0C005A1DE1 /* Diff */ = { isa = PBXGroup; children = ( @@ -604,8 +619,6 @@ children = ( 93F7857D0EA3ABF100C1F443 /* PBCommitMessageView.h */, 93F7857E0EA3ABF100C1F443 /* PBCommitMessageView.m */, - F5E927F60E883E7200056E75 /* PBChangedFile.h */, - F5E927F70E883E7200056E75 /* PBChangedFile.m */, F593DF760E9E636C003A8559 /* PBFileChangesTableView.h */, F593DF770E9E636C003A8559 /* PBFileChangesTableView.m */, ); @@ -854,6 +867,7 @@ 47DBDBCA0E95016F00671A1E /* PBNSURLPathUserDefaultsTransfomer.m in Sources */, F562C8870FE1766C000EC528 /* NSString_RegEx.m in Sources */, EB2A734A0FEE3F09006601CF /* PBCollapsibleSplitView.m in Sources */, + F59F1DD5105C4FF300115F88 /* PBGitIndex.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/PBGitIndex.h b/PBGitIndex.h new file mode 100644 index 0000000..9fc784e --- /dev/null +++ b/PBGitIndex.h @@ -0,0 +1,52 @@ +// +// PBGitIndex.h +// GitX +// +// Created by Pieter de Bie on 9/12/09. +// Copyright 2009 Pieter de Bie. All rights reserved. +// + +#import + +@class PBGitRepository; + +// Represents a git index for a given work tree. +// As a single git repository can have multiple trees, +// the tree has to be given explicitly, even though +// multiple trees is not yet supported in GitX +@interface PBGitIndex : NSObject { + +@private + PBGitRepository *repository; + NSURL *workingDirectory; + NSMutableArray *files; + + NSUInteger refreshStatus; + NSDictionary *amendEnvironment; + BOOL amend; +} + +// Whether we want the changes for amending, +// or for +@property BOOL amend; + +- (id)initWithRepository:(PBGitRepository *)repository workingDirectory:(NSURL *)workingDirectory; + +// A list of PBChangedFile's with differences between the work tree and the index +// This method is KVO-aware, so changes when any of the index-modifying methods are called +// (including -refresh) +- (NSArray *)indexChanges; + +// Refresh the index +- (void)refresh; + +//- (void)commit; + +// Inter-file changes: +//- (void)stageFiles:(NSArray *)files; +//- (void)unstageFiles:(NSArray *)files; + +// Intra-file changes +//- (void)applyPatch:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse; + +@end diff --git a/PBGitIndex.m b/PBGitIndex.m new file mode 100644 index 0000000..29e9ff8 --- /dev/null +++ b/PBGitIndex.m @@ -0,0 +1,345 @@ +// +// PBGitIndex.m +// GitX +// +// Created by Pieter de Bie on 9/12/09. +// Copyright 2009 Pieter de Bie. All rights reserved. +// + +#import "PBGitIndex.h" +#import "PBGitRepository.h" +#import "PBGitBinary.h" +#import "PBEasyPipe.h" +#import "NSString_RegEx.h" +#import "PBChangedFile.h" + +@interface PBGitIndex (IndexRefreshMethods) + +- (NSArray *)linesFromNotification:(NSNotification *)notification; +- (NSMutableDictionary *)dictionaryForLines:(NSArray *)lines; +- (void)addFilesFromDictionary:(NSMutableDictionary *)dictionary staged:(BOOL)staged tracked:(BOOL)tracked; + +- (void)indexStepComplete; + +- (void)indexRefreshFinished:(NSNotification *)notification; +- (void)readOtherFiles:(NSNotification *)notification; +- (void)readUnstagedFiles:(NSNotification *)notification; +- (void)readStagedFiles:(NSNotification *)notification; + +@end + +@interface PBGitIndex () + +// Returns the tree to compare the index to, based +// on whether amend is set or not. +- (NSString *) parentTree; + +@end + +@implementation PBGitIndex + +@synthesize amend; + +- (id)initWithRepository:(PBGitRepository *)theRepository workingDirectory:(NSURL *)theWorkingDirectory +{ + if (!(self = [super init])) + return nil; + + NSAssert(theWorkingDirectory, @"PBGitIndex requires a working directory"); + NSAssert(theRepository, @"PBGitIndex requires a repository"); + + repository = theRepository; + workingDirectory = theWorkingDirectory; + files = [NSMutableArray array]; + + return self; +} + +- (NSArray *)indexChanges +{ + return files; +} + +- (void)setAmend:(BOOL)newAmend +{ + if (newAmend == amend) + return; + + amend = newAmend; + amendEnvironment = nil; + + [self refresh]; + + if (!newAmend) + return; + + // If we amend, we want to keep the author information for the previous commit + // We do this by reading in the previous commit, and storing the information + // in a dictionary. This dictionary will then later be read by [self commit:] + NSString *message = [repository outputForCommand:@"cat-file commit HEAD"]; + NSArray *match = [message substringsMatchingRegularExpression:@"\nauthor ([^\n]*) <([^\n>]*)> ([0-9]+[^\n]*)\n" count:3 options:0 ranges:nil error:nil]; + if (match) + amendEnvironment = [NSDictionary dictionaryWithObjectsAndKeys:[match objectAtIndex:1], @"GIT_AUTHOR_NAME", + [match objectAtIndex:2], @"GIT_AUTHOR_EMAIL", + [match objectAtIndex:3], @"GIT_AUTHOR_DATE", + nil]; +} + +- (void)refresh +{ + // If we were already refreshing the index, we don't want + // double notifications. As we can't stop the tasks anymore, + // just cancel the notifications + refreshStatus = 0; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:self]; + + // Ask Git to refresh the index + NSFileHandle *updateHandle = [PBEasyPipe handleForCommand:[PBGitBinary path] + withArgs:[NSArray arrayWithObjects:@"update-index", @"-q", @"--unmerged", @"--ignore-missing", @"--refresh", nil] + inDir:[workingDirectory path]]; + + [nc addObserver:self + selector:@selector(indexRefreshFinished:) + name:NSFileHandleReadToEndOfFileCompletionNotification + object:updateHandle]; + [updateHandle readToEndOfFileInBackgroundAndNotify]; + +} + +- (NSString *) parentTree +{ + NSString *parent = amend ? @"HEAD^" : @"HEAD"; + + if (![repository parseReference:parent]) + // We don't have a head ref. Return the empty tree. + return @"4b825dc642cb6eb9a060e54bf8d69288fbee4904"; + + return parent; +} + +@end + +@implementation PBGitIndex (IndexRefreshMethods) + +- (void)indexRefreshFinished:(NSNotification *)notification +{ + if ([(NSNumber *)[(NSDictionary *)[notification userInfo] objectForKey:@"NSFileHandleError"] intValue]) + { + // TODO: send updatefailed notification? + return; + } + + // Now that the index is refreshed, we need to read the information from the index + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + + // Other files (not tracked, not ignored) + NSFileHandle *handle = [PBEasyPipe handleForCommand:[PBGitBinary path] + withArgs:[NSArray arrayWithObjects:@"ls-files", @"--others", @"--exclude-standard", @"-z", nil] + inDir:[workingDirectory path]]; + [nc addObserver:self selector:@selector(readOtherFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle]; + [handle readToEndOfFileInBackgroundAndNotify]; + refreshStatus++; + + // Unstaged files + handle = [PBEasyPipe handleForCommand:[PBGitBinary path] + withArgs:[NSArray arrayWithObjects:@"diff-files", @"-z", nil] + inDir:[workingDirectory path]]; + [nc addObserver:self selector:@selector(readUnstagedFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle]; + [handle readToEndOfFileInBackgroundAndNotify]; + refreshStatus++; + + // Staged files + handle = [PBEasyPipe handleForCommand:[PBGitBinary path] + withArgs:[NSArray arrayWithObjects:@"diff-index", @"--cached", @"-z", [self parentTree], nil] + inDir:[workingDirectory path]]; + [nc addObserver:self selector:@selector(readStagedFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle]; + [handle readToEndOfFileInBackgroundAndNotify]; + refreshStatus++; +} + +- (void)readOtherFiles:(NSNotification *)notification +{ + NSArray *lines = [self linesFromNotification:notification]; + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:[lines count]]; + // Other files are untracked, so we don't have any real index information. Instead, we can just fake it. + // The line below is used to add the file to the index + // FIXME: request the real file mode + NSArray *fileStatus = [NSArray arrayWithObjects:@":000000", @"100644", @"0000000000000000000000000000000000000000", @"0000000000000000000000000000000000000000", @"A", nil]; + for (NSString *path in lines) { + if ([path length] == 0) + continue; + [dictionary setObject:fileStatus forKey:path]; + } + + [self addFilesFromDictionary:dictionary staged:NO tracked:NO]; + [self indexStepComplete]; +} + +- (void) readStagedFiles:(NSNotification *)notification +{ + NSArray *lines = [self linesFromNotification:notification]; + NSMutableDictionary *dic = [self dictionaryForLines:lines]; + [self addFilesFromDictionary:dic staged:YES tracked:YES]; + [self indexStepComplete]; +} + +- (void) readUnstagedFiles:(NSNotification *)notification +{ + NSArray *lines = [self linesFromNotification:notification]; + NSMutableDictionary *dic = [self dictionaryForLines:lines]; + [self addFilesFromDictionary:dic staged:NO tracked:YES]; + [self indexStepComplete]; +} + +- (void) addFilesFromDictionary:(NSMutableDictionary *)dictionary staged:(BOOL)staged tracked:(BOOL)tracked +{ + // TODO: Stop tracking files + // Iterate over all existing files + for (PBChangedFile *file in files) { + NSArray *fileStatus = [dictionary objectForKey:file.path]; + // Object found, this is still a cached / uncached thing + if (fileStatus) { + if (tracked) { + NSString *mode = [[fileStatus objectAtIndex:0] substringFromIndex:1]; + NSString *sha = [fileStatus objectAtIndex:2]; + file.commitBlobSHA = sha; + file.commitBlobMode = mode; + + if (staged) + file.hasStagedChanges = YES; + else + file.hasUnstagedChanges = YES; + } else { + // Untracked file, set status to NEW, only unstaged changes + file.hasStagedChanges = NO; + file.hasUnstagedChanges = YES; + file.status = NEW; + } + + // We handled this file, remove it from the dictionary + [dictionary removeObjectForKey:file.path]; + } else { + // Object not found in the dictionary, so let's reset its appropriate + // change (stage or untracked) if necessary. + + // Staged dictionary, so file does not have staged changes + if (staged) + file.hasStagedChanges = NO; + // Tracked file does not have unstaged changes, file is not new, + // so we can set it to No. (If it would be new, it would not + // be in this dictionary, but in the "other dictionary"). + else if (tracked && file.status != NEW) + file.hasUnstagedChanges = NO; + // Unstaged, untracked dictionary ("Other" files), and file + // is indicated as new (which would be untracked), so let's + // remove it + else if (!tracked && file.status == NEW) + file.hasUnstagedChanges = NO; + } + } + // TODO: Finish tracking files + + // Do new files only if necessary + if (![[dictionary allKeys] count]) + return; + + // All entries left in the dictionary haven't been accounted for + // above, so we need to add them to the "files" array + [self willChangeValueForKey:@"indexChanges"]; + for (NSString *path in [dictionary allKeys]) { + NSArray *fileStatus = [dictionary objectForKey:path]; + + PBChangedFile *file = [[PBChangedFile alloc] initWithPath:path]; + if ([[fileStatus objectAtIndex:4] isEqualToString:@"D"]) + file.status = DELETED; + else if([[fileStatus objectAtIndex:0] isEqualToString:@":000000"]) + file.status = NEW; + else + file.status = MODIFIED; + + if (tracked) { + file.commitBlobMode = [[fileStatus objectAtIndex:0] substringFromIndex:1]; + file.commitBlobSHA = [fileStatus objectAtIndex:2]; + } + + file.hasStagedChanges = staged; + file.hasUnstagedChanges = !staged; + + [files addObject:file]; + } + [self didChangeValueForKey:@"indexChanges"]; +} + +# pragma mark Utility methods +- (NSArray *)linesFromNotification:(NSNotification *)notification +{ + NSData *data = [[notification userInfo] valueForKey:NSFileHandleNotificationDataItem]; + if (!data) + return [NSArray array]; + + NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + // FIXME: Return an error? + if (!string) + return [NSArray array]; + + // Strip trailing null + if ([string hasSuffix:@"\0"]) + string = [string substringToIndex:[string length]-1]; + + if ([string length] == 0) + return [NSArray array]; + + return [string componentsSeparatedByString:@"\0"]; +} + +- (NSMutableDictionary *)dictionaryForLines:(NSArray *)lines +{ + NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:[lines count]/2]; + + // Fill the dictionary with the new information. These lines are in the form of: + // :00000 :0644 OTHER INDEX INFORMATION + // Filename + + NSAssert1([lines count] % 2 == 0, @"Lines must have an even number of lines: %@", lines); + + NSEnumerator *enumerator = [lines objectEnumerator]; + NSString *fileStatus; + while (fileStatus = [enumerator nextObject]) { + NSString *fileName = [enumerator nextObject]; + [dictionary setObject:[fileStatus componentsSeparatedByString:@" "] forKey:fileName]; + } + + return dictionary; +} + +// This method is called for each of the three processes from above. +// If all three are finished (self.busy == 0), then we can delete +// all files previously marked as deletable +- (void)indexStepComplete +{ + // if we're still busy, do nothing :) + if (--refreshStatus) + return; + + // At this point, all index operations have finished. + // We need to find all files that don't have either + // staged or unstaged files, and delete them + + NSMutableArray *deleteFiles = [NSMutableArray array]; + for (PBChangedFile *file in files) { + if (!file.hasStagedChanges && !file.hasUnstagedChanges) + [deleteFiles addObject:file]; + } + + if ([deleteFiles count]) { + [self willChangeValueForKey:@"indexChanges"]; + for (PBChangedFile *file in deleteFiles) + [files removeObject:file]; + [self didChangeValueForKey:@"indexChanges"]; + } + + // TODO: Sent index refresh finished operation +} + +@end From 03e1d3e882ef051bf0acbb645c14c848847218b0 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 01:59:48 +0200 Subject: [PATCH 02/24] WIP: Add GUI support for the new index --- PBGitCommitController.h | 26 +--- PBGitCommitController.m | 273 ++++----------------------------------- PBGitCommitView.xib | 109 ++++++++-------- PBGitIndexController.m | 2 +- PBWebChangesController.m | 8 +- 5 files changed, 88 insertions(+), 330 deletions(-) diff --git a/PBGitCommitController.h b/PBGitCommitController.h index 0976738..f96e986 100644 --- a/PBGitCommitController.h +++ b/PBGitCommitController.h @@ -9,12 +9,10 @@ #import #import "PBViewController.h" -@class PBGitIndexController; -@class PBIconAndTextCell; -@class PBWebChangesController; +@class PBGitIndexController, PBIconAndTextCell, PBWebChangesController, PBGitIndex; @interface PBGitCommitController : PBViewController { - NSMutableArray *files; + PBGitIndex *index; IBOutlet NSTextView *commitMessageView; IBOutlet NSArrayController *unstagedFilesController; @@ -25,28 +23,14 @@ NSString *status; - // We use busy as a count of active processes. - // You can increase it when your process start - // And decrease it after you have finished. - int busy; - BOOL amend; NSDictionary *amendEnvironment; } -@property (retain) NSMutableArray *files; -@property (copy) NSString *status; -@property (assign) int busy; -@property (assign) BOOL amend; - -- (void) readCachedFiles:(NSNotification *)notification; -- (void) readOtherFiles:(NSNotification *)notification; -- (void) readUnstagedFiles:(NSNotification *)notification; -- (void) stageHunk: (NSString *)hunk reverse:(BOOL)reverse; -- (void)discardHunk:(NSString *)hunk; - -- (NSString *)parentTree; +@property(copy) NSString *status; +@property(readonly) PBGitIndex *index; +// FIXME: redo 0823ff859dc65db238951c16e49293ea411c2b5a - (IBAction) refresh:(id) sender; - (IBAction) commit:(id) sender; - (IBAction)signOff:(id)sender; diff --git a/PBGitCommitController.m b/PBGitCommitController.m index 1e894ee..be3f309 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -10,26 +10,36 @@ #import "NSFileHandleExt.h" #import "PBChangedFile.h" #import "PBWebChangesController.h" +#import "PBGitIndex.h" #import "NSString_RegEx.h" @interface PBGitCommitController (PrivateMethods) -- (NSArray *) linesFromNotification:(NSNotification *)notification; -- (void) doneProcessingIndex; -- (NSMutableDictionary *)dictionaryForLines:(NSArray *)lines; -- (void) addFilesFromDictionary:(NSMutableDictionary *)dictionary staged:(BOOL)staged tracked:(BOOL)tracked; - (void)processHunk:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse; @end @implementation PBGitCommitController -@synthesize files, status, busy, amend; +@synthesize status, index; + +- (id)initWithRepository:(PBGitRepository *)theRepository superController:(PBGitWindowController *)controller +{ + if (!(self = [super initWithRepository:theRepository superController:controller])) + return nil; + + index = [[PBGitIndex alloc] initWithRepository:theRepository workingDirectory:[NSURL fileURLWithPath:[theRepository workingDirectory]]]; + [index refresh]; + return self; +} + +- (BOOL)busy +{ + return NO; +} - (void)awakeFromNib { - self.files = [NSMutableArray array]; [super awakeFromNib]; - [self refresh:self]; [commitMessageView setTypingAttributes:[NSDictionary dictionaryWithObject:[NSFont fontWithName:@"Monaco" size:12.0] forKey:NSFontAttributeName]]; @@ -68,106 +78,9 @@ } } -- (void) setAmend:(BOOL)newAmend -{ - if (newAmend == amend) - return; - - amend = newAmend; - amendEnvironment = nil; - - // If we amend, we want to keep the author information for the previous commit - // We do this by reading in the previous commit, and storing the information - // in a dictionary. This dictionary will then later be read by [self commit:] - if (amend) { - NSString *message = [repository outputForCommand:@"cat-file commit HEAD"]; - NSArray *match = [message substringsMatchingRegularExpression:@"\nauthor ([^\n]*) <([^\n>]*)> ([0-9]+[^\n]*)\n" count:3 options:0 ranges:nil error:nil]; - if (match) - amendEnvironment = [NSDictionary dictionaryWithObjectsAndKeys:[match objectAtIndex:1], @"GIT_AUTHOR_NAME", - [match objectAtIndex:2], @"GIT_AUTHOR_EMAIL", - [match objectAtIndex:3], @"GIT_AUTHOR_DATE", - nil]; - - // Replace commit message with the old one if it's less than 3 characters long. - // This is just a random number. - if ([[commitMessageView string] length] <= 3) { - // Find the commit message - NSRange r = [message rangeOfString:@"\n\n"]; - if (r.location != NSNotFound) - message = [message substringFromIndex:r.location + 2]; - - commitMessageView.string = message; - } - } - - [self refresh:self]; -} - -- (NSArray *) linesFromNotification:(NSNotification *)notification -{ - NSDictionary *userInfo = [notification userInfo]; - NSData *data = [userInfo valueForKey:NSFileHandleNotificationDataItem]; - if (!data) - return NULL; - - NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - if (!string) - return NULL; - - // Strip trailing newline - if ([string hasSuffix:@"\n"]) - string = [string substringToIndex:[string length]-1]; - - NSArray *lines = [string componentsSeparatedByString:@"\0"]; - return lines; -} - -- (NSString *) parentTree -{ - NSString *parent = amend ? @"HEAD^" : @"HEAD"; - - if (![repository parseReference:parent]) - // We don't have a head ref. Return the empty tree. - return @"4b825dc642cb6eb9a060e54bf8d69288fbee4904"; - - return parent; -} - - (void) refresh:(id) sender { - if (![repository workingDirectory]) - return; - - self.status = @"Refreshing index…"; - - // If self.busy reaches 0, all tasks have finished - self.busy = 0; - - // Refresh the index, necessary for the next methods (that's why it's blocking) - // FIXME: Make this non-blocking. This call can be expensive in large repositories - [repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"update-index", @"-q", @"--unmerged", @"--ignore-missing", @"--refresh", nil]]; - - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - [nc removeObserver:self]; - - // Other files (not tracked, not ignored) - NSArray *arguments = [NSArray arrayWithObjects:@"ls-files", @"--others", @"--exclude-standard", @"-z", nil]; - NSFileHandle *handle = [repository handleInWorkDirForArguments:arguments]; - [nc addObserver:self selector:@selector(readOtherFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle]; - self.busy++; - [handle readToEndOfFileInBackgroundAndNotify]; - - // Unstaged files - handle = [repository handleInWorkDirForArguments:[NSArray arrayWithObjects:@"diff-files", @"-z", nil]]; - [nc addObserver:self selector:@selector(readUnstagedFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle]; - self.busy++; - [handle readToEndOfFileInBackgroundAndNotify]; - - // Staged files - handle = [repository handleInWorkDirForArguments:[NSArray arrayWithObjects:@"diff-index", @"--cached", @"-z", [self parentTree], nil]]; - [nc addObserver:self selector:@selector(readCachedFiles:) name:NSFileHandleReadToEndOfFileCompletionNotification object:handle]; - self.busy++; - [handle readToEndOfFileInBackgroundAndNotify]; + [index refresh]; // Reload refs (in case HEAD changed) [repository reloadRefs]; @@ -178,147 +91,9 @@ [self refresh:nil]; } -// This method is called for each of the three processes from above. -// If all three are finished (self.busy == 0), then we can delete -// all files previously marked as deletable -- (void) doneProcessingIndex -{ - // if we're still busy, do nothing :) - if (--self.busy) - return; - - NSMutableArray *deleteFiles = [NSMutableArray array]; - for (PBChangedFile *file in files) { - if (!file.hasStagedChanges && !file.hasUnstagedChanges) - [deleteFiles addObject:file]; - } - - if ([deleteFiles count]) { - [self willChangeValueForKey:@"files"]; - for (PBChangedFile *file in deleteFiles) - [files removeObject:file]; - [self didChangeValueForKey:@"files"]; - } - self.status = @"Ready"; -} - -- (void) readOtherFiles:(NSNotification *)notification; -{ - NSArray *lines = [self linesFromNotification:notification]; - NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:[lines count]]; - // We fake this files status as good as possible. - NSArray *fileStatus = [NSArray arrayWithObjects:@":000000", @"100644", @"0000000000000000000000000000000000000000", @"0000000000000000000000000000000000000000", @"A", nil]; - for (NSString *path in lines) { - if ([path length] == 0) - continue; - [dictionary setObject:fileStatus forKey:path]; - } - [self addFilesFromDictionary:dictionary staged:NO tracked:NO]; - [self doneProcessingIndex]; -} - -- (NSMutableDictionary *)dictionaryForLines:(NSArray *)lines -{ - NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:[lines count]/2]; - - // Fill the dictionary with the new information - NSArray *fileStatus; - BOOL even = FALSE; - for (NSString *line in lines) { - if (!even) { - even = TRUE; - fileStatus = [line componentsSeparatedByString:@" "]; - continue; - } - - even = FALSE; - [dictionary setObject:fileStatus forKey:line]; - } - return dictionary; -} - -- (void) addFilesFromDictionary:(NSMutableDictionary *)dictionary staged:(BOOL)staged tracked:(BOOL)tracked -{ - // Iterate over all existing files - for (PBChangedFile *file in files) { - NSArray *fileStatus = [dictionary objectForKey:file.path]; - // Object found, this is still a cached / uncached thing - if (fileStatus) { - if (tracked) { - NSString *mode = [[fileStatus objectAtIndex:0] substringFromIndex:1]; - NSString *sha = [fileStatus objectAtIndex:2]; - file.commitBlobSHA = sha; - file.commitBlobMode = mode; - - if (staged) - file.hasStagedChanges = YES; - else - file.hasUnstagedChanges = YES; - } else { - // Untracked file, set status to NEW, only unstaged changes - file.hasStagedChanges = NO; - file.hasUnstagedChanges = YES; - file.status = NEW; - } - [dictionary removeObjectForKey:file.path]; - } else { // Object not found, let's remove it from the changes - if (staged) - file.hasStagedChanges = NO; - else if (tracked && file.status != NEW) // Only remove it if it's not an untracked file. We handle that with the other thing - file.hasUnstagedChanges = NO; - else if (!tracked && file.status == NEW) - file.hasUnstagedChanges = NO; - } - } - - // Do new files - if (![[dictionary allKeys] count]) - return; - - [self willChangeValueForKey:@"files"]; - for (NSString *path in [dictionary allKeys]) { - NSArray *fileStatus = [dictionary objectForKey:path]; - - PBChangedFile *file = [[PBChangedFile alloc] initWithPath:path]; - if ([[fileStatus objectAtIndex:4] isEqualToString:@"D"]) - file.status = DELETED; - else if([[fileStatus objectAtIndex:0] isEqualToString:@":000000"]) - file.status = NEW; - else - file.status = MODIFIED; - - if (tracked) { - file.commitBlobMode = [[fileStatus objectAtIndex:0] substringFromIndex:1]; - file.commitBlobSHA = [fileStatus objectAtIndex:2]; - } - - file.hasStagedChanges = staged; - file.hasUnstagedChanges = !staged; - - [files addObject: file]; - } - [self didChangeValueForKey:@"files"]; -} - -- (void) readUnstagedFiles:(NSNotification *)notification -{ - NSArray *lines = [self linesFromNotification:notification]; - NSMutableDictionary *dic = [self dictionaryForLines:lines]; - [self addFilesFromDictionary:dic staged:NO tracked:YES]; - [self doneProcessingIndex]; -} - -- (void) readCachedFiles:(NSNotification *)notification -{ - NSArray *lines = [self linesFromNotification:notification]; - NSMutableDictionary *dic = [self dictionaryForLines:lines]; - [self addFilesFromDictionary:dic staged:YES tracked:YES]; - [self doneProcessingIndex]; -} - - (void) commitFailedBecause:(NSString *)reason { - self.busy--; + //self.busy--; self.status = [@"Commit failed: " stringByAppendingString:reason]; [[repository windowController] showMessageSheet:@"Commit failed" infoText:reason]; return; @@ -360,7 +135,7 @@ [commitMessage writeToFile:commitMessageFile atomically:YES encoding:NSUTF8StringEncoding error:nil]; - self.busy++; + //self.busy++; self.status = @"Creating tree.."; NSString *tree = [repository outputForCommand:@"write-tree"]; if ([tree length] != 40) @@ -369,7 +144,7 @@ int ret; NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"commit-tree", tree, nil]; - NSString *parent = amend ? @"HEAD^" : @"HEAD"; + NSString *parent = index.amend ? @"HEAD^" : @"HEAD"; if ([repository parseReference:parent]) { [arguments addObject:@"-p"]; [arguments addObject:parent]; @@ -400,12 +175,10 @@ [webController setStateMessage:[NSString stringWithFormat:@"Successfully created commit %@", commit]]; repository.hasChanged = YES; - self.busy--; + //self.busy--; [commitMessageView setString:@""]; - amend = NO; amendEnvironment = nil; - [self refresh:self]; - self.amend = NO; + index.amend = NO; } - (void) stageHunk:(NSString *)hunk reverse:(BOOL)reverse diff --git a/PBGitCommitView.xib b/PBGitCommitView.xib index 643bfa3..49beeb5 100644 --- a/PBGitCommitView.xib +++ b/PBGitCommitView.xib @@ -2,15 +2,14 @@ 1050 - 9J61 + 9L31a 677 - 949.46 + 949.54 353.00 YES + - - YES @@ -127,7 +126,7 @@ YES - + @@ -963,38 +962,6 @@ 139 - - - contentArray: files - - - - - - contentArray: files - contentArray - files - 2 - - - 149 - - - - contentArray: files - - - - - - contentArray: files - contentArray - files - 2 - - - 150 - cachedFilesController @@ -1067,22 +1034,6 @@ 241 - - - value: amend - - - - - - value: amend - value - amend - 2 - - - 252 - webController @@ -1219,6 +1170,54 @@ 280 + + + contentArray: index.indexChanges + + + + + + contentArray: index.indexChanges + contentArray + index.indexChanges + 2 + + + 281 + + + + contentArray: index.indexChanges + + + + + + contentArray: index.indexChanges + contentArray + index.indexChanges + 2 + + + 282 + + + + value: index.amend + + + + + + value: index.amend + value + index.amend + 2 + + + 283 + @@ -1616,7 +1615,7 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilderKit com.apple.InterfaceBuilderKit - {{59, 63}, {852, 432}} + {{428, 510}, {852, 432}} com.apple.InterfaceBuilder.CocoaPlugin @@ -1680,7 +1679,7 @@ - 280 + 283 diff --git a/PBGitIndexController.m b/PBGitIndexController.m index 21c7076..a03b3a2 100644 --- a/PBGitIndexController.m +++ b/PBGitIndexController.m @@ -136,7 +136,7 @@ if (file.status == NEW) return [commitController.repository outputForArguments:[NSArray arrayWithObjects:@"show", indexPath, nil]]; - return [commitController.repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-index", [self contextParameter], @"--cached", [commitController parentTree], @"--", file.path, nil]]; + return [commitController.repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-index", [self contextParameter], @"--cached", [commitController.index parentTree], @"--", file.path, nil]]; } - (NSString *)unstagedChangesForFile:(PBChangedFile *)file diff --git a/PBWebChangesController.m b/PBWebChangesController.m index d24a8af..697307d 100644 --- a/PBWebChangesController.m +++ b/PBWebChangesController.m @@ -8,6 +8,7 @@ #import "PBWebChangesController.h" #import "PBGitIndexController.h" +#import "PBGitIndex.h" @implementation PBWebChangesController @@ -31,7 +32,7 @@ - (BOOL) amend { - return controller.amend; + return controller.index.amend; } - (void)observeValueForKeyPath:(NSString *)keyPath @@ -83,7 +84,8 @@ - (void) stageHunk:(NSString *)hunk reverse:(BOOL)reverse { - [controller stageHunk: hunk reverse:reverse]; + //[controller stageHunk: hunk reverse:reverse]; + // FIXME: Don't need a hard refresh [self refresh]; } @@ -99,7 +101,7 @@ } if (ret == NSAlertDefaultReturn) { - [controller discardHunk:hunk]; + // [controller discardHunk:hunk]; [self refresh]; } } From 07417acd51d5eb4b8109c93d6b58b38485de0989 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 02:15:17 +0200 Subject: [PATCH 03/24] GitIndex: add support for retrieving diffs --- PBGitIndex.h | 2 ++ PBGitIndex.m | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/PBGitIndex.h b/PBGitIndex.h index 9fc784e..548983f 100644 --- a/PBGitIndex.h +++ b/PBGitIndex.h @@ -9,6 +9,7 @@ #import @class PBGitRepository; +@class PBChangedFile; // Represents a git index for a given work tree. // As a single git repository can have multiple trees, @@ -48,5 +49,6 @@ // Intra-file changes //- (void)applyPatch:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse; +- (NSString *)diffForFile:(PBChangedFile *)file staged:(BOOL)staged contextLines:(NSUInteger)context; @end diff --git a/PBGitIndex.m b/PBGitIndex.m index 29e9ff8..cfc3166 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -118,6 +118,42 @@ return parent; } +- (NSString *)diffForFile:(PBChangedFile *)file staged:(BOOL)staged contextLines:(NSUInteger)context +{ + NSString *parameter = [NSString stringWithFormat:@"-U%u", context]; + if (staged) { + NSString *indexPath = [@":0:" stringByAppendingString:file.path]; + + if (file.status == NEW) + return [repository outputForArguments:[NSArray arrayWithObjects:@"show", indexPath, nil]]; + + return [repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-index", parameter, @"--cached", [self parentTree], @"--", file.path, nil]]; + } + + // unstaged + if (file.status == NEW) { + NSStringEncoding encoding; + NSError *error = nil; + NSString *path = [[repository workingDirectory] stringByAppendingPathComponent:file.path]; + NSString *contents = [NSString stringWithContentsOfFile:path + usedEncoding:&encoding + error:&error]; + if (error) + return nil; + + return contents; + } + + return [repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-files", parameter, @"--", file.path, nil]]; +} + +# pragma mark WebKit Accessibility + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + return NO; +} + @end @implementation PBGitIndex (IndexRefreshMethods) From 64a52ad9e0292dcceabecdd716ca463dbc8f3a93 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 02:16:31 +0200 Subject: [PATCH 04/24] CommitView: Migrate diff displaying away from IndexController --- PBGitCommitController.h | 2 ++ PBGitIndexController.h | 3 --- PBGitIndexController.m | 27 --------------------------- PBWebChangesController.m | 2 +- html/views/commit/commit.js | 21 ++++++++------------- 5 files changed, 11 insertions(+), 44 deletions(-) diff --git a/PBGitCommitController.h b/PBGitCommitController.h index f96e986..a8b2802 100644 --- a/PBGitCommitController.h +++ b/PBGitCommitController.h @@ -12,6 +12,8 @@ @class PBGitIndexController, PBIconAndTextCell, PBWebChangesController, PBGitIndex; @interface PBGitCommitController : PBViewController { + // This might have to transfer over to the PBGitRepository + // object sometime PBGitIndex *index; IBOutlet NSTextView *commitMessageView; diff --git a/PBGitIndexController.h b/PBGitIndexController.h index a3bc191..87b3cab 100644 --- a/PBGitIndexController.h +++ b/PBGitIndexController.h @@ -33,8 +33,5 @@ - (IBAction) rowClicked:(NSCell *) sender; - (IBAction) tableClicked:(NSTableView *)tableView; -- (NSString *) stagedChangesForFile:(PBChangedFile *)file; -- (NSString *) unstagedChangesForFile:(PBChangedFile *)file; - - (NSMenu *) menuForTable:(NSTableView *)table; @end diff --git a/PBGitIndexController.m b/PBGitIndexController.m index a03b3a2..0517a0b 100644 --- a/PBGitIndexController.m +++ b/PBGitIndexController.m @@ -129,33 +129,6 @@ # pragma mark Displaying diffs -- (NSString *) stagedChangesForFile:(PBChangedFile *)file -{ - NSString *indexPath = [@":0:" stringByAppendingString:file.path]; - - if (file.status == NEW) - return [commitController.repository outputForArguments:[NSArray arrayWithObjects:@"show", indexPath, nil]]; - - return [commitController.repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-index", [self contextParameter], @"--cached", [commitController.index parentTree], @"--", file.path, nil]]; -} - -- (NSString *)unstagedChangesForFile:(PBChangedFile *)file -{ - if (file.status == NEW) { - NSStringEncoding encoding; - NSError *error = nil; - NSString *path = [[commitController.repository workingDirectory] stringByAppendingPathComponent:file.path]; - NSString *contents = [NSString stringWithContentsOfFile:path - usedEncoding:&encoding - error:&error]; - if (error) - return nil; - - return contents; - } - - return [commitController.repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-files", [self contextParameter], @"--", file.path, nil]]; -} - (void)discardChangesForFiles:(NSArray *)files force:(BOOL)force { diff --git a/PBWebChangesController.m b/PBWebChangesController.m index 697307d..96b9a5c 100644 --- a/PBWebChangesController.m +++ b/PBWebChangesController.m @@ -26,7 +26,7 @@ - (void) didLoad { - [[self script] setValue:indexController forKey:@"IndexController"]; + [[self script] setValue:controller.index forKey:@"Index"]; [self refresh]; } diff --git a/html/views/commit/commit.js b/html/views/commit/commit.js index df0cb42..cdec998 100644 --- a/html/views/commit/commit.js +++ b/html/views/commit/commit.js @@ -1,11 +1,13 @@ /* Commit: Interface for selecting, staging, discarding, and unstaging hunks, individual lines, or ranges of lines. */ +var contextLines = 5; + var showNewFile = function(file) { setTitle("New file: " + file.path); - var contents = IndexController.unstagedChangesForFile_(file); + var contents = Index.diffForFile_staged_contextLines_(file, false, contextLines); if (!contents) { notify("Can not display changes (Binary file?)", -1); diff.innerHTML = ""; @@ -49,23 +51,16 @@ var showFileChanges = function(file, cached) { hideState(); $("contextSize").oninput = function(element) { - Controller.setContextSize_($("contextSize").value); + contextSize = $("contextSize").value; } if (file.status == 0) // New file? return showNewFile(file); - var changes; - if (cached) { - setTitle("Staged changes for " + file.path); - displayContext(); - changes = IndexController.stagedChangesForFile_(file); - } - else { - setTitle("Unstaged changes for " + file.path); - displayContext(); - changes = IndexController.unstagedChangesForFile_(file); - } + setTitle((cached ? "Staged": "Unstaged") + " changes for" + file.path); + displayContext(); + var changes = Index.diffForFile_staged_contextLines_(file, cached, contextLines); + if (changes == "") { notify("This file has no more changes", 1); From 35a4dc37e2181a029a5326085f421f8fec849951 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 02:33:26 +0200 Subject: [PATCH 05/24] GitIndex: Add methods to stage and unstage files These are mostly copies from PBGitIndexController, and they can be refactored to a common method. I'm not sure of a name for that yet, so I'll keep it like this for now :) --- PBGitIndex.h | 4 ++-- PBGitIndex.m | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/PBGitIndex.h b/PBGitIndex.h index 548983f..19bfe43 100644 --- a/PBGitIndex.h +++ b/PBGitIndex.h @@ -44,8 +44,8 @@ //- (void)commit; // Inter-file changes: -//- (void)stageFiles:(NSArray *)files; -//- (void)unstageFiles:(NSArray *)files; +- (BOOL)stageFiles:(NSArray *)stageFiles; +- (BOOL)unstageFiles:(NSArray *)unstageFiles; // Intra-file changes //- (void)applyPatch:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse; diff --git a/PBGitIndex.m b/PBGitIndex.m index cfc3166..1109140 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -118,6 +118,71 @@ return parent; } +- (BOOL)stageFiles:(NSArray *)stageFiles +{ + // Input string for update-index + // This will be a list of filenames that + // should be updated. It's similar to + // "git add -- + NSMutableString *input = [NSMutableString string]; + + for (PBChangedFile *file in stageFiles) { + [input appendFormat:@"%@\0", file.path]; + } + + int ret = 1; + [repository outputForArguments:[NSArray arrayWithObjects:@"update-index", @"--add", @"--remove", @"-z", @"--stdin", nil] + inputString:input + retValue:&ret]; + + if (ret) { + // FIXME: failed notification? + NSLog(@"Error when updating index. Retvalue: %i", ret); + return NO; + } + + // TODO: Stop Tracking + for (PBChangedFile *file in stageFiles) + { + file.hasUnstagedChanges = NO; + file.hasStagedChanges = YES; + } + // TODO: Resume tracking + return YES; +} + +// TODO: Refactor with above. What's a better name for this? +- (BOOL)unstageFiles:(NSArray *)unstageFiles +{ + NSMutableString *input = [NSMutableString string]; + + for (PBChangedFile *file in unstageFiles) { + [input appendString:[file indexInfo]]; + } + + int ret = 1; + [repository outputForArguments:[NSArray arrayWithObjects:@"update-index", @"-z", @"--index-info", nil] + inputString:input + retValue:&ret]; + + if (ret) + { + // FIXME: Failed notification + NSLog(@"Error when updating index. Retvalue: %i", ret); + return NO; + } + + // TODO: stop tracking + for (PBChangedFile *file in unstageFiles) + { + file.hasUnstagedChanges = YES; + file.hasStagedChanges = NO; + } + // TODO: resume tracking + + return YES; +} + - (NSString *)diffForFile:(PBChangedFile *)file staged:(BOOL)staged contextLines:(NSUInteger)context { NSString *parameter = [NSString stringWithFormat:@"-U%u", context]; @@ -147,6 +212,7 @@ return [repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-files", parameter, @"--", file.path, nil]]; } + # pragma mark WebKit Accessibility + (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector From f51fd6c21478b6d7e0677f613a83b153faee6b11 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 02:33:53 +0200 Subject: [PATCH 06/24] GitIndexController: Migrate stageFiles functions to GitIndex --- PBGitIndexController.h | 3 -- PBGitIndexController.m | 66 +++++------------------------------------- 2 files changed, 7 insertions(+), 62 deletions(-) diff --git a/PBGitIndexController.h b/PBGitIndexController.h index 87b3cab..7b718ac 100644 --- a/PBGitIndexController.h +++ b/PBGitIndexController.h @@ -27,9 +27,6 @@ - (NSString *) contextParameter; -- (void) stageFiles:(NSArray *)files; -- (void) unstageFiles:(NSArray *)files; - - (IBAction) rowClicked:(NSCell *) sender; - (IBAction) tableClicked:(NSTableView *)tableView; diff --git a/PBGitIndexController.m b/PBGitIndexController.m index 0517a0b..148c8e1 100644 --- a/PBGitIndexController.m +++ b/PBGitIndexController.m @@ -9,6 +9,7 @@ #import "PBGitIndexController.h" #import "PBChangedFile.h" #import "PBGitRepository.h" +#import "PBGitIndex.h" #define FileChangesTableViewType @"GitFileChangedType" @@ -36,59 +37,6 @@ } -- (void) stageFiles:(NSArray *)files -{ - NSMutableString *input = [NSMutableString string]; - - for (PBChangedFile *file in files) { - [input appendFormat:@"%@\0", file.path]; - } - - int ret = 1; - [commitController.repository outputForArguments:[NSArray arrayWithObjects:@"update-index", @"--add", @"--remove", @"-z", @"--stdin", nil] - inputString:input retValue:&ret]; - - if (ret) - { - NSLog(@"Error when updating index. Retvalue: %i", ret); - return; - } - - [self stopTrackingIndex]; - for (PBChangedFile *file in files) - { - file.hasUnstagedChanges = NO; - file.hasStagedChanges = YES; - } - [self resumeTrackingIndex]; -} - -- (void) unstageFiles:(NSArray *)files -{ - NSMutableString *input = [NSMutableString string]; - - for (PBChangedFile *file in files) { - [input appendString:[file indexInfo]]; - } - - int ret = 1; - [commitController.repository outputForArguments:[NSArray arrayWithObjects:@"update-index", @"-z", @"--index-info", nil] - inputString:input retValue:&ret]; - - if (ret) - { - NSLog(@"Error when updating index. Retvalue: %i", ret); - return; - } - - [self stopTrackingIndex]; - for (PBChangedFile *file in files) - { - file.hasUnstagedChanges = YES; - file.hasStagedChanges = NO; - } - [self resumeTrackingIndex]; -} - (void) ignoreFiles:(NSArray *)files { @@ -233,12 +181,12 @@ - (void) stageFilesAction:(id) sender { - [self stageFiles:[sender representedObject]]; + [commitController.index stageFiles:[sender representedObject]]; } - (void) unstageFilesAction:(id) sender { - [self unstageFiles:[sender representedObject]]; + [commitController.index unstageFiles:[sender representedObject]]; } - (void) openFilesAction:(id) sender @@ -298,9 +246,9 @@ NSIndexSet *selectionIndexes = [tableView selectedRowIndexes]; NSArray *files = [[controller arrangedObjects] objectsAtIndexes:selectionIndexes]; if ([tableView tag] == 0) - [self stageFiles:files]; + [commitController.index stageFiles:files]; else - [self unstageFiles:files]; + [commitController.index unstageFiles:files]; } - (void) rowClicked:(NSCell *)sender @@ -360,9 +308,9 @@ writeRowsWithIndexes:(NSIndexSet *)rowIndexes NSArray *files = [[controller arrangedObjects] objectsAtIndexes:rowIndexes]; if ([aTableView tag] == 0) - [self unstageFiles:files]; + [commitController.index unstageFiles:files]; else - [self stageFiles:files]; + [commitController.index stageFiles:files]; return YES; } From 8df614cb53deb9f1fe7e66e6a9db82ff69cbc155 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 02:47:39 +0200 Subject: [PATCH 07/24] GitIndex: add basic commit method --- PBGitIndex.h | 2 +- PBGitIndex.m | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/PBGitIndex.h b/PBGitIndex.h index 19bfe43..261b226 100644 --- a/PBGitIndex.h +++ b/PBGitIndex.h @@ -41,7 +41,7 @@ // Refresh the index - (void)refresh; -//- (void)commit; +- (void)commitWithMessage:(NSString *)commitMessage; // Inter-file changes: - (BOOL)stageFiles:(NSArray *)stageFiles; diff --git a/PBGitIndex.m b/PBGitIndex.m index 1109140..5097158 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -118,6 +118,69 @@ return parent; } +- (void)commitWithMessage:(NSString *)commitMessage +{ + NSMutableString *commitSubject = [@"commit: " mutableCopy]; + NSRange newLine = [commitMessage rangeOfString:@"\n"]; + if (newLine.location == NSNotFound) + [commitSubject appendString:commitMessage]; + else + [commitSubject appendString:[commitMessage substringToIndex:newLine.location]]; + + NSString *commitMessageFile; + commitMessageFile = [repository.fileURL.path stringByAppendingPathComponent:@"COMMIT_EDITMSG"]; + + [commitMessage writeToFile:commitMessageFile atomically:YES encoding:NSUTF8StringEncoding error:nil]; + + // TODO: Notification: @"Creating tree.."; + NSString *tree = [repository outputForCommand:@"write-tree"]; + if ([tree length] != 40) + return; //TODO: commitFailedBecause:@"Could not create a tree"; + + + NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"commit-tree", tree, nil]; + NSString *parent = amend ? @"HEAD^" : @"HEAD"; + if ([repository parseReference:parent]) { + [arguments addObject:@"-p"]; + [arguments addObject:parent]; + } + + int ret = 1; + NSString *commit = [repository outputForArguments:arguments + inputString:commitMessage + byExtendingEnvironment:amendEnvironment + retValue: &ret]; + + if (ret || [commit length] != 40) + return; // TODO: [self commitFailedBecause:@"Could not create a commit object"]; + + if (![repository executeHook:@"pre-commit" output:nil]) + return; // TODO: [self commitFailedBecause:@"Pre-commit hook failed"]; + + if (![repository executeHook:@"commit-msg" withArgs:[NSArray arrayWithObject:commitMessageFile] output:nil]) + return; // TODO: [self commitFailedBecause:@"Commit-msg hook failed"]; + + [repository outputForArguments:[NSArray arrayWithObjects:@"update-ref", @"-m", commitSubject, @"HEAD", commit, nil] + retValue: &ret]; + if (ret) + return; // TODO: [self commitFailedBecause:@"Could not update HEAD"]; + + if (![repository executeHook:@"post-commit" output:nil]) + return; // [webController setStateMessage:[NSString stringWithFormat:@"Post-commit hook failed, however, successfully created commit %@", commit]]; + else + //[webController setStateMessage:[NSString stringWithFormat:@"Successfully created commit %@", commit]]; + ; + + repository.hasChanged = YES; + + amendEnvironment = nil; + if (amend) + self.amend = NO; + else + [self refresh]; + +} + - (BOOL)stageFiles:(NSArray *)stageFiles { // Input string for update-index From 87dfb47f4f6aa0f4a547fbf6819ba8b983f0e7aa Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 02:47:59 +0200 Subject: [PATCH 08/24] CommitController: Replace commit method with the one from GitIndex --- PBGitCommitController.m | 58 ++--------------------------------------- 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/PBGitCommitController.m b/PBGitCommitController.m index be3f309..d1b29ec 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -120,65 +120,11 @@ [cachedFilesController setSelectionIndexes:[NSIndexSet indexSet]]; [unstagedFilesController setSelectionIndexes:[NSIndexSet indexSet]]; - NSString *commitSubject; - NSRange newLine = [commitMessage rangeOfString:@"\n"]; - if (newLine.location == NSNotFound) - commitSubject = commitMessage; - else - commitSubject = [commitMessage substringToIndex:newLine.location]; - - commitSubject = [@"commit: " stringByAppendingString:commitSubject]; + [index commitWithMessage:commitMessage]; - NSString *commitMessageFile; - commitMessageFile = [repository.fileURL.path - stringByAppendingPathComponent:@"COMMIT_EDITMSG"]; + [webController setStateMessage:[NSString stringWithFormat:@"Successfully created commit"]]; - [commitMessage writeToFile:commitMessageFile atomically:YES encoding:NSUTF8StringEncoding error:nil]; - - //self.busy++; - self.status = @"Creating tree.."; - NSString *tree = [repository outputForCommand:@"write-tree"]; - if ([tree length] != 40) - return [self commitFailedBecause:@"Could not create a tree"]; - - int ret; - - NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"commit-tree", tree, nil]; - NSString *parent = index.amend ? @"HEAD^" : @"HEAD"; - if ([repository parseReference:parent]) { - [arguments addObject:@"-p"]; - [arguments addObject:parent]; - } - - NSString *commit = [repository outputForArguments:arguments - inputString:commitMessage - byExtendingEnvironment:amendEnvironment - retValue: &ret]; - - if (ret || [commit length] != 40) - return [self commitFailedBecause:@"Could not create a commit object"]; - - if (![repository executeHook:@"pre-commit" output:nil]) - return [self commitFailedBecause:@"Pre-commit hook failed"]; - - if (![repository executeHook:@"commit-msg" withArgs:[NSArray arrayWithObject:commitMessageFile] output:nil]) - return [self commitFailedBecause:@"Commit-msg hook failed"]; - - [repository outputForArguments:[NSArray arrayWithObjects:@"update-ref", @"-m", commitSubject, @"HEAD", commit, nil] - retValue: &ret]; - if (ret) - return [self commitFailedBecause:@"Could not update HEAD"]; - - if (![repository executeHook:@"post-commit" output:nil]) - [webController setStateMessage:[NSString stringWithFormat:@"Post-commit hook failed, however, successfully created commit %@", commit]]; - else - [webController setStateMessage:[NSString stringWithFormat:@"Successfully created commit %@", commit]]; - - repository.hasChanged = YES; - //self.busy--; [commitMessageView setString:@""]; - amendEnvironment = nil; - index.amend = NO; } - (void) stageHunk:(NSString *)hunk reverse:(BOOL)reverse From 57dc38f58786f194e4cfe990d6bd6be1e4565de9 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 02:57:48 +0200 Subject: [PATCH 09/24] GitIndex: Add support for applying patches --- PBGitIndex.h | 2 +- PBGitIndex.m | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/PBGitIndex.h b/PBGitIndex.h index 261b226..a358f5a 100644 --- a/PBGitIndex.h +++ b/PBGitIndex.h @@ -48,7 +48,7 @@ - (BOOL)unstageFiles:(NSArray *)unstageFiles; // Intra-file changes -//- (void)applyPatch:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse; +- (BOOL)applyPatch:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse; - (NSString *)diffForFile:(PBChangedFile *)file staged:(BOOL)staged contextLines:(NSUInteger)context; @end diff --git a/PBGitIndex.m b/PBGitIndex.m index 5097158..717ceff 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -246,6 +246,31 @@ return YES; } +- (BOOL)applyPatch:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse; +{ + NSMutableArray *array = [NSMutableArray arrayWithObjects:@"apply", nil]; + if (stage) + [array addObject:@"--cached"]; + if (reverse) + [array addObject:@"--reverse"]; + + int ret = 1; + NSString *error = [repository outputForArguments:array + inputString:hunk + retValue:&ret]; + + // FIXME: show this error, rather than just logging it + if (ret) { + NSLog(@"Error: %@", error); + return NO; + } + + // TODO: Try to be smarter about what to refresh + [self refresh]; + return YES; +} + + - (NSString *)diffForFile:(PBChangedFile *)file staged:(BOOL)staged contextLines:(NSUInteger)context { NSString *parameter = [NSString stringWithFormat:@"-U%u", context]; From cdae809f4132a95459933bf2e5333e03cd7959a5 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 02:58:05 +0200 Subject: [PATCH 10/24] CommitView: Migrate patch apply stuff to GitIndex --- PBGitCommitController.m | 30 ------------------------------ PBWebChangesController.m | 7 ++++--- 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/PBGitCommitController.m b/PBGitCommitController.m index d1b29ec..38ecc13 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -127,35 +127,5 @@ [commitMessageView setString:@""]; } -- (void) stageHunk:(NSString *)hunk reverse:(BOOL)reverse -{ - [self processHunk:hunk stage:TRUE reverse:reverse]; -} - -- (void)discardHunk:(NSString *)hunk -{ - [self processHunk:hunk stage:FALSE reverse:TRUE]; -} - -- (void)processHunk:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse -{ - NSMutableArray *array = [NSMutableArray arrayWithObjects:@"apply", nil]; - if (stage) - [array addObject:@"--cached"]; - if (reverse) - [array addObject:@"--reverse"]; - - int ret = 1; - NSString *error = [repository outputForArguments:array - inputString:hunk - retValue:&ret]; - - // FIXME: show this error, rather than just logging it - if (ret) - NSLog(@"Error: %@", error); - - // TODO: We should do this smarter by checking if the file diff is empty, which is faster. - [self refresh:self]; -} @end diff --git a/PBWebChangesController.m b/PBWebChangesController.m index 96b9a5c..592e596 100644 --- a/PBWebChangesController.m +++ b/PBWebChangesController.m @@ -82,10 +82,11 @@ [NSNumber numberWithBool:selectedFileIsCached], nil]]; } -- (void) stageHunk:(NSString *)hunk reverse:(BOOL)reverse +- (void)stageHunk:(NSString *)hunk reverse:(BOOL)reverse { - //[controller stageHunk: hunk reverse:reverse]; + [controller.index applyPatch:hunk stage:YES reverse:reverse]; // FIXME: Don't need a hard refresh + [self refresh]; } @@ -101,7 +102,7 @@ } if (ret == NSAlertDefaultReturn) { - // [controller discardHunk:hunk]; + [controller.index applyPatch:hunk stage:NO reverse:YES]; [self refresh]; } } From ff263c6717cc3cf13f26669ff923634157b8873c Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 03:20:12 +0200 Subject: [PATCH 11/24] GitIndex: Add a few notifications --- PBGitIndex.h | 6 ++++++ PBGitIndex.m | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/PBGitIndex.h b/PBGitIndex.h index a358f5a..7dd0e93 100644 --- a/PBGitIndex.h +++ b/PBGitIndex.h @@ -11,6 +11,12 @@ @class PBGitRepository; @class PBChangedFile; +extern NSString *PBGitIndexIndexRefreshStatus; +extern NSString *PBGitIndexIndexRefreshFailed; +extern NSString *PBGitIndexFinishedIndexRefresh; +extern NSString *PBGitIndexCommitFailed; +extern NSString *PBGitIndexFinishedCommit; + // Represents a git index for a given work tree. // As a single git repository can have multiple trees, // the tree has to be given explicitly, even though diff --git a/PBGitIndex.m b/PBGitIndex.m index 717ceff..2ce84ab 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -13,6 +13,13 @@ #import "NSString_RegEx.h" #import "PBChangedFile.h" +NSString *PBGitIndexIndexRefreshStatus = @"PBGitIndexIndexRefreshStatus"; +NSString *PBGitIndexIndexRefreshFailed = @"PBGitIndexIndexRefreshFailed"; +NSString *PBGitIndexFinishedIndexRefresh = @"PBGitIndexFinishedIndexRefresh"; +NSString *PBGitIndexCommitFailed = @"PBGitIndexCommitFailed"; +NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; + + @interface PBGitIndex (IndexRefreshMethods) - (NSArray *)linesFromNotification:(NSNotification *)notification; @@ -316,10 +323,16 @@ { if ([(NSNumber *)[(NSDictionary *)[notification userInfo] objectForKey:@"NSFileHandleError"] intValue]) { - // TODO: send updatefailed notification? + [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexIndexRefreshFailed + object:self + userInfo:[NSDictionary dictionaryWithObject:@"update-index failed" forKey:@"description"]]; return; } + [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexIndexRefreshStatus + object:self + userInfo:[NSDictionary dictionaryWithObject:@"update-index success" forKey:@"description"]]; + // Now that the index is refreshed, we need to read the information from the index NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; @@ -529,7 +542,8 @@ [self didChangeValueForKey:@"indexChanges"]; } - // TODO: Sent index refresh finished operation + [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexFinishedIndexRefresh + object:self]; } @end From c6d2b61020455875fabe45a6f7e97d369e916858 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 03:20:42 +0200 Subject: [PATCH 12/24] CommitController: Add status messages for index operations --- PBGitCommitController.h | 2 ++ PBGitCommitController.m | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/PBGitCommitController.h b/PBGitCommitController.h index a8b2802..78ce470 100644 --- a/PBGitCommitController.h +++ b/PBGitCommitController.h @@ -24,6 +24,7 @@ IBOutlet PBWebChangesController *webController; NSString *status; + BOOL busy; NSDictionary *amendEnvironment; @@ -31,6 +32,7 @@ @property(copy) NSString *status; @property(readonly) PBGitIndex *index; +@property(assign) BOOL busy; // FIXME: redo 0823ff859dc65db238951c16e49293ea411c2b5a - (IBAction) refresh:(id) sender; diff --git a/PBGitCommitController.m b/PBGitCommitController.m index 38ecc13..0643402 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -14,13 +14,13 @@ #import "NSString_RegEx.h" -@interface PBGitCommitController (PrivateMethods) -- (void)processHunk:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse; +@interface PBGitCommitController () +- (void)refreshFinished:(NSNotification *)notification; @end @implementation PBGitCommitController -@synthesize status, index; +@synthesize status, index, busy; - (id)initWithRepository:(PBGitRepository *)theRepository superController:(PBGitWindowController *)controller { @@ -29,14 +29,10 @@ index = [[PBGitIndex alloc] initWithRepository:theRepository workingDirectory:[NSURL fileURLWithPath:[theRepository workingDirectory]]]; [index refresh]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshFinished:) name:PBGitIndexFinishedIndexRefresh object:index]; return self; } -- (BOOL)busy -{ - return NO; -} - - (void)awakeFromNib { [super awakeFromNib]; @@ -80,6 +76,8 @@ - (void) refresh:(id) sender { + self.busy = YES; + self.status = @"Refreshing index…"; [index refresh]; // Reload refs (in case HEAD changed) @@ -128,4 +126,9 @@ } +- (void)refreshFinished:(NSNotification *)notification +{ + self.busy = NO; + self.status = @"Index refresh finished"; +} @end From 4192d6a03f08fa347d4600071eb08042cca594a5 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 03:37:30 +0200 Subject: [PATCH 13/24] GitIndex: add commit notifications --- PBGitCommitController.m | 28 ++++++++++++++++++++++++---- PBGitIndex.h | 2 ++ PBGitIndex.m | 39 +++++++++++++++++++++++++++++++++------ 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/PBGitCommitController.m b/PBGitCommitController.m index 0643402..b5163be 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -16,6 +16,8 @@ @interface PBGitCommitController () - (void)refreshFinished:(NSNotification *)notification; +- (void)commitStatusUpdated:(NSNotification *)notification; +- (void)commitFinished:(NSNotification *)notification; @end @implementation PBGitCommitController @@ -29,7 +31,11 @@ index = [[PBGitIndex alloc] initWithRepository:theRepository workingDirectory:[NSURL fileURLWithPath:[theRepository workingDirectory]]]; [index refresh]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshFinished:) name:PBGitIndexFinishedIndexRefresh object:index]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitStatusUpdated:) name:PBGitIndexCommitStatus object:index]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFinished:) name:PBGitIndexFinishedCommit object:index]; + return self; } @@ -118,11 +124,10 @@ [cachedFilesController setSelectionIndexes:[NSIndexSet indexSet]]; [unstagedFilesController setSelectionIndexes:[NSIndexSet indexSet]]; + self.busy = YES; + [index commitWithMessage:commitMessage]; - - [webController setStateMessage:[NSString stringWithFormat:@"Successfully created commit"]]; - - [commitMessageView setString:@""]; + [commitMessageView setEditable:NO]; } @@ -131,4 +136,19 @@ self.busy = NO; self.status = @"Index refresh finished"; } + +- (void)commitStatusUpdated:(NSNotification *)notification +{ + self.status = [[notification userInfo] objectForKey:@"description"]; +} + +- (void)commitFinished:(NSNotification *)notification +{ + [webController setStateMessage:[NSString stringWithFormat:[[notification userInfo] objectForKey:@"description"]]]; + + BOOL success = [[[notification userInfo] objectForKey:@"success"] boolValue]; + if (success) + [commitMessageView setString:@""]; + [commitMessageView setEditable:YES]; +} @end diff --git a/PBGitIndex.h b/PBGitIndex.h index 7dd0e93..f1fc8c9 100644 --- a/PBGitIndex.h +++ b/PBGitIndex.h @@ -14,6 +14,8 @@ extern NSString *PBGitIndexIndexRefreshStatus; extern NSString *PBGitIndexIndexRefreshFailed; extern NSString *PBGitIndexFinishedIndexRefresh; + +extern NSString *PBGitIndexCommitStatus; extern NSString *PBGitIndexCommitFailed; extern NSString *PBGitIndexFinishedCommit; diff --git a/PBGitIndex.m b/PBGitIndex.m index 2ce84ab..e641102 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -16,6 +16,8 @@ NSString *PBGitIndexIndexRefreshStatus = @"PBGitIndexIndexRefreshStatus"; NSString *PBGitIndexIndexRefreshFailed = @"PBGitIndexIndexRefreshFailed"; NSString *PBGitIndexFinishedIndexRefresh = @"PBGitIndexFinishedIndexRefresh"; + +NSString *PBGitIndexCommitStatus = @"PBGitIndexCommitStatus"; NSString *PBGitIndexCommitFailed = @"PBGitIndexCommitFailed"; NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; @@ -40,6 +42,7 @@ NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; // Returns the tree to compare the index to, based // on whether amend is set or not. - (NSString *) parentTree; +- (void)postCommitUpdate:(NSString *)update; @end @@ -138,8 +141,9 @@ NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; commitMessageFile = [repository.fileURL.path stringByAppendingPathComponent:@"COMMIT_EDITMSG"]; [commitMessage writeToFile:commitMessageFile atomically:YES encoding:NSUTF8StringEncoding error:nil]; + - // TODO: Notification: @"Creating tree.."; + [self postCommitUpdate:@"Creating tree"]; NSString *tree = [repository outputForCommand:@"write-tree"]; if ([tree length] != 40) return; //TODO: commitFailedBecause:@"Could not create a tree"; @@ -152,6 +156,7 @@ NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; [arguments addObject:parent]; } + [self postCommitUpdate:@"Creating commit"]; int ret = 1; NSString *commit = [repository outputForArguments:arguments inputString:commitMessage @@ -161,23 +166,38 @@ NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; if (ret || [commit length] != 40) return; // TODO: [self commitFailedBecause:@"Could not create a commit object"]; + [self postCommitUpdate:@"Running hooks"]; if (![repository executeHook:@"pre-commit" output:nil]) return; // TODO: [self commitFailedBecause:@"Pre-commit hook failed"]; if (![repository executeHook:@"commit-msg" withArgs:[NSArray arrayWithObject:commitMessageFile] output:nil]) return; // TODO: [self commitFailedBecause:@"Commit-msg hook failed"]; + [self postCommitUpdate:@"Updating HEAD"]; [repository outputForArguments:[NSArray arrayWithObjects:@"update-ref", @"-m", commitSubject, @"HEAD", commit, nil] retValue: &ret]; if (ret) return; // TODO: [self commitFailedBecause:@"Could not update HEAD"]; - if (![repository executeHook:@"post-commit" output:nil]) - return; // [webController setStateMessage:[NSString stringWithFormat:@"Post-commit hook failed, however, successfully created commit %@", commit]]; - else - //[webController setStateMessage:[NSString stringWithFormat:@"Successfully created commit %@", commit]]; - ; + [self postCommitUpdate:@"Running post-commit hook"]; + BOOL success = [repository executeHook:@"post-commit" output:nil]; + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithBool:success] forKey:@"success"]; + NSString *description; + if (success) + description = [NSString stringWithFormat:@"Successfull created commit %@", commit]; + else + description = [NSString stringWithFormat:@"Post-commit hook failed, but successfully created commit %@", commit]; + + [userInfo setObject:description forKey:@"description"]; + [userInfo setObject:commit forKey:@"sha"]; + + [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexFinishedCommit + object:self + userInfo:userInfo]; + if (!success) + return; + repository.hasChanged = YES; amendEnvironment = nil; @@ -188,6 +208,13 @@ NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; } +- (void)postCommitUpdate:(NSString *)update +{ + [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexCommitStatus + object:self + userInfo:[NSDictionary dictionaryWithObject:update forKey:@"description"]]; +} + - (BOOL)stageFiles:(NSArray *)stageFiles { // Input string for update-index From 5323b9159686b2d40f5a50077e704f6880b3aff3 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 03:44:00 +0200 Subject: [PATCH 14/24] Add failed commit notifications --- PBGitCommitController.m | 24 ++++++++++++------------ PBGitIndex.m | 20 ++++++++++++++------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/PBGitCommitController.m b/PBGitCommitController.m index b5163be..861f8b7 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -18,6 +18,7 @@ - (void)refreshFinished:(NSNotification *)notification; - (void)commitStatusUpdated:(NSNotification *)notification; - (void)commitFinished:(NSNotification *)notification; +- (void)commitFailed:(NSNotification *)notification; @end @implementation PBGitCommitController @@ -35,6 +36,7 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshFinished:) name:PBGitIndexFinishedIndexRefresh object:index]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitStatusUpdated:) name:PBGitIndexCommitStatus object:index]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFinished:) name:PBGitIndexFinishedCommit object:index]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFailed:) name:PBGitIndexCommitFailed object:index]; return self; } @@ -95,14 +97,6 @@ [self refresh:nil]; } -- (void) commitFailedBecause:(NSString *)reason -{ - //self.busy--; - self.status = [@"Commit failed: " stringByAppendingString:reason]; - [[repository windowController] showMessageSheet:@"Commit failed" infoText:reason]; - return; -} - - (IBAction) commit:(id) sender { if ([[NSFileManager defaultManager] fileExistsAtPath:[repository.fileURL.path stringByAppendingPathComponent:@"MERGE_HEAD"]]) { @@ -145,10 +139,16 @@ - (void)commitFinished:(NSNotification *)notification { [webController setStateMessage:[NSString stringWithFormat:[[notification userInfo] objectForKey:@"description"]]]; - - BOOL success = [[[notification userInfo] objectForKey:@"success"] boolValue]; - if (success) - [commitMessageView setString:@""]; [commitMessageView setEditable:YES]; } + +- (void)commitFailed:(NSNotification *)notification +{ + self.busy = NO; + NSString *reason = [[notification userInfo] objectForKey:@"description"]; + self.status = [@"Commit failed: " stringByAppendingString:reason]; + [[repository windowController] showMessageSheet:@"Commit failed" infoText:reason]; +} + + @end diff --git a/PBGitIndex.m b/PBGitIndex.m index e641102..13c82a6 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -43,7 +43,7 @@ NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; // on whether amend is set or not. - (NSString *) parentTree; - (void)postCommitUpdate:(NSString *)update; - +- (void)postCommitFailure:(NSString *)reason; @end @implementation PBGitIndex @@ -146,7 +146,7 @@ NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; [self postCommitUpdate:@"Creating tree"]; NSString *tree = [repository outputForCommand:@"write-tree"]; if ([tree length] != 40) - return; //TODO: commitFailedBecause:@"Could not create a tree"; + return [self postCommitFailure:@"Creating tree failed"]; NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"commit-tree", tree, nil]; @@ -164,20 +164,20 @@ NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; retValue: &ret]; if (ret || [commit length] != 40) - return; // TODO: [self commitFailedBecause:@"Could not create a commit object"]; + return [self postCommitFailure:@"Could not create a commit object"]; [self postCommitUpdate:@"Running hooks"]; if (![repository executeHook:@"pre-commit" output:nil]) - return; // TODO: [self commitFailedBecause:@"Pre-commit hook failed"]; + return [self postCommitFailure:@"Pre-commit hook failed"]; if (![repository executeHook:@"commit-msg" withArgs:[NSArray arrayWithObject:commitMessageFile] output:nil]) - return; // TODO: [self commitFailedBecause:@"Commit-msg hook failed"]; + return [self postCommitFailure:@"Commit-msg hook failed"]; [self postCommitUpdate:@"Updating HEAD"]; [repository outputForArguments:[NSArray arrayWithObjects:@"update-ref", @"-m", commitSubject, @"HEAD", commit, nil] retValue: &ret]; if (ret) - return; // TODO: [self commitFailedBecause:@"Could not update HEAD"]; + return [self postCommitFailure:@"Could not update HEAD"]; [self postCommitUpdate:@"Running post-commit hook"]; @@ -215,6 +215,14 @@ NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; userInfo:[NSDictionary dictionaryWithObject:update forKey:@"description"]]; } +- (void)postCommitFailure:(NSString *)reason +{ + [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexCommitFailed + object:self + userInfo:[NSDictionary dictionaryWithObject:reason forKey:@"description"]]; +} + + - (BOOL)stageFiles:(NSArray *)stageFiles { // Input string for update-index From 6265c774ac8893c38ef462a057fd0e111604bf37 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 03:51:36 +0200 Subject: [PATCH 15/24] CommitView: Remove cruft --- PBGitCommitController.h | 3 --- PBGitIndexController.h | 4 ---- PBGitIndexController.m | 9 --------- PBWebChangesController.h | 1 - PBWebChangesController.m | 8 -------- 5 files changed, 25 deletions(-) diff --git a/PBGitCommitController.h b/PBGitCommitController.h index 78ce470..135e581 100644 --- a/PBGitCommitController.h +++ b/PBGitCommitController.h @@ -25,9 +25,6 @@ NSString *status; BOOL busy; - - NSDictionary *amendEnvironment; - } @property(copy) NSString *status; diff --git a/PBGitIndexController.h b/PBGitIndexController.h index 7b718ac..49454cc 100644 --- a/PBGitIndexController.h +++ b/PBGitIndexController.h @@ -23,10 +23,6 @@ IBOutlet NSTableView *stagedTable; } -@property (assign) int contextSize; - -- (NSString *) contextParameter; - - (IBAction) rowClicked:(NSCell *) sender; - (IBAction) tableClicked:(NSTableView *)tableView; diff --git a/PBGitIndexController.m b/PBGitIndexController.m index 148c8e1..1637fc5 100644 --- a/PBGitIndexController.m +++ b/PBGitIndexController.m @@ -20,12 +20,8 @@ @implementation PBGitIndexController -@synthesize contextSize; - - (void)awakeFromNib { - contextSize = 3; - [unstagedTable setDoubleAction:@selector(tableClicked:)]; [stagedTable setDoubleAction:@selector(tableClicked:)]; @@ -315,11 +311,6 @@ writeRowsWithIndexes:(NSIndexSet *)rowIndexes return YES; } -- (NSString *) contextParameter -{ - return [[NSString alloc] initWithFormat:@"-U%i", contextSize]; -} - # pragma mark WebKit Accessibility + (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector diff --git a/PBWebChangesController.h b/PBWebChangesController.h index 0b0ec13..069f6fc 100644 --- a/PBWebChangesController.h +++ b/PBWebChangesController.h @@ -27,5 +27,4 @@ - (void) setStateMessage:(NSString *)state; - (void) showMultiple:(NSArray *)files; -- (void) setContextSize:(int)size; @end diff --git a/PBWebChangesController.m b/PBWebChangesController.m index 592e596..2aa96e3 100644 --- a/PBWebChangesController.m +++ b/PBWebChangesController.m @@ -113,12 +113,4 @@ [script callWebScriptMethod:@"setState" withArguments: [NSArray arrayWithObject:state]]; } -- (void) setContextSize:(int)size -{ - if (size == indexController.contextSize) - return; - - indexController.contextSize = size; - [self refresh]; -} @end From 2b317eee5c42fb93ba5f44a83d451f06ab9fe178 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 03:52:18 +0200 Subject: [PATCH 16/24] CommitController: Empty commit title when commit is successful --- PBGitCommitController.m | 1 + 1 file changed, 1 insertion(+) diff --git a/PBGitCommitController.m b/PBGitCommitController.m index 861f8b7..11b470d 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -138,6 +138,7 @@ - (void)commitFinished:(NSNotification *)notification { + [commitMessageView setString:@""]; [webController setStateMessage:[NSString stringWithFormat:[[notification userInfo] objectForKey:@"description"]]]; [commitMessageView setEditable:YES]; } From 249233114dbb4653fbac2821de68d066f2cbc09a Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 04:02:52 +0200 Subject: [PATCH 17/24] Show previous commit message when amending --- PBGitCommitController.m | 15 +++++++++++++++ PBGitIndex.h | 1 + PBGitIndex.m | 11 +++++++++++ 3 files changed, 27 insertions(+) diff --git a/PBGitCommitController.m b/PBGitCommitController.m index 11b470d..9520056 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -19,6 +19,7 @@ - (void)commitStatusUpdated:(NSNotification *)notification; - (void)commitFinished:(NSNotification *)notification; - (void)commitFailed:(NSNotification *)notification; +- (void)amendCommit:(NSNotification *)notification; @end @implementation PBGitCommitController @@ -37,6 +38,7 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitStatusUpdated:) name:PBGitIndexCommitStatus object:index]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFinished:) name:PBGitIndexFinishedCommit object:index]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFailed:) name:PBGitIndexCommitFailed object:index]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(amendCommit:) name:PBGitIndexAmendMessageAvailable object:index]; return self; } @@ -56,11 +58,13 @@ [cachedFilesController setSortDescriptors:[NSArray arrayWithObject: [[NSSortDescriptor alloc] initWithKey:@"path" ascending:true]]]; } + - (void) removeView { [webController closeView]; [super finalize]; } + - (NSResponder *)firstResponder; { return commitMessageView; @@ -151,5 +155,16 @@ [[repository windowController] showMessageSheet:@"Commit failed" infoText:reason]; } +- (void)amendCommit:(NSNotification *)notification +{ + // Replace commit message with the old one if it's less than 3 characters long. + // This is just a random number. + if ([[commitMessageView string] length] > 3) + return; + + NSString *message = [[notification userInfo] objectForKey:@"message"]; + commitMessageView.string = message; +} + @end diff --git a/PBGitIndex.h b/PBGitIndex.h index f1fc8c9..cc4ae77 100644 --- a/PBGitIndex.h +++ b/PBGitIndex.h @@ -19,6 +19,7 @@ extern NSString *PBGitIndexCommitStatus; extern NSString *PBGitIndexCommitFailed; extern NSString *PBGitIndexFinishedCommit; +extern NSString *PBGitIndexAmendMessageAvailable; // Represents a git index for a given work tree. // As a single git repository can have multiple trees, // the tree has to be given explicitly, even though diff --git a/PBGitIndex.m b/PBGitIndex.m index 13c82a6..2b45988 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -21,6 +21,7 @@ NSString *PBGitIndexCommitStatus = @"PBGitIndexCommitStatus"; NSString *PBGitIndexCommitFailed = @"PBGitIndexCommitFailed"; NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; +NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; @interface PBGitIndex (IndexRefreshMethods) @@ -93,6 +94,16 @@ NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; [match objectAtIndex:2], @"GIT_AUTHOR_EMAIL", [match objectAtIndex:3], @"GIT_AUTHOR_DATE", nil]; + + // Find the commit message + NSRange r = [message rangeOfString:@"\n\n"]; + if (r.location != NSNotFound) { + NSString *commitMessage = [message substringFromIndex:r.location + 2]; + [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexAmendMessageAvailable + object: self + userInfo:[NSDictionary dictionaryWithObject:commitMessage forKey:@"message"]]; + } + } - (void)refresh From 9b1fcd76280fe5e3e71cf4445379877b521735b0 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 04:07:52 +0200 Subject: [PATCH 18/24] Remove cruft --- PBGitCommitController.h | 1 - PBGitCommitController.m | 2 -- PBGitIndexController.h | 2 -- PBGitIndexController.m | 2 -- PBWebChangesController.m | 5 ----- 5 files changed, 12 deletions(-) diff --git a/PBGitCommitController.h b/PBGitCommitController.h index 135e581..f29f884 100644 --- a/PBGitCommitController.h +++ b/PBGitCommitController.h @@ -31,7 +31,6 @@ @property(readonly) PBGitIndex *index; @property(assign) BOOL busy; -// FIXME: redo 0823ff859dc65db238951c16e49293ea411c2b5a - (IBAction) refresh:(id) sender; - (IBAction) commit:(id) sender; - (IBAction)signOff:(id)sender; diff --git a/PBGitCommitController.m b/PBGitCommitController.m index 9520056..0e1fdfd 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -11,8 +11,6 @@ #import "PBChangedFile.h" #import "PBWebChangesController.h" #import "PBGitIndex.h" -#import "NSString_RegEx.h" - @interface PBGitCommitController () - (void)refreshFinished:(NSNotification *)notification; diff --git a/PBGitIndexController.h b/PBGitIndexController.h index 49454cc..4bd969f 100644 --- a/PBGitIndexController.h +++ b/PBGitIndexController.h @@ -11,8 +11,6 @@ #import "PBChangedFile.h" @interface PBGitIndexController : NSObject { - int contextSize; - IBOutlet NSArrayController *stagedFilesController, *unstagedFilesController; IBOutlet PBGitCommitController *commitController; diff --git a/PBGitIndexController.m b/PBGitIndexController.m index 1637fc5..21429f6 100644 --- a/PBGitIndexController.m +++ b/PBGitIndexController.m @@ -30,10 +30,8 @@ [unstagedTable registerForDraggedTypes: [NSArray arrayWithObject:FileChangesTableViewType]]; [stagedTable registerForDraggedTypes: [NSArray arrayWithObject:FileChangesTableViewType]]; - } - - (void) ignoreFiles:(NSArray *)files { // Build output string diff --git a/PBWebChangesController.m b/PBWebChangesController.m index 2aa96e3..933fecc 100644 --- a/PBWebChangesController.m +++ b/PBWebChangesController.m @@ -30,11 +30,6 @@ [self refresh]; } -- (BOOL) amend -{ - return controller.index.amend; -} - - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change From 029b42c5401a868078271132c49b813928e398ce Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 04:16:51 +0200 Subject: [PATCH 19/24] GitIndex: explicitly tell when stuff is updated --- PBGitCommitController.m | 11 ++++++++++- PBGitIndex.h | 5 +++++ PBGitIndex.m | 21 ++++++++++++++++----- PBGitIndexController.m | 22 ++++------------------ 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/PBGitCommitController.m b/PBGitCommitController.m index 0e1fdfd..c0af324 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -18,6 +18,7 @@ - (void)commitFinished:(NSNotification *)notification; - (void)commitFailed:(NSNotification *)notification; - (void)amendCommit:(NSNotification *)notification; +- (void)indexChanged:(NSNotification *)notification; @end @implementation PBGitCommitController @@ -37,6 +38,7 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFinished:) name:PBGitIndexFinishedCommit object:index]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFailed:) name:PBGitIndexCommitFailed object:index]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(amendCommit:) name:PBGitIndexAmendMessageAvailable object:index]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(indexChanged:) name:PBGitIndexIndexUpdated object:index]; return self; } @@ -55,6 +57,9 @@ [[NSSortDescriptor alloc] initWithKey:@"path" ascending:true], nil]]; [cachedFilesController setSortDescriptors:[NSArray arrayWithObject: [[NSSortDescriptor alloc] initWithKey:@"path" ascending:true]]]; + + [cachedFilesController setAutomaticallyRearrangesObjects:NO]; + [unstagedFilesController setAutomaticallyRearrangesObjects:NO]; } - (void) removeView @@ -164,5 +169,9 @@ commitMessageView.string = message; } - +- (void)indexChanged:(NSNotification *)notification +{ + [cachedFilesController rearrangeObjects]; + [unstagedFilesController rearrangeObjects]; +} @end diff --git a/PBGitIndex.h b/PBGitIndex.h index cc4ae77..ee57245 100644 --- a/PBGitIndex.h +++ b/PBGitIndex.h @@ -15,11 +15,16 @@ extern NSString *PBGitIndexIndexRefreshStatus; extern NSString *PBGitIndexIndexRefreshFailed; extern NSString *PBGitIndexFinishedIndexRefresh; +// The "Files" array has changed +extern NSString *PBGitIndexIndexUpdated; + extern NSString *PBGitIndexCommitStatus; extern NSString *PBGitIndexCommitFailed; extern NSString *PBGitIndexFinishedCommit; extern NSString *PBGitIndexAmendMessageAvailable; + + // Represents a git index for a given work tree. // As a single git repository can have multiple trees, // the tree has to be given explicitly, even though diff --git a/PBGitIndex.m b/PBGitIndex.m index 2b45988..fb4ef3f 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -17,6 +17,8 @@ NSString *PBGitIndexIndexRefreshStatus = @"PBGitIndexIndexRefreshStatus"; NSString *PBGitIndexIndexRefreshFailed = @"PBGitIndexIndexRefreshFailed"; NSString *PBGitIndexFinishedIndexRefresh = @"PBGitIndexFinishedIndexRefresh"; +NSString *PBGitIndexIndexUpdated = @"GBGitIndexIndexUpdated"; + NSString *PBGitIndexCommitStatus = @"PBGitIndexCommitStatus"; NSString *PBGitIndexCommitFailed = @"PBGitIndexCommitFailed"; NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; @@ -45,6 +47,7 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; - (NSString *) parentTree; - (void)postCommitUpdate:(NSString *)update; - (void)postCommitFailure:(NSString *)reason; +- (void)postIndexChange; @end @implementation PBGitIndex @@ -257,13 +260,13 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; return NO; } - // TODO: Stop Tracking for (PBChangedFile *file in stageFiles) { file.hasUnstagedChanges = NO; file.hasStagedChanges = YES; } - // TODO: Resume tracking + + [self postIndexChange]; return YES; } @@ -288,14 +291,13 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; return NO; } - // TODO: stop tracking for (PBChangedFile *file in unstageFiles) { file.hasUnstagedChanges = YES; file.hasStagedChanges = NO; } - // TODO: resume tracking + [self postIndexChange]; return YES; } @@ -353,6 +355,11 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; return [repository outputInWorkdirForArguments:[NSArray arrayWithObjects:@"diff-files", parameter, @"--", file.path, nil]]; } +- (void)postIndexChange +{ + [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexIndexUpdated + object:self]; +} # pragma mark WebKit Accessibility @@ -568,8 +575,10 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; - (void)indexStepComplete { // if we're still busy, do nothing :) - if (--refreshStatus) + if (--refreshStatus) { + [self postIndexChange]; return; + } // At this point, all index operations have finished. // We need to find all files that don't have either @@ -590,6 +599,8 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexFinishedIndexRefresh object:self]; + [self postIndexChange]; + } @end diff --git a/PBGitIndexController.m b/PBGitIndexController.m index 21429f6..8ab9033 100644 --- a/PBGitIndexController.m +++ b/PBGitIndexController.m @@ -13,11 +13,6 @@ #define FileChangesTableViewType @"GitFileChangedType" -@interface PBGitIndexController (PrivateMethods) -- (void)stopTrackingIndex; -- (void)resumeTrackingIndex; -@end - @implementation PBGitIndexController - (void)awakeFromNib @@ -67,6 +62,8 @@ [ignoreFile writeToFile:gitIgnoreName atomically:YES encoding:enc error:&error]; if (error) [[commitController.repository windowController] showErrorSheet:error]; + + // TODO: Post index change } # pragma mark Displaying diffs @@ -97,6 +94,8 @@ for (PBChangedFile *file in files) file.hasUnstagedChanges = NO; + + // TODO: Post index update } # pragma mark Context Menu methods @@ -316,17 +315,4 @@ writeRowsWithIndexes:(NSIndexSet *)rowIndexes return NO; } -#pragma mark Private Methods -- (void)stopTrackingIndex -{ - [stagedFilesController setAutomaticallyRearrangesObjects:NO]; - [unstagedFilesController setAutomaticallyRearrangesObjects:NO]; -} -- (void)resumeTrackingIndex -{ - [stagedFilesController setAutomaticallyRearrangesObjects:YES]; - [unstagedFilesController setAutomaticallyRearrangesObjects:YES]; - [stagedFilesController rearrangeObjects]; - [unstagedFilesController rearrangeObjects]; -} @end From 59d4a159a47945543398599f70d7de2db1e0a7cd Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 16:14:11 +0200 Subject: [PATCH 20/24] GitIndex: Fix a few comments --- PBGitIndex.m | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/PBGitIndex.m b/PBGitIndex.m index fb4ef3f..47a0986 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -142,6 +142,7 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; return parent; } +// TODO: make Asynchronous - (void)commitWithMessage:(NSString *)commitMessage { NSMutableString *commitSubject = [@"commit: " mutableCopy]; @@ -419,8 +420,7 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; NSArray *lines = [self linesFromNotification:notification]; NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithCapacity:[lines count]]; // Other files are untracked, so we don't have any real index information. Instead, we can just fake it. - // The line below is used to add the file to the index - // FIXME: request the real file mode + // The line below is not used at all, as for these files the commitBlob isn't set NSArray *fileStatus = [NSArray arrayWithObjects:@":000000", @"100644", @"0000000000000000000000000000000000000000", @"0000000000000000000000000000000000000000", @"A", nil]; for (NSString *path in lines) { if ([path length] == 0) @@ -450,7 +450,6 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; - (void) addFilesFromDictionary:(NSMutableDictionary *)dictionary staged:(BOOL)staged tracked:(BOOL)tracked { - // TODO: Stop tracking files // Iterate over all existing files for (PBChangedFile *file in files) { NSArray *fileStatus = [dictionary objectForKey:file.path]; @@ -494,7 +493,6 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; file.hasUnstagedChanges = NO; } } - // TODO: Finish tracking files // Do new files only if necessary if (![[dictionary allKeys] count]) @@ -535,7 +533,7 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; return [NSArray array]; NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - // FIXME: Return an error? + // FIXME: throw an error? if (!string) return [NSArray array]; From e17b454c39d7556f2d676d424496e3f68b7f16fe Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 16:15:23 +0200 Subject: [PATCH 21/24] CommitController: Make commit message editable after commit failed --- PBGitCommitController.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/PBGitCommitController.m b/PBGitCommitController.m index c0af324..a6200dc 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -126,9 +126,9 @@ [unstagedFilesController setSelectionIndexes:[NSIndexSet indexSet]]; self.busy = YES; + [commitMessageView setEditable:NO]; [index commitWithMessage:commitMessage]; - [commitMessageView setEditable:NO]; } @@ -145,9 +145,9 @@ - (void)commitFinished:(NSNotification *)notification { + [commitMessageView setEditable:YES]; [commitMessageView setString:@""]; [webController setStateMessage:[NSString stringWithFormat:[[notification userInfo] objectForKey:@"description"]]]; - [commitMessageView setEditable:YES]; } - (void)commitFailed:(NSNotification *)notification @@ -155,6 +155,7 @@ self.busy = NO; NSString *reason = [[notification userInfo] objectForKey:@"description"]; self.status = [@"Commit failed: " stringByAppendingString:reason]; + [commitMessageView setEditable:YES]; [[repository windowController] showMessageSheet:@"Commit failed" infoText:reason]; } From 3dc312ff2e5971e528c89da63946cc2f67820558 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 16:16:53 +0200 Subject: [PATCH 22/24] PBGitIndex: Migrate discardChanges to the GitIndex --- PBGitIndex.h | 1 + PBGitIndex.m | 22 ++++++++++++++++++++++ PBGitIndexController.m | 18 ++---------------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/PBGitIndex.h b/PBGitIndex.h index ee57245..67a474a 100644 --- a/PBGitIndex.h +++ b/PBGitIndex.h @@ -60,6 +60,7 @@ extern NSString *PBGitIndexAmendMessageAvailable; // Inter-file changes: - (BOOL)stageFiles:(NSArray *)stageFiles; - (BOOL)unstageFiles:(NSArray *)unstageFiles; +- (void)discardChangesForFiles:(NSArray *)discardFiles; // Intra-file changes - (BOOL)applyPatch:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse; diff --git a/PBGitIndex.m b/PBGitIndex.m index 47a0986..d3d0263 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -302,6 +302,28 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; return YES; } +- (void)discardChangesForFiles:(NSArray *)discardFiles +{ + NSArray *paths = [discardFiles valueForKey:@"path"]; + NSString *input = [paths componentsJoinedByString:@"\0"]; + + NSArray *arguments = [NSArray arrayWithObjects:@"checkout-index", @"--index", @"--quiet", @"--force", @"-z", @"--stdin", nil]; + + int ret = 1; + [PBEasyPipe outputForCommand:[PBGitBinary path] withArgs:arguments inDir:[workingDirectory path] inputString:input retValue:&ret]; + + if (ret) { + // TODO: Post failed notification + // [[commitController.repository windowController] showMessageSheet:@"Discarding changes failed" infoText:[NSString stringWithFormat:@"Discarding changes failed with error code %i", ret]]; + return; + } + + for (PBChangedFile *file in discardFiles) + file.hasUnstagedChanges = NO; + + [self postIndexChange]; +} + - (BOOL)applyPatch:(NSString *)hunk stage:(BOOL)stage reverse:(BOOL)reverse; { NSMutableArray *array = [NSMutableArray arrayWithObjects:@"apply", nil]; diff --git a/PBGitIndexController.m b/PBGitIndexController.m index 8ab9033..a19c6b9 100644 --- a/PBGitIndexController.m +++ b/PBGitIndexController.m @@ -71,7 +71,7 @@ - (void)discardChangesForFiles:(NSArray *)files force:(BOOL)force { - if(!force) { + if (!force) { int ret = [[NSAlert alertWithMessageText:@"Discard changes" defaultButton:nil alternateButton:@"Cancel" @@ -81,21 +81,7 @@ return; } - NSArray *paths = [files valueForKey:@"path"]; - NSString *input = [paths componentsJoinedByString:@"\0"]; - - NSArray *arguments = [NSArray arrayWithObjects:@"checkout-index", @"--index", @"--quiet", @"--force", @"-z", @"--stdin", nil]; - int ret = 1; - [commitController.repository outputForArguments:arguments inputString:input retValue:&ret]; - if (ret) { - [[commitController.repository windowController] showMessageSheet:@"Discarding changes failed" infoText:[NSString stringWithFormat:@"Discarding changes failed with error code %i", ret]]; - return; - } - - for (PBChangedFile *file in files) - file.hasUnstagedChanges = NO; - - // TODO: Post index update + [commitController.index discardChangesForFiles:files]; } # pragma mark Context Menu methods From 438a3f808dede8589d47ea36f695727522d8b6dc Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 16:32:35 +0200 Subject: [PATCH 23/24] GitIndexController: reorder methods a bit, remove unnecessary stuff --- PBGitCommitView.xib | 20 --------------- PBGitIndexController.h | 3 --- PBGitIndexController.m | 57 ++++++++++++++++++------------------------ 3 files changed, 25 insertions(+), 55 deletions(-) diff --git a/PBGitCommitView.xib b/PBGitCommitView.xib index 49beeb5..5b8021f 100644 --- a/PBGitCommitView.xib +++ b/PBGitCommitView.xib @@ -1114,22 +1114,6 @@ 264 - - - stagedButtonCell - - - - 265 - - - - unstagedButtonCell - - - - 266 - rowClicked: @@ -1763,20 +1747,16 @@ YES commitController - stagedButtonCell stagedFilesController stagedTable - unstagedButtonCell unstagedFilesController unstagedTable YES PBGitCommitController - PBIconAndTextCell NSArrayController NSTableView - PBIconAndTextCell NSArrayController NSTableView diff --git a/PBGitIndexController.h b/PBGitIndexController.h index 4bd969f..1a455e6 100644 --- a/PBGitIndexController.h +++ b/PBGitIndexController.h @@ -14,9 +14,6 @@ IBOutlet NSArrayController *stagedFilesController, *unstagedFilesController; IBOutlet PBGitCommitController *commitController; - IBOutlet PBIconAndTextCell* unstagedButtonCell; - IBOutlet PBIconAndTextCell* stagedButtonCell; - IBOutlet NSTableView *unstagedTable; IBOutlet NSTableView *stagedTable; } diff --git a/PBGitIndexController.m b/PBGitIndexController.m index a19c6b9..5d2a949 100644 --- a/PBGitIndexController.m +++ b/PBGitIndexController.m @@ -13,6 +13,10 @@ #define FileChangesTableViewType @"GitFileChangedType" +@interface PBGitIndexController () +- (void)discardChangesForFiles:(NSArray *)files force:(BOOL)force; +@end + @implementation PBGitIndexController - (void)awakeFromNib @@ -27,7 +31,8 @@ [stagedTable registerForDraggedTypes: [NSArray arrayWithObject:FileChangesTableViewType]]; } -- (void) ignoreFiles:(NSArray *)files +// FIXME: Find a proper place for this method -- this is not it. +- (void)ignoreFiles:(NSArray *)files { // Build output string NSMutableArray *fileList = [NSMutableArray array]; @@ -62,26 +67,6 @@ [ignoreFile writeToFile:gitIgnoreName atomically:YES encoding:enc error:&error]; if (error) [[commitController.repository windowController] showErrorSheet:error]; - - // TODO: Post index change -} - -# pragma mark Displaying diffs - - -- (void)discardChangesForFiles:(NSArray *)files force:(BOOL)force -{ - if (!force) { - int ret = [[NSAlert alertWithMessageText:@"Discard changes" - defaultButton:nil - alternateButton:@"Cancel" - otherButton:nil - informativeTextWithFormat:@"Are you sure you wish to discard the changes to this file?\n\nYou cannot undo this operation."] runModal]; - if (ret != NSAlertDefaultReturn) - return; - } - - [commitController.index discardChangesForFiles:files]; } # pragma mark Context Menu methods @@ -179,10 +164,11 @@ - (void) ignoreFilesAction:(id) sender { NSArray *selectedFiles = [sender representedObject]; - if ([selectedFiles count] > 0) { - [self ignoreFiles:selectedFiles]; - } - [commitController refresh:NULL]; + if ([selectedFiles count] == 0) + return; + + [self ignoreFiles:selectedFiles]; + [commitController.index refresh]; } - (void)discardFilesAction:(id) sender @@ -210,6 +196,20 @@ [ws selectFile: path inFileViewerRootedAtPath:nil]; } +- (void)discardChangesForFiles:(NSArray *)files force:(BOOL)force +{ + if (!force) { + int ret = [[NSAlert alertWithMessageText:@"Discard changes" + defaultButton:nil + alternateButton:@"Cancel" + otherButton:nil + informativeTextWithFormat:@"Are you sure you wish to discard the changes to this file?\n\nYou cannot undo this operation."] runModal]; + if (ret != NSAlertDefaultReturn) + return; + } + + [commitController.index discardChangesForFiles:files]; +} # pragma mark TableView icon delegate - (void)tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)rowIndex @@ -294,11 +294,4 @@ writeRowsWithIndexes:(NSIndexSet *)rowIndexes return YES; } -# pragma mark WebKit Accessibility - -+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector -{ - return NO; -} - @end From a2b3bf3d1e05c581468c32b41008223322f2a718 Mon Sep 17 00:00:00 2001 From: Pieter de Bie Date: Sun, 13 Sep 2009 16:47:30 +0200 Subject: [PATCH 24/24] PBGitIndex: post notifications when index stuff fails We use notifications so that we can make all these methods async later on --- PBGitCommitController.m | 9 +++++++++ PBGitIndex.h | 13 ++++++++++++- PBGitIndex.m | 20 ++++++++++++-------- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/PBGitCommitController.m b/PBGitCommitController.m index a6200dc..6a77348 100644 --- a/PBGitCommitController.m +++ b/PBGitCommitController.m @@ -19,6 +19,7 @@ - (void)commitFailed:(NSNotification *)notification; - (void)amendCommit:(NSNotification *)notification; - (void)indexChanged:(NSNotification *)notification; +- (void)indexOperationFailed:(NSNotification *)notification; @end @implementation PBGitCommitController @@ -39,6 +40,7 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitFailed:) name:PBGitIndexCommitFailed object:index]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(amendCommit:) name:PBGitIndexAmendMessageAvailable object:index]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(indexChanged:) name:PBGitIndexIndexUpdated object:index]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(indexOperationFailed:) name:PBGitIndexOperationFailed object:index]; return self; } @@ -132,6 +134,7 @@ } +# pragma mark PBGitIndex Notification handling - (void)refreshFinished:(NSNotification *)notification { self.busy = NO; @@ -175,4 +178,10 @@ [cachedFilesController rearrangeObjects]; [unstagedFilesController rearrangeObjects]; } + +- (void)indexOperationFailed:(NSNotification *)notification +{ + [[repository windowController] showMessageSheet:@"Index operation failed" infoText:[[notification userInfo] objectForKey:@"description"]]; +} + @end diff --git a/PBGitIndex.h b/PBGitIndex.h index 67a474a..7ca1db7 100644 --- a/PBGitIndex.h +++ b/PBGitIndex.h @@ -11,19 +11,30 @@ @class PBGitRepository; @class PBChangedFile; +/* + * Notifications this class will send + */ + +// Refreshing index extern NSString *PBGitIndexIndexRefreshStatus; extern NSString *PBGitIndexIndexRefreshFailed; extern NSString *PBGitIndexFinishedIndexRefresh; -// The "Files" array has changed +// The "indexChanges" array has changed extern NSString *PBGitIndexIndexUpdated; +// Committing files extern NSString *PBGitIndexCommitStatus; extern NSString *PBGitIndexCommitFailed; extern NSString *PBGitIndexFinishedCommit; +// Changing to amend extern NSString *PBGitIndexAmendMessageAvailable; +// This is for general operations, like applying a patch +extern NSString *PBGitIndexOperationFailed; + + // Represents a git index for a given work tree. // As a single git repository can have multiple trees, diff --git a/PBGitIndex.m b/PBGitIndex.m index d3d0263..4174d49 100644 --- a/PBGitIndex.m +++ b/PBGitIndex.m @@ -24,6 +24,7 @@ NSString *PBGitIndexCommitFailed = @"PBGitIndexCommitFailed"; NSString *PBGitIndexFinishedCommit = @"PBGitIndexFinishedCommit"; NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; +NSString *PBGitIndexOperationFailed = @"PBGitIndexOperationFailed"; @interface PBGitIndex (IndexRefreshMethods) @@ -48,6 +49,7 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; - (void)postCommitUpdate:(NSString *)update; - (void)postCommitFailure:(NSString *)reason; - (void)postIndexChange; +- (void)postOperationFailed:(NSString *)description; @end @implementation PBGitIndex @@ -237,6 +239,12 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; userInfo:[NSDictionary dictionaryWithObject:reason forKey:@"description"]]; } +- (void)postOperationFailed:(NSString *)description +{ + [[NSNotificationCenter defaultCenter] postNotificationName:PBGitIndexOperationFailed + object:self + userInfo:[NSDictionary dictionaryWithObject:description forKey:@"description"]]; +} - (BOOL)stageFiles:(NSArray *)stageFiles { @@ -256,8 +264,7 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; retValue:&ret]; if (ret) { - // FIXME: failed notification? - NSLog(@"Error when updating index. Retvalue: %i", ret); + [self postOperationFailed:[NSString stringWithFormat:@"Error in staging files. Return value: %i", ret]]; return NO; } @@ -287,8 +294,7 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; if (ret) { - // FIXME: Failed notification - NSLog(@"Error when updating index. Retvalue: %i", ret); + [self postOperationFailed:[NSString stringWithFormat:@"Error in unstaging files. Return value: %i", ret]]; return NO; } @@ -313,8 +319,7 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; [PBEasyPipe outputForCommand:[PBGitBinary path] withArgs:arguments inDir:[workingDirectory path] inputString:input retValue:&ret]; if (ret) { - // TODO: Post failed notification - // [[commitController.repository windowController] showMessageSheet:@"Discarding changes failed" infoText:[NSString stringWithFormat:@"Discarding changes failed with error code %i", ret]]; + [self postOperationFailed:[NSString stringWithFormat:@"Discarding changes failed with return value %i", ret]]; return; } @@ -337,9 +342,8 @@ NSString *PBGitIndexAmendMessageAvailable = @"PBGitIndexAmendMessageAvailable"; inputString:hunk retValue:&ret]; - // FIXME: show this error, rather than just logging it if (ret) { - NSLog(@"Error: %@", error); + [self postOperationFailed:[NSString stringWithFormat:@"Applying patch failed with return value %i. Error: %@", ret, error]]; return NO; }