mirror of
https://github.com/mas-cli/mas
synced 2024-11-22 03:23:08 +00:00
Improve DocC.
Partial #592 Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
This commit is contained in:
parent
a100f3acd0
commit
3eaffa5c3e
22 changed files with 61 additions and 56 deletions
|
@ -12,11 +12,12 @@ import StoreFoundation
|
|||
|
||||
/// Downloads a list of apps, one after the other, printing progress to the console.
|
||||
///
|
||||
/// - Parameter appIDs: The IDs of the apps to be downloaded
|
||||
/// - Parameter purchase: Flag indicating whether the apps needs to be purchased.
|
||||
/// Only works for free apps. Defaults to false.
|
||||
/// - Parameters:
|
||||
/// - appIDs: The IDs of the apps to be downloaded
|
||||
/// - purchase: Flag indicating whether the apps needs to be purchased.
|
||||
/// 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.
|
||||
/// 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
|
||||
|
|
|
@ -10,8 +10,9 @@ import ArgumentParser
|
|||
import CommerceKit
|
||||
|
||||
extension Mas {
|
||||
/// Command which installs the first search result. This is handy as many MAS titles
|
||||
/// can be long with embedded keywords.
|
||||
/// Command which installs the first search result.
|
||||
///
|
||||
/// This is handy as many MAS titles can be long with embedded keywords.
|
||||
struct Lucky: ParsableCommand {
|
||||
static let configuration = CommandConfiguration(
|
||||
abstract: "Install the first result from the Mac App Store"
|
||||
|
@ -54,6 +55,7 @@ extension Mas {
|
|||
/// - Parameters:
|
||||
/// - appID: App identifier
|
||||
/// - appLibrary: Library of installed apps
|
||||
/// - Throws: Any error that occurs while attempting to install the app.
|
||||
fileprivate func install(appID: AppID, appLibrary: AppLibrary) throws {
|
||||
// Try to download applications with given identifiers and collect results
|
||||
if let product = appLibrary.installedApp(withAppID: appID), !force {
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
import ArgumentParser
|
||||
|
||||
extension Mas {
|
||||
/// Search the Mac App Store using the iTunes Search API:
|
||||
/// https://performance-partners.apple.com/search-api
|
||||
/// Search the Mac App Store using the iTunes Search API.
|
||||
///
|
||||
/// See - https://performance-partners.apple.com/search-api
|
||||
struct Search: ParsableCommand {
|
||||
static let configuration = CommandConfiguration(
|
||||
abstract: "Search for apps from the Mac App Store"
|
||||
|
|
|
@ -17,7 +17,7 @@ extension Mas {
|
|||
abstract: "Uninstall app installed from the Mac App Store"
|
||||
)
|
||||
|
||||
/// Flag indicating that removal shouldn't be performed
|
||||
/// Flag indicating that removal shouldn't be performed.
|
||||
@Flag(help: "dry run")
|
||||
var dryRun = false
|
||||
@Argument(help: "ID of app to uninstall")
|
||||
|
|
|
@ -13,10 +13,10 @@ protocol AppLibrary {
|
|||
/// Entire set of installed apps.
|
||||
var installedApps: [SoftwareProduct] { get }
|
||||
|
||||
/// Finds an app by ID.
|
||||
/// Finds an app for appID.
|
||||
///
|
||||
/// - Parameter withAppID: MAS ID for app.
|
||||
/// - Returns: Software Product of app if found; nil otherwise.
|
||||
/// - Parameter appID: app ID for app.
|
||||
/// - Returns: SoftwareProduct of app if found; nil otherwise.
|
||||
func installedApp(withAppID appID: AppID) -> SoftwareProduct?
|
||||
|
||||
/// Uninstalls an app.
|
||||
|
@ -28,10 +28,10 @@ protocol AppLibrary {
|
|||
|
||||
/// Common logic
|
||||
extension AppLibrary {
|
||||
/// Finds an app by ID.
|
||||
/// Finds an app for appID.
|
||||
///
|
||||
/// - Parameter withAppID: MAS ID for app.
|
||||
/// - Returns: Software Product of app if found; nil otherwise.
|
||||
/// - Parameter appID: app ID for app.
|
||||
/// - Returns: SoftwareProduct of app if found; nil otherwise.
|
||||
func installedApp(withAppID appID: AppID) -> SoftwareProduct? {
|
||||
let appID = NSNumber(value: appID)
|
||||
return installedApps.first { $0.itemIdentifier == appID }
|
||||
|
|
|
@ -34,9 +34,8 @@ class MasStoreSearch: StoreSearch {
|
|||
|
||||
/// Searches for an app.
|
||||
///
|
||||
/// - Parameter appName: MAS ID of app
|
||||
/// - Parameter completion: A closure that receives the search results or an Error if there is a
|
||||
/// problem with the network request. Results array will be empty if there were no matches.
|
||||
/// - Parameter searchTerm: a search term matched against app names
|
||||
/// - Returns: A Promise of an Array of SearchResults matching searchTerm
|
||||
func search(for appName: String) -> Promise<[SearchResult]> {
|
||||
// Search for apps for compatible platforms, in order of preference.
|
||||
// Macs with Apple Silicon can run iPad and iPhone apps.
|
||||
|
@ -115,11 +114,9 @@ class MasStoreSearch: StoreSearch {
|
|||
}
|
||||
}
|
||||
|
||||
// App Store pages indicate:
|
||||
// - compatibility with Macs with Apple Silicon
|
||||
// - (often) a version that is newer than what is listed in search results
|
||||
//
|
||||
// We attempt to scrape this information here.
|
||||
/// Scrape the app version from the App Store webpage at the given URL.
|
||||
///
|
||||
/// App Store webpages frequently report a version that is newer than what is reported by the iTunes Search API.
|
||||
private func scrapeAppStoreVersion(_ pageUrl: URL) -> Promise<Version?> {
|
||||
firstly {
|
||||
networkManager.loadData(from: pageUrl)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Copyright © 2020 mas-cli. All rights reserved.
|
||||
//
|
||||
|
||||
/// Somewhat analogous to CKSoftwareMap
|
||||
/// Somewhat analogous to CKSoftwareMap.
|
||||
protocol SoftwareMap {
|
||||
func allSoftwareProducts() -> [SoftwareProduct]
|
||||
func product(for bundleIdentifier: String) -> SoftwareProduct?
|
||||
|
|
|
@ -40,7 +40,10 @@ private enum URLAction {
|
|||
extension StoreSearch {
|
||||
/// Builds the search URL for an app.
|
||||
///
|
||||
/// - Parameter searchTerm: term for which to search in MAS.
|
||||
/// - Parameters:
|
||||
/// - searchTerm: term for which to search in MAS.
|
||||
/// - country: 2-letter ISO region code of the MAS in which to search.
|
||||
/// - entity: OS platform of apps for which to search.
|
||||
/// - Returns: URL for the search service or nil if searchTerm can't be encoded.
|
||||
func searchURL(
|
||||
for searchTerm: String,
|
||||
|
@ -52,7 +55,10 @@ extension StoreSearch {
|
|||
|
||||
/// Builds the lookup URL for an app.
|
||||
///
|
||||
/// - Parameter appID: MAS app identifier.
|
||||
/// - Parameters:
|
||||
/// - appID: MAS app identifier.
|
||||
/// - country: 2-letter ISO region code of the MAS in which to search.
|
||||
/// - entity: OS platform of apps for which to search.
|
||||
/// - Returns: URL for the lookup service or nil if appID can't be encoded.
|
||||
func lookupURL(
|
||||
forAppID appID: AppID,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
/// CLI command
|
||||
/// Represents a CLI command.
|
||||
protocol ExternalCommand {
|
||||
var binaryPath: String { get set }
|
||||
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
/// Wrapper for the external open system command.
|
||||
/// https://ss64.com/osx/open.html
|
||||
/// Wrapper for the external 'open' system command (https://ss64.com/osx/open.html).
|
||||
struct OpenSystemCommand: ExternalCommand {
|
||||
var binaryPath: String
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
/// Wrapper for the external sysctl system command.
|
||||
/// https://ss64.com/osx/sysctl.html
|
||||
/// Wrapper for the external 'sysctl' system command.
|
||||
///
|
||||
/// See - https://ss64.com/osx/sysctl.html
|
||||
struct SysCtlSystemCommand: ExternalCommand {
|
||||
var binaryPath: String
|
||||
|
||||
|
|
|
@ -10,9 +10,11 @@ import Foundation
|
|||
|
||||
/// Formats text output for the search command.
|
||||
enum SearchResultFormatter {
|
||||
/// Formats text output with search results.
|
||||
/// Formats search results as text.
|
||||
///
|
||||
/// - Parameter results: Search results with app data
|
||||
/// - Parameters:
|
||||
/// - results: Search results containing app data
|
||||
/// - includePrice: Indicates whether to include prices in the output
|
||||
/// - Returns: Multiline text output.
|
||||
static func format(results: [SearchResult], includePrice: Bool = false) -> String {
|
||||
// find longest appName for formatting, default 50
|
||||
|
|
|
@ -8,14 +8,15 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
/// A collection of output formatting helpers
|
||||
// A collection of output formatting helpers
|
||||
|
||||
/// Terminal Control Sequence Indicator
|
||||
/// Terminal Control Sequence Indicator.
|
||||
let csi = "\u{001B}["
|
||||
|
||||
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 }
|
||||
write(data)
|
||||
|
|
|
@ -19,12 +19,15 @@ protocol SoftwareProduct {
|
|||
}
|
||||
|
||||
extension SoftwareProduct {
|
||||
/// Returns bundleIdentifier if appName is empty string.
|
||||
/// - Returns: bundleIdentifier if appName is empty string.
|
||||
var appNameOrBundleIdentifier: String {
|
||||
appName.isEmpty ? bundleIdentifier : appName
|
||||
}
|
||||
|
||||
/// Determines whether the app is considered outdated. Updates that require a higher OS version are excluded.
|
||||
/// Determines whether the app is considered outdated.
|
||||
///
|
||||
/// Updates that require a higher OS version are excluded.
|
||||
///
|
||||
/// - Parameter storeApp: App from search result.
|
||||
/// - Returns: true if the app is outdated; false otherwise.
|
||||
func isOutdatedWhenComparedTo(_ storeApp: SearchResult) -> Bool {
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
import Foundation
|
||||
import PromiseKit
|
||||
|
||||
/// Network abstraction
|
||||
/// Network abstraction.
|
||||
class NetworkManager {
|
||||
private let session: NetworkSession
|
||||
|
||||
/// Designated initializer
|
||||
/// Designated initializer.
|
||||
///
|
||||
/// - Parameter session: A networking session.
|
||||
init(session: NetworkSession = URLSession(configuration: .ephemeral)) {
|
||||
|
@ -28,8 +28,7 @@ class NetworkManager {
|
|||
|
||||
/// Loads data asynchronously.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - url: URL to load data from.
|
||||
/// - Parameter url: URL from which to load data.
|
||||
/// - Returns: A Promise for the Data of the response.
|
||||
func loadData(from url: URL) -> Promise<Data> {
|
||||
session.loadData(from: url)
|
||||
|
|
|
@ -11,7 +11,7 @@ import Quick
|
|||
|
||||
@testable import mas
|
||||
|
||||
// Deprecated test
|
||||
/// Deprecated test.
|
||||
public class AccountSpec: QuickSpec {
|
||||
override public func spec() {
|
||||
beforeSuite {
|
||||
|
|
|
@ -11,7 +11,7 @@ import Quick
|
|||
|
||||
@testable import mas
|
||||
|
||||
// Deprecated test
|
||||
/// Deprecated test.
|
||||
public class SignInSpec: QuickSpec {
|
||||
override public func spec() {
|
||||
beforeSuite {
|
||||
|
|
|
@ -17,7 +17,9 @@ class MASErrorTestCase: XCTestCase {
|
|||
var nserror: NSError!
|
||||
|
||||
/// Convenience property for setting the value which will be use for the localized description
|
||||
/// value of the next NSError created. Only used when the NSError does not have a user info
|
||||
/// value of the next NSError created.
|
||||
///
|
||||
/// Only used when the NSError does not have a user info
|
||||
/// entry for localized description.
|
||||
var localizedDescription: String {
|
||||
get { "dummy value" }
|
||||
|
|
|
@ -10,7 +10,8 @@ import Foundation
|
|||
|
||||
extension Data {
|
||||
/// Unsafe initializer for loading data from string paths.
|
||||
/// - Parameter file: Relative path within the JSON folder
|
||||
///
|
||||
/// - Parameter fileName: Relative path within the JSON folder
|
||||
init(from fileName: String) {
|
||||
let fileURL = Bundle.url(for: fileName)!
|
||||
try! self.init(contentsOf: fileURL, options: .mappedIfSafe)
|
||||
|
|
|
@ -18,11 +18,6 @@ class NetworkSessionMock: NetworkSession {
|
|||
var data: Data?
|
||||
var error: Error?
|
||||
|
||||
/// Immediately passes data and error to completion handler.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - url: unused
|
||||
/// - completionHandler: Closure which is delivered either data or an error.
|
||||
func loadData(from _: URL) -> Promise<Data> {
|
||||
guard let data else {
|
||||
return Promise(error: error ?? MASError.noData)
|
||||
|
|
|
@ -21,11 +21,6 @@ class NetworkSessionMockFromFile: NetworkSessionMock {
|
|||
self.responseFile = responseFile
|
||||
}
|
||||
|
||||
/// Loads data from a file.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - url: unused
|
||||
/// - completionHandler: Closure which is delivered either data or an error.
|
||||
override func loadData(from _: URL) -> Promise<Data> {
|
||||
guard let fileURL = Bundle.url(for: responseFile)
|
||||
else { fatalError("Unable to load file \(responseFile)") }
|
||||
|
|
|
@ -20,7 +20,7 @@ VERSION=$(git describe --abbrev=0 --tags)
|
|||
VERSION=${VERSION#v}
|
||||
|
||||
cat <<EOF >"Sources/mas/Package.swift"
|
||||
// Generated by: script/version
|
||||
/// Generated by \`script/version\`.
|
||||
enum Package {
|
||||
static let version = "${VERSION}"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue