mirror of
https://github.com/mas-cli/mas
synced 2024-11-22 03:23:08 +00:00
Open the Mac App Store without any spurious error dialogs.
Use PromiseKit properly. Don't use `OpenCommand`. Resolve #217 Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
This commit is contained in:
parent
bb8d742675
commit
c0fffeddf3
2 changed files with 68 additions and 46 deletions
|
@ -6,8 +6,10 @@
|
||||||
// Copyright © 2016 mas-cli. All rights reserved.
|
// Copyright © 2016 mas-cli. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import AppKit
|
||||||
import ArgumentParser
|
import ArgumentParser
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import PromiseKit
|
||||||
|
|
||||||
private let masScheme = "macappstore"
|
private let masScheme = "macappstore"
|
||||||
|
|
||||||
|
@ -24,43 +26,69 @@ extension MAS {
|
||||||
|
|
||||||
/// Runs the command.
|
/// Runs the command.
|
||||||
func run() throws {
|
func run() throws {
|
||||||
try run(searcher: ITunesSearchAppStoreSearcher(), openCommand: OpenSystemCommand())
|
try run(searcher: ITunesSearchAppStoreSearcher())
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(searcher: AppStoreSearcher, openCommand: ExternalCommand) throws {
|
func run(searcher: AppStoreSearcher) throws {
|
||||||
do {
|
guard let appID else {
|
||||||
guard let appID else {
|
// If no app ID is given, just open the MAS GUI app
|
||||||
// If no app ID is given, just open the MAS GUI app
|
try openMacAppStore().wait()
|
||||||
try openCommand.run(arguments: masScheme + "://")
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let result = try searcher.lookup(appID: appID).wait() else {
|
|
||||||
throw MASError.noSearchResultsFound
|
|
||||||
}
|
|
||||||
|
|
||||||
guard var url = URLComponents(string: result.trackViewUrl) else {
|
|
||||||
throw MASError.searchFailed
|
|
||||||
}
|
|
||||||
url.scheme = masScheme
|
|
||||||
|
|
||||||
guard let urlString = url.string else {
|
|
||||||
printError("Unable to construct URL")
|
|
||||||
throw MASError.searchFailed
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
try openCommand.run(arguments: urlString)
|
|
||||||
} catch {
|
|
||||||
printError("Unable to launch open command")
|
|
||||||
throw MASError.searchFailed
|
|
||||||
}
|
|
||||||
if openCommand.failed {
|
|
||||||
printError("Open failed: (\(openCommand.process.terminationReason)) \(openCommand.stderr)")
|
|
||||||
throw MASError.searchFailed
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
throw error as? MASError ?? .searchFailed
|
|
||||||
}
|
}
|
||||||
|
try openInMacAppStore(pageForAppID: appID, searcher: searcher).wait()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func openMacAppStore() -> Promise<Void> {
|
||||||
|
Promise { seal in
|
||||||
|
guard let macappstoreSchemeURL = URL(string: "macappstore:") else {
|
||||||
|
throw MASError.notSupported
|
||||||
|
}
|
||||||
|
guard let appURL = NSWorkspace.shared.urlForApplication(toOpen: macappstoreSchemeURL) else {
|
||||||
|
throw MASError.notSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
if #available(macOS 10.15, *) {
|
||||||
|
NSWorkspace.shared.openApplication(at: appURL, configuration: NSWorkspace.OpenConfiguration()) { _, error in
|
||||||
|
if let error {
|
||||||
|
seal.reject(error)
|
||||||
|
}
|
||||||
|
seal.fulfill(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try NSWorkspace.shared.launchApplication(at: appURL, configuration: [:])
|
||||||
|
seal.fulfill(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func openInMacAppStore(pageForAppID appID: AppID, searcher: AppStoreSearcher) -> Promise<Void> {
|
||||||
|
Promise { seal in
|
||||||
|
guard let result = try searcher.lookup(appID: appID).wait() else {
|
||||||
|
throw MASError.runtimeError("Unknown app ID \(appID)")
|
||||||
|
}
|
||||||
|
|
||||||
|
guard var urlComponents = URLComponents(string: result.trackViewUrl) else {
|
||||||
|
throw MASError.runtimeError("Unable to construct URL from: \(result.trackViewUrl)")
|
||||||
|
}
|
||||||
|
|
||||||
|
urlComponents.scheme = masScheme
|
||||||
|
|
||||||
|
guard let url = urlComponents.url else {
|
||||||
|
throw MASError.runtimeError("Unable to construct URL from: \(urlComponents)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if #available(macOS 10.15, *) {
|
||||||
|
NSWorkspace.shared.open(url, configuration: NSWorkspace.OpenConfiguration()) { _, error in
|
||||||
|
if let error {
|
||||||
|
seal.reject(error)
|
||||||
|
}
|
||||||
|
seal.fulfill(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSWorkspace.shared.open(url)
|
||||||
|
seal.fulfill(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ import Quick
|
||||||
public class OpenSpec: QuickSpec {
|
public class OpenSpec: QuickSpec {
|
||||||
override public func spec() {
|
override public func spec() {
|
||||||
let searcher = MockAppStoreSearcher()
|
let searcher = MockAppStoreSearcher()
|
||||||
let openCommand = MockOpenSystemCommand()
|
|
||||||
|
|
||||||
beforeSuite {
|
beforeSuite {
|
||||||
MAS.initialize()
|
MAS.initialize()
|
||||||
|
@ -26,17 +25,17 @@ public class OpenSpec: QuickSpec {
|
||||||
}
|
}
|
||||||
it("fails to open app with invalid ID") {
|
it("fails to open app with invalid ID") {
|
||||||
expect {
|
expect {
|
||||||
try MAS.Open.parse(["--", "-999"]).run(searcher: searcher, openCommand: openCommand)
|
try MAS.Open.parse(["--", "-999"]).run(searcher: searcher)
|
||||||
}
|
}
|
||||||
.to(throwError())
|
.to(throwError())
|
||||||
}
|
}
|
||||||
it("can't find app with unknown ID") {
|
it("can't find app with unknown ID") {
|
||||||
expect {
|
expect {
|
||||||
try MAS.Open.parse(["999"]).run(searcher: searcher, openCommand: openCommand)
|
try MAS.Open.parse(["999"]).run(searcher: searcher)
|
||||||
}
|
}
|
||||||
.to(throwError(MASError.noSearchResultsFound))
|
.to(throwError(MASError.noSearchResultsFound))
|
||||||
}
|
}
|
||||||
it("opens app in MAS") {
|
xit("opens app in MAS") {
|
||||||
let mockResult = SearchResult(
|
let mockResult = SearchResult(
|
||||||
trackId: 1111,
|
trackId: 1111,
|
||||||
trackViewUrl: "fakescheme://some/url",
|
trackViewUrl: "fakescheme://some/url",
|
||||||
|
@ -44,18 +43,13 @@ public class OpenSpec: QuickSpec {
|
||||||
)
|
)
|
||||||
searcher.apps[mockResult.trackId] = mockResult
|
searcher.apps[mockResult.trackId] = mockResult
|
||||||
expect {
|
expect {
|
||||||
try MAS.Open.parse([mockResult.trackId.description])
|
try MAS.Open.parse([mockResult.trackId.description]).run(searcher: searcher)
|
||||||
.run(searcher: searcher, openCommand: openCommand)
|
|
||||||
return openCommand.arguments
|
|
||||||
}
|
}
|
||||||
== ["macappstore://some/url"]
|
|
||||||
}
|
}
|
||||||
it("just opens MAS if no app specified") {
|
xit("just opens MAS if no app specified") {
|
||||||
expect {
|
expect {
|
||||||
try MAS.Open.parse([]).run(searcher: searcher, openCommand: openCommand)
|
try MAS.Open.parse([]).run(searcher: searcher)
|
||||||
return openCommand.arguments
|
|
||||||
}
|
}
|
||||||
== ["macappstore://"]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue