mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 03:50:08 +02:00
🏗 WIP: Shell rework
This commit is contained in:
@ -12,8 +12,7 @@ class ShellTest: XCTestCase {
|
||||
func test_default_shell_is_system_shell() {
|
||||
XCTAssertTrue(Shell is SystemShell)
|
||||
|
||||
XCTAssertTrue(Shell.syncPipe("php -v")
|
||||
.contains("Copyright (c) The PHP Group"))
|
||||
XCTAssertTrue(Shell.sync("php -v").output.contains("Copyright (c) The PHP Group"))
|
||||
}
|
||||
|
||||
func test_system_shell_has_path() {
|
||||
@ -45,8 +44,14 @@ class ShellTest: XCTestCase {
|
||||
|
||||
XCTAssertTrue(Shell is TestableShell)
|
||||
|
||||
XCTAssertEqual(expectedPhpOutput, Shell.syncPipe("php -v"))
|
||||
XCTAssertEqual(expectedPhpOutput, Shell.sync("php -v").output)
|
||||
|
||||
XCTAssertEqual(expectedPhpOutput, Shell.syncPipe("php --version"))
|
||||
XCTAssertEqual(expectedPhpOutput, Shell.sync("php --version").output)
|
||||
}
|
||||
|
||||
func test_unrecognized_commands_output_stderr() {
|
||||
ActiveShell.useTestable([:])
|
||||
|
||||
XCTAssertEqual("Unexpected Command", Shell.sync("unrecognized command").output)
|
||||
}
|
||||
}
|
||||
|
@ -8,10 +8,37 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol Shellable {
|
||||
typealias Output = String
|
||||
struct ShellOutput: CustomStringConvertible {
|
||||
var output: String
|
||||
var isError: Bool
|
||||
|
||||
func syncPipe(_ command: String) -> Output
|
||||
|
||||
func pipe(_ command: String) async -> Output
|
||||
var description: String {
|
||||
return output
|
||||
}
|
||||
}
|
||||
|
||||
protocol Shellable {
|
||||
/**
|
||||
Run a command synchronously. Waits until the command is done.
|
||||
*/
|
||||
func sync(_ command: String) -> ShellOutput
|
||||
|
||||
/**
|
||||
Run a command asynchronously.
|
||||
*/
|
||||
func pipe(_ command: String) async -> ShellOutput
|
||||
|
||||
/**
|
||||
Run a command asynchronously, without returning the output of the command.
|
||||
*/
|
||||
func quiet(_ command: String) async
|
||||
|
||||
/**
|
||||
Attach to a given command and listen for progress updates.
|
||||
Any data that ends up in standard out or standard error becomes available.
|
||||
*/
|
||||
func attach(
|
||||
_ command: String,
|
||||
didReceiveOutput: @escaping (ShellOutput) -> Void
|
||||
) async -> ShellOutput
|
||||
}
|
||||
|
@ -82,21 +82,43 @@ class SystemShell: Shellable {
|
||||
|
||||
// MARK: - Shellable Protocol
|
||||
|
||||
func syncPipe(_ command: String) -> String {
|
||||
func sync(_ command: String) -> ShellOutput {
|
||||
let task = getShellProcess(for: command)
|
||||
let pipe = Pipe()
|
||||
|
||||
task.standardOutput = pipe
|
||||
let outputPipe = Pipe()
|
||||
let errorPipe = Pipe()
|
||||
|
||||
task.standardOutput = outputPipe
|
||||
task.standardError = errorPipe
|
||||
task.waitUntilExit()
|
||||
task.launch()
|
||||
|
||||
return String(
|
||||
data: pipe.fileHandleForReading.readDataToEndOfFile(),
|
||||
let stdOut = String(
|
||||
data: outputPipe.fileHandleForReading.readDataToEndOfFile(),
|
||||
encoding: .utf8
|
||||
) ?? ""
|
||||
)!
|
||||
|
||||
let stdErr = String(
|
||||
data: errorPipe.fileHandleForReading.readDataToEndOfFile(),
|
||||
encoding: .utf8
|
||||
)!
|
||||
|
||||
if stdErr.lengthOfBytes(using: .utf8) > 0 {
|
||||
return ShellOutput(output: stdErr, isError: true)
|
||||
}
|
||||
|
||||
return ShellOutput(output: stdOut, isError: false)
|
||||
}
|
||||
|
||||
func pipe(_ command: String) async -> String {
|
||||
// TODO
|
||||
return ""
|
||||
func pipe(_ command: String) async -> ShellOutput {
|
||||
return sync(command)
|
||||
}
|
||||
|
||||
func quiet(_ command: String) async {
|
||||
_ = await self.pipe(command)
|
||||
}
|
||||
|
||||
func attach(_ command: String, didReceiveOutput: @escaping (ShellOutput) -> Void) async -> ShellOutput {
|
||||
return sync(command)
|
||||
}
|
||||
}
|
||||
|
@ -18,14 +18,24 @@ public class TestableShell: Shellable {
|
||||
|
||||
var expectations: [Input: OutputsToShell] = [:]
|
||||
|
||||
func pipe(_ command: String) async -> String {
|
||||
// TODO: Deal with the duration and output to error
|
||||
return expectations[command]?.getOutputAsString() ?? ""
|
||||
func quiet(_ command: String) async {
|
||||
return
|
||||
}
|
||||
|
||||
func syncPipe(_ command: String) -> String {
|
||||
// TODO: Deal with the duration and output to error
|
||||
return expectations[command]?.getOutputAsString() ?? ""
|
||||
func pipe(_ command: String) async -> ShellOutput {
|
||||
self.sync(command)
|
||||
}
|
||||
|
||||
func attach(_ command: String, didReceiveOutput: @escaping (ShellOutput) -> Void) async -> ShellOutput {
|
||||
self.sync(command)
|
||||
}
|
||||
|
||||
func sync(_ command: String) -> ShellOutput {
|
||||
guard let expectation = expectations[command] else {
|
||||
return ShellOutput(output: "Unexpected Command", isError: true)
|
||||
}
|
||||
|
||||
return ShellOutput(output: expectation.getOutputAsString(), isError: expectation.outputsToError())
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user