mirror of
https://github.com/mas-cli/mas
synced 2024-11-21 19:23:01 +00:00
Improve spacing.
Partial #592 Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
This commit is contained in:
parent
3eaffa5c3e
commit
71fbe2e444
13 changed files with 75 additions and 59 deletions
|
@ -20,19 +20,23 @@ import StoreFoundation
|
|||
/// the promise is rejected with the first error, after all remaining downloads are attempted.
|
||||
func downloadAll(_ appIDs: [AppID], purchase: Bool = false) -> Promise<Void> {
|
||||
var firstError: Error?
|
||||
return appIDs.reduce(Guarantee.value(())) { previous, appID in
|
||||
previous.then {
|
||||
downloadWithRetries(appID, purchase: purchase).recover { error in
|
||||
if firstError == nil {
|
||||
firstError = error
|
||||
}
|
||||
return
|
||||
appIDs
|
||||
.reduce(Guarantee.value(())) { previous, appID in
|
||||
previous.then {
|
||||
downloadWithRetries(appID, purchase: purchase)
|
||||
.recover { error in
|
||||
if firstError == nil {
|
||||
firstError = error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.done {
|
||||
if let error = firstError {
|
||||
throw error
|
||||
.done {
|
||||
if let error = firstError {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func downloadWithRetries(_ appID: AppID, purchase: Bool = false, attempts: Int = 3) -> Promise<Void> {
|
||||
|
|
|
@ -15,13 +15,15 @@ extension ISStoreAccount: StoreAccount {
|
|||
if #available(macOS 10.13, *) {
|
||||
return race(
|
||||
Promise { seal in
|
||||
ISServiceProxy.genericShared().accountService.primaryAccount { storeAccount in
|
||||
seal.fulfill(storeAccount)
|
||||
}
|
||||
ISServiceProxy.genericShared().accountService
|
||||
.primaryAccount { storeAccount in
|
||||
seal.fulfill(storeAccount)
|
||||
}
|
||||
},
|
||||
after(seconds: 30).then {
|
||||
Promise(error: MASError.notSignedIn)
|
||||
}
|
||||
after(seconds: 30)
|
||||
.then {
|
||||
Promise(error: MASError.notSignedIn)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
return .value(CKAccountStore.shared().primaryAccount)
|
||||
|
@ -76,9 +78,10 @@ extension ISStoreAccount: StoreAccount {
|
|||
|
||||
return race(
|
||||
signInPromise,
|
||||
after(seconds: 30).then {
|
||||
Promise(error: MASError.signInFailed(error: nil))
|
||||
}
|
||||
after(seconds: 30)
|
||||
.then {
|
||||
Promise(error: MASError.signInFailed(error: nil))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
import CommerceKit
|
||||
import StoreFoundation
|
||||
|
||||
@objc class PurchaseDownloadObserver: NSObject, CKDownloadQueueObserver {
|
||||
@objc
|
||||
class PurchaseDownloadObserver: NSObject, CKDownloadQueueObserver {
|
||||
let purchase: SSPurchase
|
||||
var completionHandler: (() -> Void)?
|
||||
var errorHandler: ((MASError) -> Void)?
|
||||
|
|
|
@ -23,7 +23,6 @@ extension SSPurchase {
|
|||
if purchase {
|
||||
parameters["macappinstalledconfirmed"] = 1
|
||||
parameters["pricingParameters"] = "STDQ"
|
||||
|
||||
} else {
|
||||
parameters["pricingParameters"] = "STDRDL"
|
||||
}
|
||||
|
@ -63,19 +62,20 @@ extension SSPurchase {
|
|||
|
||||
private func perform() -> Promise<Void> {
|
||||
Promise<SSPurchase> { seal in
|
||||
CKPurchaseController.shared().perform(self, withOptions: 0) { purchase, _, error, response in
|
||||
if let error {
|
||||
seal.reject(MASError.purchaseFailed(error: error as NSError?))
|
||||
return
|
||||
}
|
||||
CKPurchaseController.shared()
|
||||
.perform(self, withOptions: 0) { purchase, _, error, response in
|
||||
if let error {
|
||||
seal.reject(MASError.purchaseFailed(error: error as NSError?))
|
||||
return
|
||||
}
|
||||
|
||||
guard response?.downloads.isEmpty == false, let purchase else {
|
||||
seal.reject(MASError.noDownloads)
|
||||
return
|
||||
}
|
||||
guard response?.downloads.isEmpty == false, let purchase else {
|
||||
seal.reject(MASError.noDownloads)
|
||||
return
|
||||
}
|
||||
|
||||
seal.fulfill(purchase)
|
||||
}
|
||||
seal.fulfill(purchase)
|
||||
}
|
||||
}
|
||||
.then { purchase in
|
||||
let observer = PurchaseDownloadObserver(purchase: purchase)
|
||||
|
|
|
@ -35,13 +35,11 @@ extension Mas {
|
|||
return
|
||||
}
|
||||
|
||||
guard let result = try storeSearch.lookup(appID: appID).wait()
|
||||
else {
|
||||
guard let result = try storeSearch.lookup(appID: appID).wait() else {
|
||||
throw MASError.noSearchResultsFound
|
||||
}
|
||||
|
||||
guard var url = URLComponents(string: result.trackViewUrl)
|
||||
else {
|
||||
guard var url = URLComponents(string: result.trackViewUrl) else {
|
||||
throw MASError.searchFailed
|
||||
}
|
||||
url.scheme = masScheme
|
||||
|
|
|
@ -32,7 +32,8 @@ extension Mas {
|
|||
appLibrary.installedApps.map { installedApp in
|
||||
firstly {
|
||||
storeSearch.lookup(appID: installedApp.itemIdentifier.appIDValue)
|
||||
}.done { storeApp in
|
||||
}
|
||||
.done { storeApp in
|
||||
guard let storeApp else {
|
||||
if verbose {
|
||||
printWarning(
|
||||
|
|
|
@ -41,7 +41,8 @@ extension Mas {
|
|||
print("Upgrading \(apps.count) outdated application\(apps.count > 1 ? "s" : ""):")
|
||||
print(
|
||||
apps.map { "\($0.installedApp.appName) (\($0.installedApp.bundleVersion)) -> (\($0.storeApp.version))" }
|
||||
.joined(separator: "\n"))
|
||||
.joined(separator: "\n")
|
||||
)
|
||||
|
||||
do {
|
||||
try downloadAll(apps.map(\.installedApp.itemIdentifier.appIDValue)).wait()
|
||||
|
@ -71,7 +72,8 @@ extension Mas {
|
|||
// only upgrade apps whose local version differs from the store version
|
||||
firstly {
|
||||
storeSearch.lookup(appID: installedApp.itemIdentifier.appIDValue)
|
||||
}.map { result -> (SoftwareProduct, SearchResult)? in
|
||||
}
|
||||
.map { result -> (SoftwareProduct, SearchResult)? in
|
||||
guard let storeApp = result, installedApp.isOutdatedWhenComparedTo(storeApp) else {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -26,13 +26,13 @@ extension Mas {
|
|||
|
||||
func run(storeSearch: StoreSearch, openCommand: ExternalCommand) throws {
|
||||
do {
|
||||
guard let result = try storeSearch.lookup(appID: appID).wait()
|
||||
else {
|
||||
guard let result = try storeSearch.lookup(appID: appID).wait() else {
|
||||
throw MASError.noSearchResultsFound
|
||||
}
|
||||
|
||||
guard let vendorWebsite = result.sellerUrl
|
||||
else { throw MASError.noVendorWebsite }
|
||||
guard let vendorWebsite = result.sellerUrl else {
|
||||
throw MASError.noVendorWebsite
|
||||
}
|
||||
|
||||
do {
|
||||
try openCommand.run(arguments: vendorWebsite)
|
||||
|
|
|
@ -14,9 +14,10 @@ class MasAppLibrary: AppLibrary {
|
|||
private let softwareMap: SoftwareMap
|
||||
|
||||
/// Array of installed software products.
|
||||
lazy var installedApps: [SoftwareProduct] = softwareMap.allSoftwareProducts().filter { product in
|
||||
product.bundlePath.starts(with: "/Applications/")
|
||||
}
|
||||
lazy var installedApps: [SoftwareProduct] = softwareMap.allSoftwareProducts()
|
||||
.filter { product in
|
||||
product.bundlePath.starts(with: "/Applications/")
|
||||
}
|
||||
|
||||
/// Internal initializer for providing a mock software map.
|
||||
/// - Parameter softwareMap: SoftwareMap to use
|
||||
|
|
|
@ -53,9 +53,11 @@ class MasStoreSearch: StoreSearch {
|
|||
|
||||
// Combine the results, removing any duplicates.
|
||||
var seenAppIDs = Set<AppID>()
|
||||
return when(fulfilled: results).flatMapValues { $0 }.filterValues { result in
|
||||
seenAppIDs.insert(result.trackId).inserted
|
||||
}
|
||||
return when(fulfilled: results)
|
||||
.flatMapValues { $0 }
|
||||
.filterValues { result in
|
||||
seenAppIDs.insert(result.trackId).inserted
|
||||
}
|
||||
}
|
||||
|
||||
/// Looks up app details.
|
||||
|
@ -75,14 +77,14 @@ class MasStoreSearch: StoreSearch {
|
|||
return .value(nil)
|
||||
}
|
||||
|
||||
guard let pageUrl = URL(string: result.trackViewUrl)
|
||||
else {
|
||||
guard let pageUrl = URL(string: result.trackViewUrl) else {
|
||||
return .value(result)
|
||||
}
|
||||
|
||||
return firstly {
|
||||
self.scrapeAppStoreVersion(pageUrl)
|
||||
}.map { pageVersion in
|
||||
}
|
||||
.map { pageVersion in
|
||||
guard let pageVersion,
|
||||
let searchVersion = Version(tolerant: result.version),
|
||||
pageVersion > searchVersion
|
||||
|
@ -94,7 +96,8 @@ class MasStoreSearch: StoreSearch {
|
|||
var result = result
|
||||
result.version = pageVersion.description
|
||||
return result
|
||||
}.recover { _ in
|
||||
}
|
||||
.recover { _ in
|
||||
// If we were unable to scrape the App Store page, assume compatibility.
|
||||
.value(result)
|
||||
}
|
||||
|
@ -120,7 +123,8 @@ class MasStoreSearch: StoreSearch {
|
|||
private func scrapeAppStoreVersion(_ pageUrl: URL) -> Promise<Version?> {
|
||||
firstly {
|
||||
networkManager.loadData(from: pageUrl)
|
||||
}.map { data in
|
||||
}
|
||||
.map { data in
|
||||
guard let html = String(data: data, encoding: .utf8),
|
||||
let capture = MasStoreSearch.appVersionExpression.firstMatch(in: html)?.captures[0],
|
||||
let version = Version(tolerant: capture)
|
||||
|
|
|
@ -18,7 +18,9 @@ private var standardError = FileHandle.standardError
|
|||
extension FileHandle: TextOutputStream {
|
||||
/// Appends the given string to the stream.
|
||||
public func write(_ string: String) {
|
||||
guard let data = string.data(using: .utf8) else { return }
|
||||
guard let data = string.data(using: .utf8) else {
|
||||
return
|
||||
}
|
||||
write(data)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@ class StoreSearchMock: StoreSearch {
|
|||
}
|
||||
|
||||
func lookup(appID: AppID) -> Promise<SearchResult?> {
|
||||
guard let result = apps[appID]
|
||||
else {
|
||||
guard let result = apps[appID] else {
|
||||
return Promise(error: MASError.noSearchResultsFound)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,9 @@ class NetworkSessionMockFromFile: NetworkSessionMock {
|
|||
}
|
||||
|
||||
override func loadData(from _: URL) -> Promise<Data> {
|
||||
guard let fileURL = Bundle.url(for: responseFile)
|
||||
else { fatalError("Unable to load file \(responseFile)") }
|
||||
guard let fileURL = Bundle.url(for: responseFile) else {
|
||||
fatalError("Unable to load file \(responseFile)")
|
||||
}
|
||||
|
||||
do {
|
||||
return .value(try Data(contentsOf: fileURL, options: .mappedIfSafe))
|
||||
|
|
Loading…
Reference in a new issue