Files

72 lines
2.0 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Argument Parser open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
import Foundation
enum SubprocessError: Swift.Error, LocalizedError, CustomStringConvertible {
case missingExecutable(url: URL)
case failedToLaunch(error: Swift.Error)
case nonZeroExitCode(code: Int)
var description: String {
switch self {
case .missingExecutable(let url):
return "No executable at '\(url.standardizedFileURL.path)'."
case .failedToLaunch(let error):
return "Couldn't run command process. \(error.localizedDescription)"
case .nonZeroExitCode(let code):
return "Process returned non-zero exit code '\(code)'."
}
}
var errorDescription: String? { self.description }
}
func executeCommand(
executable: URL,
arguments: [String]
) throws -> String {
guard (try? executable.checkResourceIsReachable()) ?? false else {
throw SubprocessError.missingExecutable(url: executable)
}
let process = Process()
if #available(macOS 10.13, *) {
process.executableURL = executable
} else {
process.launchPath = executable.path
}
process.arguments = arguments
let output = Pipe()
process.standardOutput = output
process.standardError = FileHandle.nullDevice
do {
try process.run()
} catch {
throw SubprocessError.failedToLaunch(error: error)
}
let outputData = output.fileHandleForReading.readDataToEndOfFile()
process.waitUntilExit()
guard process.terminationStatus == 0 else {
throw SubprocessError.nonZeroExitCode(code: Int(process.terminationStatus))
}
let outputActual =
String(data: outputData, encoding: .utf8)?
.trimmingCharacters(in: .whitespacesAndNewlines)
?? ""
return outputActual
}