mirror of
https://github.com/apple/swift-argument-parser.git
synced 2026-06-06 20:18:23 +00:00
72 lines
2.0 KiB
Swift
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
|
|
}
|