Merge pull request #459 from Grublady/installation-stage

Fixes in adjusted installation process
This commit is contained in:
David Bureš 2025-02-09 20:33:46 +01:00 committed by GitHub
commit e2cfc6e81b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 113 additions and 143 deletions

View File

@ -1,52 +0,0 @@
//
// Package Installation Status.swift
// Cork
//
// Created by David Bureš on 22.02.2023.
//
import Foundation
enum PackageInstallationStage: CustomStringConvertible
{
case ready, loadingDependencies, fetchingDependencies, installingDependencies, installingPackage, finished // For Formulae
case downloadingCask, installingCask, movingCask, linkingCaskBinary // For Casks
case requiresSudoPassword, wrongArchitecture, binaryAlreadyExists, terminatedUnexpectedly // For Both
var description: String
{
switch self
{
case .ready:
return "Ready"
case .loadingDependencies:
return "Loading Dependencies"
case .fetchingDependencies:
return "Fetching Dependencies"
case .installingDependencies:
return "Installing Dependencies"
case .installingPackage:
return "Installing Package"
case .finished:
return "Installation Finished"
case .downloadingCask:
return "Downloaing Cask"
case .installingCask:
return "Installing Cask"
case .movingCask:
return "Moving Cask"
case .linkingCaskBinary:
return "Linking Cask Binary"
case .requiresSudoPassword:
return "Sudo Password Required"
case .wrongArchitecture:
return "Wrong Package Architecture"
case .binaryAlreadyExists:
return "Binary Already Exists"
case .terminatedUnexpectedly:
return "Terminated Unexpectedly"
}
}
}

View File

@ -7410,6 +7410,16 @@
}
}
},
"add-package.install.calculating-dependencies" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Calculating Dependencies..."
}
}
}
},
"add-package.install.downloading-cask-%@" : {
"localizations" : {
"cs" : {
@ -8139,6 +8149,7 @@
}
},
"add-package.install.loading-dependencies" : {
"extractionState" : "stale",
"localizations" : {
"cs" : {
"stringUnit" : {

View File

@ -10,7 +10,7 @@ import Foundation
class InstallationProgressTracker: ObservableObject
{
@Published var packageBeingInstalled: PackageInProgressOfBeingInstalled = .init(package: .init(name: "", type: .formula, installedOn: nil, versions: [], sizeInBytes: 0), installationStage: .downloadingCask, packageInstallationProgress: 0)
@Published var packageBeingInstalled: PackageInProgressOfBeingInstalled = .init(package: .init(name: "", type: .formula, installedOn: nil, versions: [], sizeInBytes: 0), installationStage: .ready, packageInstallationProgress: 0)
@Published var numberOfPackageDependencies: Int = 0
@Published var numberInLineOfPackageCurrentlyBeingFetched: Int = 0
@ -76,7 +76,10 @@ class InstallationProgressTracker: ObservableObject
{
switch output
{
case .standardOutput(let outputLine):
case .standardOutput(let outputLines):
for outputLine in outputLines.split(separator: "\n")
{
let outputLine: String = String(outputLine)
AppConstants.shared.logger.debug("Package install line out: \(outputLine, privacy: .public)")
if showRealTimeTerminalOutputs
@ -91,6 +94,7 @@ class InstallationProgressTracker: ObservableObject
hasAlreadyMatchedPackage: hasAlreadyMatchedPackage
)
{
packageBeingInstalled.installationStage = stage
switch stage
{
case .calculatingDependencies:
@ -109,7 +113,6 @@ class InstallationProgressTracker: ObservableObject
case .fetchingDependencies(let packageDependencies):
AppConstants.shared.logger.info("Will fetch dependencies!")
packageBeingInstalled.installationStage = .fetchingDependencies
numberInLineOfPackageCurrentlyBeingFetched = numberInLineOfPackageCurrentlyBeingFetched + 1
@ -117,17 +120,15 @@ class InstallationProgressTracker: ObservableObject
packageBeingInstalled.packageInstallationProgress = packageBeingInstalled.packageInstallationProgress + Double(Double(10) / (Double(3) * (Double(numberOfPackageDependencies) * Double(5))))
case .installingDependencies(let packageName):
case .installingDependencies:
AppConstants.shared.logger.info("Will install dependencies!")
packageBeingInstalled.installationStage = .installingDependencies
numberInLineOfPackageCurrentlyBeingInstalled += 1
packageBeingInstalled.packageInstallationProgress += Double(10) / (3 * Double(numberOfPackageDependencies))
case .installingPackage(let packageName, let isFirstMatch):
case .installingPackage:
if hasAlreadyMatchedPackage
{
AppConstants.shared.logger.info("Will install the package itself!")
packageBeingInstalled.installationStage = .installingPackage
}
else
{
@ -150,23 +151,24 @@ class InstallationProgressTracker: ObservableObject
installOutput.append(outputLine)
AppConstants.shared.logger.debug("Current installation stage: \(self.packageBeingInstalled.installationStage.description, privacy: .public)")
}
case .standardError(let errorLine):
AppConstants.shared.logger.error("Errored out: \(errorLine, privacy: .public)")
case .standardError(let errorLines):
AppConstants.shared.logger.error("Errored out: \(errorLines, privacy: .public)")
if showRealTimeTerminalOutputs
{
packageBeingInstalled.realTimeTerminalOutput.append(RealTimeTerminalLine(line: errorLine))
packageBeingInstalled.realTimeTerminalOutput.append(RealTimeTerminalLine(line: errorLines))
}
if let stage = BrewInstallationStage.matchingFormula(
errorLine,
errorLines,
packageName: package.name,
packageDependencies: packageDependencies,
hasAlreadyMatchedPackage: hasAlreadyMatchedPackage
)
{
packageBeingInstalled.installationStage = .requiresSudoPassword
packageBeingInstalled.installationStage = stage
}
}
}
@ -198,31 +200,27 @@ class InstallationProgressTracker: ObservableObject
if let stage = BrewInstallationStage.matchingCask(outputLine)
{
packageBeingInstalled.installationStage = stage
switch stage
{
case .downloadingCask:
AppConstants.shared.logger.info("Will download Cask")
packageBeingInstalled.installationStage = .downloadingCask
packageBeingInstalled.packageInstallationProgress += 2
case .installingCask:
AppConstants.shared.logger.info("Will install Cask")
packageBeingInstalled.installationStage = .installingCask
packageBeingInstalled.packageInstallationProgress += 2
case .movingCask:
AppConstants.shared.logger.info("Moving App")
packageBeingInstalled.installationStage = .movingCask
packageBeingInstalled.packageInstallationProgress += 2
case .linkingCaskBinary:
AppConstants.shared.logger.info("Linking Binary")
packageBeingInstalled.installationStage = .linkingCaskBinary
packageBeingInstalled.packageInstallationProgress += 2
case .finished:
AppConstants.shared.logger.info("Finished installing app")
packageBeingInstalled.installationStage = .finished
packageBeingInstalled.packageInstallationProgress = 10
default:
@ -240,7 +238,7 @@ class InstallationProgressTracker: ObservableObject
if let stage = BrewInstallationStage.matchingCask(errorLine)
{
packageBeingInstalled.installationStage = .terminatedUnexpectedly
packageBeingInstalled.installationStage = stage
}
}
}
@ -262,7 +260,7 @@ private protocol InstallationStage
// MARK: - Installation Stage Enum
enum BrewInstallationStage: InstallationStage
enum BrewInstallationStage: InstallationStage, Equatable
{
// Formula-specific stages
case calculatingDependencies
@ -277,10 +275,12 @@ enum BrewInstallationStage: InstallationStage
case linkingCaskBinary
// Common stages
case ready
case requiresSudoPassword
case finished
case binaryAlreadyExists
case wrongArchitecture
case terminatedUnexpectedly
fileprivate var matchConditions: [MatchCondition]
{
@ -308,7 +308,7 @@ enum BrewInstallationStage: InstallationStage
}
]
case .installingPackage(let packageName, let isFirstMatch):
case .installingPackage(let packageName, _):
return [
.simple("Fetching \(packageName)"),
.simple("Installing \(packageName)")
@ -335,6 +335,9 @@ enum BrewInstallationStage: InstallationStage
.simple("==> Linking binary")
]
case .ready:
return []
case .requiresSudoPassword:
return [
.simple("password is required")
@ -358,6 +361,9 @@ enum BrewInstallationStage: InstallationStage
line.contains("but you are running")
}
]
case .terminatedUnexpectedly:
return []
}
}
@ -381,6 +387,8 @@ enum BrewInstallationStage: InstallationStage
return "Moving Cask"
case .linkingCaskBinary:
return "Linking Binary"
case .ready:
return "Ready"
case .requiresSudoPassword:
return "Requires Sudo Password"
case .finished:
@ -389,6 +397,8 @@ enum BrewInstallationStage: InstallationStage
return "Binary Already Exists"
case .wrongArchitecture:
return "Wrong Architecture"
case .terminatedUnexpectedly:
return "Terminated Unexpectedly"
}
}

View File

@ -18,7 +18,7 @@ struct PackageInProgressOfBeingInstalled: Identifiable
let id: UUID = .init()
let package: BrewPackage
var installationStage: PackageInstallationStage
var installationStage: BrewInstallationStage
var packageInstallationProgress: Double
var realTimeTerminalOutput: [RealTimeTerminalLine] = .init()

View File

@ -39,8 +39,8 @@ struct InstallingPackageView: View
Text("add-package.install.ready")
// FORMULAE
case .loadingDependencies:
Text("add-package.install.loading-dependencies")
case .calculatingDependencies:
Text("add-package.install.calculating-dependencies")
case .fetchingDependencies:
Text("add-package.install.fetching-dependencies")
@ -125,12 +125,13 @@ struct InstallingPackageView: View
AppConstants.shared.logger.debug("Installation result:\nStandard output: \(installationResult.standardOutput, privacy: .public)\nStandard error: \(installationResult.standardError, privacy: .public)")
/// Check if the package installation stag at the end of the install process was something unexpected. Normal package installations go through multiple steps, and the three listed below are not supposed to be the end state. This means that something went wrong during the installation
let installationStage: PackageInstallationStage = installationProgressTracker.packageBeingInstalled.installationStage
if [.installingCask, .installingPackage, .ready].contains(installationStage)
{
switch installationProgressTracker.packageBeingInstalled.installationStage {
case .installingCask, .installingPackage, .ready:
AppConstants.shared.logger.warning("The installation process quit before it was supposed to")
installationProgressTracker.packageBeingInstalled.installationStage = .terminatedUnexpectedly
default:
break
}
}
catch let fatalInstallationError