From 39f77c01a9c1889d6f26a5d24ade9ea53684a3f3 Mon Sep 17 00:00:00 2001 From: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> Date: Mon, 14 Oct 2024 01:22:47 -0400 Subject: [PATCH 1/2] Create `typealias AppID = UInt64`. Use `AppID` everywhere appropriate. Associated appID cleanup. Partial #478 Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> --- Sources/mas/AppStore/Downloader.swift | 4 ++-- Sources/mas/AppStore/SSPurchase.swift | 2 +- Sources/mas/Commands/Home.swift | 2 +- Sources/mas/Commands/Info.swift | 2 +- Sources/mas/Commands/Install.swift | 2 +- Sources/mas/Commands/Lucky.swift | 6 +++--- Sources/mas/Commands/Open.swift | 11 ++--------- Sources/mas/Commands/Outdated.swift | 2 +- Sources/mas/Commands/Purchase.swift | 2 +- Sources/mas/Commands/Uninstall.swift | 4 +--- Sources/mas/Commands/Upgrade.swift | 8 ++++---- Sources/mas/Commands/Vendor.swift | 2 +- Sources/mas/Controllers/AppLibrary.swift | 4 ++-- Sources/mas/Controllers/MasStoreSearch.swift | 4 ++-- Sources/mas/Controllers/StoreSearch.swift | 4 ++-- Sources/mas/Formatters/SearchResultFormatter.swift | 4 ++-- Sources/mas/Mas.swift | 2 ++ Sources/mas/Models/SearchResult.swift | 4 ++-- Tests/masTests/Commands/HomeSpec.swift | 2 +- Tests/masTests/Commands/InfoSpec.swift | 2 +- Tests/masTests/Commands/OpenSpec.swift | 4 ++-- Tests/masTests/Commands/UninstallSpec.swift | 2 +- Tests/masTests/Commands/VendorSpec.swift | 2 +- Tests/masTests/Controllers/MasStoreSearchSpec.swift | 2 +- Tests/masTests/Controllers/StoreSearchMock.swift | 9 ++------- 25 files changed, 40 insertions(+), 52 deletions(-) diff --git a/Sources/mas/AppStore/Downloader.swift b/Sources/mas/AppStore/Downloader.swift index b8323358..3dd44a51 100644 --- a/Sources/mas/AppStore/Downloader.swift +++ b/Sources/mas/AppStore/Downloader.swift @@ -17,7 +17,7 @@ import StoreFoundation /// Only works for free apps. Defaults to false. /// - Returns: A promise that completes when the downloads are complete. If any fail, /// the promise is rejected with the first error, after all remaining downloads are attempted. -func downloadAll(_ appIDs: [UInt64], purchase: Bool = false) -> Promise { +func downloadAll(_ appIDs: [AppID], purchase: Bool = false) -> Promise { var firstError: Error? return appIDs.reduce(Guarantee.value(())) { previous, appID in previous.then { @@ -34,7 +34,7 @@ func downloadAll(_ appIDs: [UInt64], purchase: Bool = false) -> Promise { } } -private func downloadWithRetries(_ appID: UInt64, purchase: Bool = false, attempts: Int = 3) -> Promise { +private func downloadWithRetries(_ appID: AppID, purchase: Bool = false, attempts: Int = 3) -> Promise { SSPurchase().perform(adamId: appID, purchase: purchase) .recover { error -> Promise in guard attempts > 1 else { diff --git a/Sources/mas/AppStore/SSPurchase.swift b/Sources/mas/AppStore/SSPurchase.swift index 3fd57038..62f2651f 100644 --- a/Sources/mas/AppStore/SSPurchase.swift +++ b/Sources/mas/AppStore/SSPurchase.swift @@ -11,7 +11,7 @@ import PromiseKit import StoreFoundation extension SSPurchase { - func perform(adamId: UInt64, purchase: Bool) -> Promise { + func perform(adamId: AppID, purchase: Bool) -> Promise { var parameters: [String: Any] = [ "productType": "C", "price": 0, diff --git a/Sources/mas/Commands/Home.swift b/Sources/mas/Commands/Home.swift index 37162af3..f538f2e2 100644 --- a/Sources/mas/Commands/Home.swift +++ b/Sources/mas/Commands/Home.swift @@ -17,7 +17,7 @@ extension Mas { ) @Argument(help: "ID of app to show on MAS Preview") - var appId: Int + var appId: AppID /// Runs the command. func run() throws { diff --git a/Sources/mas/Commands/Info.swift b/Sources/mas/Commands/Info.swift index cf0b6861..a330f423 100644 --- a/Sources/mas/Commands/Info.swift +++ b/Sources/mas/Commands/Info.swift @@ -18,7 +18,7 @@ extension Mas { ) @Argument(help: "ID of app to show info") - var appId: Int + var appId: AppID /// Runs the command. func run() throws { diff --git a/Sources/mas/Commands/Install.swift b/Sources/mas/Commands/Install.swift index a7d55f70..ff0b0e87 100644 --- a/Sources/mas/Commands/Install.swift +++ b/Sources/mas/Commands/Install.swift @@ -19,7 +19,7 @@ extension Mas { @Flag(help: "force reinstall") var force = false @Argument(help: "app ID(s) to install") - var appIds: [UInt64] + var appIds: [AppID] /// Runs the command. func run() throws { diff --git a/Sources/mas/Commands/Lucky.swift b/Sources/mas/Commands/Lucky.swift index de16507e..bad05111 100644 --- a/Sources/mas/Commands/Lucky.swift +++ b/Sources/mas/Commands/Lucky.swift @@ -28,7 +28,7 @@ extension Mas { } func run(appLibrary: AppLibrary, storeSearch: StoreSearch) throws { - var appId: Int? + var appId: AppID? do { let results = try storeSearch.search(for: appName).wait() @@ -44,7 +44,7 @@ extension Mas { guard let identifier = appId else { fatalError() } - try install(UInt64(identifier), appLibrary: appLibrary) + try install(identifier, appLibrary: appLibrary) } /// Installs an app. @@ -52,7 +52,7 @@ extension Mas { /// - Parameters: /// - appId: App identifier /// - appLibrary: Library of installed apps - fileprivate func install(_ appId: UInt64, appLibrary: AppLibrary) throws { + fileprivate func install(_ appId: AppID, appLibrary: AppLibrary) throws { // Try to download applications with given identifiers and collect results if let product = appLibrary.installedApp(forId: appId), !force { printWarning("\(product.appName) is already installed") diff --git a/Sources/mas/Commands/Open.swift b/Sources/mas/Commands/Open.swift index a7dd37e5..bc0afc9d 100644 --- a/Sources/mas/Commands/Open.swift +++ b/Sources/mas/Commands/Open.swift @@ -9,7 +9,6 @@ import ArgumentParser import Foundation -private let markerValue = "appstore" private let masScheme = "macappstore" extension Mas { @@ -21,7 +20,7 @@ extension Mas { ) @Argument(help: "the app ID") - var appId: String = markerValue + var appId: AppID? /// Runs the command. func run() throws { @@ -30,18 +29,12 @@ extension Mas { func run(storeSearch: StoreSearch, openCommand: ExternalCommand) throws { do { - if appId == markerValue { + guard let appId else { // If no app ID is given, just open the MAS GUI app try openCommand.run(arguments: masScheme + "://") return } - guard let appId = Int(appId) - else { - printError("Invalid app ID") - throw MASError.noSearchResultsFound - } - guard let result = try storeSearch.lookup(app: appId).wait() else { throw MASError.noSearchResultsFound diff --git a/Sources/mas/Commands/Outdated.swift b/Sources/mas/Commands/Outdated.swift index ab78ab41..aeb99f0f 100644 --- a/Sources/mas/Commands/Outdated.swift +++ b/Sources/mas/Commands/Outdated.swift @@ -33,7 +33,7 @@ extension Mas { fulfilled: appLibrary.installedApps.map { installedApp in firstly { - storeSearch.lookup(app: installedApp.itemIdentifier.intValue) + storeSearch.lookup(app: installedApp.itemIdentifier.uint64Value) }.done { storeApp in guard let storeApp else { if verbose { diff --git a/Sources/mas/Commands/Purchase.swift b/Sources/mas/Commands/Purchase.swift index 7ac1c755..601f6b2d 100644 --- a/Sources/mas/Commands/Purchase.swift +++ b/Sources/mas/Commands/Purchase.swift @@ -16,7 +16,7 @@ extension Mas { ) @Argument(help: "app ID(s) to install") - var appIds: [UInt64] + var appIds: [AppID] /// Runs the command. func run() throws { diff --git a/Sources/mas/Commands/Uninstall.swift b/Sources/mas/Commands/Uninstall.swift index 2d37cef1..96d572a1 100644 --- a/Sources/mas/Commands/Uninstall.swift +++ b/Sources/mas/Commands/Uninstall.swift @@ -21,7 +21,7 @@ extension Mas { @Flag(help: "dry run") var dryRun = false @Argument(help: "ID of app to uninstall") - var appId: Int + var appId: AppID /// Runs the uninstall command. func run() throws { @@ -29,8 +29,6 @@ extension Mas { } func run(appLibrary: AppLibrary) throws { - let appId = UInt64(appId) - guard let product = appLibrary.installedApp(forId: appId) else { throw MASError.notInstalled } diff --git a/Sources/mas/Commands/Upgrade.swift b/Sources/mas/Commands/Upgrade.swift index 603902e4..fc602b21 100644 --- a/Sources/mas/Commands/Upgrade.swift +++ b/Sources/mas/Commands/Upgrade.swift @@ -58,11 +58,11 @@ extension Mas { appIds.isEmpty ? appLibrary.installedApps : appIds.compactMap { - if let appId = UInt64($0) { - // if argument a UInt64, lookup app by id using argument + if let appId = AppID($0) { + // if argument an AppID, lookup app by id using argument return appLibrary.installedApp(forId: appId) } else { - // if argument not a UInt64, lookup app by name using argument + // if argument not an AppID, lookup app by name using argument return appLibrary.installedApp(named: $0) } } @@ -70,7 +70,7 @@ extension Mas { let promises = apps.map { installedApp in // only upgrade apps whose local version differs from the store version firstly { - storeSearch.lookup(app: installedApp.itemIdentifier.intValue) + storeSearch.lookup(app: installedApp.itemIdentifier.uint64Value) }.map { result -> (SoftwareProduct, SearchResult)? in guard let storeApp = result, installedApp.isOutdatedWhenComparedTo(storeApp) else { return nil diff --git a/Sources/mas/Commands/Vendor.swift b/Sources/mas/Commands/Vendor.swift index 10e4eeef..32fa0fba 100644 --- a/Sources/mas/Commands/Vendor.swift +++ b/Sources/mas/Commands/Vendor.swift @@ -17,7 +17,7 @@ extension Mas { ) @Argument(help: "the app ID to show the vendor's website") - var appId: Int + var appId: AppID /// Runs the command. func run() throws { diff --git a/Sources/mas/Controllers/AppLibrary.swift b/Sources/mas/Controllers/AppLibrary.swift index d481a522..477876f0 100644 --- a/Sources/mas/Controllers/AppLibrary.swift +++ b/Sources/mas/Controllers/AppLibrary.swift @@ -17,7 +17,7 @@ protocol AppLibrary { /// /// - Parameter forId: MAS ID for app. /// - Returns: Software Product of app if found; nil otherwise. - func installedApp(forId: UInt64) -> SoftwareProduct? + func installedApp(forId: AppID) -> SoftwareProduct? /// Uninstalls an app. /// @@ -32,7 +32,7 @@ extension AppLibrary { /// /// - Parameter forId: MAS ID for app. /// - Returns: Software Product of app if found; nil otherwise. - func installedApp(forId identifier: UInt64) -> SoftwareProduct? { + func installedApp(forId identifier: AppID) -> SoftwareProduct? { let appId = NSNumber(value: identifier) return installedApps.first { $0.itemIdentifier == appId } } diff --git a/Sources/mas/Controllers/MasStoreSearch.swift b/Sources/mas/Controllers/MasStoreSearch.swift index dda28f82..b5738ed9 100644 --- a/Sources/mas/Controllers/MasStoreSearch.swift +++ b/Sources/mas/Controllers/MasStoreSearch.swift @@ -53,7 +53,7 @@ class MasStoreSearch: StoreSearch { } // Combine the results, removing any duplicates. - var seenAppIDs = Set() + var seenAppIDs = Set() return when(fulfilled: results).flatMapValues { $0 }.filterValues { result in seenAppIDs.insert(result.trackId).inserted } @@ -64,7 +64,7 @@ class MasStoreSearch: StoreSearch { /// - Parameter appId: MAS ID of app /// - Returns: A Promise for the search result record of app, or nil if no apps match the ID, /// or an Error if there is a problem with the network request. - func lookup(app appId: Int) -> Promise { + func lookup(app appId: AppID) -> Promise { guard let url = lookupURL(forApp: appId, inCountry: country) else { fatalError("Failed to build URL for \(appId)") } diff --git a/Sources/mas/Controllers/StoreSearch.swift b/Sources/mas/Controllers/StoreSearch.swift index c326699e..2b4e11ed 100644 --- a/Sources/mas/Controllers/StoreSearch.swift +++ b/Sources/mas/Controllers/StoreSearch.swift @@ -11,7 +11,7 @@ import PromiseKit /// Protocol for searching the MAS catalog. protocol StoreSearch { - func lookup(app appId: Int) -> Promise + func lookup(app appId: AppID) -> Promise func search(for appName: String) -> Promise<[SearchResult]> } @@ -49,7 +49,7 @@ extension StoreSearch { /// /// - Parameter appId: MAS app identifier. /// - Returns: URL for the lookup service or nil if appId can't be encoded. - func lookupURL(forApp appId: Int, inCountry country: String?) -> URL? { + func lookupURL(forApp appId: AppID, inCountry country: String?) -> URL? { guard var components = URLComponents(string: "https://itunes.apple.com/lookup") else { return nil } diff --git a/Sources/mas/Formatters/SearchResultFormatter.swift b/Sources/mas/Formatters/SearchResultFormatter.swift index 15fa4aa9..ed01448c 100644 --- a/Sources/mas/Formatters/SearchResultFormatter.swift +++ b/Sources/mas/Formatters/SearchResultFormatter.swift @@ -26,9 +26,9 @@ enum SearchResultFormatter { let price = result.price ?? 0.0 if includePrice { - output += String(format: "%12d %@ $%5.2f (%@)\n", appId, appName, price, version) + output += String(format: "%12lu %@ $%5.2f (%@)\n", appId, appName, price, version) } else { - output += String(format: "%12d %@ (%@)\n", appId, appName, version) + output += String(format: "%12lu %@ (%@)\n", appId, appName, version) } } diff --git a/Sources/mas/Mas.swift b/Sources/mas/Mas.swift index 1b95c021..a3a28ec8 100644 --- a/Sources/mas/Mas.swift +++ b/Sources/mas/Mas.swift @@ -9,6 +9,8 @@ import ArgumentParser import PromiseKit +typealias AppID = UInt64 + @main struct Mas: ParsableCommand { static let configuration = CommandConfiguration( diff --git a/Sources/mas/Models/SearchResult.swift b/Sources/mas/Models/SearchResult.swift index 7ac757b5..129df7cc 100644 --- a/Sources/mas/Models/SearchResult.swift +++ b/Sources/mas/Models/SearchResult.swift @@ -14,7 +14,7 @@ struct SearchResult: Decodable { var price: Double? var sellerName: String var sellerUrl: String? - var trackId: Int + var trackId: AppID var trackName: String var trackViewUrl: String var version: String @@ -27,7 +27,7 @@ struct SearchResult: Decodable { price: Double = 0.0, sellerName: String = "", sellerUrl: String = "", - trackId: Int = 0, + trackId: AppID = 0, trackName: String = "", trackViewUrl: String = "", version: String = "" diff --git a/Tests/masTests/Commands/HomeSpec.swift b/Tests/masTests/Commands/HomeSpec.swift index 158ae77a..6f740d32 100644 --- a/Tests/masTests/Commands/HomeSpec.swift +++ b/Tests/masTests/Commands/HomeSpec.swift @@ -32,7 +32,7 @@ public class HomeSpec: QuickSpec { expect { try Mas.Home.parse(["--", "-999"]).run(storeSearch: storeSearch, openCommand: openCommand) } - .to(throwError(MASError.searchFailed)) + .to(throwError()) } it("can't find app with unknown ID") { expect { diff --git a/Tests/masTests/Commands/InfoSpec.swift b/Tests/masTests/Commands/InfoSpec.swift index 99604ef8..8047c950 100644 --- a/Tests/masTests/Commands/InfoSpec.swift +++ b/Tests/masTests/Commands/InfoSpec.swift @@ -46,7 +46,7 @@ public class InfoSpec: QuickSpec { expect { try Mas.Info.parse(["--", "-999"]).run(storeSearch: storeSearch) } - .to(throwError(MASError.searchFailed)) + .to(throwError()) } it("can't find app with unknown ID") { expect { diff --git a/Tests/masTests/Commands/OpenSpec.swift b/Tests/masTests/Commands/OpenSpec.swift index 54d3bbea..c0cca204 100644 --- a/Tests/masTests/Commands/OpenSpec.swift +++ b/Tests/masTests/Commands/OpenSpec.swift @@ -33,7 +33,7 @@ public class OpenSpec: QuickSpec { expect { try Mas.Open.parse(["--", "-999"]).run(storeSearch: storeSearch, openCommand: openCommand) } - .to(throwError(MASError.searchFailed)) + .to(throwError()) } it("can't find app with unknown ID") { expect { @@ -55,7 +55,7 @@ public class OpenSpec: QuickSpec { } it("just opens MAS if no app specified") { expect { - try Mas.Open.parse(["appstore"]).run(storeSearch: storeSearch, openCommand: openCommand) + try Mas.Open.parse([]).run(storeSearch: storeSearch, openCommand: openCommand) } .toNot(throwError()) expect(openCommand.arguments).toNot(beNil()) diff --git a/Tests/masTests/Commands/UninstallSpec.swift b/Tests/masTests/Commands/UninstallSpec.swift index e779c9d9..691692db 100644 --- a/Tests/masTests/Commands/UninstallSpec.swift +++ b/Tests/masTests/Commands/UninstallSpec.swift @@ -18,7 +18,7 @@ public class UninstallSpec: QuickSpec { Mas.initialize() } describe("uninstall command") { - let appId = 12345 + let appId: AppID = 12345 let app = SoftwareProductMock( appName: "Some App", bundleIdentifier: "com.some.app", diff --git a/Tests/masTests/Commands/VendorSpec.swift b/Tests/masTests/Commands/VendorSpec.swift index de38f2ae..499534aa 100644 --- a/Tests/masTests/Commands/VendorSpec.swift +++ b/Tests/masTests/Commands/VendorSpec.swift @@ -32,7 +32,7 @@ public class VendorSpec: QuickSpec { expect { try Mas.Vendor.parse(["--", "-999"]).run(storeSearch: storeSearch, openCommand: openCommand) } - .to(throwError(MASError.searchFailed)) + .to(throwError()) } it("can't find app with unknown ID") { expect { diff --git a/Tests/masTests/Controllers/MasStoreSearchSpec.swift b/Tests/masTests/Controllers/MasStoreSearchSpec.swift index 99e1bdb0..335700a0 100644 --- a/Tests/masTests/Controllers/MasStoreSearchSpec.swift +++ b/Tests/masTests/Controllers/MasStoreSearchSpec.swift @@ -54,7 +54,7 @@ public class MasStoreSearchSpec: QuickSpec { context("when lookup used") { it("can find slack") { - let appId = 803_453_959 + let appId: AppID = 803_453_959 let networkSession = NetworkSessionMockFromFile(responseFile: "lookup/slack.json") let storeSearch = MasStoreSearch(networkManager: NetworkManager(session: networkSession)) diff --git a/Tests/masTests/Controllers/StoreSearchMock.swift b/Tests/masTests/Controllers/StoreSearchMock.swift index 5037b92d..a2769514 100644 --- a/Tests/masTests/Controllers/StoreSearchMock.swift +++ b/Tests/masTests/Controllers/StoreSearchMock.swift @@ -11,7 +11,7 @@ import PromiseKit @testable import mas class StoreSearchMock: StoreSearch { - var apps: [Int: SearchResult] = [:] + var apps: [AppID: SearchResult] = [:] func search(for appName: String) -> Promise<[SearchResult]> { let filtered = apps.filter { $1.trackName.contains(appName) } @@ -19,12 +19,7 @@ class StoreSearchMock: StoreSearch { return .value(results) } - func lookup(app appId: Int) -> Promise { - // Negative numbers are invalid - guard appId > 0 else { - return Promise(error: MASError.searchFailed) - } - + func lookup(app appId: AppID) -> Promise { guard let result = apps[appId] else { return Promise(error: MASError.noSearchResultsFound) From 006273bb8104515e6d3f18c76f62519a5d32fe2a Mon Sep 17 00:00:00 2001 From: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> Date: Mon, 14 Oct 2024 01:50:10 -0400 Subject: [PATCH 2/2] Standardize names of variables & parameters relating to AppIDs. Resolve #478 Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> --- Sources/mas/AppStore/Downloader.swift | 2 +- Sources/mas/AppStore/SSPurchase.swift | 8 ++++---- Sources/mas/Commands/Home.swift | 4 ++-- Sources/mas/Commands/Info.swift | 4 ++-- Sources/mas/Commands/Install.swift | 8 ++++---- Sources/mas/Commands/Lucky.swift | 18 ++++++++++-------- Sources/mas/Commands/Open.swift | 6 +++--- Sources/mas/Commands/Outdated.swift | 2 +- Sources/mas/Commands/Purchase.swift | 8 ++++---- Sources/mas/Commands/Uninstall.swift | 4 ++-- Sources/mas/Commands/Upgrade.swift | 12 ++++++------ Sources/mas/Commands/Vendor.swift | 4 ++-- Sources/mas/Controllers/AppLibrary.swift | 12 ++++++------ Sources/mas/Controllers/MasStoreSearch.swift | 8 ++++---- Sources/mas/Controllers/StoreSearch.swift | 10 +++++----- Sources/mas/Formatters/AppListFormatter.swift | 4 ++-- .../mas/Formatters/SearchResultFormatter.swift | 6 +++--- Tests/masTests/Commands/UninstallSpec.swift | 8 ++++---- .../Controllers/MasStoreSearchSpec.swift | 6 +++--- .../masTests/Controllers/StoreSearchMock.swift | 4 ++-- 20 files changed, 70 insertions(+), 68 deletions(-) diff --git a/Sources/mas/AppStore/Downloader.swift b/Sources/mas/AppStore/Downloader.swift index 3dd44a51..65a23731 100644 --- a/Sources/mas/AppStore/Downloader.swift +++ b/Sources/mas/AppStore/Downloader.swift @@ -35,7 +35,7 @@ func downloadAll(_ appIDs: [AppID], purchase: Bool = false) -> Promise { } private func downloadWithRetries(_ appID: AppID, purchase: Bool = false, attempts: Int = 3) -> Promise { - SSPurchase().perform(adamId: appID, purchase: purchase) + SSPurchase().perform(appID: appID, purchase: purchase) .recover { error -> Promise in guard attempts > 1 else { throw error diff --git a/Sources/mas/AppStore/SSPurchase.swift b/Sources/mas/AppStore/SSPurchase.swift index 62f2651f..cabfa51e 100644 --- a/Sources/mas/AppStore/SSPurchase.swift +++ b/Sources/mas/AppStore/SSPurchase.swift @@ -11,11 +11,11 @@ import PromiseKit import StoreFoundation extension SSPurchase { - func perform(adamId: AppID, purchase: Bool) -> Promise { + func perform(appID: AppID, purchase: Bool) -> Promise { var parameters: [String: Any] = [ "productType": "C", "price": 0, - "salableAdamId": adamId, + "salableAdamId": appID, "pg": "default", "appExtVrsId": 0, ] @@ -34,7 +34,7 @@ extension SSPurchase { } .joined(separator: "&") - itemIdentifier = adamId + itemIdentifier = appID // Not sure if this is needed… if purchase { @@ -43,7 +43,7 @@ extension SSPurchase { downloadMetadata = SSDownloadMetadata() downloadMetadata.kind = "software" - downloadMetadata.itemIdentifier = adamId + downloadMetadata.itemIdentifier = appID // Monterey obscures the user's App Store account, but allows // redownloads without passing any account IDs to SSPurchase. diff --git a/Sources/mas/Commands/Home.swift b/Sources/mas/Commands/Home.swift index f538f2e2..be04111b 100644 --- a/Sources/mas/Commands/Home.swift +++ b/Sources/mas/Commands/Home.swift @@ -17,7 +17,7 @@ extension Mas { ) @Argument(help: "ID of app to show on MAS Preview") - var appId: AppID + var appID: AppID /// Runs the command. func run() throws { @@ -26,7 +26,7 @@ extension Mas { func run(storeSearch: StoreSearch, openCommand: ExternalCommand) throws { do { - guard let result = try storeSearch.lookup(app: appId).wait() else { + guard let result = try storeSearch.lookup(appID: appID).wait() else { throw MASError.noSearchResultsFound } diff --git a/Sources/mas/Commands/Info.swift b/Sources/mas/Commands/Info.swift index a330f423..0e6b71da 100644 --- a/Sources/mas/Commands/Info.swift +++ b/Sources/mas/Commands/Info.swift @@ -18,7 +18,7 @@ extension Mas { ) @Argument(help: "ID of app to show info") - var appId: AppID + var appID: AppID /// Runs the command. func run() throws { @@ -27,7 +27,7 @@ extension Mas { func run(storeSearch: StoreSearch) throws { do { - guard let result = try storeSearch.lookup(app: appId).wait() else { + guard let result = try storeSearch.lookup(appID: appID).wait() else { throw MASError.noSearchResultsFound } diff --git a/Sources/mas/Commands/Install.swift b/Sources/mas/Commands/Install.swift index ff0b0e87..88c26882 100644 --- a/Sources/mas/Commands/Install.swift +++ b/Sources/mas/Commands/Install.swift @@ -19,7 +19,7 @@ extension Mas { @Flag(help: "force reinstall") var force = false @Argument(help: "app ID(s) to install") - var appIds: [AppID] + var appIDs: [AppID] /// Runs the command. func run() throws { @@ -28,8 +28,8 @@ extension Mas { func run(appLibrary: AppLibrary) throws { // Try to download applications with given identifiers and collect results - let appIds = appIds.filter { appId in - if let product = appLibrary.installedApp(forId: appId), !force { + let appIDs = appIDs.filter { appID in + if let product = appLibrary.installedApp(withAppID: appID), !force { printWarning("\(product.appName) is already installed") return false } @@ -38,7 +38,7 @@ extension Mas { } do { - try downloadAll(appIds).wait() + try downloadAll(appIDs).wait() } catch { throw error as? MASError ?? .downloadFailed(error: error as NSError) } diff --git a/Sources/mas/Commands/Lucky.swift b/Sources/mas/Commands/Lucky.swift index bad05111..3b567fd0 100644 --- a/Sources/mas/Commands/Lucky.swift +++ b/Sources/mas/Commands/Lucky.swift @@ -28,7 +28,7 @@ extension Mas { } func run(appLibrary: AppLibrary, storeSearch: StoreSearch) throws { - var appId: AppID? + var appID: AppID? do { let results = try storeSearch.search(for: appName).wait() @@ -37,28 +37,30 @@ extension Mas { throw MASError.noSearchResultsFound } - appId = result.trackId + appID = result.trackId } catch { throw error as? MASError ?? .searchFailed } - guard let identifier = appId else { fatalError() } + guard let appID else { + fatalError() + } - try install(identifier, appLibrary: appLibrary) + try install(appID: appID, appLibrary: appLibrary) } /// Installs an app. /// /// - Parameters: - /// - appId: App identifier + /// - appID: App identifier /// - appLibrary: Library of installed apps - fileprivate func install(_ appId: AppID, appLibrary: AppLibrary) throws { + fileprivate func install(appID: AppID, appLibrary: AppLibrary) throws { // Try to download applications with given identifiers and collect results - if let product = appLibrary.installedApp(forId: appId), !force { + if let product = appLibrary.installedApp(withAppID: appID), !force { printWarning("\(product.appName) is already installed") } else { do { - try downloadAll([appId]).wait() + try downloadAll([appID]).wait() } catch { throw error as? MASError ?? .downloadFailed(error: error as NSError) } diff --git a/Sources/mas/Commands/Open.swift b/Sources/mas/Commands/Open.swift index bc0afc9d..e2a143f4 100644 --- a/Sources/mas/Commands/Open.swift +++ b/Sources/mas/Commands/Open.swift @@ -20,7 +20,7 @@ extension Mas { ) @Argument(help: "the app ID") - var appId: AppID? + var appID: AppID? /// Runs the command. func run() throws { @@ -29,13 +29,13 @@ extension Mas { func run(storeSearch: StoreSearch, openCommand: ExternalCommand) throws { do { - guard let appId else { + guard let appID else { // If no app ID is given, just open the MAS GUI app try openCommand.run(arguments: masScheme + "://") return } - guard let result = try storeSearch.lookup(app: appId).wait() + guard let result = try storeSearch.lookup(appID: appID).wait() else { throw MASError.noSearchResultsFound } diff --git a/Sources/mas/Commands/Outdated.swift b/Sources/mas/Commands/Outdated.swift index aeb99f0f..52b12bab 100644 --- a/Sources/mas/Commands/Outdated.swift +++ b/Sources/mas/Commands/Outdated.swift @@ -33,7 +33,7 @@ extension Mas { fulfilled: appLibrary.installedApps.map { installedApp in firstly { - storeSearch.lookup(app: installedApp.itemIdentifier.uint64Value) + storeSearch.lookup(appID: installedApp.itemIdentifier.uint64Value) }.done { storeApp in guard let storeApp else { if verbose { diff --git a/Sources/mas/Commands/Purchase.swift b/Sources/mas/Commands/Purchase.swift index 601f6b2d..841d26df 100644 --- a/Sources/mas/Commands/Purchase.swift +++ b/Sources/mas/Commands/Purchase.swift @@ -16,7 +16,7 @@ extension Mas { ) @Argument(help: "app ID(s) to install") - var appIds: [AppID] + var appIDs: [AppID] /// Runs the command. func run() throws { @@ -25,8 +25,8 @@ extension Mas { func run(appLibrary: AppLibrary) throws { // Try to download applications with given identifiers and collect results - let appIds = appIds.filter { appId in - if let product = appLibrary.installedApp(forId: appId) { + let appIDs = appIDs.filter { appID in + if let product = appLibrary.installedApp(withAppID: appID) { printWarning("\(product.appName) has already been purchased.") return false } @@ -35,7 +35,7 @@ extension Mas { } do { - try downloadAll(appIds, purchase: true).wait() + try downloadAll(appIDs, purchase: true).wait() } catch { throw error as? MASError ?? .downloadFailed(error: error as NSError) } diff --git a/Sources/mas/Commands/Uninstall.swift b/Sources/mas/Commands/Uninstall.swift index 96d572a1..82652963 100644 --- a/Sources/mas/Commands/Uninstall.swift +++ b/Sources/mas/Commands/Uninstall.swift @@ -21,7 +21,7 @@ extension Mas { @Flag(help: "dry run") var dryRun = false @Argument(help: "ID of app to uninstall") - var appId: AppID + var appID: AppID /// Runs the uninstall command. func run() throws { @@ -29,7 +29,7 @@ extension Mas { } func run(appLibrary: AppLibrary) throws { - guard let product = appLibrary.installedApp(forId: appId) else { + guard let product = appLibrary.installedApp(withAppID: appID) else { throw MASError.notInstalled } diff --git a/Sources/mas/Commands/Upgrade.swift b/Sources/mas/Commands/Upgrade.swift index fc602b21..afa1b5d6 100644 --- a/Sources/mas/Commands/Upgrade.swift +++ b/Sources/mas/Commands/Upgrade.swift @@ -18,7 +18,7 @@ extension Mas { ) @Argument(help: "app(s) to upgrade") - var appIds: [String] = [] + var appIDs: [String] = [] /// Runs the command. func run() throws { @@ -55,12 +55,12 @@ extension Mas { storeSearch: StoreSearch ) throws -> [(SoftwareProduct, SearchResult)] { let apps: [SoftwareProduct] = - appIds.isEmpty + appIDs.isEmpty ? appLibrary.installedApps - : appIds.compactMap { - if let appId = AppID($0) { + : appIDs.compactMap { + if let appID = AppID($0) { // if argument an AppID, lookup app by id using argument - return appLibrary.installedApp(forId: appId) + return appLibrary.installedApp(withAppID: appID) } else { // if argument not an AppID, lookup app by name using argument return appLibrary.installedApp(named: $0) @@ -70,7 +70,7 @@ extension Mas { let promises = apps.map { installedApp in // only upgrade apps whose local version differs from the store version firstly { - storeSearch.lookup(app: installedApp.itemIdentifier.uint64Value) + storeSearch.lookup(appID: installedApp.itemIdentifier.uint64Value) }.map { result -> (SoftwareProduct, SearchResult)? in guard let storeApp = result, installedApp.isOutdatedWhenComparedTo(storeApp) else { return nil diff --git a/Sources/mas/Commands/Vendor.swift b/Sources/mas/Commands/Vendor.swift index 32fa0fba..546865ee 100644 --- a/Sources/mas/Commands/Vendor.swift +++ b/Sources/mas/Commands/Vendor.swift @@ -17,7 +17,7 @@ extension Mas { ) @Argument(help: "the app ID to show the vendor's website") - var appId: AppID + var appID: AppID /// Runs the command. func run() throws { @@ -26,7 +26,7 @@ extension Mas { func run(storeSearch: StoreSearch, openCommand: ExternalCommand) throws { do { - guard let result = try storeSearch.lookup(app: appId).wait() + guard let result = try storeSearch.lookup(appID: appID).wait() else { throw MASError.noSearchResultsFound } diff --git a/Sources/mas/Controllers/AppLibrary.swift b/Sources/mas/Controllers/AppLibrary.swift index 477876f0..1db3ff90 100644 --- a/Sources/mas/Controllers/AppLibrary.swift +++ b/Sources/mas/Controllers/AppLibrary.swift @@ -15,9 +15,9 @@ protocol AppLibrary { /// Finds an app by ID. /// - /// - Parameter forId: MAS ID for app. + /// - Parameter withAppID: MAS ID for app. /// - Returns: Software Product of app if found; nil otherwise. - func installedApp(forId: AppID) -> SoftwareProduct? + func installedApp(withAppID appID: AppID) -> SoftwareProduct? /// Uninstalls an app. /// @@ -30,11 +30,11 @@ protocol AppLibrary { extension AppLibrary { /// Finds an app by ID. /// - /// - Parameter forId: MAS ID for app. + /// - Parameter withAppID: MAS ID for app. /// - Returns: Software Product of app if found; nil otherwise. - func installedApp(forId identifier: AppID) -> SoftwareProduct? { - let appId = NSNumber(value: identifier) - return installedApps.first { $0.itemIdentifier == appId } + func installedApp(withAppID appID: AppID) -> SoftwareProduct? { + let appID = NSNumber(value: appID) + return installedApps.first { $0.itemIdentifier == appID } } /// Finds an app by name. diff --git a/Sources/mas/Controllers/MasStoreSearch.swift b/Sources/mas/Controllers/MasStoreSearch.swift index b5738ed9..b921d1eb 100644 --- a/Sources/mas/Controllers/MasStoreSearch.swift +++ b/Sources/mas/Controllers/MasStoreSearch.swift @@ -61,12 +61,12 @@ class MasStoreSearch: StoreSearch { /// Looks up app details. /// - /// - Parameter appId: MAS ID of app + /// - Parameter appID: MAS ID of app /// - Returns: A Promise for the search result record of app, or nil if no apps match the ID, /// or an Error if there is a problem with the network request. - func lookup(app appId: AppID) -> Promise { - guard let url = lookupURL(forApp: appId, inCountry: country) else { - fatalError("Failed to build URL for \(appId)") + func lookup(appID: AppID) -> Promise { + guard let url = lookupURL(forAppID: appID, inCountry: country) else { + fatalError("Failed to build URL for \(appID)") } return firstly { loadSearchResults(url) diff --git a/Sources/mas/Controllers/StoreSearch.swift b/Sources/mas/Controllers/StoreSearch.swift index 2b4e11ed..b04ef13e 100644 --- a/Sources/mas/Controllers/StoreSearch.swift +++ b/Sources/mas/Controllers/StoreSearch.swift @@ -11,7 +11,7 @@ import PromiseKit /// Protocol for searching the MAS catalog. protocol StoreSearch { - func lookup(app appId: AppID) -> Promise + func lookup(appID: AppID) -> Promise func search(for appName: String) -> Promise<[SearchResult]> } @@ -47,15 +47,15 @@ extension StoreSearch { /// Builds the lookup URL for an app. /// - /// - Parameter appId: MAS app identifier. - /// - Returns: URL for the lookup service or nil if appId can't be encoded. - func lookupURL(forApp appId: AppID, inCountry country: String?) -> URL? { + /// - Parameter appID: MAS app identifier. + /// - Returns: URL for the lookup service or nil if appID can't be encoded. + func lookupURL(forAppID appID: AppID, inCountry country: String?) -> URL? { guard var components = URLComponents(string: "https://itunes.apple.com/lookup") else { return nil } components.queryItems = [ - URLQueryItem(name: "id", value: "\(appId)"), + URLQueryItem(name: "id", value: "\(appID)"), URLQueryItem(name: "entity", value: "desktopSoftware"), ] diff --git a/Sources/mas/Formatters/AppListFormatter.swift b/Sources/mas/Formatters/AppListFormatter.swift index 5edd055c..8bafbf88 100644 --- a/Sources/mas/Formatters/AppListFormatter.swift +++ b/Sources/mas/Formatters/AppListFormatter.swift @@ -24,12 +24,12 @@ enum AppListFormatter { var output = "" for product in products { - let appId = product.itemIdentifier.stringValue + let appID = product.itemIdentifier.stringValue .padding(toLength: idColumnMinWidth, withPad: " ", startingAt: 0) let appName = product.appNameOrBundleIdentifier.padding(toLength: maxLength, withPad: " ", startingAt: 0) let version = product.bundleVersion - output += "\(appId) \(appName) (\(version))\n" + output += "\(appID) \(appName) (\(version))\n" } return output.trimmingCharacters(in: .newlines) diff --git a/Sources/mas/Formatters/SearchResultFormatter.swift b/Sources/mas/Formatters/SearchResultFormatter.swift index ed01448c..eac80a7a 100644 --- a/Sources/mas/Formatters/SearchResultFormatter.swift +++ b/Sources/mas/Formatters/SearchResultFormatter.swift @@ -20,15 +20,15 @@ enum SearchResultFormatter { var output = "" for result in results { - let appId = result.trackId + let appID = result.trackId let appName = result.trackName.padding(toLength: maxLength, withPad: " ", startingAt: 0) let version = result.version let price = result.price ?? 0.0 if includePrice { - output += String(format: "%12lu %@ $%5.2f (%@)\n", appId, appName, price, version) + output += String(format: "%12lu %@ $%5.2f (%@)\n", appID, appName, price, version) } else { - output += String(format: "%12lu %@ (%@)\n", appId, appName, version) + output += String(format: "%12lu %@ (%@)\n", appID, appName, version) } } diff --git a/Tests/masTests/Commands/UninstallSpec.swift b/Tests/masTests/Commands/UninstallSpec.swift index 691692db..76018ede 100644 --- a/Tests/masTests/Commands/UninstallSpec.swift +++ b/Tests/masTests/Commands/UninstallSpec.swift @@ -18,18 +18,18 @@ public class UninstallSpec: QuickSpec { Mas.initialize() } describe("uninstall command") { - let appId: AppID = 12345 + let appID: AppID = 12345 let app = SoftwareProductMock( appName: "Some App", bundleIdentifier: "com.some.app", bundlePath: "/tmp/Some.app", bundleVersion: "1.0", - itemIdentifier: NSNumber(value: appId) + itemIdentifier: NSNumber(value: appID) ) let mockLibrary = AppLibraryMock() context("dry run") { - let uninstall = try! Mas.Uninstall.parse(["--dry-run", String(appId)]) + let uninstall = try! Mas.Uninstall.parse(["--dry-run", String(appID)]) beforeEach { mockLibrary.reset() @@ -49,7 +49,7 @@ public class UninstallSpec: QuickSpec { } } context("wet run") { - let uninstall = try! Mas.Uninstall.parse([String(appId)]) + let uninstall = try! Mas.Uninstall.parse([String(appID)]) beforeEach { mockLibrary.reset() diff --git a/Tests/masTests/Controllers/MasStoreSearchSpec.swift b/Tests/masTests/Controllers/MasStoreSearchSpec.swift index 335700a0..e05a2a68 100644 --- a/Tests/masTests/Controllers/MasStoreSearchSpec.swift +++ b/Tests/masTests/Controllers/MasStoreSearchSpec.swift @@ -54,13 +54,13 @@ public class MasStoreSearchSpec: QuickSpec { context("when lookup used") { it("can find slack") { - let appId: AppID = 803_453_959 + let appID: AppID = 803_453_959 let networkSession = NetworkSessionMockFromFile(responseFile: "lookup/slack.json") let storeSearch = MasStoreSearch(networkManager: NetworkManager(session: networkSession)) var lookup: SearchResult? do { - lookup = try storeSearch.lookup(app: appId).wait() + lookup = try storeSearch.lookup(appID: appID).wait() } catch { let maserror = error as! MASError if case .jsonParsing(let nserror) = maserror { @@ -70,7 +70,7 @@ public class MasStoreSearchSpec: QuickSpec { guard let result = lookup else { fatalError("lookup result was nil") } - expect(result.trackId) == appId + expect(result.trackId) == appID expect(result.bundleId) == "com.tinyspeck.slackmacgap" expect(result.price) == 0 expect(result.sellerName) == "Slack Technologies, Inc." diff --git a/Tests/masTests/Controllers/StoreSearchMock.swift b/Tests/masTests/Controllers/StoreSearchMock.swift index a2769514..3b83df89 100644 --- a/Tests/masTests/Controllers/StoreSearchMock.swift +++ b/Tests/masTests/Controllers/StoreSearchMock.swift @@ -19,8 +19,8 @@ class StoreSearchMock: StoreSearch { return .value(results) } - func lookup(app appId: AppID) -> Promise { - guard let result = apps[appId] + func lookup(appID: AppID) -> Promise { + guard let result = apps[appID] else { return Promise(error: MASError.noSearchResultsFound) }