//
// HgOperation.m
// Murky
//
// Copyright 2008-2009 Jens Alfke. All rights reserved.
//
#import "HgOperation.h"
#import "HgDir.h"
static NSString *sHgToolPath;
static NSMutableDictionary *sEnvironment;
static NSString* runShell( NSString* command, NSError **outError) {
NSString *shellPath = [sEnvironment objectForKey: @"SHELL"];
if (!shellPath) {
Warn(@"No value for $SHELL!");
return nil;
}
MYTask *sh = [[MYTask alloc] initWithCommand: shellPath
arguments: [NSArray arrayWithObjects: @"-c", command ,nil]];
if ($equal(shellPath,@"/bin/bash"))
[sh prependArguments: @"--login",nil]; // To get @*%&$ bash to read its .profile script
if ([sh run: outError])
return [sh.output stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
else {
if (outError)
Warn(@"Shell command '%@' failed with output: '%@'", command,sh.output);
return nil;
}
}
@implementation HgOperation
+ (void) setupEnvironment {
sEnvironment = [[[NSProcessInfo processInfo] environment] mutableCopy];
// Enable UTF-8 output. I don't like hardcoding the 'en_US' part, but it looks as though
// some language has to be specified there or the variable doesn't do anything.
[sEnvironment setObject: @"en_US.UTF-8" forKey: @"LANG"];
// hg may need a custom PYTHONPATH. If so, the user's shell will set up that variable, so
// to get it, fire up a shell and ask it:
NSString *pythonPath = runShell(@"echo $PYTHONPATH", NULL);
Log(@"PYTHONPATH = '%@'", pythonPath);
if (pythonPath.length > 0)
[sEnvironment setObject: pythonPath forKey: @"PYTHONPATH"];
}
+ (NSString*) findHgTool
{
// See if there's a custom hg path configured:
NSString *hgPath = [[NSUserDefaults standardUserDefaults] objectForKey: @"HgToolPath"];
if( hgPath ) {
// If so, it may come with a custom python path:
NSString *pythonPath = [[NSUserDefaults standardUserDefaults] objectForKey: @"HgPythonPath"];
if( pythonPath )
[sEnvironment setObject: pythonPath forKey: @"PYTHONPATH"];
return hgPath;
}
// Ask the shell where 'hg' is. (Note that we can't check the PATH env var directly,
// because it's not set up by the app's parent, launchd. Only shells define it, and user
// setup scripts like .cshrc and .bash_profile customize it.)
NSError *error = nil;
hgPath = runShell(@"which hg", &error);
if (hgPath) {
Log(@"'hg' path = '%@'", hgPath);
if ([hgPath hasPrefix: @"/"])
return hgPath;
else
Log(@"...which isn't a path! Ignoring it");
}
// As a last resort, guess that it's /usr/local/bin/hg:
hgPath = @"/usr/local/bin/hg";
Warn(@"Couldn't locate hg via shell ... assuming it's at %@", hgPath);
return hgPath;
}
static NSString* getAbsolutePath( id dir )
{
if( [dir isKindOfClass: [NSString class]] )
return dir;
else
return [dir absolutePath];
}
- (id) initWithDirectory: (id)dir
command: (NSString*)subcommand
arguments: (NSArray*)arguments
{
Assert(subcommand);
if (!sHgToolPath) {
// First-time initialization:
[HgOperation setupEnvironment];
sHgToolPath = [HgOperation findHgTool];
}
self = [super initWithCommand: sHgToolPath arguments: arguments];
if (self != nil) {
_subcommand = subcommand;
if( dir ) {
NSString *absPath = getAbsolutePath(dir);
Assert(absPath.length>0, @"Bad absolutePath for %@ %@",[dir class],dir);
self.currentDirectoryPath = absPath;
}
}
return self;
}
- (id) initWithDirectory: (id)dir
command: (NSString*)subcommand, ...
{
self = [self initWithDirectory: dir command: subcommand arguments: nil];
if( self ) {
va_list args;
va_start(args,subcommand);
id arg;
while( nil != (arg=va_arg(args,id)) )
[self addArgument: arg];
va_end(args);
}
return self;
}
- (NSTask*) createTask
{
[self prependArguments: _subcommand,nil];
NSTask *task = [super createTask];
task.environment = sEnvironment;
return task;
}
@end