Skip to content

Commit

Permalink
Major overhaul of the handling/effect of CLI args (gitx/PBCLIProxy).
Browse files Browse the repository at this point in the history
Since we now have that gorgeous sidebar and commit list with branch filters, 
command line arguments to gitx should utilize these to greater effect.

For example, if I pass:

"--local" >> read current branch and set the branch filter to "Local"
"--all" >> same as above but set "All" branch filter
- partial or full SHA-1 >> should get the branch most likely associated with 
that SHA, select it in the sidebar and scroll the commit list to the commit 
with the passed SHA.
- partial ref like "xyz/master" >> select the master branch
of the "xyz" folder in the sidebar and scroll the commit list to its most
recent commit.
"--subject=Test" >> filter commit list using a predicate on the commit list's 
array controller (basically populating the search field programmatically).
For other "--..." CLI switches it's the same, just the filter predicate is a 
bit different each time. You get the idea.

To accomplish this we make the following changes:

- gitx sets two environment variables via setenv(), one for a concatenated 
  version of the CLI args, and one for the indicator that we launched from gitx.
  Using setenv() is unfortunate but I couldn't find a way to do it through DO
  and PBCLIProxy since that proxy will do it's processing far too late into 
  the app's event cycle. 

- the now shared application controller stores the two env vars in a BOOL
  'launchedFromGitx' and an NSString 'cliArgs'.

- Because GitX makes heavy use of KVO and context switching during the app
  launch we introduce the notion of a deferred selection so that we can worry
  about selecting the branch and commit the user has passed to gitx in some 
  form or another, when the app has finished launching completely and all 
  KVO notifications up to this point have been handled.
  
- ApplicationController does the bulk work. It stores most state
  changes, handles most command line switches (except for a few still in gitx.m),
  deals with the deferredSelectObject.

- PBGitSidebarController populateList includes logic for fixing up a ref or 
  a partial SHA when appController.launchedFromGitx is true. If it can be
  resolved we set this as the deferred select object so it can be selected
  later on.

I'll leave the excess NSLogs in there for this commit so another can see
what went into this before.
  • Loading branch information
andreberg committed Apr 5, 2010
1 parent f87cfa6 commit 10daa22
Show file tree
Hide file tree
Showing 8 changed files with 423 additions and 186 deletions.
11 changes: 11 additions & 0 deletions ApplicationController.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,20 @@
NSManagedObjectContext *managedObjectContext;

PBCLIProxy *cliProxy;
NSString * cliArgs;

// CLI set state
BOOL launchedFromGitx;
NSString * deferredSelectSha;
NSArray * launchedDocuments;

PBCloneRepositoryPanel *cloneRepositoryPanel;
}
@property (retain) PBCLIProxy* cliProxy;
@property (copy) NSString *cliArgs;
@property (assign) BOOL launchedFromGitx;
@property (copy) NSString *deferredSelectSha;

+ (ApplicationController *) sharedApplicationController;

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator;
Expand Down
97 changes: 92 additions & 5 deletions ApplicationController.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@
#import "PBNSURLPathUserDefaultsTransfomer.h"
#import "PBGitDefaults.h"
#import "PBCloneRepositoryPanel.h"
#import "BMScript.h"
#import "PBGitSidebarController.h"

@implementation ApplicationController
@synthesize cliProxy;
@synthesize cliArgs;
@synthesize launchedFromGitx;
@synthesize deferredSelectSha;

static ApplicationController * sharedApplicationControllerInstance = nil;

Expand Down Expand Up @@ -66,6 +71,11 @@ - (ApplicationController *) init
if(![[NSBundle bundleWithPath:@"/System/Library/Frameworks/Quartz.framework/Frameworks/QuickLookUI.framework"] load])
if(![[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/QuickLookUI.framework"] load])
NSLog(@"Could not load QuickLook");

self.cliProxy = [PBCLIProxy new];
launchedFromGitx = NO;
cliArgs = nil;
deferredSelectSha = nil;
}
/* Value Transformers */
NSValueTransformer *transformer = [[PBNSURLPathUserDefaultsTransfomer alloc] init];
Expand Down Expand Up @@ -101,11 +111,31 @@ - (void)applicationDidFinishLaunching:(NSNotification*)notification
// Make sure Git's SSH password requests get forwarded to our little UI tool:
setenv( "SSH_ASKPASS", [[[NSBundle mainBundle] pathForResource: @"gitx_askpasswd" ofType: @""] UTF8String], 1 );
setenv( "DISPLAY", "localhost:0", 1 );


char * launchedfromgitx = getenv("GITX_LAUNCHED_FROM_CLI");
char * cliargs = getenv("GITX_CLI_ARGUMENTS");

self.launchedFromGitx = (launchedfromgitx ? YES : NO);

if (cliargs) {
self.cliArgs = [NSString stringWithUTF8String:(cliargs)];
}

NSLog(@"[%@ %s] launchedFromGitx = %@", [self class], _cmd, (launchedFromGitx ? @"YES" : @"NO"));
NSLog(@"[%@ %s] cliArgs = %@", [self class], _cmd, cliArgs);

[self registerServices];

if ([cliArgs isEqualToString:@"--all"]) {
[PBGitDefaults setBranchFilter:kGitXAllBranchesFilter];
[[NSUserDefaults standardUserDefaults] synchronize];
} else if ([cliArgs isEqualToString:@"--local"]) {
[PBGitDefaults setBranchFilter:kGitXLocalRemoteBranchesFilter];
[[NSUserDefaults standardUserDefaults] synchronize];
}

BOOL hasOpenedDocuments = NO;
NSArray *launchedDocuments = [[[PBRepositoryDocumentController sharedDocumentController] documents] copy];
launchedDocuments = [[[PBRepositoryDocumentController sharedDocumentController] documents] copy];

// Only try to open a default document if there are no documents open already.
// For example, the application might have been launched by double-clicking a .git repository,
Expand All @@ -123,7 +153,7 @@ - (void)applicationDidFinishLaunching:(NSNotification*)notification
}
}

// Try to find the current directory, to open that as a repository
// Try to find the current directory, to open that as a repository...
if ([PBGitDefaults openCurDirOnLaunch] && !hasOpenedDocuments) {
NSString *curPath = [[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"];
NSURL *url = nil;
Expand All @@ -135,9 +165,47 @@ - (void)applicationDidFinishLaunching:(NSNotification*)notification
hasOpenedDocuments = YES;
}

// to bring the launched documents to the front
for (PBGitRepository *document in launchedDocuments)
launchedDocuments = [[[PBRepositoryDocumentController sharedDocumentController] documents] copy];

// ...to bring the launched documents to the front
for (PBGitRepository *document in launchedDocuments) {

PBGitWindowController * wc = [(PBGitRepository *)document windowController];
PBGitHistoryController * historyViewController = wc.historyController;
NSArrayController * ccontroller = historyViewController.commitController;

// determine what to show right after start - stage or standard history view?
if ([cliArgs isEqualToString:@"--commit"] || [cliArgs isEqualToString:@"-c"]) {
[wc showCommitView:self];
launchedFromGitx = NO;
} else {
[wc showHistoryView:self];
}

if ([cliArgs hasPrefix:@"--author"]) {
NSArray * components = [cliArgs componentsSeparatedByString:@"="];
NSString * author = [components objectAtIndex:1];
[ccontroller setFilterPredicate:[NSPredicate predicateWithFormat:@"author contains[c] %@", author]];
[historyViewController.commitList selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
} else if ([cliArgs hasPrefix:@"--subject"]) {
NSArray * components = [cliArgs componentsSeparatedByString:@"="];
NSString * subject = [components objectAtIndex:1];
[ccontroller setFilterPredicate:[NSPredicate predicateWithFormat:@"subject contains[c] %@", subject]];
} else if ([cliArgs hasPrefix:@"--sha"]) {
NSArray * components = [cliArgs componentsSeparatedByString:@"="];
NSString * sha = [components objectAtIndex:1];
[ccontroller setFilterPredicate:[NSPredicate predicateWithFormat:@"realSha contains[c] %@", sha]];
} else if ([cliArgs hasPrefix:@"-S"]) {
NSString * subject = [cliArgs substringFromIndex:2];
[ccontroller setFilterPredicate:[NSPredicate predicateWithFormat:@"subject contains[c] %@", subject]];
}

[document showWindows];
}

if (launchedFromGitx) {
[self performSelector:@selector(finalizeCLILaunch:) withObject:self afterDelay:0.5];
}

if (![[NSApplication sharedApplication] isActive])
return;
Expand All @@ -148,6 +216,25 @@ - (void)applicationDidFinishLaunching:(NSNotification*)notification
[[PBRepositoryDocumentController sharedDocumentController] openDocument:self];
}

- (void) finalizeCLILaunch:(id)object {
for (PBGitRepository * document in launchedDocuments) {
BOOL success = [[[(PBGitRepository *)document windowController] historyController] selectCommit:self.deferredSelectSha];
NSLog(@"[%@ %s] trying to select commit with sha %@ (success = %@)", [self class], _cmd, self.deferredSelectSha, BMStringFromBOOL(success));
if (success) {
PBGitWindowController * wc = [(PBGitRepository *)document windowController];
PBGitHistoryController * histController = wc.historyController;
PBCommitList * clist = histController.commitList;
// updating the selection with the selection seems redundant but it also updates the row select indicator
[clist selectRowIndexes:[clist selectedRowIndexes] byExtendingSelection:NO];
[histController scrollSelectionToTopOfViewFrom:0];
[histController updateKeys];
}
}
// Reset CLI indication status so KVO all over the controllers can go the intended ways again...
self.deferredSelectSha = nil;
self.launchedFromGitx = NO;
}


- (void) windowWillClose:(id)sender
{
Expand Down
100 changes: 70 additions & 30 deletions PBCLIProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,25 @@ - (id)init

- (BOOL) openRepository:(in bycopy NSString *)repositoryPath arguments:(in bycopy NSArray *)args error:(byref NSError **)error
{
NSLog(@"============================== PBCLIProxy START ==============================");

if (!repositoryPath || !args) {
return NO;
}

// FIXME I found that creating this redundant NSURL reference was necessary to
// work around an apparent bug with GC and Distributed Objects
// I am not familiar with GC though, so perhaps I was doing something wrong.

//
// !!! Andre Berg 20100326: This is because NSURL objects are passed as proxies
// See also http://jens.mooseyard.com/2009/07/the-subtle-dangers-of-distributed-objects/#comment-3069
// We should be able to adjust this by using bycopy modifiers.
//
NSURL* url = [NSURL fileURLWithPath:repositoryPath isDirectory:YES];
NSArray* arguments = [NSArray arrayWithArray:args];

NSString * fullargs = [args componentsJoinedByString:@" "];
PBGitRepository *document = [[PBRepositoryDocumentController sharedDocumentController] documentForLocation:url];
if (!document) {

if (!document) {
if (error) {
NSString *suggestion = nil;
NSInteger errCode = -1;
Expand All @@ -59,38 +66,71 @@ - (BOOL) openRepository:(in bycopy NSString *)repositoryPath arguments:(in bycop

*error = [NSError errorWithDomain:PBCLIProxyErrorDomain code:errCode userInfo:userInfo];
}
NSLog(@"============================== PBCLIProxy Abort ==============================");
return NO;
}
} else if (![document checkRefFormat:fullargs] &&
![document checkRefFormatForBranch:fullargs]) {

NSString * suggestion = @"the arguments passed do not constitute a valid ref format";
NSString * recoveryInfo = @"(see git help check-ref-format)";
NSInteger errCode = PBNotAValidRefFormatErrorCode;

NSLog(@"document = %@ at path = %@", document, repositoryPath);
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat: @"Ignoring parameters passed to gitx. It appears %@.",
suggestion], NSLocalizedFailureReasonErrorKey,
recoveryInfo, NSLocalizedRecoverySuggestionErrorKey, nil];

*error = [NSError errorWithDomain:PBCLIProxyErrorDomain code:errCode userInfo:userInfo];

fprintf(stderr, "\t%s\n", [[*error localizedFailureReason] UTF8String]);
}

NSLog(@"document = %@ at path = %@", document, repositoryPath);

// if ([args count] > 0 && ([[args objectAtIndex:0] isEqualToString:@"--commit"] ||
// [[args objectAtIndex:0] isEqualToString:@"-c"])) {
// [document.windowController showCommitView:self];
// }
// else if ([args count] > 0 && ([[args objectAtIndex:0] hasPrefix:@"--author"])) {
// NSArray * components = [[args objectAtIndex:0] componentsSeparatedByString:@"="];
// NSString * author = [components objectAtIndex:1];
// NSArrayController * ccontroller = document.windowController.historyController.commitController;
// [ccontroller setFilterPredicate:[NSPredicate predicateWithFormat:@"author contains[c] %@", author]];
// [document.windowController.historyController.commitList selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
// } else if ([args count] > 0 && ([[args objectAtIndex:0] hasPrefix:@"--subject"])) {
// NSArray * components = [[args objectAtIndex:0] componentsSeparatedByString:@"="];
// NSString * subject = [components objectAtIndex:1];
// NSArrayController * ccontroller = document.windowController.historyController.commitController;
// [ccontroller setFilterPredicate:[NSPredicate predicateWithFormat:@"subject contains[c] %@", subject]];
// } else if ([args count] > 0 && ([[args objectAtIndex:0] hasPrefix:@"--sha"])) {
// NSArray * components = [[args objectAtIndex:0] componentsSeparatedByString:@"="];
// NSString * sha = [components objectAtIndex:1];
// NSArrayController * ccontroller = document.windowController.historyController.commitController;
// [ccontroller setFilterPredicate:[NSPredicate predicateWithFormat:@"realSha contains[c] %@", sha]];
// } else if ([args count] > 0 && ([[args objectAtIndex:0] hasPrefix:@"-S"])) {
// NSString * subject = [[args objectAtIndex:0] substringFromIndex:2];
// NSArrayController * ccontroller = document.windowController.historyController.commitController;
// [ccontroller setFilterPredicate:[NSPredicate predicateWithFormat:@"subject contains[c] %@", subject]];
// }

// if ([args count] > 0 && [[args objectAtIndex:0] isEqualToString:@"--all"]) {
// document.currentBranchFilter = kGitXAllBranchesFilter;
// } else if ([args count] > 0 && [[args objectAtIndex:0] isEqualToString:@"--local"]) {
// document.currentBranchFilter = kGitXLocalRemoteBranchesFilter;
// }

document.launchedFromCLI = YES;

if ([arguments count] > 0 && ([[arguments objectAtIndex:0] isEqualToString:@"--commit"] ||
[[arguments objectAtIndex:0] isEqualToString:@"-c"]))
[document.windowController showCommitView:self];
else {
PBGitRevSpecifier* rev = nil;
if ([arguments count] > 0 && [[arguments objectAtIndex:0] isEqualToString:@"--all"]) {
document.currentBranchFilter = kGitXAllBranchesFilter;
[document readCurrentBranch];
rev = document.currentBranch;
} else if ([arguments count] > 0 && [[arguments objectAtIndex:0] isEqualToString:@"--local"]) {
document.currentBranchFilter = kGitXLocalRemoteBranchesFilter;
[document readCurrentBranch];
rev = document.currentBranch;
}

if (!rev) {
rev = [[PBGitRevSpecifier alloc] initWithParameters:arguments];
rev.workingDirectory = url;
document.currentBranch = [document addBranch: rev];
}
// [document readCurrentBranch];
// rev = document.currentBranch;
//
// if (!rev && [args count] > 0) {
// rev = [[PBGitRevSpecifier alloc] initWithParameters:args];
// document.currentBranch = rev;
// document.currentBranchFilter = kGitXSelectedBranchFilter;
// }

[document.windowController showHistoryView:self];
}
[NSApp activateIgnoringOtherApps:YES];

NSLog(@"============================== PBCLIProxy END ==============================");
return YES;
}

Expand Down
2 changes: 0 additions & 2 deletions PBGitRevSpecifier.m
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,6 @@ - (NSString *) title
title = @"detached HEAD";
else if ([self isSimpleRef])
title = [[self ref] shortName];
else if ([self.description hasPrefix:@"-S"])
title = [self.description substringFromIndex:[@"-S" length]];
else if ([self.description hasPrefix:@"HEAD -- "])
title = [self.description substringFromIndex:[@"HEAD -- " length]];
else if ([self.description hasPrefix:@"-- "])
Expand Down
8 changes: 6 additions & 2 deletions PBGitSidebarController.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
@class PBSourceViewItem;
@class PBGitHistoryController;
@class PBGitCommitController;
@class ApplicationController;

@interface PBGitSidebarController : PBViewController {
IBOutlet NSWindow *window;
Expand All @@ -25,20 +26,23 @@
PBSourceViewItem *stage;

PBSourceViewItem *branches, *remotes, *tags, *others;
PBSourceViewItem * deferredSelectObject;

PBGitHistoryController *historyViewController;
PBGitCommitController *commitViewController;
}

- (void) selectStage;
- (void) selectBranch:(PBSourceViewItem *)branchItem;
- (void) selectCurrentBranch;

- (NSMenu *) menuForRow:(NSInteger)row;
- (PBSourceViewItem *) selectedItem;

- (IBAction) fetchPullPushAction:(id)sender;
- (NSMenu *) menuForRow:(NSInteger)row;

@property(readonly) NSMutableArray *items;
@property(readonly) NSView *sourceListControlsView;
@property(readonly) PBSourceViewItem * remotes;
@property(readonly) NSOutlineView * sourceView;
@property(assign) PBSourceViewItem * deferredSelectObject;
@end
Loading

0 comments on commit 10daa22

Please sign in to comment.