// // RunProcessUseCase.swift // Piper ~ App // // Created by Javier Cicchelli on 05/10/2024. // Copyright © 2024 Röck+Cöde. All rights reserved. // import Foundation struct RunProcessUseCase { // MARK: Type aliases typealias Output = String // MARK: Properties private let path: String private let arguments: [String]? // MARK: Initialisers init( path: String, arguments: [String] = [] ) { self.path = path self.arguments = arguments } // MARK: Functions func callAsFunction() async throws -> Output { let process = Process() process.executableURL = URL(fileURLWithPath: path) process.arguments = arguments let pipeError = Pipe() let pipeOutput = Pipe() process.standardError = pipeError process.standardOutput = pipeOutput async let streamOutput = pipeOutput.availableData.append() async let streamError = pipeError.availableData.append() do { try process.run() let dataOutput = await streamOutput let dataError = await streamError guard dataError.isEmpty else { guard let errorOutput = String(data: dataError, encoding: .utf8) else { throw RunProcessError.unexpected } throw RunProcessError.output(errorOutput) } guard let output = String(data: dataOutput, encoding: .utf8) else { throw RunProcessError.unexpected } return await withCheckedContinuation { continuation in process.terminationHandler = { _ in continuation.resume(returning: output) } } } catch let error as RunProcessError { throw error } catch { throw RunProcessError.captured(error) } } } // MARK: - Errors enum RunProcessError: Error { case captured(_ error: Error) case output(_ output: String) case unexpected }