Files
gitx/gitx.m
T
André Berg 10daa222b5 Major overhaul of the handling/effect of CLI args (gitx/PBCLIProxy).
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.
2010-04-05 23:50:03 +02:00

186 lines
5.8 KiB
Objective-C

//
// gitx.m
// GitX
//
// Created by Ciarán Walsh on 15/08/2008.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "PBCLIProxy.h"
#import "PBGitBinary.h"
#import "PBEasyPipe.h"
#import "PBGitRepository.h"
#include <sys/syslimits.h> /* for ARG_MAX */
NSDistantObject* connectToProxy()
{
id proxy = [NSConnection rootProxyForConnectionWithRegisteredName:PBDOConnectionName host:nil];
[proxy setProtocolForProxy:@protocol(GitXCliToolProtocol)];
return proxy;
}
NSDistantObject *createProxy()
{
NSDistantObject * proxy = connectToProxy();
if (proxy) {
return proxy;
}
// The connection failed, so try to launch the app
[[NSWorkspace sharedWorkspace] launchAppWithBundleIdentifier:@"nl.frim.GitX"
options:NSWorkspaceLaunchWithoutActivation
additionalEventParamDescriptor:nil
launchIdentifier:nil];
// Now attempt to connect, allowing the app time to startup
int attempt;
for (attempt = 0; proxy == nil && attempt < 50; ++attempt) {
if (proxy = connectToProxy())
break;
usleep(15000);
}
if (proxy) {
return proxy;
}
// not succesful!
fprintf(stderr, "Couldn't connect to app server!\n");
exit(1);
return nil;
}
void usage(char const *programName)
{
printf("Usage: %s (-h|--help|--version)\n", programName);
printf(" or: %s (--commit)\n", programName);
printf(" or: %s (--subject=<subject>|--sha=<sha>|--author=<author>)\n", programName);
printf(" or: %s <revlist options>\n", programName);
printf("\n");
printf("\t-h, --help print this help\n");
printf("\t--commit, -c start GitX in commit mode\n");
printf("\n");
printf("RevList options\n");
printf("\tSee 'man git-log' and 'man git-rev-list' for options you can pass to gitx\n");
printf("\n");
printf("\t--all show all branches\n");
printf("\t--local show local branches\n");
printf("\t--sha=<sha> filter the current branch for <sha>\n");
printf("\t--author=<author> filter the current branch for <author>\n");
printf("\t--subject=<subject> filter the current branch for <subject>\n");
printf("\t-S<subject> same as above (included for legacy compatibility)\n");
printf("\t<branch> show specific branch\n");
printf("\t -- <path> show commits touching paths\n");
exit(1);
}
void version_info()
{
NSString *version = [[[NSBundle bundleForClass:[PBGitBinary class]] infoDictionary] valueForKey:@"CFBundleVersion"];
printf("This is GitX version %s\n", [version UTF8String]);
if ([PBGitBinary path])
printf("Using git found at %s, version %s\n", [[PBGitBinary path] UTF8String], [[PBGitBinary version] UTF8String]);
else
printf("GitX cannot find a git binary\n");
exit(1);
}
void git_path()
{
if (![PBGitBinary path])
exit(101);
NSString *path = [[PBGitBinary path] stringByDeletingLastPathComponent];
printf("%s", [path UTF8String]);
exit(0);
}
void handleSTDINDiff(id<GitXCliToolProtocol> proxy)
{
NSFileHandle *handle = [NSFileHandle fileHandleWithStandardInput];
NSData *data = [handle readDataToEndOfFile];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (string && [string length] > 0) {
[proxy openDiffWindowWithDiff:string];
exit(0);
}
}
void handleDiffWithArguments(NSArray *arguments, NSString *directory, id<GitXCliToolProtocol> proxy)
{
int ret;
arguments = [[NSArray arrayWithObject:@"diff"] arrayByAddingObjectsFromArray:arguments];
NSString *diff = [PBEasyPipe outputForCommand:[PBGitBinary path] withArgs:arguments inDir:directory retValue:&ret];
if (ret) {
printf("Invalid diff command\n");
exit(3);
}
[proxy openDiffWindowWithDiff:diff];
exit(0);
}
int main(int argc, const char** argv)
{
if (argc >= 2 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
usage(argv[0]);
if (argc >= 2 && (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-v")))
version_info();
if (argc >= 2 && !strcmp(argv[1], "--git-path"))
git_path();
if (![PBGitBinary path]) {
printf("%s\n", [[PBGitBinary notFoundError] UTF8String]);
exit(2);
}
// Create arguments
argv++; argc--;
NSMutableArray* arguments = [NSMutableArray arrayWithCapacity:argc];
int i = 0;
for (i = 0; i < argc; i++)
[arguments addObject: [NSString stringWithUTF8String:argv[i]]];
// I hate using env vars for this but I don't see how else we get the parameters
// to the Application client as the proxy connection routines above start up the
// ApplicationController which in turn initializes the PBCLIProxy and starts with
// the usual business of calling -populateList from PBGitSidebarController.
NSString * fullargs = [arguments componentsJoinedByString:@" "];
if ([fullargs length] <= ARG_MAX) {
setenv("GITX_CLI_ARGUMENTS", [fullargs UTF8String], 1);
setenv("GITX_LAUNCHED_FROM_CLI", "YES", 1);
} else {
fprintf(stderr, "Argument size exceeds system limit of (%d)! Ignoring args.", ARG_MAX);
}
id proxy = createProxy();
if (!isatty(STDIN_FILENO) && fdopen(STDIN_FILENO, "r"))
handleSTDINDiff(proxy);
// From this point, we require a working directory
NSString *pwd = [[[NSProcessInfo processInfo] environment] objectForKey:@"PWD"];
if (!pwd)
exit(2);
if ([arguments count] > 0 && ([[arguments objectAtIndex:0] isEqualToString:@"--diff"] ||
[[arguments objectAtIndex:0] isEqualToString:@"-d"]))
handleDiffWithArguments([arguments subarrayWithRange:NSMakeRange(1, [arguments count] - 1)], pwd, proxy);
// No diff, just open the current dir
NSError* error = nil;
if (![proxy openRepository:pwd arguments: arguments error:&error]) {
fprintf(stderr, "Error opening repository at %s\n", [pwd UTF8String]);
if (error)
fprintf(stderr, "\t%s\n", [[error localizedFailureReason] UTF8String]);
return 1;
}
return 0;
}