Skip to content

Commit

Permalink
Merge pull request #312 from rgoldberg/outdated
Browse files Browse the repository at this point in the history
Fix outdated & upgrade commands
  • Loading branch information
phatblat authored Mar 14, 2021
2 parents a38235a + 754d4be commit 5539145
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 59 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]

- 🍼 Formula updates from 1.8 release #319
- 🎨 Fix `mas outdated` & `mas upgrade` commands #312
thanks, [@rgoldberg](https://github.com/rgoldberg)!
- 🎨 Fix errors being output with "Warning" when not on TTY #312
thanks, [@rgoldberg](https://github.com/rgoldberg)!

## [v1.8.0] 💪🏼 arm64 support for M1 Macs - 2021-02-12

Expand Down
35 changes: 22 additions & 13 deletions MasKit/Commands/Outdated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//

import Commandant
import CommerceKit

/// Command which displays a list of installed apps which have available updates
/// ready to be installed from the Mac App Store.
Expand All @@ -17,31 +16,41 @@ public struct OutdatedCommand: CommandProtocol {
public let function = "Lists pending updates from the Mac App Store"

private let appLibrary: AppLibrary
private let storeSearch: StoreSearch

/// Public initializer.
/// - Parameter appLibrary: AppLibrary manager.
public init() {
self.init(appLibrary: MasAppLibrary())
}

/// Internal initializer.
/// - Parameter appLibrary: AppLibrary manager.
init(appLibrary: AppLibrary = MasAppLibrary()) {
/// - Parameter storeSearch: StoreSearch manager.
init(appLibrary: AppLibrary = MasAppLibrary(), storeSearch: StoreSearch = MasStoreSearch()) {
self.appLibrary = appLibrary
self.storeSearch = storeSearch
}

/// Runs the command.
public func run(_: Options) -> Result<(), MASError> {
let updateController = CKUpdateController.shared()
let updates = updateController?.availableUpdates()
for update in updates! {
if let installed = appLibrary.installedApp(forBundleId: update.bundleID) {
// Display version of installed app compared to available update.
print("""
\(update.itemIdentifier) \(update.title) (\(installed.bundleVersion) -> \(update.bundleVersion))
""")
} else {
print("\(update.itemIdentifier) \(update.title) (unknown -> \(update.bundleVersion))")
for installedApp in appLibrary.installedApps {
do {
if let storeApp = try storeSearch.lookup(app: installedApp.itemIdentifier.intValue) {
if installedApp.bundleVersion != storeApp.version {
print("""
\(installedApp.itemIdentifier) \(installedApp.appName) (\(installedApp.bundleVersion) -> \(storeApp.version))
""")
}
} else {
printWarning("""
Identifier \(installedApp.itemIdentifier) not found in store. Was expected to identify \(installedApp.appName).
""")
}
} catch {
// Bubble up MASErrors
// swiftlint:disable force_cast
return .failure(error is MASError ? error as! MASError : .searchFailed)
// swiftlint:enable force_cast
}
}
return .success(())
Expand Down
100 changes: 55 additions & 45 deletions MasKit/Commands/Upgrade.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//

import Commandant
import CommerceKit

/// Command which upgrades apps with new versions available in the Mac App Store.
public struct UpgradeCommand: CommandProtocol {
Expand All @@ -16,71 +15,82 @@ public struct UpgradeCommand: CommandProtocol {
public let function = "Upgrade outdated apps from the Mac App Store"

private let appLibrary: AppLibrary
private let storeSearch: StoreSearch

/// Public initializer.
/// - Parameter appLibrary: AppLibrary manager.
public init() {
self.init(appLibrary: MasAppLibrary())
}

/// Internal initializer.
/// - Parameter appLibrary: AppLibrary manager.
init(appLibrary: AppLibrary = MasAppLibrary()) {
/// - Parameter storeSearch: StoreSearch manager.
init(appLibrary: AppLibrary = MasAppLibrary(), storeSearch: StoreSearch = MasStoreSearch()) {
self.appLibrary = appLibrary
self.storeSearch = storeSearch
}

/// Runs the command.
public func run(_ options: Options) -> Result<(), MASError> {
let updateController = CKUpdateController.shared()
let updates: [CKUpdate]
let apps = options.apps
if apps.count > 0 {
// convert input into a list of appId's
let appIds: [UInt64]

appIds = apps.compactMap {
if let appId = UInt64($0) {
return appId
do {
let apps =
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
}
}
if let appId = appLibrary.appIdsByName[$0] {
return appId
}
return nil
}

// check each of those for updates
updates = appIds.compactMap {
updateController?.availableUpdate(withItemIdentifier: $0)
}

guard updates.count > 0 else {
guard apps.count > 0 else {
printWarning("Nothing found to upgrade")
return .success(())
}
} else {
updates = updateController?.availableUpdates() ?? []

// Upgrade everything
guard updates.count > 0 else {
print("Everything is up-to-date")
return .success(())
}
}

print("Upgrading \(updates.count) outdated application\(updates.count > 1 ? "s" : ""):")
print(updates.map({ "\($0.title) (\($0.bundleVersion))" }).joined(separator: ", "))
print("Upgrading \(apps.count) outdated application\(apps.count > 1 ? "s" : ""):")
print(apps.map {"\($0.appName) (\($0.bundleVersion))"}.joined(separator: ", "))

let updateResults = updates.compactMap {
download($0.itemIdentifier.uint64Value)
}
var updatedAppCount = 0
var failedUpgradeResults = [MASError]()
for app in apps {
if let upgradeResult = download(app.itemIdentifier.uint64Value) {
failedUpgradeResults.append(upgradeResult)
} else {
updatedAppCount += 1
}
}

switch updateResults.count {
case 0:
return .success(())
case 1:
return .failure(updateResults[0])
default:
return .failure(.downloadFailed(error: nil))
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
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion MasKit/Formatters/Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func printWarning(_ message: String) {

public func printError(_ message: String) {
guard isatty(fileno(stdout)) != 0 else {
print("Warning: \(message)")
print("Error: \(message)")
return
}

Expand Down

0 comments on commit 5539145

Please sign in to comment.