From 7081f7b755a935b068875c03314cd6327e438195 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sat, 18 Jan 2025 20:05:37 +0100 Subject: [PATCH] Implemented the RunProcessTask task in the library target. --- .../Internal/Tasks/RunProcessTask.swift | 75 +++++++++++++++++++ .../Public/Tasks/CreateRootFolderTask.swift | 5 +- 2 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 Library/Sources/Internal/Tasks/RunProcessTask.swift diff --git a/Library/Sources/Internal/Tasks/RunProcessTask.swift b/Library/Sources/Internal/Tasks/RunProcessTask.swift new file mode 100644 index 0000000..7835b87 --- /dev/null +++ b/Library/Sources/Internal/Tasks/RunProcessTask.swift @@ -0,0 +1,75 @@ +import Foundation + +struct RunProcessTask { + + // MARK: Type aliases + + typealias Output = String + + // MARK: Properties + + private var process: Processable + + // MARK: Initialisers + + init(process: Processable) { + self.process = process + } + + // MARK: Functions + + @discardableResult + mutating func callAsFunction( + path: String, arguments: [String] = [] + ) async throws (RunProcessError) -> Output { + process.executableURL = URL(at: 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 + +public enum RunProcessError: Error { + case captured(_ error: Error) + case output(_ output: String) + case unexpected +} diff --git a/Library/Sources/Public/Tasks/CreateRootFolderTask.swift b/Library/Sources/Public/Tasks/CreateRootFolderTask.swift index 6345aee..06f6643 100644 --- a/Library/Sources/Public/Tasks/CreateRootFolderTask.swift +++ b/Library/Sources/Public/Tasks/CreateRootFolderTask.swift @@ -14,10 +14,7 @@ public struct CreateRootFolderTask { // MARK: Functions - public func callAsFunction( - name: String, - at location: URL? = nil - ) async throws -> URL { + public func callAsFunction(name: String, at location: URL? = nil) async throws -> URL { guard !name.isEmpty else { throw CreateRootFolderError.nameIsEmpty }