Merge branch 'fix/upgrade-failures'
This commit is contained in:
commit
3d6f39048a
|
|
@ -47,6 +47,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
/// last known outdated list, shown in the Upgrade All confirmation
|
||||
var cachedOutdated: OutdatedPackages = .none
|
||||
var lastNotifiedOutdated: Set<String> = []
|
||||
/// packages whose last upgrade attempt failed; reset when an upgrade
|
||||
/// run starts, displayed once by updateStatus after the run's refetch
|
||||
var failedUpgrades: [String] = []
|
||||
|
||||
let pathMonitor = NWPathMonitor()
|
||||
/// false until the monitor's first update, so the launch refresh waits
|
||||
|
|
@ -354,12 +357,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
|
||||
statusMenuItem.title = "Upgrading..."
|
||||
setMenuBarIcon("brewbar-updating")
|
||||
failedUpgrades = []
|
||||
|
||||
runBrew("update") { _, _ in
|
||||
// packages that turn outdated only after this brew update are not
|
||||
// in cachedOutdated yet; the final refetch will surface them
|
||||
let formulaNames = formulae ? self.cachedOutdated.formulae.map(\.name) : []
|
||||
let caskNames = casks ? self.cachedOutdated.casks.map(\.name) : []
|
||||
let upgradeCasksThenRefresh = {
|
||||
|
||||
self.upgradeFormulaeSequentially(formulaNames) {
|
||||
self.upgradeCasksSequentially(caskNames) {
|
||||
self.cleanupAfterUpgradeIfEnabled {
|
||||
// a manual upgrade just ran; don't chain an auto-upgrade
|
||||
|
|
@ -367,14 +373,24 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if formulae, !self.cachedOutdated.formulae.isEmpty {
|
||||
self.runBrew("upgrade --formula") { _, _ in
|
||||
upgradeCasksThenRefresh()
|
||||
/// Formulae also upgrade one at a time: a single broken formula (no
|
||||
/// bottle for this macOS, deprecated, …) makes brew's batch upgrade
|
||||
/// error out, taking every other pending formula down with it.
|
||||
func upgradeFormulaeSequentially(_ names: [String], completion: @escaping () -> Void) {
|
||||
guard let next = names.first else {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
upgradeCasksThenRefresh()
|
||||
|
||||
statusMenuItem.title = "Upgrading \(next)..."
|
||||
runBrew("upgrade --formula \(next)", askpassMessage: "upgrade \(next)") { _, success in
|
||||
if !success {
|
||||
self.failedUpgrades.append(next)
|
||||
}
|
||||
self.upgradeFormulaeSequentially(Array(names.dropFirst()), completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -398,12 +414,18 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
/// (An explicitly named cask upgrades even when self-updating, no
|
||||
/// --greedy needed.)
|
||||
func upgradeCask(_ name: String, completion: @escaping () -> Void) {
|
||||
runBrew("upgrade --cask \(name)", askpassMessage: "upgrade \(name)") { output, _ in
|
||||
runBrew("upgrade --cask \(name)", askpassMessage: "upgrade \(name)") { output, success in
|
||||
guard output.contains("cannot be upgraded as-is") else {
|
||||
if !success {
|
||||
self.failedUpgrades.append(name)
|
||||
}
|
||||
completion()
|
||||
return
|
||||
}
|
||||
self.runBrew("reinstall --cask --force \(name)", askpassMessage: "reinstall \(name)") { _, _ in
|
||||
self.runBrew("reinstall --cask --force \(name)", askpassMessage: "reinstall \(name)") { _, reinstalled in
|
||||
if !reinstalled {
|
||||
self.failedUpgrades.append(name)
|
||||
}
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
|
@ -507,23 +529,18 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
func runAutoUpgrade(formulae: Bool, casks: Bool) {
|
||||
statusMenuItem.title = "Auto-upgrading..."
|
||||
setMenuBarIcon("brewbar-updating")
|
||||
failedUpgrades = []
|
||||
|
||||
let formulaNames = formulae ? cachedOutdated.formulae.map(\.name) : []
|
||||
let caskNames = casks ? cachedOutdated.casks.map(\.name) : []
|
||||
let upgradeCasksThenRefresh = {
|
||||
|
||||
upgradeFormulaeSequentially(formulaNames) {
|
||||
self.upgradeCasksSequentially(caskNames) {
|
||||
self.cleanupAfterUpgradeIfEnabled {
|
||||
self.fetchOutdated(allowAutoUpgrade: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if formulae {
|
||||
runBrew("upgrade --formula") { _, _ in
|
||||
upgradeCasksThenRefresh()
|
||||
}
|
||||
} else {
|
||||
upgradeCasksThenRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
func updateOutdatedMenu(with outdated: OutdatedPackages) {
|
||||
|
|
@ -552,7 +569,13 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
}
|
||||
|
||||
func updateStatus(count: Int) {
|
||||
if count == 0 {
|
||||
// surface what the last upgrade run could not handle — brew only
|
||||
// reports these in its output, which lands in the logs. Consumed
|
||||
// here so the next plain refresh shows the normal state again.
|
||||
if !failedUpgrades.isEmpty {
|
||||
statusMenuItem.title = "⚠️ Upgrade failed: \(failedUpgrades.joined(separator: ", ")) — see Logs"
|
||||
failedUpgrades = []
|
||||
} else if count == 0 {
|
||||
statusMenuItem.title = "✅ All up to date"
|
||||
} else {
|
||||
statusMenuItem.title = "⚠️ \(count) outdated"
|
||||
|
|
@ -564,6 +587,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
|
||||
statusMenuItem.title = "Upgrading \(name)..."
|
||||
setMenuBarIcon("brewbar-updating")
|
||||
failedUpgrades = []
|
||||
|
||||
let finish = {
|
||||
self.cleanupAfterUpgradeIfEnabled {
|
||||
|
|
@ -576,7 +600,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
if cachedOutdated.casks.contains(where: { $0.name == name }) {
|
||||
upgradeCask(name, completion: finish)
|
||||
} else {
|
||||
runBrew("upgrade \(name)", askpassMessage: "upgrade \(name)") { _, _ in finish() }
|
||||
runBrew("upgrade \(name)", askpassMessage: "upgrade \(name)") { _, success in
|
||||
if !success {
|
||||
self.failedUpgrades.append(name)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue