mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 03:50:08 +02:00
👌 Shell tweaks, fix ComposerWindow async issue
This commit is contained in:
@ -125,6 +125,8 @@
|
|||||||
C449B4F427EE7FC800C47E8A /* DomainListKindCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AC51FB27E27F47008528CA /* DomainListKindCell.swift */; };
|
C449B4F427EE7FC800C47E8A /* DomainListKindCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AC51FB27E27F47008528CA /* DomainListKindCell.swift */; };
|
||||||
C44A874828905BB000498BC4 /* ProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44A874728905BB000498BC4 /* ProgressVC.swift */; };
|
C44A874828905BB000498BC4 /* ProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44A874728905BB000498BC4 /* ProgressVC.swift */; };
|
||||||
C44A874928905BB000498BC4 /* ProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44A874728905BB000498BC4 /* ProgressVC.swift */; };
|
C44A874928905BB000498BC4 /* ProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44A874728905BB000498BC4 /* ProgressVC.swift */; };
|
||||||
|
C44B3A4628E5C70100718CB1 /* TimeIntervalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44B3A4528E5C70100718CB1 /* TimeIntervalExtension.swift */; };
|
||||||
|
C44B3A4728E5C70100718CB1 /* TimeIntervalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44B3A4528E5C70100718CB1 /* TimeIntervalExtension.swift */; };
|
||||||
C44C198D276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; };
|
C44C198D276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; };
|
||||||
C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; };
|
C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; };
|
||||||
C44C1991276E44CB0072762D /* ProgressWindow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C44C1990276E44CB0072762D /* ProgressWindow.storyboard */; };
|
C44C1991276E44CB0072762D /* ProgressWindow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C44C1990276E44CB0072762D /* ProgressWindow.storyboard */; };
|
||||||
@ -412,6 +414,7 @@
|
|||||||
C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIHelper.swift; sourceTree = "<group>"; };
|
C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIHelper.swift; sourceTree = "<group>"; };
|
||||||
C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionPopoverView.swift; sourceTree = "<group>"; };
|
C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionPopoverView.swift; sourceTree = "<group>"; };
|
||||||
C44A874728905BB000498BC4 /* ProgressVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressVC.swift; sourceTree = "<group>"; };
|
C44A874728905BB000498BC4 /* ProgressVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressVC.swift; sourceTree = "<group>"; };
|
||||||
|
C44B3A4528E5C70100718CB1 /* TimeIntervalExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeIntervalExtension.swift; sourceTree = "<group>"; };
|
||||||
C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalProgressWindowController.swift; sourceTree = "<group>"; };
|
C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalProgressWindowController.swift; sourceTree = "<group>"; };
|
||||||
C44C1990276E44CB0072762D /* ProgressWindow.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ProgressWindow.storyboard; sourceTree = "<group>"; };
|
C44C1990276E44CB0072762D /* ProgressWindow.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ProgressWindow.storyboard; sourceTree = "<group>"; };
|
||||||
C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertableError.swift; sourceTree = "<group>"; };
|
C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertableError.swift; sourceTree = "<group>"; };
|
||||||
@ -1202,6 +1205,7 @@
|
|||||||
C40508B028ADAB44008FAC1F /* NSMenuItemExtension.swift */,
|
C40508B028ADAB44008FAC1F /* NSMenuItemExtension.swift */,
|
||||||
C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */,
|
C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */,
|
||||||
C4EB53E628553117006F9937 /* ArrayExtension.swift */,
|
C4EB53E628553117006F9937 /* ArrayExtension.swift */,
|
||||||
|
C44B3A4528E5C70100718CB1 /* TimeIntervalExtension.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1388,6 +1392,7 @@
|
|||||||
C463E380284930EE00422731 /* PresetHelper.swift in Sources */,
|
C463E380284930EE00422731 /* PresetHelper.swift in Sources */,
|
||||||
C41C02A927E61A65009F26CB /* ValetSite+Fake.swift in Sources */,
|
C41C02A927E61A65009F26CB /* ValetSite+Fake.swift in Sources */,
|
||||||
C4C0E8DF27F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */,
|
C4C0E8DF27F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */,
|
||||||
|
C44B3A4628E5C70100718CB1 /* TimeIntervalExtension.swift in Sources */,
|
||||||
C44264BE2850B86C007400F1 /* SwiftUIHelper.swift in Sources */,
|
C44264BE2850B86C007400F1 /* SwiftUIHelper.swift in Sources */,
|
||||||
C4E9D2C02878B336008FFDAD /* OnboardingView.swift in Sources */,
|
C4E9D2C02878B336008FFDAD /* OnboardingView.swift in Sources */,
|
||||||
C4F2E4372752F0870020E974 /* HomebrewDiagnostics.swift in Sources */,
|
C4F2E4372752F0870020E974 /* HomebrewDiagnostics.swift in Sources */,
|
||||||
@ -1510,6 +1515,7 @@
|
|||||||
C4205A7F27F4D21800191A39 /* ValetProxy.swift in Sources */,
|
C4205A7F27F4D21800191A39 /* ValetProxy.swift in Sources */,
|
||||||
C42F26742805B4B400938AC7 /* DomainListable.swift in Sources */,
|
C42F26742805B4B400938AC7 /* DomainListable.swift in Sources */,
|
||||||
C46EBC4528DB95F0007ACC74 /* Shellable.swift in Sources */,
|
C46EBC4528DB95F0007ACC74 /* Shellable.swift in Sources */,
|
||||||
|
C44B3A4728E5C70100718CB1 /* TimeIntervalExtension.swift in Sources */,
|
||||||
C4F780C425D80B75000DBC97 /* MainMenu.swift in Sources */,
|
C4F780C425D80B75000DBC97 /* MainMenu.swift in Sources */,
|
||||||
54FCFD2B276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */,
|
54FCFD2B276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */,
|
||||||
C415D3B82770F294005EF286 /* Actions.swift in Sources */,
|
C415D3B82770F294005EF286 /* Actions.swift in Sources */,
|
||||||
|
@ -31,7 +31,7 @@ class SystemShellTest: XCTestCase {
|
|||||||
func test_system_shell_can_buffer_output() async {
|
func test_system_shell_can_buffer_output() async {
|
||||||
var bits: [String] = []
|
var bits: [String] = []
|
||||||
|
|
||||||
let shellOutput = try! await Shell.attach(
|
let (_, shellOutput) = try! await Shell.attach(
|
||||||
"php -r \"echo 'Hello world' . PHP_EOL; usleep(200); echo 'Goodbye world';\"",
|
"php -r \"echo 'Hello world' . PHP_EOL; usleep(200); echo 'Goodbye world';\"",
|
||||||
didReceiveOutput: { incoming in
|
didReceiveOutput: { incoming in
|
||||||
bits.append(incoming.out)
|
bits.append(incoming.out)
|
||||||
|
15
phpmon/Common/Extensions/TimeIntervalExtension.swift
Normal file
15
phpmon/Common/Extensions/TimeIntervalExtension.swift
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// TimeExtension.swift
|
||||||
|
// PHP Monitor
|
||||||
|
//
|
||||||
|
// Created by Nico Verbruggen on 29/09/2022.
|
||||||
|
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension TimeInterval {
|
||||||
|
public static func minutes(_ amount: Int) -> TimeInterval {
|
||||||
|
return Double(amount * 60)
|
||||||
|
}
|
||||||
|
}
|
@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class ComposerWindow {
|
@MainActor class ComposerWindow {
|
||||||
|
|
||||||
private var menu: MainMenu?
|
private var menu: MainMenu?
|
||||||
private var shouldNotify: Bool! = nil
|
private var shouldNotify: Bool! = nil
|
||||||
private var completion: ((Bool) -> Void)! = nil
|
private var completion: ((Bool) -> Void)! = nil
|
||||||
@ -42,39 +41,37 @@ class ComposerWindow {
|
|||||||
|
|
||||||
window?.setType(info: true)
|
window?.setType(info: true)
|
||||||
|
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [self] in
|
Task { await performComposerUpdate() }
|
||||||
let task = LegacyShell.user.createTask(
|
}
|
||||||
for: "\(Paths.composer!) global update", requiresPath: true
|
|
||||||
)
|
private func performComposerUpdate() async {
|
||||||
|
do {
|
||||||
|
let command = "\(Paths.composer!) global update"
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.window?.addToConsole("\(Paths.composer!) global update\n")
|
self.window?.addToConsole("\(command)\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
task.listen(
|
let (process, _) = try await Shell.attach(
|
||||||
didReceiveStandardOutputData: { [weak self] string in
|
command,
|
||||||
DispatchQueue.main.async {
|
didReceiveOutput: { [weak self] output in
|
||||||
self?.window?.addToConsole(string)
|
if output.hasError {
|
||||||
|
DispatchQueue.main.async { self?.window?.addToConsole(output.err) }
|
||||||
|
}
|
||||||
|
if !output.out.isEmpty {
|
||||||
|
DispatchQueue.main.async { self?.window?.addToConsole(output.out) }
|
||||||
}
|
}
|
||||||
// Log.perf("\(string.trimmingCharacters(in: .newlines))")
|
|
||||||
},
|
},
|
||||||
didReceiveStandardErrorData: { [weak self] string in
|
withTimeout: .minutes(5)
|
||||||
DispatchQueue.main.async {
|
|
||||||
self?.window?.addToConsole(string)
|
|
||||||
}
|
|
||||||
// Log.perf("\(string.trimmingCharacters(in: .newlines))")
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
task.launch()
|
if process.terminationStatus <= 0 {
|
||||||
task.waitUntilExit()
|
composerUpdateSucceeded()
|
||||||
task.haltListening()
|
} else {
|
||||||
|
composerUpdateFailed()
|
||||||
if task.terminationStatus <= 0 {
|
}
|
||||||
composerUpdateSucceeded()
|
} catch {
|
||||||
} else {
|
composerUpdateFailed()
|
||||||
composerUpdateFailed()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ extension MainMenu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateGlobalComposerDependencies() {
|
@MainActor @objc func updateGlobalComposerDependencies() {
|
||||||
ComposerWindow().updateGlobalDependencies(
|
ComposerWindow().updateGlobalDependencies(
|
||||||
notify: true,
|
notify: true,
|
||||||
completion: { _ in }
|
completion: { _ in }
|
||||||
|
@ -58,7 +58,7 @@ protocol Shellable {
|
|||||||
_ command: String,
|
_ command: String,
|
||||||
didReceiveOutput: @escaping (ShellOutput) -> Void,
|
didReceiveOutput: @escaping (ShellOutput) -> Void,
|
||||||
withTimeout timeout: TimeInterval
|
withTimeout timeout: TimeInterval
|
||||||
) async throws -> ShellOutput
|
) async throws -> (Process, ShellOutput)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ShellError: Error {
|
enum ShellError: Error {
|
||||||
|
@ -118,7 +118,7 @@ class SystemShell: Shellable {
|
|||||||
_ command: String,
|
_ command: String,
|
||||||
didReceiveOutput: @escaping (ShellOutput) -> Void,
|
didReceiveOutput: @escaping (ShellOutput) -> Void,
|
||||||
withTimeout timeout: TimeInterval = 5.0
|
withTimeout timeout: TimeInterval = 5.0
|
||||||
) async throws -> ShellOutput {
|
) async throws -> (Process, ShellOutput) {
|
||||||
let task = getShellProcess(for: command)
|
let task = getShellProcess(for: command)
|
||||||
|
|
||||||
var allOut: String = ""
|
var allOut: String = ""
|
||||||
@ -139,10 +139,10 @@ class SystemShell: Shellable {
|
|||||||
timer?.invalidate()
|
timer?.invalidate()
|
||||||
|
|
||||||
if !allErr.isEmpty {
|
if !allErr.isEmpty {
|
||||||
return continuation.resume(returning: .err(allErr))
|
return continuation.resume(returning: (process, .err(allErr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return continuation.resume(returning: .out(allOut))
|
return continuation.resume(returning: (process, .out(allOut)))
|
||||||
}
|
}
|
||||||
|
|
||||||
timer = Timer.scheduledTimer(withTimeInterval: timeout, repeats: false) { _ in
|
timer = Timer.scheduledTimer(withTimeInterval: timeout, repeats: false) { _ in
|
||||||
|
@ -29,8 +29,8 @@ public class TestableShell: Shellable {
|
|||||||
_ command: String,
|
_ command: String,
|
||||||
didReceiveOutput: @escaping (ShellOutput) -> Void,
|
didReceiveOutput: @escaping (ShellOutput) -> Void,
|
||||||
withTimeout timeout: TimeInterval
|
withTimeout timeout: TimeInterval
|
||||||
) async throws -> ShellOutput {
|
) async throws -> (Process, ShellOutput) {
|
||||||
self.sync(command)
|
return (Process(), self.sync(command))
|
||||||
}
|
}
|
||||||
|
|
||||||
func sync(_ command: String) -> ShellOutput {
|
func sync(_ command: String) -> ShellOutput {
|
||||||
|
Reference in New Issue
Block a user