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?
I guess that because of the sandboxing this is not possible. You could bundle the clang-format executable and use it from there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With