snej / Murky

A GUI client app for the Mercurial version-control system. Written for Mac OS X, in Objective-C.

Clone this repository (size: 6.0 MB): HTTPS / SSH
$ hg clone http://bitbucket.org/snej/murky/
commit 166: 37108b3d3246
parent 165: d3c6eb46caa9
branch: default
tags: tip
Added tag 0.7.2 for changeset d3c6eb46caa9
Jens Alfke / snej
10 hours ago
Murky / Source / HgOperation.m
r166:37108b3d3246 147 loc 4.3 KB embed / history / annotate / raw /
//
//  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