BrewBar/BrewBar/BrewParser.swift
maxsoch 813fc47461 fetch outdated as JSON; auto-upgrade only for matching package kinds
fetchOutdated now uses --json and the typed parser, so cachedOutdated
knows formulae from casks. The auto-upgrade trigger checks each kind
against its own toggle: an outdated cask no longer starts a pointless
"upgrade --formula" run (previously any outdated package triggered
whichever auto-upgrades were enabled). runAutoUpgrade takes explicit
formulae/casks flags instead of re-reading settings.

Bonus from the version info now available: outdated menu items and the
Upgrade All confirmation show "name installed → current" instead of
bare names. The legacy line parser and its tests are removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 22:27:37 +02:00

54 lines
1.5 KiB
Swift

import Foundation
struct OutdatedPackage: Codable, Equatable {
let name: String
let installedVersions: [String]
let currentVersion: String
/// Menu label, e.g. "wget 1.21 1.22"
var label: String {
let installed = installedVersions.joined(separator: ", ")
return "\(name) \(installed)\(currentVersion)"
}
}
struct OutdatedPackages: Codable, Equatable {
let formulae: [OutdatedPackage]
let casks: [OutdatedPackage]
var all: [OutdatedPackage] {
formulae + casks
}
var isEmpty: Bool {
formulae.isEmpty && casks.isEmpty
}
var count: Int {
formulae.count + casks.count
}
static let none = OutdatedPackages(formulae: [], casks: [])
}
enum BrewParser {
/// Parses `brew outdated --json` output. Returns .none for anything
/// undecodable (brew error text, empty output) same effect as an
/// empty result, and the raw output is already in the log window.
static func parseOutdatedJSON(_ output: String) -> OutdatedPackages {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase // installed_versions installedVersions
guard let data = output.data(using: .utf8),
let parsed = try? decoder.decode(OutdatedPackages.self, from: data)
else {
return .none
}
return parsed
}
static func parseVersion(_ output: String) -> String {
output.split(separator: "\n").first.map(String.init) ?? "Unknown"
}
}