mas/MasKit/Commands/Upgrade.swift

110 lines
3.8 KiB
Swift
Raw Normal View History

//
// Upgrade.swift
// mas-cli
//
// Created by Andrew Naylor on 30/12/2015.
// Copyright © 2015 Andrew Naylor. All rights reserved.
//
2018-07-04 20:56:10 +00:00
import Commandant
/// Command which upgrades apps with new versions available in the Mac App Store.
public struct UpgradeCommand: CommandProtocol {
public typealias Options = UpgradeOptions
public let verb = "upgrade"
public let function = "Upgrade outdated apps from the Mac App Store"
private let appLibrary: AppLibrary
private let storeSearch: StoreSearch
2020-03-29 03:15:07 +00:00
/// Public initializer.
public init() {
self.init(appLibrary: MasAppLibrary())
}
/// Internal initializer.
/// - Parameter appLibrary: AppLibrary manager.
/// - Parameter storeSearch: StoreSearch manager.
init(appLibrary: AppLibrary = MasAppLibrary(), storeSearch: StoreSearch = MasStoreSearch()) {
self.appLibrary = appLibrary
self.storeSearch = storeSearch
}
2019-01-12 01:28:03 +00:00
/// Runs the command.
public func run(_ options: Options) -> Result<(), MASError> {
do {
let apps =
2021-03-22 05:25:18 +00:00
try
(options.apps.count == 0
? appLibrary.installedApps
: options.apps.compactMap {
if let appId = UInt64($0) {
// if argument a UInt64, lookup app by id using argument
return appLibrary.installedApp(forId: appId)
} else {
// if argument not a UInt64, lookup app by name using argument
return appLibrary.installedApp(named: $0)
}
})
.compactMap { (installedApp: SoftwareProduct) -> SoftwareProduct? in
// only upgrade apps whose local version differs from the store version
if let storeApp = try storeSearch.lookup(app: installedApp.itemIdentifier.intValue) {
return storeApp.version != installedApp.bundleVersion
? installedApp
: nil
} else {
return nil
}
}
guard apps.count > 0 else {
2016-09-25 21:13:23 +00:00
printWarning("Nothing found to upgrade")
2016-09-17 12:58:38 +00:00
return .success(())
}
2019-01-12 01:06:02 +00:00
print("Upgrading \(apps.count) outdated application\(apps.count > 1 ? "s" : ""):")
2021-03-22 05:25:18 +00:00
print(apps.map { "\($0.appName) (\($0.bundleVersion))" }.joined(separator: ", "))
2019-01-12 01:06:02 +00:00
var updatedAppCount = 0
var failedUpgradeResults = [MASError]()
for app in apps {
if let upgradeResult = download(app.itemIdentifier.uint64Value) {
failedUpgradeResults.append(upgradeResult)
} else {
updatedAppCount += 1
}
}
2016-09-14 21:55:04 +00:00
switch failedUpgradeResults.count {
case 0:
if updatedAppCount == 0 {
print("Everything is up-to-date")
}
return .success(())
case 1:
return .failure(failedUpgradeResults[0])
default:
return .failure(.downloadFailed(error: nil))
}
} catch {
// Bubble up MASErrors
// swiftlint:disable force_cast
return .failure(error is MASError ? error as! MASError : .searchFailed)
// swiftlint:enable force_cast
}
}
2015-12-30 21:20:25 +00:00
}
2016-09-14 21:55:04 +00:00
public struct UpgradeOptions: OptionsProtocol {
let apps: [String]
2019-01-12 01:06:02 +00:00
static func create(_ apps: [String]) -> UpgradeOptions {
return UpgradeOptions(apps: apps)
2016-09-14 21:55:04 +00:00
}
2019-01-12 01:06:02 +00:00
public static func evaluate(_ mode: CommandMode) -> Result<UpgradeOptions, CommandantError<MASError>> {
2016-09-14 21:55:04 +00:00
return create
2019-01-12 01:06:02 +00:00
<*> mode <| Argument(defaultValue: [], usage: "app(s) to upgrade")
2016-09-14 21:55:04 +00:00
}
2016-09-17 12:58:38 +00:00
}