Skip to content

Commit

Permalink
Merge pull request #175 from mas-cli/maskit
Browse files Browse the repository at this point in the history
🧰 MasKit Framework
  • Loading branch information
phatblat authored Oct 15, 2018
2 parents c1199d6 + 1a0d4a6 commit 6cfd520
Show file tree
Hide file tree
Showing 63 changed files with 937 additions and 405 deletions.
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

0 comments on commit 6cfd520

Please sign in to comment.