Refactor AppLibrary.installedApp(…) as AppLibrary.installedApps(…)

because multiple installed apps can have the same app ID or app name.

Partial #313

Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
This commit is contained in:
Ross Goldberg 2024-10-23 12:51:59 -04:00
parent 4e0a471d81
commit 222646159d
No known key found for this signature in database
6 changed files with 30 additions and 26 deletions

View file

@ -29,8 +29,8 @@ extension Mas {
func run(appLibrary: AppLibrary) throws { func run(appLibrary: AppLibrary) throws {
// Try to download applications with given identifiers and collect results // Try to download applications with given identifiers and collect results
let appIDs = appIDs.filter { appID in let appIDs = appIDs.filter { appID in
if let product = appLibrary.installedApp(withAppID: appID), !force { if let appName = appLibrary.installedApps(withAppID: appID).first?.appName, !force {
printWarning("\(product.appName) is already installed") printWarning("\(appName) is already installed")
return false return false
} }

View file

@ -58,8 +58,8 @@ extension Mas {
/// - Throws: Any error that occurs while attempting to install the app. /// - Throws: Any error that occurs while attempting to install the app.
private func install(appID: AppID, appLibrary: AppLibrary) throws { private func install(appID: AppID, appLibrary: AppLibrary) throws {
// Try to download applications with given identifiers and collect results // Try to download applications with given identifiers and collect results
if let product = appLibrary.installedApp(withAppID: appID), !force { if let appName = appLibrary.installedApps(withAppID: appID).first?.appName, !force {
printWarning("\(product.appName) is already installed") printWarning("\(appName) is already installed")
} else { } else {
do { do {
try downloadAll([appID]).wait() try downloadAll([appID]).wait()

View file

@ -26,8 +26,8 @@ extension Mas {
func run(appLibrary: AppLibrary) throws { func run(appLibrary: AppLibrary) throws {
// Try to download applications with given identifiers and collect results // Try to download applications with given identifiers and collect results
let appIDs = appIDs.filter { appID in let appIDs = appIDs.filter { appID in
if let product = appLibrary.installedApp(withAppID: appID) { if let appName = appLibrary.installedApps(withAppID: appID).first?.appName {
printWarning("\(product.appName) has already been purchased.") printWarning("\(appName) has already been purchased.")
return false return false
} }

View file

@ -7,8 +7,7 @@
// //
import ArgumentParser import ArgumentParser
import CommerceKit import Foundation
import StoreFoundation
extension Mas { extension Mas {
/// Command which uninstalls apps managed by the Mac App Store. /// Command which uninstalls apps managed by the Mac App Store.
@ -29,16 +28,21 @@ extension Mas {
} }
func run(appLibrary: AppLibrary) throws { func run(appLibrary: AppLibrary) throws {
guard let product = appLibrary.installedApp(withAppID: appID) else { let installedApps = appLibrary.installedApps(withAppID: appID)
guard !installedApps.isEmpty else {
throw MASError.notInstalled throw MASError.notInstalled
} }
if dryRun { if dryRun {
printInfo("\(product.appName) \(product.bundlePath)") for installedApp in installedApps {
printInfo("\(installedApp.appName) \(installedApp.bundlePath)")
}
printInfo("(not removed, dry run)") printInfo("(not removed, dry run)")
} else { } else {
do { do {
try appLibrary.uninstallApp(app: product) for installedApp in installedApps {
try appLibrary.uninstallApp(app: installedApp)
}
} catch { } catch {
throw MASError.uninstallFailed throw MASError.uninstallFailed
} }

View file

@ -58,14 +58,14 @@ extension Mas {
let apps = let apps =
appIDs.isEmpty appIDs.isEmpty
? appLibrary.installedApps ? appLibrary.installedApps
: appIDs.compactMap { appID in : appIDs.flatMap { appID in
if let appID = AppID(appID) { if let appID = AppID(appID) {
// argument is an AppID, lookup app by id using argument // argument is an AppID, lookup apps by id using argument
return appLibrary.installedApp(withAppID: appID) return appLibrary.installedApps(withAppID: appID)
} }
// argument is not an AppID, lookup app by name using argument // argument is not an AppID, lookup apps by name using argument
return appLibrary.installedApp(named: appID) return appLibrary.installedApps(named: appID)
} }
let promises = apps.map { installedApp in let promises = apps.map { installedApp in

View file

@ -22,20 +22,20 @@ protocol AppLibrary {
/// Common logic /// Common logic
extension AppLibrary { extension AppLibrary {
/// Finds an app for appID. /// Finds all installed instances of apps whose app ID is `appID`.
/// ///
/// - Parameter appID: app ID for app. /// - Parameter appID: app ID for app(s).
/// - Returns: SoftwareProduct of app if found; nil otherwise. /// - Returns: [SoftwareProduct] of matching apps.
func installedApp(withAppID appID: AppID) -> SoftwareProduct? { func installedApps(withAppID appID: AppID) -> [SoftwareProduct] {
let appID = NSNumber(value: appID) let appID = NSNumber(value: appID)
return installedApps.first { $0.itemIdentifier == appID } return installedApps.filter { $0.itemIdentifier == appID }
} }
/// Finds an app by name. /// Finds all installed instances of apps whose name is `appName`.
/// ///
/// - Parameter appName: Full title of an app. /// - Parameter appName: Full name of app(s).
/// - Returns: Software Product of app if found; nil otherwise. /// - Returns: [SoftwareProduct] of matching apps.
func installedApp(named appName: String) -> SoftwareProduct? { func installedApps(named appName: String) -> [SoftwareProduct] {
installedApps.first { $0.appName == appName } installedApps.filter { $0.appName == appName }
} }
} }