2016-09-09 19 views
9

Mục tiêu của tôi là tạo tiện ích mở rộng thực thi định dạng clang. Mã của tôi trông giống như sau:Mở rộng Xcode 8 thực hiện 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); 
} 

Lý do tôi cần khối try-catch đó là vì ngoại lệ được ném khi tôi cố gắng chạy mã này. Lý do ngoại lệ là:

Error: launch path not accessible

Đường dẫn cho định dạng clang của tôi là/usr/local/bin/clang-format. Những gì tôi phát hiện ra là nó không giống như tôi đang cố gắng truy cập vào một ứng dụng trong/usr/local/bin, nhưng/bin là ok (ví dụ: Nếu tôi cố gắng thực thi/bin/ls thì không có vấn đề gì).

Một giải pháp tôi đã cố gắng là để chạy/bin/bash bằng cách thiết lập các con đường ra mắt và lập luận như thế này:

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

này sẽ khởi chạy thành công nhiệm vụ, nhưng nó không thành công với sản lượng lỗi sau:

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

Thông báo lỗi đầu tiên là do cố gắng gọi tham số -l trong bash, cố gắng đăng nhập với tư cách người dùng.

Bất kỳ ý tưởng nào về cách tôi có thể bật quyền truy cập vào các thư mục khác? Có một số loại thiết lập môi trường sandbox tôi cần phải kích hoạt?

Trả lời

1

Tôi đoán rằng vì hộp cát này không thể thực hiện được. Bạn có thể thực thi định dạng clang và sử dụng nó từ đó.

0

Cá nhân, tôi nghĩ bạn đang gặp phải tất cả sai. Tiện ích mở rộng được cho là nhanh (nếu bạn xem video trên các phần mở rộng Xcode, anh ấy lặp lại nhiều lần để vào và ra). Và chúng bị hạn chế nghiêm trọng.

Tuy nhiên, có một ứng dụng khác - ứng dụng vùng chứa có thể thực hiện việc xử lý này cho tiện ích mở rộng của bạn mà không có tất cả các phần mềm. Nhược điểm là bạn phải vượt qua bộ đệm đến và đi từ phần mở rộng.

Không dễ, nhưng có thể thực hiện được. Cách dễ dàng peasy để có được container của bạn để chạy. Trước tiên, hãy sửa đổi Info.plist của ứng dụng vùng chứa (không phải là Info.plist của tiện ích mở rộng) để có loại URL.

Info.plist

Trong phần mở rộng của bạn, bạn có thể “thức dậy” ứng dụng chứa bằng cách chạy như sau:

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

Đối với thông tin liên lạc giữa hai, Apple có rất nhiều phương pháp. Tôi, tôi là trường học cũ, vì vậy tôi đang sử dụng DistributedNotificationCenter - cho thời điểm này.

Mặc dù tôi chưa dùng thử, tôi không thấy lý do khiến ứng dụng vùng chứa gặp sự cố khi trò chuyện với tiếng kêu vang (tôi đang sử dụng ứng dụng vùng chứa cho cài đặt).

+0

Tuyệt vời, cảm ơn! Tôi sẽ thử :) –

+0

Nếu công trình này hoạt động, vui lòng đánh dấu nó là câu trả lời được chấp nhận. –

Các vấn đề liên quan