From 2931b800749f007b8d9bc0fcce5839b2e1310618 Mon Sep 17 00:00:00 2001 From: maxsoch Date: Mon, 13 Jul 2026 18:58:32 +0200 Subject: [PATCH] fall back to reinstall when a cask cannot be upgraded as-is MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Self-updating apps (Zen, Chrome, …) drift from what brew installed; brew then refuses to upgrade the cask in place, prints a warning and does nothing, so the package stayed outdated forever. Detect the warning and run the fix brew itself suggests (reinstall --cask --force). Single-package upgrades now also route casks through upgrade --cask instead of a bare brew upgrade. Co-Authored-By: Claude Fable 5 --- BrewBar/BrewBarApp.swift | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/BrewBar/BrewBarApp.swift b/BrewBar/BrewBarApp.swift index 27f9255..45e2a19 100644 --- a/BrewBar/BrewBarApp.swift +++ b/BrewBar/BrewBarApp.swift @@ -368,12 +368,28 @@ class AppDelegate: NSObject, NSApplicationDelegate { } statusMenuItem.title = "Upgrading \(next)..." - // an explicitly named cask upgrades even when self-updating, no --greedy needed - runBrew("upgrade --cask \(next)", askpassMessage: "upgrade \(next)") { _, _ in + upgradeCask(next) { self.upgradeCasksSequentially(Array(names.dropFirst()), completion: completion) } } + /// Self-updating apps (Zen, Chrome, …) can drift from what brew + /// installed, and brew then refuses to upgrade the cask in place — + /// it only prints a warning naming the fix. Run that fix for it. + /// (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 + guard output.contains("cannot be upgraded as-is") else { + completion() + return + } + self.runBrew("reinstall --cask --force \(name)", askpassMessage: "reinstall \(name)") { _, _ in + completion() + } + } + } + func confirmUpgrade(formulae: Bool, casks: Bool) -> Bool { let packages = (formulae ? cachedOutdated.formulae : []) + (casks ? cachedOutdated.casks : []) @@ -524,13 +540,21 @@ class AppDelegate: NSObject, NSApplicationDelegate { } @objc func upgradeSingle(_ sender: NSMenuItem) { - guard let formula = sender.representedObject as? String else { return } + guard let name = sender.representedObject as? String else { return } - runBrew("upgrade \(formula)", askpassMessage: "upgrade \(formula)") { _, _ in + let finish = { self.cleanupAfterUpgradeIfEnabled { self.refreshAll() } } + + // casks go through upgradeCask for the reinstall fallback; a bare + // "brew upgrade " would hit the same warning and do nothing + if cachedOutdated.casks.contains(where: { $0.name == name }) { + upgradeCask(name, completion: finish) + } else { + runBrew("upgrade \(name)", askpassMessage: "upgrade \(name)") { _, _ in finish() } + } } /// Refreshing offline would silently succeed on stale data: brew update