Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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