Расширение Xcode 8, выполняющее NSTask

Моя цель - создать расширение, которое выполняет формат clang. Мой код выглядит примерно так:

- (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);
}

Причина, по которой мне нужен этот блок try-catch, заключается в том, что при попытке запустить этот код возникает исключение. Причина исключения:

Ошибка: путь запуска недоступен

Путь к моему clang-формату - / usr / local / bin / clang-format. Я обнаружил, что мне не нравится, когда я пытаюсь получить доступ к приложению в / usr / local / bin, но с / bin все в порядке (например, если я пытаюсь выполнить / bin / ls, проблем нет).

Другое решение, которое я попробовал, состояло в том, чтобы запустить / bin / bash, установив путь запуска и аргументы, подобные этому:

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

Это успешно запускает задачу, но завершается неудачно со следующей ошибкой:

/ bin / bash: / etc / profile: операция запрещена / bin / bash: / usr / local / bin / clang-format: операция запрещена

Первое сообщение об ошибке связано с попыткой вызвать параметр -l в bash, который пытается войти в систему как пользователь.

Любая идея, как я могу разрешить доступ к этим другим папкам? Есть ли какая-то настройка среды песочницы, которую мне нужно включить?

2 ответа

Я думаю, что из-за песочницы это невозможно. Вы можете связать исполняемый файл в формате clang и использовать его оттуда.

Лично я думаю, что вы все делаете неправильно. Расширения должны быть быстрыми (если вы смотрите видео на расширениях XCode, он повторяется несколько раз, чтобы войти и выйти). И они сильно ограничены.

Однако есть и другое - приложение-контейнер может выполнить эту обработку для вашего расширения без всех взломов. Недостатком является то, что вы должны передать буфер в и из расширения.

Это не легко, но это может быть сделано. Простой и удобный способ заставить ваш контейнер работать. Сначала измените Info.plist приложения контейнера (не расширение Info.plist), чтобы он имел тип URL.

Info.plist

В своем расширении вы можете "разбудить" приложение контейнера, выполнив следующее:

let customurl = NSURL.init(string: “yoururlschemehere://")
NSWorkspace.shared().open(customurl as! URL)

Что касается связи между двумя, у Apple есть множество методов. Я, я старая школа, поэтому я использую DistributedNotificationCenter - на данный момент.

Хотя я не пробовал, я не понимаю, почему у приложения-контейнера возникла проблема с чатом в clang (я использую приложение-контейнер для настроек).

Другие вопросы по тегам