From 5ebafdb4e319fb99a0a606fd24ea0980c5757663 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Thu, 29 Sep 2022 19:08:40 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=8C=20Shell=20tweaks,=20fix=20Composer?= =?UTF-8?q?Window=20async=20issue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 6 +++ phpmon-tests/Next/SystemShellTest.swift | 2 +- .../Extensions/TimeIntervalExtension.swift | 15 ++++++ .../Composer/ComposerWindow.swift | 51 +++++++++---------- phpmon/Domain/Menu/MainMenu+Actions.swift | 2 +- phpmon/Next/Shellable.swift | 2 +- phpmon/Next/SystemShell.swift | 6 +-- phpmon/Next/TestableShell.swift | 4 +- 8 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 phpmon/Common/Extensions/TimeIntervalExtension.swift diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index fcceb87..4ad3a28 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -125,6 +125,8 @@ C449B4F427EE7FC800C47E8A /* DomainListKindCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AC51FB27E27F47008528CA /* DomainListKindCell.swift */; }; C44A874828905BB000498BC4 /* 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 */; }; C44C198E276E3A1C0072762D /* TerminalProgressWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */; }; 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 = ""; }; C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionPopoverView.swift; sourceTree = ""; }; C44A874728905BB000498BC4 /* ProgressVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressVC.swift; sourceTree = ""; }; + C44B3A4528E5C70100718CB1 /* TimeIntervalExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeIntervalExtension.swift; sourceTree = ""; }; C44C198C276E3A1C0072762D /* TerminalProgressWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalProgressWindowController.swift; sourceTree = ""; }; C44C1990276E44CB0072762D /* ProgressWindow.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ProgressWindow.storyboard; sourceTree = ""; }; C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertableError.swift; sourceTree = ""; }; @@ -1202,6 +1205,7 @@ C40508B028ADAB44008FAC1F /* NSMenuItemExtension.swift */, C4E0F7EC27BEBDA9007475F2 /* NSWindowExtension.swift */, C4EB53E628553117006F9937 /* ArrayExtension.swift */, + C44B3A4528E5C70100718CB1 /* TimeIntervalExtension.swift */, ); path = Extensions; sourceTree = ""; @@ -1388,6 +1392,7 @@ C463E380284930EE00422731 /* PresetHelper.swift in Sources */, C41C02A927E61A65009F26CB /* ValetSite+Fake.swift in Sources */, C4C0E8DF27F88AEB002D32A9 /* FakeSiteScanner.swift in Sources */, + C44B3A4628E5C70100718CB1 /* TimeIntervalExtension.swift in Sources */, C44264BE2850B86C007400F1 /* SwiftUIHelper.swift in Sources */, C4E9D2C02878B336008FFDAD /* OnboardingView.swift in Sources */, C4F2E4372752F0870020E974 /* HomebrewDiagnostics.swift in Sources */, @@ -1510,6 +1515,7 @@ C4205A7F27F4D21800191A39 /* ValetProxy.swift in Sources */, C42F26742805B4B400938AC7 /* DomainListable.swift in Sources */, C46EBC4528DB95F0007ACC74 /* Shellable.swift in Sources */, + C44B3A4728E5C70100718CB1 /* TimeIntervalExtension.swift in Sources */, C4F780C425D80B75000DBC97 /* MainMenu.swift in Sources */, 54FCFD2B276C8AA4004CE748 /* CheckboxPreferenceView.swift in Sources */, C415D3B82770F294005EF286 /* Actions.swift in Sources */, diff --git a/phpmon-tests/Next/SystemShellTest.swift b/phpmon-tests/Next/SystemShellTest.swift index 8e411bc..28530ff 100644 --- a/phpmon-tests/Next/SystemShellTest.swift +++ b/phpmon-tests/Next/SystemShellTest.swift @@ -31,7 +31,7 @@ class SystemShellTest: XCTestCase { func test_system_shell_can_buffer_output() async { 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';\"", didReceiveOutput: { incoming in bits.append(incoming.out) diff --git a/phpmon/Common/Extensions/TimeIntervalExtension.swift b/phpmon/Common/Extensions/TimeIntervalExtension.swift new file mode 100644 index 0000000..19d3854 --- /dev/null +++ b/phpmon/Common/Extensions/TimeIntervalExtension.swift @@ -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) + } +} diff --git a/phpmon/Domain/Integrations/Composer/ComposerWindow.swift b/phpmon/Domain/Integrations/Composer/ComposerWindow.swift index 90faa60..3822789 100644 --- a/phpmon/Domain/Integrations/Composer/ComposerWindow.swift +++ b/phpmon/Domain/Integrations/Composer/ComposerWindow.swift @@ -8,8 +8,7 @@ import Foundation -class ComposerWindow { - +@MainActor class ComposerWindow { private var menu: MainMenu? private var shouldNotify: Bool! = nil private var completion: ((Bool) -> Void)! = nil @@ -42,39 +41,37 @@ class ComposerWindow { window?.setType(info: true) - DispatchQueue.global(qos: .userInitiated).async { [self] in - let task = LegacyShell.user.createTask( - for: "\(Paths.composer!) global update", requiresPath: true - ) + Task { await performComposerUpdate() } + } + + private func performComposerUpdate() async { + do { + let command = "\(Paths.composer!) global update" DispatchQueue.main.async { - self.window?.addToConsole("\(Paths.composer!) global update\n") + self.window?.addToConsole("\(command)\n") } - task.listen( - didReceiveStandardOutputData: { [weak self] string in - DispatchQueue.main.async { - self?.window?.addToConsole(string) + let (process, _) = try await Shell.attach( + command, + didReceiveOutput: { [weak self] output in + 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 - DispatchQueue.main.async { - self?.window?.addToConsole(string) - } - // Log.perf("\(string.trimmingCharacters(in: .newlines))") - } + withTimeout: .minutes(5) ) - task.launch() - task.waitUntilExit() - task.haltListening() - - if task.terminationStatus <= 0 { - composerUpdateSucceeded() - } else { - composerUpdateFailed() - } + if process.terminationStatus <= 0 { + composerUpdateSucceeded() + } else { + composerUpdateFailed() + } + } catch { + composerUpdateFailed() } } diff --git a/phpmon/Domain/Menu/MainMenu+Actions.swift b/phpmon/Domain/Menu/MainMenu+Actions.swift index 36e1f08..3f696b6 100644 --- a/phpmon/Domain/Menu/MainMenu+Actions.swift +++ b/phpmon/Domain/Menu/MainMenu+Actions.swift @@ -200,7 +200,7 @@ extension MainMenu { } } - @objc func updateGlobalComposerDependencies() { + @MainActor @objc func updateGlobalComposerDependencies() { ComposerWindow().updateGlobalDependencies( notify: true, completion: { _ in } diff --git a/phpmon/Next/Shellable.swift b/phpmon/Next/Shellable.swift index 3c50b75..40bc8d2 100644 --- a/phpmon/Next/Shellable.swift +++ b/phpmon/Next/Shellable.swift @@ -58,7 +58,7 @@ protocol Shellable { _ command: String, didReceiveOutput: @escaping (ShellOutput) -> Void, withTimeout timeout: TimeInterval - ) async throws -> ShellOutput + ) async throws -> (Process, ShellOutput) } enum ShellError: Error { diff --git a/phpmon/Next/SystemShell.swift b/phpmon/Next/SystemShell.swift index 1901d55..dfab315 100644 --- a/phpmon/Next/SystemShell.swift +++ b/phpmon/Next/SystemShell.swift @@ -118,7 +118,7 @@ class SystemShell: Shellable { _ command: String, didReceiveOutput: @escaping (ShellOutput) -> Void, withTimeout timeout: TimeInterval = 5.0 - ) async throws -> ShellOutput { + ) async throws -> (Process, ShellOutput) { let task = getShellProcess(for: command) var allOut: String = "" @@ -139,10 +139,10 @@ class SystemShell: Shellable { timer?.invalidate() 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 diff --git a/phpmon/Next/TestableShell.swift b/phpmon/Next/TestableShell.swift index 41a6fd2..cb3f962 100644 --- a/phpmon/Next/TestableShell.swift +++ b/phpmon/Next/TestableShell.swift @@ -29,8 +29,8 @@ public class TestableShell: Shellable { _ command: String, didReceiveOutput: @escaping (ShellOutput) -> Void, withTimeout timeout: TimeInterval - ) async throws -> ShellOutput { - self.sync(command) + ) async throws -> (Process, ShellOutput) { + return (Process(), self.sync(command)) } func sync(_ command: String) -> ShellOutput {