🔥 AsyncParsableCommand

386자
4분

AsyncParsableCommand는 비동기로 실행할 수 있는 명령 타입입니다. 중첩된 명령 트리 일부로 작동해요. 아래 코드는 AsyncParsableCommand 프로토콜을 정의하고 있습니다.

protocol AsyncParsableCommand : ParsableCommand
 
swift

명령 run() 메서드 구현에서 async/await 코드를 사용하려면 다음 단계를 따르세요:

  1. 커맨드 라인 도구 루트 명령에 AsyncParsableCommand를 따르도록 선언하세요. 해당 명령이 비동기 코드를 사용하는지 여부는 상관없습니다.
  2. 루트 명령에 @main 속성을 적용하세요. (참고: 루트 명령이 main.swift 파일에 있다면 파일 이름을 명령 이름으로 바꾸세요.)
  3. 비동기 코드를 사용해야 하는 모든 명령에 AsyncParsableCommand를 따르도록 선언하고 run() 메서드를 async로 표시하세요. 비동기 코드를 사용하지 않는 하위 명령은 변경이 필요 없습니다.

다음 예제는 Foundation 비동기 FileHandle.AsyncBytes를 사용해 파일에서 줄 수를 세는 CountLines 명령을 선언합니다. 여기서 CountLines는 커맨드 라인 도구 루트 명령입니다:

import Foundation
import ArgumentParser
 
struct CountLines: AsyncParsableCommand {
    @Argument(transform: URL.init(fileURLWithPath:))
    var inputFile: URL
 
    mutating func run() async throws {
        let fileHandle = try FileHandle(forReadingFrom: inputFile)
        let lineCount = try await fileHandle.bytes.lines.reduce(into: 0)
            { count, _ in count += 1 }
        print(lineCount)
    }
}
 
swift

코드 설명:

  • import Foundation: Foundation 프레임워크를 가져옵니다.
  • struct CountLines: AsyncParsableCommand: CountLines 구조체를 선언하고 AsyncParsableCommand 프로토콜을 따릅니다.
  • @Argument(transform: URL.init(fileURLWithPath:)): 명령줄 인수로 받은 파일 경로를 URL로 변환합니다.
  • var inputFile: URL: 입력 파일 URL을 저장할 프로퍼티입니다.
  • mutating func run() async throws: 비동기로 실행되는 run() 메서드를 선언합니다.
  • let fileHandle = try FileHandle(forReadingFrom: inputFile): 입력 파일을 읽기 위한 FileHandle을 생성합니다.
  • let lineCount = try await fileHandle.bytes.lines.reduce(into: 0) { count, _ in count += 1 }: 파일 각 줄을 비동기로 읽어 줄 수를 계산합니다.
  • print(lineCount): 줄 수를 출력합니다.

Swift 5.5에서 사용

Swift 5.5에서는 비동기 @main 진입점으로 별도 독립형 타입을 선언해야 합니다. 아래 코드 스니펫처럼 AsyncMainProtocol을 따르는 구조체를 선언하고 typealias Command를 루트 명령으로 지정하세요.

@main struct AsyncMain: AsyncMainProtocol {
    typealias Command = <#RootCommand#>
}
 
swift

여기서 <#RootCommand#>를 실제 루트 명령 이름으로 변경합니다. 위 예제에서는 CountLines가 루트 명령이므로 다음과 같이 작성할 수 있습니다:

@main struct AsyncMain: AsyncMainProtocol {
    typealias Command = CountLines
}
 
swift

그리고 CountLines 명령을 구현합니다:

import Foundation
 
struct CountLines: AsyncParsableCommand {
    @Argument(transform: URL.init(fileURLWithPath:))
    var inputFile: URL
 
    mutating func run() async throws {
        let fileHandle = try FileHandle(forReadingFrom: inputFile)
        let lineCount = try await fileHandle.bytes.lines.reduce(into: 0)
            { count, _ in count += 1 }
        print(lineCount)
    }
}
 
swift

이렇게 하면 AsyncParsableCommand를 사용해 커맨드 라인 도구에 비동기 코드를 쉽게 통합할 수 있습니다. 그리고 명령 run() 메서드에서 async/await을 활용하면 다양한 비동기 작업을 수행할 수 있습니다.