Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🧰 MasKit Framework #175

Merged
merged 14 commits into from
Oct 15, 2018
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
2 changes: 2 additions & 0 deletions App/AppStore/CKSoftwareMap+AppLookup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import CommerceKit

private var appIdsByName : [String:UInt64]?

extension CKSoftwareMap {
Expand Down
5 changes: 4 additions & 1 deletion App/AppStore/Downloader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
// Copyright (c) 2015 Andrew Naylor. All rights reserved.
//

import CommerceKit
import StoreFoundation

func download(_ adamId: UInt64) -> MASError? {

guard let account = ISStoreAccount.primaryAccount else {
return .notSignedIn
}

let group = DispatchGroup()
let purchase = SSPurchase(adamId: adamId, account: account)
let purchase = SSPurchase(adamId: adamId, account: account as! ISStoreAccount)

var purchaseError: MASError?
var observerIdentifier: CKDownloadQueueObserver? = nil
Expand Down
9 changes: 6 additions & 3 deletions App/AppStore/ISStoreAccount.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
// Copyright (c) 2015 Andrew Naylor. All rights reserved.
//

extension ISStoreAccount {
import StoreFoundation
import CommerceKit

extension ISStoreAccount: StoreAccount {
static var primaryAccountIsPresentAndSignedIn: Bool {
return CKAccountStore.shared().primaryAccountIsPresentAndSignedIn
}

static var primaryAccount: ISStoreAccount? {
static var primaryAccount: StoreAccount? {
var account: ISStoreAccount?

if #available(macOS 10.13, *) {
Expand All @@ -34,7 +37,7 @@ extension ISStoreAccount {
return account
}

static func signIn(username: String, password: String, systemDialog: Bool = false) throws -> ISStoreAccount {
static func signIn(username: String, password: String, systemDialog: Bool = false) throws -> StoreAccount {
var account: ISStoreAccount? = nil
var error: MASError? = nil

Expand Down
3 changes: 3 additions & 0 deletions App/AppStore/PurchaseDownloadObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
// Copyright (c) 2015 Andrew Naylor. All rights reserved.
//

import CommerceKit
import StoreFoundation

@objc class PurchaseDownloadObserver: NSObject, CKDownloadQueueObserver {
let purchase: SSPurchase
var completionHandler: (() -> ())?
Expand Down
3 changes: 3 additions & 0 deletions App/AppStore/SSPurchase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
// Copyright (c) 2015 Andrew Naylor. All rights reserved.
//

import CommerceKit
import StoreFoundation

typealias SSPurchaseCompletion = (_ purchase: SSPurchase?, _ completed: Bool, _ error: Error?, _ response: SSPurchaseResponse?) -> ()

extension SSPurchase {
Expand Down
15 changes: 15 additions & 0 deletions App/AppStore/StoreAccount.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// StoreAccount.swift
// mas-cli
//
// Created by Ben Chatelain on 4/3/18.
// Copyright © 2018 Andrew Naylor. All rights reserved.
//

protocol StoreAccount {
static var primaryAccountIsPresentAndSignedIn: Bool { get }
static var primaryAccount: StoreAccount? { get }
static func signIn(username: String, password: String, systemDialog: Bool) throws -> StoreAccount

var identifier: String { get set }
}
15 changes: 9 additions & 6 deletions App/Commands/Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@

import Commandant
import Result
import StoreFoundation

struct AccountCommand: CommandProtocol {
typealias Options = NoOptions<MASError>
let verb = "account"
let function = "Prints the primary account Apple ID"
public struct AccountCommand: CommandProtocol {
public typealias Options = NoOptions<MASError>
public let verb = "account"
public let function = "Prints the primary account Apple ID"

public init() {}

func run(_ options: Options) -> Result<(), MASError> {
public func run(_ options: Options) -> Result<(), MASError> {
if let account = ISStoreAccount.primaryAccount {
print(account.identifier)
print(String(describing: account.identifier))
}
else {
print("Not signed in")
Expand Down
15 changes: 8 additions & 7 deletions App/Commands/Info.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import Commandant
import Result
import Foundation

struct InfoCommand: CommandProtocol {
let verb = "info"
let function = "Display app information from the Mac App Store"
public struct InfoCommand: CommandProtocol {
public let verb = "info"
public let function = "Display app information from the Mac App Store"

func run(_ options: InfoOptions) -> Result<(), MASError> {
public init() {}

public func run(_ options: InfoOptions) -> Result<(), MASError> {
guard let infoURLString = infoURLString(options.appId),
let searchJson = URLSession.requestSynchronousJSONWithURLString(infoURLString) as? [String: Any] else {
return .failure(.searchFailed)
Expand All @@ -40,21 +42,20 @@ struct InfoCommand: CommandProtocol {
}
}

struct InfoOptions: OptionsProtocol {
public struct InfoOptions: OptionsProtocol {
let appId: String

static func create(_ appId: String) -> InfoOptions {
return InfoOptions(appId: appId)
}

static func evaluate(_ m: CommandMode) -> Result<InfoOptions, CommandantError<MASError>> {
public static func evaluate(_ m: CommandMode) -> Result<InfoOptions, CommandantError<MASError>> {
return create
<*> m <| Argument(usage: "the app id to show info")
}
}

private struct AppInfoFormatter {

private enum Keys {
static let Name = "trackCensoredName"
static let Version = "version"
Expand Down
23 changes: 13 additions & 10 deletions App/Commands/Install.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@

import Commandant
import Result
import CommerceKit

struct InstallCommand: CommandProtocol {
typealias Options = InstallOptions
let verb = "install"
let function = "Install from the Mac App Store"
public struct InstallCommand: CommandProtocol {
public typealias Options = InstallOptions
public let verb = "install"
public let function = "Install from the Mac App Store"

public init() {}

func run(_ options: Options) -> Result<(), MASError> {
public func run(_ options: Options) -> Result<(), MASError> {
// Try to download applications with given identifiers and collect results
let downloadResults = options.appIds.compactMap { (appId) -> MASError? in
if let product = installedApp(appId) , !options.forceInstall {
Expand Down Expand Up @@ -43,17 +46,17 @@ struct InstallCommand: CommandProtocol {
}
}

struct InstallOptions: OptionsProtocol {
public struct InstallOptions: OptionsProtocol {
let appIds: [UInt64]
let forceInstall: Bool
static func create(_ appIds: [Int]) -> (_ forceInstall: Bool) -> InstallOptions {

public static func create(_ appIds: [Int]) -> (_ forceInstall: Bool) -> InstallOptions {
return { forceInstall in
return InstallOptions(appIds: appIds.map{UInt64($0)}, forceInstall: forceInstall)
}
}
static func evaluate(_ m: CommandMode) -> Result<InstallOptions, CommandantError<MASError>> {

public static func evaluate(_ m: CommandMode) -> Result<InstallOptions, CommandantError<MASError>> {
return create
<*> m <| Argument(usage: "app ID(s) to install")
<*> m <| Switch(flag: nil, key: "force", usage: "force reinstall")
Expand Down
15 changes: 9 additions & 6 deletions App/Commands/List.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@

import Commandant
import Result
import CommerceKit

struct ListCommand: CommandProtocol {
typealias Options = NoOptions<MASError>
let verb = "list"
let function = "Lists apps from the Mac App Store which are currently installed"

func run(_ options: Options) -> Result<(), MASError> {
public struct ListCommand: CommandProtocol {
public typealias Options = NoOptions<MASError>
public let verb = "list"
public let function = "Lists apps from the Mac App Store which are currently installed"

public init() {}

public func run(_ options: Options) -> Result<(), MASError> {
let softwareMap = CKSoftwareMap.shared()
guard let products = softwareMap.allProducts() else {
print("No installed apps found")
Expand Down
25 changes: 14 additions & 11 deletions App/Commands/Lucky.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@
import Commandant
import Result

struct LuckyCommand: CommandProtocol {
typealias Options = LuckyOptions
let verb = "lucky"
let function = "Install the first result from the Mac App Store"
import CommerceKit

func run(_ options: Options) -> Result<(), MASError> {
public struct LuckyCommand: CommandProtocol {
public typealias Options = LuckyOptions
public let verb = "lucky"
public let function = "Install the first result from the Mac App Store"

public init() {}

public func run(_ options: Options) -> Result<(), MASError> {

guard let searchURLString = searchURLString(options.appName),
let searchJson = URLSession.requestSynchronousJSONWithURLString(searchURLString) as? [String: Any] else {
Expand Down Expand Up @@ -69,20 +73,19 @@ struct LuckyCommand: CommandProtocol {
}
}

struct LuckyOptions: OptionsProtocol {
public struct LuckyOptions: OptionsProtocol {
let appName: String
let forceInstall: Bool
static func create(_ appName: String) -> (_ forceInstall: Bool) -> LuckyOptions {

public static func create(_ appName: String) -> (_ forceInstall: Bool) -> LuckyOptions {
return { forceInstall in
return LuckyOptions(appName: appName, forceInstall: forceInstall)
}
}
static func evaluate(_ m: CommandMode) -> Result<LuckyOptions, CommandantError<MASError>> {

public static func evaluate(_ m: CommandMode) -> Result<LuckyOptions, CommandantError<MASError>> {
return create
<*> m <| Argument(usage: "the app name to install")
<*> m <| Switch(flag: nil, key: "force", usage: "force reinstall")
}

}
13 changes: 8 additions & 5 deletions App/Commands/Outdated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@

import Commandant
import Result
import CommerceKit

struct OutdatedCommand: CommandProtocol {
typealias Options = NoOptions<MASError>
let verb = "outdated"
let function = "Lists pending updates from the Mac App Store"
public struct OutdatedCommand: CommandProtocol {
public typealias Options = NoOptions<MASError>
public let verb = "outdated"
public let function = "Lists pending updates from the Mac App Store"

public init() {}

func run(_ options: Options) -> Result<(), MASError> {
public func run(_ options: Options) -> Result<(), MASError> {
let updateController = CKUpdateController.shared()
let updates = updateController?.availableUpdates()
let softwareMap = CKSoftwareMap.shared()
Expand Down
25 changes: 14 additions & 11 deletions App/Commands/Reset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@

import Commandant
import Result
import CommerceKit

struct ResetCommand: CommandProtocol {
typealias Options = ResetOptions
let verb = "reset"
let function = "Resets the Mac App Store"
public struct ResetCommand: CommandProtocol {
public typealias Options = ResetOptions
public let verb = "reset"
public let function = "Resets the Mac App Store"

public init() {}

func run(_ options: Options) -> Result<(), MASError> {
public func run(_ options: Options) -> Result<(), MASError> {
/*
The "Reset Application" command in the Mac App Store debug menu performs
the following steps
Expand Down Expand Up @@ -70,19 +73,19 @@ struct ResetCommand: CommandProtocol {
}
}
}

return .success(())
}
}

struct ResetOptions: OptionsProtocol {
public struct ResetOptions: OptionsProtocol {
let debug: Bool
static func create(debug: Bool) -> ResetOptions {

public static func create(debug: Bool) -> ResetOptions {
return ResetOptions(debug: debug)
}
static func evaluate(_ m: CommandMode) -> Result<ResetOptions, CommandantError<MASError>> {

public static func evaluate(_ m: CommandMode) -> Result<ResetOptions, CommandantError<MASError>> {
return create
<*> m <| Switch(flag: nil, key: "debug", usage: "Enable debug mode")
}
Expand Down
22 changes: 12 additions & 10 deletions App/Commands/Search.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ struct ResultKeys {
static let Price = "price"
}

struct SearchCommand: CommandProtocol {
typealias Options = SearchOptions
let verb = "search"
let function = "Search for apps from the Mac App Store"
public struct SearchCommand: CommandProtocol {
public typealias Options = SearchOptions
public let verb = "search"
public let function = "Search for apps from the Mac App Store"

public init() {}

func run(_ options: Options) -> Result<(), MASError> {
public func run(_ options: Options) -> Result<(), MASError> {

guard let searchURLString = searchURLString(options.appName),
let searchJson = URLSession.requestSynchronousJSONWithURLString(searchURLString) as? [String: Any] else {
Expand Down Expand Up @@ -77,17 +79,17 @@ struct SearchCommand: CommandProtocol {
}
}

struct SearchOptions: OptionsProtocol {
public struct SearchOptions: OptionsProtocol {
let appName: String
let price: Bool
static func create(_ appName: String) -> (_ price: Bool) -> SearchOptions {

public static func create(_ appName: String) -> (_ price: Bool) -> SearchOptions {
return { price in
SearchOptions(appName: appName, price: price)
}
}
static func evaluate(_ m: CommandMode) -> Result<SearchOptions, CommandantError<MASError>> {

public static func evaluate(_ m: CommandMode) -> Result<SearchOptions, CommandantError<MASError>> {
return create
<*> m <| Argument(usage: "the app name to search")
<*> m <| Option(key: "price", defaultValue: false, usage: "Show price of found apps")
Expand Down
Loading