Skip to content

Commit 5a48dfe

Browse files
committed
~ Matcher enum structure
1 parent 575aae5 commit 5a48dfe

8 files changed

Lines changed: 116 additions & 86 deletions

File tree

Cork/Enums/Package Installation/Package Installation Steps.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ import CorkTerminalFunctions
1212

1313
enum PackageInstallationProcessSteps: Equatable
1414
{
15+
enum UnexpectedTerminalOutputType: Equatable
16+
{
17+
/// The unexpected outputs did NOT contain any STDERR outputs
18+
case containedErrors(rawOutput: [TerminalOutput])
19+
20+
/// The unexpected outputs DID contain some STDERR outputs
21+
case didNotContainErrors(rawOutput: [TerminalOutput])
22+
}
23+
1524
case ready
1625
case searching(forSearchString: String)
1726
case presentingSearchResults(
@@ -21,8 +30,8 @@ enum PackageInstallationProcessSteps: Equatable
2130
)
2231
case installing(package: MinimalHomebrewPackage)
2332
case finished
24-
case unexpectedTerminalOutput(rawOutput: [TerminalOutput])
25-
case erroredOut(withError: InstallationProgressTracker.InstallationError)
33+
case unexpectedTerminalOutput(UnexpectedTerminalOutputType)
34+
case erroredOut(withError: InstallationProgressTracker.InstallationError.ImplementedError)
2635

2736
var isDismissable: Bool
2837
{

Cork/Views/Installation/Install Package.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,15 @@ struct AddFormulaView: View
8282
InstallingPackageView(packageToInstall: package)
8383
case .finished:
8484
InstallationFinishedSuccessfullyView()
85-
case .unexpectedTerminalOutput(let rawOutput):
86-
EmptyView()
85+
case .unexpectedTerminalOutput(let unexpectedOutputType):
86+
// TODO: Implement the unexpected output views
87+
switch unexpectedOutputType
88+
{
89+
case .containedErrors(let rawOutputThatContainsErrors):
90+
EmptyView()
91+
case .didNotContainErrors(let rawOutputThatDidNotContainErrors):
92+
EmptyView()
93+
}
8794
case .erroredOut(let withError):
8895
EmptyView()
8996
}

Cork/Views/Installation/Sub-Views/Initial.swift

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct InstallationInitialView: View
3232

3333
@State private var packageRequested: String = ""
3434

35-
@State private var foundPackageSelection: BrewPackage?
35+
@State private var foundPackageSelection: MinimalHomebrewPackage?
3636

3737
@State var isSearchFieldFocused: Bool = true
3838

@@ -100,19 +100,15 @@ struct InstallationInitialView: View
100100
{
101101
PreviewPackageButtonWithCustomAction
102102
{
103-
guard let packageToPreview: BrewPackage = foundPackageSelection
103+
guard let packageToPreview: MinimalHomebrewPackage = foundPackageSelection
104104
else
105105
{
106106
AppConstants.shared.logger.error("Could not retrieve top package to preview")
107107

108108
return
109109
}
110110

111-
openWindow(value: MinimalHomebrewPackage(
112-
name: packageToPreview.name(withPrecision: .precise),
113-
type: packageToPreview.type,
114-
installedIntentionally: packageToPreview.installedIntentionally
115-
))
111+
openWindow(value: packageToPreview)
116112
}
117113
.disabled(foundPackageSelection == nil)
118114
.labelStyle(.titleOnly)
@@ -123,19 +119,15 @@ struct InstallationInitialView: View
123119
{
124120
Button
125121
{
126-
guard let packageToInstall: BrewPackage = foundPackageSelection
122+
guard let packageToInstall: MinimalHomebrewPackage = foundPackageSelection
127123
else
128124
{
129125
AppConstants.shared.logger.error("Could not retrieve top package to install")
130126

131127
return
132128
}
133129

134-
packageInstallationProcessStepTracker.advanceStep(to: .installing(package: .init(
135-
name: packageToInstall.name(withPrecision: .precise),
136-
type: packageToInstall.type,
137-
installedIntentionally: false
138-
)))
130+
packageInstallationProcessStepTracker.advanceStep(to: .installing(package: packageToInstall))
139131

140132
} label: {
141133
Text("add-package.install.action")

Cork/Views/Installation/Sub-Views/Installing.swift

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,41 +17,57 @@ struct InstallingPackageView: View
1717

1818
@InjectedObservable(\.appState) var appState: AppState
1919
@Environment(BrewPackagesTracker.self) var brewPackagesTracker: BrewPackagesTracker
20+
21+
@Environment(PackageInstallationProcessStepTracker.self) var packageInstallationProcessStepTracker: PackageInstallationProcessStepTracker
2022

2123
@Environment(CachedDownloadsTracker.self) var cachedDownloadsTracker: CachedDownloadsTracker
2224

2325
let packageToInstall: MinimalHomebrewPackage
2426

2527
@State var isShowingRealTimeOutput: Bool = false
2628

27-
@State private var installationProgressTracker: InstallationProgressTracker
28-
29-
init(packageToInstall: MinimalHomebrewPackage)
30-
{
31-
self.packageToInstall = packageToInstall
32-
self._installationProgressTracker = State(
33-
initialValue: InstallationProgressTracker(packageToInstall: packageToInstall)
34-
)
35-
}
29+
@State private var installationProgressTracker: InstallationProgressTracker?
3630

3731
var body: some View
3832
{
3933
VStack(alignment: .leading)
4034
{
41-
ProgressView(installationProgressTracker.installProgress)
42-
43-
switch installationProgressTracker.installStage
35+
if let installationProgressTracker
4436
{
45-
case .formula(let standardCases):
46-
Text(standardCases.stageDescription)
47-
case .cask(let standardCases):
48-
Text(standardCases.stageDescription)
37+
ProgressView(installationProgressTracker.installProgress)
38+
39+
switch installationProgressTracker.installStage
40+
{
41+
case .formula(let standardCases):
42+
Text(standardCases.stageDescription)
43+
case .cask(let standardCases):
44+
standardCases.view([packageToInstall])
45+
}
46+
47+
installationProgressTracker.streamedOutputsDisplay
4948
}
5049
}
5150
.task
5251
{
53-
do
54-
{}
52+
installationProgressTracker = .init(packageToInstall: packageToInstall)
53+
54+
do throws(InstallationProgressTracker.InstallationError)
55+
{
56+
try await installationProgressTracker!.installPackage(
57+
packageToInstall,
58+
using: brewPackagesTracker,
59+
cachedDownloadsTracker: cachedDownloadsTracker
60+
)
61+
} catch let installationError
62+
{
63+
switch installationError
64+
{
65+
case .implemented(let implementedError):
66+
packageInstallationProcessStepTracker.advanceStep(to: .erroredOut(withError: implementedError))
67+
case .unimplemented(let rawOutput):
68+
packageInstallationProcessStepTracker.advanceStep(to: .unexpectedTerminalOutput())
69+
}
70+
}
5571
}
5672
}
5773
}

Modules/Packages/PackagesModels/Logic/Installation & Removal/Install Package/Install Cask.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@ extension InstallationProgressTracker
1919
AppConstants.shared.logger.info("Package is Cask")
2020
AppConstants.shared.logger.debug("Installing package \(caskToInstall.name(withPrecision: .precise), privacy: .public)")
2121

22-
let (stream, process): (AsyncStream<TerminalOutput>, Process) = shell(AppConstants.shared.brewExecutablePath, ["install", caskToInstall.name(withPrecision: .precise)])
22+
let (stream, process): (AsyncStream<TerminalOutput>, Process) = shell(AppConstants.shared.brewExecutablePath, ["install", "--cask", caskToInstall.name(withPrecision: .precise)])
2323
installationProcess = process
2424

2525
var consolidatedUnimplementedOutput: [TerminalOutput] = .init()
2626
var installError: InstallationError.ImplementedError.CaskInstallError?
2727

2828
for await output in stream
2929
{
30+
print("Raw cask install output: \(output)")
31+
3032
self.insertOutput(output)
3133

3234
output.match(as: CaskInstallMatcher.self) { standardCase in
@@ -48,9 +50,6 @@ extension InstallationProgressTracker
4850
} onUnimplementedOutput: { unimplementedCase in
4951
consolidatedUnimplementedOutput.append(unimplementedCase)
5052
}
51-
52-
installationProcess?.terminate()
53-
break
5453
}
5554

5655
if let installError
@@ -62,5 +61,7 @@ extension InstallationProgressTracker
6261
{
6362
throw .implemented(.containsUnexpectedOutputs(rawOutput: consolidatedUnimplementedOutput))
6463
}
64+
65+
6566
}
6667
}

Modules/Packages/PackagesModels/Logic/Installation & Removal/Install Package/Install Package.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,17 @@ extension InstallationProgressTracker
3030
try await installCask(packageToInstall)
3131
}
3232
}
33-
catch let unexpectedError
34-
{}
33+
catch let formulaInstallError as InstallationError.ImplementedError.FormulaInstallError
34+
{
35+
print("Formula install error: \(formulaInstallError)")
36+
}
37+
catch let caskInstallError as InstallationError.ImplementedError.CaskInstallError
38+
{
39+
print("Cask install lerror: \(caskInstallError)")
40+
}
41+
catch let unexpectedError {
42+
print("Unexpected install error: \(unexpectedError)")
43+
}
3544

3645
do
3746
{

Modules/Packages/PackagesModels/Models/Package Installation/Installation Progress Tracker.swift

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
//
77

88
import BetterProgress
9+
import CorkShared
910
import CorkTerminalFunctions
1011
import Foundation
11-
import CorkShared
1212
import SwiftUI
1313

1414
@Observable
@@ -52,8 +52,9 @@ public class InstallationProgressTracker: @MainActor TerminalOutputStreamable
5252

5353
public enum FormulaInstallMatcher: TerminalOutputMatchable
5454
{
55-
public enum StandardCases: TerminalOutputCase, StageDisplayable, Sendable
55+
public enum StandardCases: TerminalOutputCase, Sendable
5656
{
57+
5758
public static let allCases: [InstallationProgressTracker.FormulaInstallMatcher.StandardCases] = [
5859
.findingDependencies,
5960
.downloadingDependencies(
@@ -71,7 +72,7 @@ public class InstallationProgressTracker: @MainActor TerminalOutputStreamable
7172
package: .init(createEmpty: true)
7273
)
7374
]
74-
75+
7576
case findingDependencies
7677
case downloadingDependencies(
7778
dependencyName: String
@@ -104,10 +105,11 @@ public class InstallationProgressTracker: @MainActor TerminalOutputStreamable
104105
["Installing \(package.name)"]
105106
}
106107
}
107-
108+
108109
public var stageDescription: LocalizedStringKey
109110
{
110-
switch self {
111+
switch self
112+
{
111113
case .findingDependencies:
112114
return "add-package.install.loading-dependencies"
113115
case .downloadingDependencies(let dependencyName):
@@ -143,24 +145,19 @@ public class InstallationProgressTracker: @MainActor TerminalOutputStreamable
143145
{
144146
public enum StandardCases: TerminalOutputCase, StageDisplayable, Sendable
145147
{
146-
public static let allCases: [InstallationProgressTracker.CaskInstallMatcher.StandardCases] = [
147-
.downloadingCask(.init(createEmpty: true)),
148-
.installingCask(.init(createEmpty: true)),
149-
.movingCask(.init(createEmpty: true)),
150-
.linkingAppToCask(.init(createEmpty: true))
151-
]
148+
public typealias Argument = MinimalHomebrewPackage
152149

153-
case downloadingCask(MinimalHomebrewPackage)
154-
case installingCask(MinimalHomebrewPackage)
155-
case movingCask(MinimalHomebrewPackage)
156-
case linkingAppToCask(MinimalHomebrewPackage)
150+
case downloadingCask
151+
case installingCask
152+
case movingCask
153+
case linkingAppToCask
157154

158155
public var patterns: [String]
159156
{
160157
switch self
161158
{
162159
case .downloadingCask:
163-
["Downloading"]
160+
["Downloading", "Fetching downloads"]
164161
case .installingCask:
165162
["Installing Cask", "Purging files"]
166163
case .movingCask:
@@ -169,19 +166,25 @@ public class InstallationProgressTracker: @MainActor TerminalOutputStreamable
169166
["Linking binary"]
170167
}
171168
}
172-
173-
public var stageDescription: LocalizedStringKey
174-
{
175-
switch self
169+
170+
@ViewBuilder
171+
public func view(_ arguments: [MinimalHomebrewPackage]) -> some View {
172+
if let caskToInstall = arguments.first(where: { $0.type == .cask })
176173
{
177-
case .downloadingCask(let caskToInstall):
178-
return "add-package.install.downloading-cask-\(caskToInstall.name)"
179-
case .installingCask(let caskToInstall):
180-
return "add-package.install.installing-cask-\(caskToInstall.name)"
181-
case .movingCask(let caskToInstall):
182-
return "add-package.install.moving-cask-\(caskToInstall.name)"
183-
case .linkingAppToCask(let caskToInstall):
184-
return "add-package.install.linking-cask-binary.\(caskToInstall.name)"
174+
switch self
175+
{
176+
case .downloadingCask:
177+
Text("add-package.install.downloading-cask-\(caskToInstall.name(withPrecision: .precise))")
178+
case .installingCask:
179+
Text("add-package.install.installing-cask-\(caskToInstall.name(withPrecision: .precise))")
180+
case .movingCask:
181+
Text("add-package.install.moving-cask-\(caskToInstall.name(withPrecision: .precise))")
182+
case .linkingAppToCask:
183+
Text("add-package.install.linking-cask-binary.\(caskToInstall.name(withPrecision: .precise))")
184+
}
185+
} else
186+
{
187+
EmptyView()
185188
}
186189
}
187190
}
@@ -214,7 +217,7 @@ public class InstallationProgressTracker: @MainActor TerminalOutputStreamable
214217
case formula(FormulaInstallMatcher.StandardCases)
215218
case cask(CaskInstallMatcher.StandardCases)
216219
}
217-
220+
218221
public func insertOutput(_ output: CorkTerminalFunctions.TerminalOutput)
219222
{
220223
self.outputs.append(output)
@@ -251,13 +254,14 @@ public class InstallationProgressTracker: @MainActor TerminalOutputStreamable
251254
return .init(totalItems: Self.CaskInstallMatcher.StandardCases.allCases.count)
252255
}
253256
}()
254-
257+
255258
let installStageType: InstallStageType = {
256-
switch packageToInstall.type {
259+
switch packageToInstall.type
260+
{
257261
case .formula:
258262
return .formula(.findingDependencies)
259263
case .cask:
260-
return .cask(.downloadingCask(packageToInstall))
264+
return .cask(.downloadingCask)
261265
}
262266
}()
263267

Modules/Shared/Protocols/Stage Displayable.swift

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,10 @@ import SwiftUI
1111
/// Attach a displayable view to an enum
1212
public protocol StageDisplayable
1313
{
14-
/// Text for the stage
15-
var stageDescription: LocalizedStringKey { get }
14+
associatedtype DisplayableView: View
15+
associatedtype Argument
1616

17-
/// Optional to display
18-
var view: (any View)? { get set }
19-
}
20-
21-
public extension StageDisplayable
22-
{
23-
var view: (any View)?
24-
{
25-
get { nil }
26-
set { }
27-
}
17+
/// View to describe the stage with
18+
@ViewBuilder
19+
func view(_ arguments: [Argument]) -> DisplayableView
2820
}

0 commit comments

Comments
 (0)