1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-08 04:20:07 +02:00

♻️ Rework how output is handled

This commit is contained in:
2021-12-18 15:53:04 +01:00
parent 313e806414
commit 35ae681c2d
3 changed files with 71 additions and 22 deletions

View File

@ -40,10 +40,9 @@ class Application {
/** Checks if the app is installed. */ /** Checks if the app is installed. */
func isInstalled() -> Bool { func isInstalled() -> Bool {
// If this script does not complain, the app exists! // If this script does not complain, the app exists!
return Shell.user.execute( return Shell.user.executeSynchronously(
"/usr/bin/open -Ra \"\(name)\"", "/usr/bin/open -Ra \"\(name)\"",
requiresPath: false, requiresPath: false
waitUntilExit: true
).task.terminationStatus == 0 ).task.terminationStatus == 0
} }

View File

@ -329,9 +329,25 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate {
@objc func updateComposerDependencies() { @objc func updateComposerDependencies() {
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.global(qos: .userInitiated).async {
let output = Shell.user.execute( let output = Shell.user.executeSynchronously(
"composer global update", requiresPath: true, waitUntilExit: true "composer global update", requiresPath: true
) )
let task = Shell.user.createTask(for: "composer global update", requiresPath: true)
Shell.captureOutput(
task,
didReceiveStdOutData: { string in
print("\(string)")
},
didReceiveStdErrData: { string in
print("\(string)")
}
)
task.launch()
task.waitUntilExit()
DispatchQueue.main.async { DispatchQueue.main.async {
if output.task.terminationStatus > 0 { if output.task.terminationStatus > 0 {
// Error code means > 0 // Error code means > 0

View File

@ -62,7 +62,7 @@ class Shell {
_ command: String, _ command: String,
requiresPath: Bool = false requiresPath: Bool = false
) -> String { ) -> String {
let shellOutput = self.execute(command, requiresPath: requiresPath) let shellOutput = self.executeSynchronously(command, requiresPath: requiresPath)
let hasError = ( let hasError = (
shellOutput.standardOutput == "" shellOutput.standardOutput == ""
&& shellOutput.errorOutput.lengthOfBytes(using: .utf8) > 0 && shellOutput.errorOutput.lengthOfBytes(using: .utf8) > 0
@ -77,35 +77,28 @@ class Shell {
- Parameter requiresPath: By default, the PATH is not resolved but some binaries might require this - Parameter requiresPath: By default, the PATH is not resolved but some binaries might require this
- Parameter waitUntilExit: Waits for the command to complete before returning the `ShellOutput` - Parameter waitUntilExit: Waits for the command to complete before returning the `ShellOutput`
*/ */
func execute( func executeSynchronously(
_ command: String, _ command: String,
requiresPath: Bool = false, requiresPath: Bool = false
waitUntilExit: Bool = false
) -> ShellOutput { ) -> ShellOutput {
let task = Process()
let outputPipe = Pipe() let outputPipe = Pipe()
let errorPipe = Pipe() let errorPipe = Pipe()
let tailoredCommand = requiresPath let task = self.createTask(for: command, requiresPath: requiresPath)
? "export PATH=\(Paths.binPath):$PATH && \(command)"
: command
task.launchPath = self.shell
task.arguments = ["--login", "-c", tailoredCommand]
task.standardOutput = outputPipe task.standardOutput = outputPipe
task.standardError = errorPipe task.standardError = errorPipe
task.launch() task.launch()
task.waitUntilExit()
if waitUntilExit {
task.waitUntilExit()
}
return ShellOutput( return ShellOutput(
standardOutput: String( standardOutput: String(
data: outputPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8 data: outputPipe.fileHandleForReading.readDataToEndOfFile(),
encoding: .utf8
)!, )!,
errorOutput: String( errorOutput: String(
data: errorPipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8 data: errorPipe.fileHandleForReading.readDataToEndOfFile(),
encoding: .utf8
)!, )!,
task: task task: task
) )
@ -118,6 +111,47 @@ class Shell {
public static func fileExists(_ path: String) -> Bool { public static func fileExists(_ path: String) -> Bool {
return Shell.pipe("if [ -f \(path) ]; then /bin/echo -n \"0\"; fi") == "0" return Shell.pipe("if [ -f \(path) ]; then /bin/echo -n \"0\"; fi") == "0"
} }
/**
Creates a new process with the correct PATH and shell.
*/
func createTask(for command: String, requiresPath: Bool) -> Process {
let tailoredCommand = requiresPath
? "export PATH=\(Paths.binPath):$PATH && \(command)"
: command
let task = Process()
task.launchPath = self.shell
task.arguments = ["--login", "-c", tailoredCommand]
return task
}
static func captureOutput(
_ task: Process,
didReceiveStdOutData: @escaping (String) -> Void,
didReceiveStdErrData: @escaping (String) -> Void
) {
let outputPipe = Pipe()
let errorPipe = Pipe()
task.standardOutput = outputPipe
task.standardError = errorPipe
outputPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable, object: outputPipe.fileHandleForReading, queue: nil) { notification in
let outputString = String(data: outputPipe.fileHandleForReading.availableData, encoding: String.Encoding.utf8) ?? ""
didReceiveStdOutData(outputString)
outputPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
}
errorPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable, object: errorPipe.fileHandleForReading, queue: nil) { notification in
let outputString = String(data: errorPipe.fileHandleForReading.availableData, encoding: String.Encoding.utf8) ?? ""
didReceiveStdErrData(outputString)
errorPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
}
}
} }
class ShellOutput { class ShellOutput {