2016-09-09 22 views
9

Moim celem jest utworzenie rozszerzenia, które wykonuje format klang. Mój kod wygląda mniej więcej tak:Rozszerzenie Xcode 8 wykonujące NSTask

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

Powodem muszę, że blok try-catch dlatego jest wyjątek, gdy próbuję uruchomić ten kod. Przyczyną wyjątku jest:

Error: launch path not accessible

Ścieżka do mojego formatu clang to/usr/local/bin/clang-format. Odkryłem, że nie podoba mi się to, że próbuję uzyskać dostęp do aplikacji w/usr/local/bin, ale/bin jest w porządku (np. Jeśli spróbuję wykonać/bin/ls nie ma problemu).

Innym rozwiązaniem Próbowałem było uruchomić/bin/bash poprzez ustawienie ścieżki uruchamiania i argumenty takiego:

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

Ten powodzeniem uruchamia zadanie, ale nie jest on z następującym wyjście błędu:

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

pierwszy komunikat o błędzie z powodu próby wywołania parametru -l w bash, który próbuje zalogować się jako użytkownik.

Masz pomysł, jak włączyć dostęp do innych folderów? Czy jest jakieś ustawienie środowiska piaskownicy, które muszę włączyć?

Odpowiedz

1

Sądzę, że z powodu piaskownicy nie jest to możliwe. Można zawinąć plik wykonywalny formatu klang i używać go z tego miejsca.

0

Osobiście uważam, że wszystko idzie źle. Rozszerzenia powinny być szybkie (jeśli oglądasz wideo na rozszerzeniach Xcode, powtarza się wiele razy, aby wejść i wyjść). I są poważnie ograniczone.

Istnieje jednak inna - aplikacja pojemnik może być w stanie zrobić tego przetwarzania dla rozszerzenia bez wszystkich hacków. Minusem jest to, że musisz przekazać bufor do i z rozszerzenia.

To nie jest łatwe, ale można to zrobić. Łatwy i prosty sposób na uruchomienie pojemnika. Najpierw zmodyfikuj plik Info.plist aplikacji kontenerowej (nie rozszerzenie Info.plist), aby zawierał typ adresu URL.

Info.plist

w rozszerzeniu można „obudzić” aplikację kontenera, uruchamiając następujące:

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

chodzi o komunikację między nimi, Apple ma mnóstwo sposobów. Ja, jestem old-school, więc używam DistributedRotificationCenter - na razie.

Mimo że nie próbowałem tego, nie widzę powodu, dla którego aplikacja do kontenera powinna mieć problem z czatem (używam aplikacji kontenera do ustawień).

+0

Awesome, thanks! Spróbuję :) –

+0

Jeśli to działa, proszę oznaczyć go jako zaakceptowaną odpowiedź. –