Created
February 21, 2023 08:55
-
-
Save AlexKobachiJP/20602d3d99b600fb6854f7d9c3bdd1e6 to your computer and use it in GitHub Desktop.
Creates a process and launches an exectuable with arguments.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright © 2022 Alex Kovács. All rights reserved. | |
#if os(macOS) | |
import Foundation | |
extension Process { | |
/// Creates a process and launches an exectuable with arguments. | |
/// | |
/// Optionally pass environment variables for the process. | |
/// - Parameters: | |
/// - launchPath: Absolute path to an exectuable. E.g., `/usr/bin/git` (not `git`). | |
/// - arguments: Array of command line arguments to pass to the executable. E.g., `["clone", "[email protected]:EbookFoundation/free-programming-books.git", "/Users/alex/Desktop"]`. | |
/// - environment: Dictionary of environment variables and their values. | |
/// - routeStdErrToStdOut: If `true`, `stderr` will be routed to `stdout` (same as `2>&1` on the command line). | |
/// - Returns: Output to `stdout`, output to `stderr`, and the termination status code of the executable. | |
public static func run(_ launchPath: String, _ arguments: [String] = [], _ environment: [String: String]? = nil, routeStdErrToStdOut: Bool = false) throws -> ProcessExecutionResult { | |
let task = Process() | |
task.executableURL = URL(filePath: launchPath) | |
task.arguments = arguments | |
task.environment = environment | |
let standardOutputPipe = Pipe() | |
task.standardOutput = standardOutputPipe | |
let standardErrorPipe = routeStdErrToStdOut ? standardOutputPipe : Pipe() | |
task.standardError = standardErrorPipe | |
try task.run() | |
task.waitUntilExit() | |
return .init( | |
output: try standardOutputPipe.fileHandleForReading.readToEnd().map { String(data: $0, encoding: .utf8)! }, | |
error: try standardErrorPipe.fileHandleForReading.readToEnd().map { String(data: $0, encoding: .utf8)! }, | |
status: Int(task.terminationStatus) | |
) | |
} | |
/// Same as ``run(_:_:_:routeStdErrToStdOut:input:)`` but defaulting the `launchPath` to `/bin/bash`. | |
/// | |
/// For example: | |
/// ``` | |
/// let result = try Process.runScript(arguments: ["Hello, Argument!"]) {""" | |
/// echo $0 | |
/// """} | |
/// ``` | |
/// - Parameters: | |
/// - switch: The switch for the shell to take input via a string. Defaults to `"-c"` which is the option of Bash to read commands from the following string. | |
/// - script: A closure returning a script string. | |
public static func runScript(_ launchPath: String = "/bin/bash", _ switch: String = "-c", arguments: [String] = [], _ environment: [String: String]? = nil, routeStdErrToStdOut: Bool = false, script: () -> String) throws -> ProcessExecutionResult { | |
let arguments = [`switch`, script()] + arguments | |
return try run(launchPath, arguments, environment, routeStdErrToStdOut: routeStdErrToStdOut) | |
} | |
} | |
/// The result of executing a process. | |
public struct ProcessExecutionResult { | |
/// The output to standard output of the executable. | |
var output: String? | |
/// The output to standard error of the executable. | |
var error: String? | |
/// The termination status code of the executable. | |
var status: Int | |
} | |
extension ProcessExecutionResult: Equatable {} | |
extension ProcessExecutionResult: Hashable {} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment