Skip to content

Commit 515ffe8

Browse files
authored
Handle differences in user environments while executing hooks (#696)
* Handle user shell not being bash * Better handling for differences evaluating PATH in user shells * Follow Git behavior and fallback to using sh to execute hooks
1 parent 0d4bb0c commit 515ffe8

File tree

3 files changed

+24
-9
lines changed

3 files changed

+24
-9
lines changed

Diff for: GitUpKit/Core/GCPrivate.h

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ extern int git_submodule_foreach_block(git_repository* repo, int (^block)(git_su
138138
@property(nonatomic) NSTimeInterval executionTimeOut; // Default is 0.0 i.e. no timeout
139139
@property(nonatomic, copy) NSDictionary* additionalEnvironment;
140140
@property(nonatomic, copy) NSString* currentDirectoryPath;
141+
@property(nonatomic) BOOL fallBackToDefaultInterpreter;
141142
- (instancetype)initWithExecutablePath:(NSString*)path;
142143
- (BOOL)runWithArguments:(NSArray*)arguments stdin:(NSData*)stdin stdout:(NSData**)stdout stderr:(NSData**)stderr exitStatus:(int*)exitStatus error:(NSError**)error; // Returns NO if "exitStatus" is NULL and executable exits with a non-zero status
143144
@end

Diff for: GitUpKit/Core/GCPrivate.m

+9-3
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,21 @@ - (void)_fileHandleDataAvailable:(NSNotification*)notification {
6767
}
6868
}
6969

70-
- (BOOL)runWithArguments:(NSArray*)arguments stdin:(NSData*)stdin stdout:(NSData**)stdout stderr:(NSData**)stderr exitStatus:(int*)exitStatus error:(NSError**)error {
70+
- (BOOL)_runWithDefaultInterpreter:(BOOL)useSH arguments:(NSArray*)arguments stdin:(NSData*)stdin stdout:(NSData**)stdout stderr:(NSData**)stderr exitStatus:(int*)exitStatus error:(NSError**)error {
7171
BOOL success = NO;
7272
NSPipe* inPipe = nil;
7373
NSPipe* outPipe = nil;
7474
NSPipe* errorPipe = nil;
7575
NSTimer* timer = nil;
7676

7777
NSTask* task = [[NSTask alloc] init];
78-
task.launchPath = _executablePath;
78+
task.launchPath = useSH ? @"/bin/sh" : _executablePath;
7979
NSMutableDictionary* environment = [[NSMutableDictionary alloc] initWithDictionary:[[NSProcessInfo processInfo] environment]];
8080
[environment addEntriesFromDictionary:_additionalEnvironment];
8181
task.environment = environment;
8282
task.currentDirectoryPath = _currentDirectoryPath ? _currentDirectoryPath : [[NSFileManager defaultManager] currentDirectoryPath];
83-
task.arguments = arguments ? arguments : @[];
83+
NSArray* interpreterArguments = useSH ? @[ _executablePath ] : @[];
84+
task.arguments = [interpreterArguments arrayByAddingObjectsFromArray:arguments];
8485

8586
if (stdin) {
8687
inPipe = [[NSPipe alloc] init];
@@ -170,6 +171,11 @@ - (BOOL)runWithArguments:(NSArray*)arguments stdin:(NSData*)stdin stdout:(NSData
170171
return success;
171172
}
172173

174+
175+
- (BOOL)runWithArguments:(NSArray*)arguments stdin:(NSData*)stdin stdout:(NSData**)stdout stderr:(NSData**)stderr exitStatus:(int*)exitStatus error:(NSError**)error {
176+
return [self _runWithDefaultInterpreter:NO arguments:arguments stdin:stdin stdout:stdout stderr:stderr exitStatus:exitStatus error:error] || (self.fallBackToDefaultInterpreter && [self _runWithDefaultInterpreter:YES arguments:arguments stdin:stdin stdout:stdout stderr:stderr exitStatus:exitStatus error:error]);
177+
}
178+
173179
@end
174180

175181
#endif

Diff for: GitUpKit/Core/GCRepository.m

+14-6
Original file line numberDiff line numberDiff line change
@@ -310,24 +310,32 @@ - (NSString*)pathForHookWithName:(NSString*)name {
310310
return [[NSFileManager defaultManager] isExecutableFileAtPath:path] ? path : nil;
311311
}
312312

313+
- (NSString*)getPATHUsingShell:(NSString*)shell error:(NSError**)error {
314+
GCTask* task = [[GCTask alloc] initWithExecutablePath:shell];
315+
NSData* data;
316+
// `-l` is not supported with `-c` in all shells (tcsh), so try without.
317+
// Some shells use quoting of $PATH to trigger POSIX compatibility behavior (fish).
318+
// Not all shells support `-n` on `echo`.
319+
if (![task runWithArguments:@[ @"-l", @"-c", @"echo \"$PATH\"" ] stdin:NULL stdout:&data stderr:NULL exitStatus:NULL error:error] && ![task runWithArguments:@[ @"-c", @"echo \"$PATH\"" ] stdin:NULL stdout:&data stderr:NULL exitStatus:NULL error:error]) {
320+
return nil;
321+
}
322+
return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
323+
}
324+
313325
- (BOOL)runHookWithName:(NSString*)name arguments:(NSArray*)arguments standardInput:(NSString*)standardInput error:(NSError**)error {
314326
NSString* path = [self pathForHookWithName:name];
315327
if (path) {
316328
static NSString* cachedPATH = nil;
317329
if (cachedPATH == nil) {
318-
GCTask* task = [[GCTask alloc] initWithExecutablePath:@"/bin/bash"]; // TODO: Handle user shell not being bash
319-
NSData* data;
320-
if (![task runWithArguments:@[ @"-l", @"-c", @"echo -n $PATH" ] stdin:NULL stdout:&data stderr:NULL exitStatus:NULL error:error]) {
321-
return NO;
322-
}
323-
cachedPATH = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
330+
cachedPATH = [self getPATHUsingShell:NSProcessInfo.processInfo.environment[@"SHELL"] error:error] ?: [self getPATHUsingShell:@"/bin/sh" error:error];
324331
XLOG_DEBUG_CHECK(cachedPATH);
325332
}
326333

327334
CFAbsoluteTime time = CFAbsoluteTimeGetCurrent();
328335
GCTask* task = [[GCTask alloc] initWithExecutablePath:path];
329336
task.currentDirectoryPath = self.workingDirectoryPath; // TODO: Is this the right working directory?
330337
task.additionalEnvironment = @{@"PATH" : cachedPATH};
338+
task.fallBackToDefaultInterpreter = YES;
331339
int status;
332340
NSData* stdoutData;
333341
NSData* stderrData;

0 commit comments

Comments
 (0)