Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode 8 extension executing NSTask

My goal is to create an extension that executes clang-format. My code looks something like this:

- (void)performCommandWithInvocation:(XCSourceEditorCommandInvocation *)invocation completionHandler:(void (^)(NSError * _Nullable nilOrError))completionHandler
{
    NSError *error = nil;

    NSURL *executableURL = [[self class] executableURL];

    if (!executableURL)
    {
          NSString *errorDescription = [NSString stringWithFormat:@"Failed to find clang-format. Ensure it is installed at any of these locations\n%@", [[self class] clangFormatUrls]];
              completionHandler([NSError errorWithDomain:SourceEditorCommandErrorDomain
              code:1
              userInfo:@{NSLocalizedDescriptionKey: errorDescription}]);
          return;
    }

    NSMutableArray *args = [NSMutableArray array];
    [args addObject:@"-style=LLVM"];
    [args addObject:@"someFile.m"];
    NSPipe *outputPipe = [NSPipe pipe];
    NSPipe *errorPipe = [NSPipe pipe];

    NSTask *task = [[NSTask alloc] init];
    task.launchPath = executableURL.path;
    task.arguments = args;

    task.standardOutput = outputPipe;
    task.standardError = errorPipe;

    @try
    {
          [task launch];
    }
    @catch (NSException *exception)
    {
          completionHandler([NSError errorWithDomain:SourceEditorCommandErrorDomain
              code:2
              userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Failed to run clang-format: %@", exception.reason]}]);
          return;
    }

    [task waitUntilExit];

    NSString *output = [[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile]
          encoding:NSUTF8StringEncoding];
    NSString *errorOutput = [[NSString alloc] initWithData:[[errorPipe fileHandleForReading] readDataToEndOfFile]
          encoding:NSUTF8StringEncoding];
    [[outputPipe fileHandleForReading] closeFile];
    [[errorPipe fileHandleForReading] closeFile];

    int status = [task terminationStatus];
    if (status == 0)
    {
          NSLog(@"Success: %@", output);
    }
    else
    {
          error = [NSError errorWithDomain:SourceEditorCommandErrorDomain
              code:3
              userInfo:@{NSLocalizedDescriptionKey: errorOutput}];
    }

    completionHandler(error);
}

The reason I need that try-catch block is because an exception is thrown when I try to run this code. The exception reason is:

Error: launch path not accessible

The path for my clang-format is /usr/local/bin/clang-format. What I discovered is that it doesn't like me trying to access an application in /usr/local/bin, but /bin is ok (e.g. If I try to execute /bin/ls there is no problem).

Another solution I tried was to run /bin/bash by setting the launch path and arguments like this:

task.launchPath = [[[NSProcessInfo processInfo] environment] objectForKey:@"SHELL"];
task.arguments = @[@"-l", @"-c", @"/usr/local/bin/clang-format -style=LLVM someFile.m"];

This successfully launches the task, but it fails with the following error output:

/bin/bash: /etc/profile: Operation not permitted /bin/bash: /usr/local/bin/clang-format: Operation not permitted

The first error message is due to trying to call the -l parameter in bash, which tries to log in as the user.

Any idea how I can enable access to those other folders? Is there some kind of sandbox environment setting I need to enable?

like image 722
Guy Kogus Avatar asked Sep 09 '16 14:09

Guy Kogus


1 Answers

I guess that because of the sandboxing this is not possible. You could bundle the clang-format executable and use it from there.

like image 127
Jochen Avatar answered Sep 28 '22 21:09

Jochen