mirror of
https://github.com/mas-cli/mas
synced 2024-11-21 19:23:01 +00:00
Switch to using CocoaSeeds for imports
This commit is contained in:
parent
634df01958
commit
d9a5baa7e6
18 changed files with 114 additions and 1275 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -69,4 +69,4 @@ Network Trash Folder
|
||||||
Temporary Items
|
Temporary Items
|
||||||
.apdisk
|
.apdisk
|
||||||
|
|
||||||
|
Seeds/
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright (c) 2014 Rob Rix. All rights reserved.
|
|
||||||
|
|
||||||
/// Wraps a type `T` in a reference type.
|
|
||||||
///
|
|
||||||
/// Typically this is used to work around limitations of value types (for example, the lack of codegen for recursive value types and type-parameterized enums with >1 case). It is also useful for sharing a single (presumably large) value without copying it.
|
|
||||||
public final class Box<T>: BoxType, Printable {
|
|
||||||
/// Initializes a `Box` with the given value.
|
|
||||||
public init(_ value: T) {
|
|
||||||
self.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Constructs a `Box` with the given `value`.
|
|
||||||
public class func unit(value: T) -> Box<T> {
|
|
||||||
return Box(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// The (immutable) value wrapped by the receiver.
|
|
||||||
public let value: T
|
|
||||||
|
|
||||||
/// Constructs a new Box by transforming `value` by `f`.
|
|
||||||
public func map<U>(@noescape f: T -> U) -> Box<U> {
|
|
||||||
return Box<U>(f(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Printable
|
|
||||||
|
|
||||||
public var description: String {
|
|
||||||
return toString(value)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
// Copyright (c) 2014 Rob Rix. All rights reserved.
|
|
||||||
|
|
||||||
// MARK: BoxType
|
|
||||||
|
|
||||||
/// The type conformed to by all boxes.
|
|
||||||
public protocol BoxType {
|
|
||||||
/// The type of the wrapped value.
|
|
||||||
typealias Value
|
|
||||||
|
|
||||||
/// Initializes an intance of the type with a value.
|
|
||||||
init(_ value: Value)
|
|
||||||
|
|
||||||
/// The wrapped value.
|
|
||||||
var value: Value { get }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The type conformed to by mutable boxes.
|
|
||||||
public protocol MutableBoxType: BoxType {
|
|
||||||
/// The (mutable) wrapped value.
|
|
||||||
var value: Value { get set }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Equality
|
|
||||||
|
|
||||||
/// Equality of `BoxType`s of `Equatable` types.
|
|
||||||
///
|
|
||||||
/// We cannot declare that e.g. `Box<T: Equatable>` conforms to `Equatable`, so this is a relatively ad hoc definition.
|
|
||||||
public func == <B: BoxType where B.Value: Equatable> (lhs: B, rhs: B) -> Bool {
|
|
||||||
return lhs.value == rhs.value
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inequality of `BoxType`s of `Equatable` types.
|
|
||||||
///
|
|
||||||
/// We cannot declare that e.g. `Box<T: Equatable>` conforms to `Equatable`, so this is a relatively ad hoc definition.
|
|
||||||
public func != <B: BoxType where B.Value: Equatable> (lhs: B, rhs: B) -> Bool {
|
|
||||||
return lhs.value != rhs.value
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Map
|
|
||||||
|
|
||||||
/// Maps the value of a box into a new box.
|
|
||||||
public func map<B: BoxType, C: BoxType>(v: B, @noescape f: B.Value -> C.Value) -> C {
|
|
||||||
return C(f(v.value))
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
// Copyright (c) 2014 Rob Rix. All rights reserved.
|
|
||||||
|
|
||||||
/// Wraps a type `T` in a mutable reference type.
|
|
||||||
///
|
|
||||||
/// While this, like `Box<T>` could be used to work around limitations of value types, it is much more useful for sharing a single mutable value such that mutations are shared.
|
|
||||||
///
|
|
||||||
/// As with all mutable state, this should be used carefully, for example as an optimization, rather than a default design choice. Most of the time, `Box<T>` will suffice where any `BoxType` is needed.
|
|
||||||
public final class MutableBox<T>: MutableBoxType, Printable {
|
|
||||||
/// Initializes a `MutableBox` with the given value.
|
|
||||||
public init(_ value: T) {
|
|
||||||
self.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The (mutable) value wrapped by the receiver.
|
|
||||||
public var value: T
|
|
||||||
|
|
||||||
/// Constructs a new MutableBox by transforming `value` by `f`.
|
|
||||||
public func map<U>(@noescape f: T -> U) -> MutableBox<U> {
|
|
||||||
return MutableBox<U>(f(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Printable
|
|
||||||
|
|
||||||
public var description: String {
|
|
||||||
return toString(value)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,189 +0,0 @@
|
||||||
//
|
|
||||||
// ArgumentParser.swift
|
|
||||||
// Commandant
|
|
||||||
//
|
|
||||||
// Created by Justin Spahr-Summers on 2014-11-21.
|
|
||||||
// Copyright (c) 2014 Carthage. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
/// Represents an argument passed on the command line.
|
|
||||||
private enum RawArgument: Equatable {
|
|
||||||
/// A key corresponding to an option (e.g., `verbose` for `--verbose`).
|
|
||||||
case Key(String)
|
|
||||||
|
|
||||||
/// A value, either associated with an option or passed as a positional
|
|
||||||
/// argument.
|
|
||||||
case Value(String)
|
|
||||||
|
|
||||||
/// One or more flag arguments (e.g 'r' and 'f' for `-rf`)
|
|
||||||
case Flag(Set<Character>)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func ==(lhs: RawArgument, rhs: RawArgument) -> Bool {
|
|
||||||
switch (lhs, rhs) {
|
|
||||||
case let (.Key(left), .Key(right)):
|
|
||||||
return left == right
|
|
||||||
|
|
||||||
case let (.Value(left), .Value(right)):
|
|
||||||
return left == right
|
|
||||||
|
|
||||||
case let (.Flag(left), .Flag(right)):
|
|
||||||
return left == right
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension RawArgument: Printable {
|
|
||||||
private var description: String {
|
|
||||||
switch self {
|
|
||||||
case let .Key(key):
|
|
||||||
return "--\(key)"
|
|
||||||
|
|
||||||
case let .Value(value):
|
|
||||||
return "\"\(value)\""
|
|
||||||
|
|
||||||
case let .Flag(flags):
|
|
||||||
return "-\(String(flags))"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Destructively parses a list of command-line arguments.
|
|
||||||
public final class ArgumentParser {
|
|
||||||
/// The remaining arguments to be extracted, in their raw form.
|
|
||||||
private var rawArguments: [RawArgument] = []
|
|
||||||
|
|
||||||
/// Initializes the generator from a simple list of command-line arguments.
|
|
||||||
public init(_ arguments: [String]) {
|
|
||||||
// The first instance of `--` terminates the option list.
|
|
||||||
let params = split(arguments, maxSplit: 1, allowEmptySlices: true) { $0 == "--" }
|
|
||||||
|
|
||||||
// Parse out the keyed and flag options.
|
|
||||||
let options = params.first!
|
|
||||||
rawArguments.extend(options.map { arg in
|
|
||||||
if arg.hasPrefix("-") {
|
|
||||||
// Do we have `--{key}` or `-{flags}`.
|
|
||||||
var opt = dropFirst(arg)
|
|
||||||
return opt.hasPrefix("-") ? .Key(dropFirst(opt)) : .Flag(Set(opt))
|
|
||||||
} else {
|
|
||||||
return .Value(arg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Remaining arguments are all positional parameters.
|
|
||||||
if params.count == 2 {
|
|
||||||
let positional = params.last!
|
|
||||||
rawArguments.extend(positional.map { .Value($0) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the given key was enabled or disabled, or nil if it
|
|
||||||
/// was not given at all.
|
|
||||||
///
|
|
||||||
/// If the key is found, it is then removed from the list of arguments
|
|
||||||
/// remaining to be parsed.
|
|
||||||
internal func consumeBooleanKey(key: String) -> Bool? {
|
|
||||||
let oldArguments = rawArguments
|
|
||||||
rawArguments.removeAll()
|
|
||||||
|
|
||||||
var result: Bool?
|
|
||||||
for arg in oldArguments {
|
|
||||||
if arg == .Key(key) {
|
|
||||||
result = true
|
|
||||||
} else if arg == .Key("no-\(key)") {
|
|
||||||
result = false
|
|
||||||
} else {
|
|
||||||
rawArguments.append(arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the value associated with the given flag, or nil if the flag was
|
|
||||||
/// not specified. If the key is presented, but no value was given, an error
|
|
||||||
/// is returned.
|
|
||||||
///
|
|
||||||
/// If a value is found, the key and the value are both removed from the
|
|
||||||
/// list of arguments remaining to be parsed.
|
|
||||||
internal func consumeValueForKey(key: String) -> Result<String?, CommandantError<NoError>> {
|
|
||||||
let oldArguments = rawArguments
|
|
||||||
rawArguments.removeAll()
|
|
||||||
|
|
||||||
var foundValue: String?
|
|
||||||
argumentLoop: for var index = 0; index < oldArguments.count; index++ {
|
|
||||||
let arg = oldArguments[index]
|
|
||||||
|
|
||||||
if arg == .Key(key) {
|
|
||||||
if ++index < oldArguments.count {
|
|
||||||
switch oldArguments[index] {
|
|
||||||
case let .Value(value):
|
|
||||||
foundValue = value
|
|
||||||
continue argumentLoop
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return .failure(missingArgumentError("--\(key)"))
|
|
||||||
} else {
|
|
||||||
rawArguments.append(arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return .success(foundValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the next positional argument that hasn't yet been returned, or
|
|
||||||
/// nil if there are no more positional arguments.
|
|
||||||
internal func consumePositionalArgument() -> String? {
|
|
||||||
for var index = 0; index < rawArguments.count; index++ {
|
|
||||||
switch rawArguments[index] {
|
|
||||||
case let .Value(value):
|
|
||||||
rawArguments.removeAtIndex(index)
|
|
||||||
return value
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the given key was specified and removes it from the
|
|
||||||
/// list of arguments remaining.
|
|
||||||
internal func consumeKey(key: String) -> Bool {
|
|
||||||
let oldArguments = rawArguments
|
|
||||||
rawArguments = oldArguments.filter { $0 != .Key(key) }
|
|
||||||
|
|
||||||
return rawArguments.count < oldArguments.count
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the given flag was specified and removes it from the
|
|
||||||
/// list of arguments remaining.
|
|
||||||
internal func consumeBooleanFlag(flag: Character) -> Bool {
|
|
||||||
for (index, arg) in enumerate(rawArguments) {
|
|
||||||
switch arg {
|
|
||||||
case var .Flag(flags) where flags.contains(flag):
|
|
||||||
flags.remove(flag)
|
|
||||||
if flags.isEmpty {
|
|
||||||
rawArguments.removeAtIndex(index)
|
|
||||||
} else {
|
|
||||||
rawArguments[index] = .Flag(flags)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,137 +0,0 @@
|
||||||
//
|
|
||||||
// Command.swift
|
|
||||||
// Commandant
|
|
||||||
//
|
|
||||||
// Created by Justin Spahr-Summers on 2014-10-10.
|
|
||||||
// Copyright (c) 2014 Carthage. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
/// Represents a subcommand that can be executed with its own set of arguments.
|
|
||||||
public protocol CommandType {
|
|
||||||
typealias ClientError
|
|
||||||
|
|
||||||
/// The action that users should specify to use this subcommand (e.g.,
|
|
||||||
/// `help`).
|
|
||||||
var verb: String { get }
|
|
||||||
|
|
||||||
/// A human-readable, high-level description of what this command is used
|
|
||||||
/// for.
|
|
||||||
var function: String { get }
|
|
||||||
|
|
||||||
/// Runs this subcommand in the given mode.
|
|
||||||
func run(mode: CommandMode) -> Result<(), CommandantError<ClientError>>
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type-erased CommandType.
|
|
||||||
public struct CommandOf<ClientError>: CommandType {
|
|
||||||
public let verb: String
|
|
||||||
public let function: String
|
|
||||||
private let runClosure: CommandMode -> Result<(), CommandantError<ClientError>>
|
|
||||||
|
|
||||||
/// Creates a command that wraps another.
|
|
||||||
public init<C: CommandType where C.ClientError == ClientError>(_ command: C) {
|
|
||||||
verb = command.verb
|
|
||||||
function = command.function
|
|
||||||
runClosure = { mode in command.run(mode) }
|
|
||||||
}
|
|
||||||
|
|
||||||
public func run(mode: CommandMode) -> Result<(), CommandantError<ClientError>> {
|
|
||||||
return runClosure(mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Describes the "mode" in which a command should run.
|
|
||||||
public enum CommandMode {
|
|
||||||
/// Options should be parsed from the given command-line arguments.
|
|
||||||
case Arguments(ArgumentParser)
|
|
||||||
|
|
||||||
/// Each option should record its usage information in an error, for
|
|
||||||
/// presentation to the user.
|
|
||||||
case Usage
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Maintains the list of commands available to run.
|
|
||||||
public final class CommandRegistry<ClientError> {
|
|
||||||
private var commandsByVerb: [String: CommandOf<ClientError>] = [:]
|
|
||||||
|
|
||||||
/// All available commands.
|
|
||||||
public var commands: [CommandOf<ClientError>] {
|
|
||||||
return sorted(commandsByVerb.values) { return $0.verb < $1.verb }
|
|
||||||
}
|
|
||||||
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
/// Registers the given command, making it available to run.
|
|
||||||
///
|
|
||||||
/// If another command was already registered with the same `verb`, it will
|
|
||||||
/// be overwritten.
|
|
||||||
public func register<C: CommandType where C.ClientError == ClientError>(command: C) {
|
|
||||||
commandsByVerb[command.verb] = CommandOf(command)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs the command corresponding to the given verb, passing it the given
|
|
||||||
/// arguments.
|
|
||||||
///
|
|
||||||
/// Returns the results of the execution, or nil if no such command exists.
|
|
||||||
public func runCommand(verb: String, arguments: [String]) -> Result<(), CommandantError<ClientError>>? {
|
|
||||||
return self[verb]?.run(.Arguments(ArgumentParser(arguments)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the command matching the given verb, or nil if no such command
|
|
||||||
/// is registered.
|
|
||||||
public subscript(verb: String) -> CommandOf<ClientError>? {
|
|
||||||
return commandsByVerb[verb]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension CommandRegistry {
|
|
||||||
/// Hands off execution to the CommandRegistry, by parsing Process.arguments
|
|
||||||
/// and then running whichever command has been identified in the argument
|
|
||||||
/// list.
|
|
||||||
///
|
|
||||||
/// If the chosen command executes successfully, the process will exit with
|
|
||||||
/// a successful exit code.
|
|
||||||
///
|
|
||||||
/// If the chosen command fails, the provided error handler will be invoked,
|
|
||||||
/// then the process will exit with a failure exit code.
|
|
||||||
///
|
|
||||||
/// If a matching command could not be found or a usage error occurred,
|
|
||||||
/// a helpful error message will be written to `stderr`, then the process
|
|
||||||
/// will exit with a failure error code.
|
|
||||||
@noreturn public func main(#defaultVerb: String, errorHandler: ClientError -> ()) {
|
|
||||||
var arguments = Process.arguments
|
|
||||||
assert(arguments.count >= 1)
|
|
||||||
|
|
||||||
// Extract the executable name.
|
|
||||||
let executableName = arguments.first!
|
|
||||||
arguments.removeAtIndex(0)
|
|
||||||
|
|
||||||
let verb = arguments.first ?? defaultVerb
|
|
||||||
if arguments.count > 0 {
|
|
||||||
// Remove the command name.
|
|
||||||
arguments.removeAtIndex(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch runCommand(verb, arguments: arguments) {
|
|
||||||
case .Some(.Success):
|
|
||||||
exit(EXIT_SUCCESS)
|
|
||||||
|
|
||||||
case let .Some(.Failure(error)):
|
|
||||||
switch error.value {
|
|
||||||
case let .UsageError(description):
|
|
||||||
fputs(description + "\n", stderr)
|
|
||||||
|
|
||||||
case let .CommandError(error):
|
|
||||||
errorHandler(error.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(EXIT_FAILURE)
|
|
||||||
|
|
||||||
case .None:
|
|
||||||
fputs("Unrecognized command: '\(verb)'. See `\(executableName) help`.\n", stderr)
|
|
||||||
exit(EXIT_FAILURE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
//
|
|
||||||
// Commandant.h
|
|
||||||
// Commandant
|
|
||||||
//
|
|
||||||
// Created by Justin Spahr-Summers on 2014-11-21.
|
|
||||||
// Copyright (c) 2014 Carthage. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
//! Project version number for Commandant.
|
|
||||||
FOUNDATION_EXPORT double CommandantVersionNumber;
|
|
||||||
|
|
||||||
//! Project version string for Commandant.
|
|
||||||
FOUNDATION_EXPORT const unsigned char CommandantVersionString[];
|
|
||||||
|
|
||||||
// In this header, you should import all the public headers of your framework using statements like #import <Commandant/PublicHeader.h>
|
|
|
@ -1,114 +0,0 @@
|
||||||
//
|
|
||||||
// Errors.swift
|
|
||||||
// Commandant
|
|
||||||
//
|
|
||||||
// Created by Justin Spahr-Summers on 2014-10-24.
|
|
||||||
// Copyright (c) 2014 Carthage. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
/// Possible errors that can originate from Commandant.
|
|
||||||
///
|
|
||||||
/// `ClientError` should be the type of error (if any) that can occur when
|
|
||||||
/// running commands.
|
|
||||||
public enum CommandantError<ClientError> {
|
|
||||||
/// An option was used incorrectly.
|
|
||||||
case UsageError(description: String)
|
|
||||||
|
|
||||||
/// An error occurred while running a command.
|
|
||||||
case CommandError(Box<ClientError>)
|
|
||||||
}
|
|
||||||
|
|
||||||
extension CommandantError: Printable {
|
|
||||||
public var description: String {
|
|
||||||
switch self {
|
|
||||||
case let .UsageError(description):
|
|
||||||
return description
|
|
||||||
|
|
||||||
case let .CommandError(error):
|
|
||||||
return toString(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used to represent that a ClientError will never occur.
|
|
||||||
internal enum NoError {}
|
|
||||||
|
|
||||||
/// Constructs an `InvalidArgument` error that indicates a missing value for
|
|
||||||
/// the argument by the given name.
|
|
||||||
internal func missingArgumentError<ClientError>(argumentName: String) -> CommandantError<ClientError> {
|
|
||||||
let description = "Missing argument for \(argumentName)"
|
|
||||||
return .UsageError(description: description)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs an error by combining the example of key (and value, if applicable)
|
|
||||||
/// with the usage description.
|
|
||||||
internal func informativeUsageError<ClientError>(keyValueExample: String, usage: String) -> CommandantError<ClientError> {
|
|
||||||
let lines = usage.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
|
|
||||||
|
|
||||||
return .UsageError(description: reduce(lines, keyValueExample) { previous, value in
|
|
||||||
return previous + "\n\t" + value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs an error that describes how to use the option, with the given
|
|
||||||
/// example of key (and value, if applicable) usage.
|
|
||||||
internal func informativeUsageError<T, ClientError>(keyValueExample: String, option: Option<T>) -> CommandantError<ClientError> {
|
|
||||||
if option.defaultValue != nil {
|
|
||||||
return informativeUsageError("[\(keyValueExample)]", option.usage)
|
|
||||||
} else {
|
|
||||||
return informativeUsageError(keyValueExample, option.usage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs an error that describes how to use the option.
|
|
||||||
internal func informativeUsageError<T: ArgumentType, ClientError>(option: Option<T>) -> CommandantError<ClientError> {
|
|
||||||
var example = ""
|
|
||||||
|
|
||||||
if let key = option.key {
|
|
||||||
example += "--\(key) "
|
|
||||||
}
|
|
||||||
|
|
||||||
var valueExample = ""
|
|
||||||
if let defaultValue = option.defaultValue {
|
|
||||||
valueExample = "\(defaultValue)"
|
|
||||||
}
|
|
||||||
|
|
||||||
if valueExample.isEmpty {
|
|
||||||
example += "(\(T.name))"
|
|
||||||
} else {
|
|
||||||
example += valueExample
|
|
||||||
}
|
|
||||||
|
|
||||||
return informativeUsageError(example, option)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs an error that describes how to use the given boolean option.
|
|
||||||
internal func informativeUsageError<ClientError>(option: Option<Bool>) -> CommandantError<ClientError> {
|
|
||||||
precondition(option.key != nil)
|
|
||||||
|
|
||||||
let key = option.key!
|
|
||||||
|
|
||||||
if let defaultValue = option.defaultValue {
|
|
||||||
return informativeUsageError((defaultValue ? "--no-\(key)" : "--\(key)"), option)
|
|
||||||
} else {
|
|
||||||
return informativeUsageError("--(no-)\(key)", option)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Combines the text of the two errors, if they're both `UsageError`s.
|
|
||||||
/// Otherwise, uses whichever one is not (biased toward the left).
|
|
||||||
internal func combineUsageErrors<ClientError>(lhs: CommandantError<ClientError>, rhs: CommandantError<ClientError>) -> CommandantError<ClientError> {
|
|
||||||
switch (lhs, rhs) {
|
|
||||||
case let (.UsageError(left), .UsageError(right)):
|
|
||||||
let combinedDescription = "\(left)\n\n\(right)"
|
|
||||||
return .UsageError(description: combinedDescription)
|
|
||||||
|
|
||||||
case (.UsageError, _):
|
|
||||||
return rhs
|
|
||||||
|
|
||||||
case (_, .UsageError), (_, _):
|
|
||||||
return lhs
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
//
|
|
||||||
// HelpCommand.swift
|
|
||||||
// Commandant
|
|
||||||
//
|
|
||||||
// Created by Justin Spahr-Summers on 2014-10-10.
|
|
||||||
// Copyright (c) 2014 Carthage. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
/// A basic implementation of a `help` command, using information available in a
|
|
||||||
/// `CommandRegistry`.
|
|
||||||
///
|
|
||||||
/// If you want to use this command, initialize it with the registry, then add
|
|
||||||
/// it to that same registry:
|
|
||||||
///
|
|
||||||
/// let commands: CommandRegistry<MyErrorType> = …
|
|
||||||
/// let helpCommand = HelpCommand(registry: commands)
|
|
||||||
/// commands.register(helpCommand)
|
|
||||||
public struct HelpCommand<ClientError>: CommandType {
|
|
||||||
public let verb = "help"
|
|
||||||
public let function = "Display general or command-specific help"
|
|
||||||
|
|
||||||
private let registry: CommandRegistry<ClientError>
|
|
||||||
|
|
||||||
/// Initializes the command to provide help from the given registry of
|
|
||||||
/// commands.
|
|
||||||
public init(registry: CommandRegistry<ClientError>) {
|
|
||||||
self.registry = registry
|
|
||||||
}
|
|
||||||
|
|
||||||
public func run(mode: CommandMode) -> Result<(), CommandantError<ClientError>> {
|
|
||||||
return HelpOptions<ClientError>.evaluate(mode)
|
|
||||||
.flatMap { options in
|
|
||||||
if let verb = options.verb {
|
|
||||||
if let command = self.registry[verb] {
|
|
||||||
println(command.function)
|
|
||||||
println()
|
|
||||||
return command.run(.Usage)
|
|
||||||
} else {
|
|
||||||
fputs("Unrecognized command: '\(verb)'\n", stderr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Available commands:\n")
|
|
||||||
|
|
||||||
let maxVerbLength = maxElement(self.registry.commands.map { count($0.verb) })
|
|
||||||
|
|
||||||
for command in self.registry.commands {
|
|
||||||
let padding = Repeat<Character>(count: maxVerbLength - count(command.verb), repeatedValue: " ")
|
|
||||||
|
|
||||||
var formattedVerb = command.verb
|
|
||||||
formattedVerb.extend(padding)
|
|
||||||
|
|
||||||
println(" \(formattedVerb) \(command.function)")
|
|
||||||
}
|
|
||||||
|
|
||||||
return .success(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct HelpOptions<ClientError>: OptionsType {
|
|
||||||
let verb: String?
|
|
||||||
|
|
||||||
init(verb: String?) {
|
|
||||||
self.verb = verb
|
|
||||||
}
|
|
||||||
|
|
||||||
static func create(verb: String) -> HelpOptions {
|
|
||||||
return self(verb: (verb == "" ? nil : verb))
|
|
||||||
}
|
|
||||||
|
|
||||||
static func evaluate(m: CommandMode) -> Result<HelpOptions, CommandantError<ClientError>> {
|
|
||||||
return create
|
|
||||||
<*> m <| Option(defaultValue: "", usage: "the command to display help for")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>en</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>org.carthage.$(PRODUCT_NAME:rfc1034identifier)</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>$(PRODUCT_NAME)</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>FMWK</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>0.6.1</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
||||||
<key>NSHumanReadableCopyright</key>
|
|
||||||
<string>Copyright © 2014 Carthage. All rights reserved.</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
|
||||||
<string></string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -1,246 +0,0 @@
|
||||||
//
|
|
||||||
// Option.swift
|
|
||||||
// Commandant
|
|
||||||
//
|
|
||||||
// Created by Justin Spahr-Summers on 2014-11-21.
|
|
||||||
// Copyright (c) 2014 Carthage. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
/// Represents a record of options for a command, which can be parsed from
|
|
||||||
/// a list of command-line arguments.
|
|
||||||
///
|
|
||||||
/// This is most helpful when used in conjunction with the `Option` and `Switch`
|
|
||||||
/// types, and `<*>` and `<|` combinators.
|
|
||||||
///
|
|
||||||
/// Example:
|
|
||||||
///
|
|
||||||
/// struct LogOptions: OptionsType {
|
|
||||||
/// let verbosity: Int
|
|
||||||
/// let outputFilename: String
|
|
||||||
/// let logName: String
|
|
||||||
///
|
|
||||||
/// static func create(verbosity: Int)(outputFilename: String)(logName: String) -> LogOptions {
|
|
||||||
/// return LogOptions(verbosity: verbosity, outputFilename: outputFilename, logName: logName)
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// static func evaluate(m: CommandMode) -> Result<LogOptions> {
|
|
||||||
/// return create
|
|
||||||
/// <*> m <| Option(key: "verbose", defaultValue: 0, usage: "the verbosity level with which to read the logs")
|
|
||||||
/// <*> m <| Option(key: "outputFilename", defaultValue: "", usage: "a file to print output to, instead of stdout")
|
|
||||||
/// <*> m <| Switch(flag: "d", key: "delete", defaultValue: false, usage: "delete the logs when finished")
|
|
||||||
/// <*> m <| Option(usage: "the log to read")
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
public protocol OptionsType {
|
|
||||||
typealias ClientError
|
|
||||||
|
|
||||||
/// Evaluates this set of options in the given mode.
|
|
||||||
///
|
|
||||||
/// Returns the parsed options or a `UsageError`.
|
|
||||||
static func evaluate(m: CommandMode) -> Result<Self, CommandantError<ClientError>>
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Describes an option that can be provided on the command line.
|
|
||||||
public struct Option<T> {
|
|
||||||
/// The key that controls this option. For example, a key of `verbose` would
|
|
||||||
/// be used for a `--verbose` option.
|
|
||||||
///
|
|
||||||
/// If this is nil, this option will not have a corresponding flag, and must
|
|
||||||
/// be specified as a plain value at the end of the argument list.
|
|
||||||
///
|
|
||||||
/// This must be non-nil for a boolean option.
|
|
||||||
public let key: String?
|
|
||||||
|
|
||||||
/// The default value for this option. This is the value that will be used
|
|
||||||
/// if the option is never explicitly specified on the command line.
|
|
||||||
///
|
|
||||||
/// If this is nil, this option is always required.
|
|
||||||
public let defaultValue: T?
|
|
||||||
|
|
||||||
/// A human-readable string describing the purpose of this option. This will
|
|
||||||
/// be shown in help messages.
|
|
||||||
///
|
|
||||||
/// For boolean operations, this should describe the effect of _not_ using
|
|
||||||
/// the default value (i.e., what will happen if you disable/enable the flag
|
|
||||||
/// differently from the default).
|
|
||||||
public let usage: String
|
|
||||||
|
|
||||||
public init(key: String? = nil, defaultValue: T? = nil, usage: String) {
|
|
||||||
self.key = key
|
|
||||||
self.defaultValue = defaultValue
|
|
||||||
self.usage = usage
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs an `InvalidArgument` error that describes how the option was
|
|
||||||
/// used incorrectly. `value` should be the invalid value given by the user.
|
|
||||||
private func invalidUsageError<ClientError>(value: String) -> CommandantError<ClientError> {
|
|
||||||
let description = "Invalid value for '\(self)': \(value)"
|
|
||||||
return .UsageError(description: description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Option: Printable {
|
|
||||||
public var description: String {
|
|
||||||
if let key = key {
|
|
||||||
return "--\(key)"
|
|
||||||
} else {
|
|
||||||
return usage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a value that can be converted from a command-line argument.
|
|
||||||
public protocol ArgumentType {
|
|
||||||
/// A human-readable name for this type.
|
|
||||||
static var name: String { get }
|
|
||||||
|
|
||||||
/// Attempts to parse a value from the given command-line argument.
|
|
||||||
static func fromString(string: String) -> Self?
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Int: ArgumentType {
|
|
||||||
public static let name = "integer"
|
|
||||||
|
|
||||||
public static func fromString(string: String) -> Int? {
|
|
||||||
return string.toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension String: ArgumentType {
|
|
||||||
public static let name = "string"
|
|
||||||
|
|
||||||
public static func fromString(string: String) -> String? {
|
|
||||||
return string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inspired by the Argo library:
|
|
||||||
// https://github.com/thoughtbot/Argo
|
|
||||||
/*
|
|
||||||
Copyright (c) 2014 thoughtbot, inc.
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
infix operator <*> {
|
|
||||||
associativity left
|
|
||||||
}
|
|
||||||
|
|
||||||
infix operator <| {
|
|
||||||
associativity left
|
|
||||||
precedence 150
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Applies `f` to the value in the given result.
|
|
||||||
///
|
|
||||||
/// In the context of command-line option parsing, this is used to chain
|
|
||||||
/// together the parsing of multiple arguments. See OptionsType for an example.
|
|
||||||
public func <*> <T, U, ClientError>(f: T -> U, value: Result<T, CommandantError<ClientError>>) -> Result<U, CommandantError<ClientError>> {
|
|
||||||
return value.map(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Applies the function in `f` to the value in the given result.
|
|
||||||
///
|
|
||||||
/// In the context of command-line option parsing, this is used to chain
|
|
||||||
/// together the parsing of multiple arguments. See OptionsType for an example.
|
|
||||||
public func <*> <T, U, ClientError>(f: Result<(T -> U), CommandantError<ClientError>>, value: Result<T, CommandantError<ClientError>>) -> Result<U, CommandantError<ClientError>> {
|
|
||||||
switch (f, value) {
|
|
||||||
case let (.Failure(left), .Failure(right)):
|
|
||||||
return .failure(combineUsageErrors(left.value, right.value))
|
|
||||||
|
|
||||||
case let (.Failure(left), .Success):
|
|
||||||
return .failure(left.value)
|
|
||||||
|
|
||||||
case let (.Success, .Failure(right)):
|
|
||||||
return .failure(right.value)
|
|
||||||
|
|
||||||
case let (.Success(f), .Success(value)):
|
|
||||||
let newValue = f.value(value.value)
|
|
||||||
return .success(newValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluates the given option in the given mode.
|
|
||||||
///
|
|
||||||
/// If parsing command line arguments, and no value was specified on the command
|
|
||||||
/// line, the option's `defaultValue` is used.
|
|
||||||
public func <| <T: ArgumentType, ClientError>(mode: CommandMode, option: Option<T>) -> Result<T, CommandantError<ClientError>> {
|
|
||||||
switch mode {
|
|
||||||
case let .Arguments(arguments):
|
|
||||||
var stringValue: String?
|
|
||||||
if let key = option.key {
|
|
||||||
switch arguments.consumeValueForKey(key) {
|
|
||||||
case let .Success(value):
|
|
||||||
stringValue = value.value
|
|
||||||
|
|
||||||
case let .Failure(error):
|
|
||||||
switch error.value {
|
|
||||||
case let .UsageError(description):
|
|
||||||
return .failure(.UsageError(description: description))
|
|
||||||
|
|
||||||
case .CommandError:
|
|
||||||
fatalError("CommandError should be impossible when parameterized over NoError")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stringValue = arguments.consumePositionalArgument()
|
|
||||||
}
|
|
||||||
|
|
||||||
if let stringValue = stringValue {
|
|
||||||
if let value = T.fromString(stringValue) {
|
|
||||||
return .success(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return .failure(option.invalidUsageError(stringValue))
|
|
||||||
} else if let defaultValue = option.defaultValue {
|
|
||||||
return .success(defaultValue)
|
|
||||||
} else {
|
|
||||||
return .failure(missingArgumentError(option.description))
|
|
||||||
}
|
|
||||||
|
|
||||||
case .Usage:
|
|
||||||
return .failure(informativeUsageError(option))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluates the given boolean option in the given mode.
|
|
||||||
///
|
|
||||||
/// If parsing command line arguments, and no value was specified on the command
|
|
||||||
/// line, the option's `defaultValue` is used.
|
|
||||||
public func <| <ClientError>(mode: CommandMode, option: Option<Bool>) -> Result<Bool, CommandantError<ClientError>> {
|
|
||||||
precondition(option.key != nil)
|
|
||||||
|
|
||||||
switch mode {
|
|
||||||
case let .Arguments(arguments):
|
|
||||||
if let value = arguments.consumeBooleanKey(option.key!) {
|
|
||||||
return .success(value)
|
|
||||||
} else if let defaultValue = option.defaultValue {
|
|
||||||
return .success(defaultValue)
|
|
||||||
} else {
|
|
||||||
return .failure(missingArgumentError(option.description))
|
|
||||||
}
|
|
||||||
|
|
||||||
case .Usage:
|
|
||||||
return .failure(informativeUsageError(option))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
//
|
|
||||||
// Switch.swift
|
|
||||||
// Commandant
|
|
||||||
//
|
|
||||||
// Created by Neil Pankey on 3/31/15.
|
|
||||||
// Copyright (c) 2015 Carthage. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
/// Describes a parameterless command line flag that defaults to false and can only
|
|
||||||
/// be switched on. Canonical examples include `--force` and `--recurse`.
|
|
||||||
///
|
|
||||||
/// For a boolean toggle that can be enabled and disabled use `Option<Bool>`.
|
|
||||||
public struct Switch {
|
|
||||||
/// The key that enables this switch. For example, a key of `verbose` would be
|
|
||||||
/// used for a `--verbose` option.
|
|
||||||
public let key: String
|
|
||||||
|
|
||||||
/// Optional single letter flag that enables this switch. For example, `-v` would
|
|
||||||
/// be used as a shorthand for `--verbose`.
|
|
||||||
///
|
|
||||||
/// Multiple flags can be grouped together as a single argument and will split
|
|
||||||
/// when parsing (e.g. `rm -rf` treats 'r' and 'f' as inidividual flags).
|
|
||||||
public let flag: Character?
|
|
||||||
|
|
||||||
/// A human-readable string describing the purpose of this option. This will
|
|
||||||
/// be shown in help messages.
|
|
||||||
public let usage: String
|
|
||||||
|
|
||||||
public init(flag: Character? = nil, key: String, usage: String) {
|
|
||||||
self.flag = flag
|
|
||||||
self.key = key
|
|
||||||
self.usage = usage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Switch: Printable {
|
|
||||||
public var description: String {
|
|
||||||
var options = "--\(key)"
|
|
||||||
if let flag = self.flag {
|
|
||||||
options += "|-\(flag)"
|
|
||||||
}
|
|
||||||
return options
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluates the given boolean switch in the given mode.
|
|
||||||
///
|
|
||||||
/// If parsing command line arguments, and no value was specified on the command
|
|
||||||
/// line, the option's `defaultValue` is used.
|
|
||||||
public func <| <ClientError> (mode: CommandMode, option: Switch) -> Result<Bool, CommandantError<ClientError>> {
|
|
||||||
switch mode {
|
|
||||||
case let .Arguments(arguments):
|
|
||||||
var enabled = arguments.consumeKey(option.key)
|
|
||||||
if let flag = option.flag {
|
|
||||||
enabled = arguments.consumeBooleanFlag(flag)
|
|
||||||
}
|
|
||||||
return .success(enabled)
|
|
||||||
|
|
||||||
case .Usage:
|
|
||||||
return .failure(informativeUsageError(option.description, option.usage))
|
|
||||||
}
|
|
||||||
}
|
|
4
Gemfile
Normal file
4
Gemfile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# A sample Gemfile
|
||||||
|
source "https://rubygems.org"
|
||||||
|
|
||||||
|
gem "cocoaseeds", "~>0.2"
|
34
Gemfile.lock
Normal file
34
Gemfile.lock
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
activesupport (4.2.3)
|
||||||
|
i18n (~> 0.7)
|
||||||
|
json (~> 1.7, >= 1.7.7)
|
||||||
|
minitest (~> 5.1)
|
||||||
|
thread_safe (~> 0.3, >= 0.3.4)
|
||||||
|
tzinfo (~> 1.1)
|
||||||
|
claide (0.9.1)
|
||||||
|
cocoaseeds (0.2.0)
|
||||||
|
colorize (~> 0.7)
|
||||||
|
xcodeproj (~> 0.24)
|
||||||
|
colored (1.2)
|
||||||
|
colorize (0.7.7)
|
||||||
|
i18n (0.7.0)
|
||||||
|
json (1.8.3)
|
||||||
|
minitest (5.8.0)
|
||||||
|
thread_safe (0.3.5)
|
||||||
|
tzinfo (1.2.2)
|
||||||
|
thread_safe (~> 0.1)
|
||||||
|
xcodeproj (0.26.3)
|
||||||
|
activesupport (>= 3)
|
||||||
|
claide (~> 0.9.1)
|
||||||
|
colored (~> 1.2)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
cocoaseeds (~> 0.2)
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
1.10.6
|
|
@ -1,7 +0,0 @@
|
||||||
// Copyright (c) 2015 Rob Rix. All rights reserved.
|
|
||||||
|
|
||||||
/// Project version number for Result.
|
|
||||||
extern double ResultVersionNumber;
|
|
||||||
|
|
||||||
/// Project version string for Result.
|
|
||||||
extern const unsigned char ResultVersionString[];
|
|
|
@ -1,218 +0,0 @@
|
||||||
// Copyright (c) 2015 Rob Rix. All rights reserved.
|
|
||||||
|
|
||||||
/// An enum representing either a failure with an explanatory error, or a success with a result value.
|
|
||||||
public enum Result<T, Error>: Printable, DebugPrintable {
|
|
||||||
case Success(Box<T>)
|
|
||||||
case Failure(Box<Error>)
|
|
||||||
|
|
||||||
// MARK: Constructors
|
|
||||||
|
|
||||||
/// Constructs a success wrapping a `value`.
|
|
||||||
public init(value: T) {
|
|
||||||
self = .Success(Box(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a failure wrapping an `error`.
|
|
||||||
public init(error: Error) {
|
|
||||||
self = .Failure(Box(error))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a result from an Optional, failing with `Error` if `nil`
|
|
||||||
public init(_ value: T?, @autoclosure failWith: () -> Error) {
|
|
||||||
self = value.map { .success($0) } ?? .failure(failWith())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a success wrapping a `value`.
|
|
||||||
public static func success(value: T) -> Result {
|
|
||||||
return Result(value: value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a failure wrapping an `error`.
|
|
||||||
public static func failure(error: Error) -> Result {
|
|
||||||
return Result(error: error)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Deconstruction
|
|
||||||
|
|
||||||
/// Returns the value from `Success` Results, `nil` otherwise.
|
|
||||||
public var value: T? {
|
|
||||||
return analysis(ifSuccess: { $0 }, ifFailure: { _ in nil })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the error from `Failure` Results, `nil` otherwise.
|
|
||||||
public var error: Error? {
|
|
||||||
return analysis(ifSuccess: { _ in nil }, ifFailure: { $0 })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Case analysis for Result.
|
|
||||||
///
|
|
||||||
/// Returns the value produced by applying `ifFailure` to `Failure` Results, or `ifSuccess` to `Success` Results.
|
|
||||||
public func analysis<Result>(@noescape #ifSuccess: T -> Result, @noescape ifFailure: Error -> Result) -> Result {
|
|
||||||
switch self {
|
|
||||||
case let .Success(value):
|
|
||||||
return ifSuccess(value.value)
|
|
||||||
case let .Failure(value):
|
|
||||||
return ifFailure(value.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Higher-order functions
|
|
||||||
|
|
||||||
/// Returns a new Result by mapping `Success`es’ values using `transform`, or re-wrapping `Failure`s’ errors.
|
|
||||||
public func map<U>(@noescape transform: T -> U) -> Result<U, Error> {
|
|
||||||
return flatMap { .success(transform($0)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the result of applying `transform` to `Success`es’ values, or re-wrapping `Failure`’s errors.
|
|
||||||
public func flatMap<U>(@noescape transform: T -> Result<U, Error>) -> Result<U, Error> {
|
|
||||||
return analysis(
|
|
||||||
ifSuccess: transform,
|
|
||||||
ifFailure: Result<U, Error>.failure)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `self.value` if this result is a .Success, or the given value otherwise. Equivalent with `??`
|
|
||||||
public func recover(@autoclosure value: () -> T) -> T {
|
|
||||||
return self.value ?? value()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns this result if it is a .Success, or the given result otherwise. Equivalent with `??`
|
|
||||||
public func recoverWith(@autoclosure result: () -> Result<T,Error>) -> Result<T,Error> {
|
|
||||||
return analysis(
|
|
||||||
ifSuccess: { _ in self },
|
|
||||||
ifFailure: { _ in result() })
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Errors
|
|
||||||
|
|
||||||
/// The domain for errors constructed by Result.
|
|
||||||
public static var errorDomain: String { return "com.antitypical.Result" }
|
|
||||||
|
|
||||||
/// The userInfo key for source functions in errors constructed by Result.
|
|
||||||
public static var functionKey: String { return "\(errorDomain).function" }
|
|
||||||
|
|
||||||
/// The userInfo key for source file paths in errors constructed by Result.
|
|
||||||
public static var fileKey: String { return "\(errorDomain).file" }
|
|
||||||
|
|
||||||
/// The userInfo key for source file line numbers in errors constructed by Result.
|
|
||||||
public static var lineKey: String { return "\(errorDomain).line" }
|
|
||||||
|
|
||||||
/// Constructs an error.
|
|
||||||
public static func error(message: String? = nil, function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__) -> NSError {
|
|
||||||
var userInfo: [String: AnyObject] = [
|
|
||||||
functionKey: function,
|
|
||||||
fileKey: file,
|
|
||||||
lineKey: line,
|
|
||||||
]
|
|
||||||
|
|
||||||
if let message = message {
|
|
||||||
userInfo[NSLocalizedDescriptionKey] = message
|
|
||||||
}
|
|
||||||
|
|
||||||
return NSError(domain: errorDomain, code: 0, userInfo: userInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Printable
|
|
||||||
|
|
||||||
public var description: String {
|
|
||||||
return analysis(
|
|
||||||
ifSuccess: { ".Success(\($0))" },
|
|
||||||
ifFailure: { ".Failure(\($0))" })
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: DebugPrintable
|
|
||||||
|
|
||||||
public var debugDescription: String {
|
|
||||||
return description
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns `true` if `left` and `right` are both `Success`es and their values are equal, or if `left` and `right` are both `Failure`s and their errors are equal.
|
|
||||||
public func == <T: Equatable, Error: Equatable> (left: Result<T, Error>, right: Result<T, Error>) -> Bool {
|
|
||||||
if let left = left.value, right = right.value {
|
|
||||||
return left == right
|
|
||||||
} else if let left = left.error, right = right.error {
|
|
||||||
return left == right
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if `left` and `right` represent different cases, or if they represent the same case but different values.
|
|
||||||
public func != <T: Equatable, Error: Equatable> (left: Result<T, Error>, right: Result<T, Error>) -> Bool {
|
|
||||||
return !(left == right)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns the value of `left` if it is a `Success`, or `right` otherwise. Short-circuits.
|
|
||||||
public func ?? <T, Error> (left: Result<T, Error>, @autoclosure right: () -> T) -> T {
|
|
||||||
return left.recover(right())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `left` if it is a `Success`es, or `right` otherwise. Short-circuits.
|
|
||||||
public func ?? <T, Error> (left: Result<T, Error>, @autoclosure right: () -> Result<T, Error>) -> Result<T, Error> {
|
|
||||||
return left.recoverWith(right())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Cocoa API conveniences
|
|
||||||
|
|
||||||
/// Constructs a Result with the result of calling `try` with an error pointer.
|
|
||||||
///
|
|
||||||
/// This is convenient for wrapping Cocoa API which returns an object or `nil` + an error, by reference. e.g.:
|
|
||||||
///
|
|
||||||
/// Result.try { NSData(contentsOfURL: URL, options: .DataReadingMapped, error: $0) }
|
|
||||||
public func try<T>(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__, try: NSErrorPointer -> T?) -> Result<T, NSError> {
|
|
||||||
var error: NSError?
|
|
||||||
return try(&error).map(Result.success) ?? Result.failure(error ?? Result<T, NSError>.error(function: function, file: file, line: line))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a Result with the result of calling `try` with an error pointer.
|
|
||||||
///
|
|
||||||
/// This is convenient for wrapping Cocoa API which returns a `Bool` + an error, by reference. e.g.:
|
|
||||||
///
|
|
||||||
/// Result.try { NSFileManager.defaultManager().removeItemAtURL(URL, error: $0) }
|
|
||||||
public func try(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__, try: NSErrorPointer -> Bool) -> Result<(), NSError> {
|
|
||||||
var error: NSError?
|
|
||||||
return try(&error) ?
|
|
||||||
.success(())
|
|
||||||
: .failure(error ?? Result<(), NSError>.error(function: function, file: file, line: line))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Operators
|
|
||||||
|
|
||||||
infix operator >>- {
|
|
||||||
// Left-associativity so that chaining works like you’d expect, and for consistency with Haskell, Runes, swiftz, etc.
|
|
||||||
associativity left
|
|
||||||
|
|
||||||
// Higher precedence than function application, but lower than function composition.
|
|
||||||
precedence 100
|
|
||||||
}
|
|
||||||
|
|
||||||
infix operator &&& {
|
|
||||||
/// Same associativity as &&.
|
|
||||||
associativity left
|
|
||||||
|
|
||||||
/// Same precedence as &&.
|
|
||||||
precedence 120
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the result of applying `transform` to `Success`es’ values, or re-wrapping `Failure`’s errors.
|
|
||||||
///
|
|
||||||
/// This is a synonym for `flatMap`.
|
|
||||||
public func >>- <T, U, Error> (result: Result<T, Error>, @noescape transform: T -> Result<U, Error>) -> Result<U, Error> {
|
|
||||||
return result.flatMap(transform)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a Result with a tuple of `left` and `right` values if both are `Success`es, or re-wrapping the error of the earlier `Failure`.
|
|
||||||
public func &&& <T, U, Error> (left: Result<T, Error>, @autoclosure right: () -> Result<U, Error>) -> Result<(T, U), Error> {
|
|
||||||
return left.flatMap { left in right().map { right in (left, right) } }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
import Foundation
|
|
3
Seedfile
Normal file
3
Seedfile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
github "Carthage/Commandant", "0.6.1", :files => "Commandant/*.swift"
|
||||||
|
github "antitypical/Result", "0.4.3", :files => "Result/*.swift"
|
||||||
|
github "robrix/Box", "1.2.1", :files => "Box/{Box,BoxType,MutableBox}.swift"
|
|
@ -7,6 +7,15 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
1CC607DA6B900AA3FEC3F6D8 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9257C5FABA335E5F060CB7F7 /* Result.swift */; };
|
||||||
|
21EC092422A3EDFE33B153B8 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1005EEE43D06F809260BEA /* Command.swift */; };
|
||||||
|
5918483F96256CDAC88FF450 /* HelpCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7F27132AB0C6BC7BA7078EF /* HelpCommand.swift */; };
|
||||||
|
66110A826B78DD6BAEC50E70 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC7B1825DB425D0D3D345597 /* Box.swift */; };
|
||||||
|
6C2E8E6E36A6598C7DA5BAB5 /* ArgumentParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52882737E43AACD9AAEF5D9D /* ArgumentParser.swift */; };
|
||||||
|
7858BCFB4D5A4251DE998CE4 /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54F23BBFDBCD3D4CAF67DE68 /* Switch.swift */; };
|
||||||
|
92828DCD99CED47F54242776 /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = AECDEA314BB1F1599638884C /* Option.swift */; };
|
||||||
|
B80C5DDD38A8F7EB6F320697 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E553CF8A2DE31278400C3A /* Errors.swift */; };
|
||||||
|
DE39BCA91D1BC3D876711677 /* MutableBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8007A86176C1DC9462A80FA /* MutableBox.swift */; };
|
||||||
ED031A7C1B5127C00097692E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED031A7B1B5127C00097692E /* main.swift */; };
|
ED031A7C1B5127C00097692E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED031A7B1B5127C00097692E /* main.swift */; };
|
||||||
ED0F237F1B87522400AE40CD /* Install.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F237E1B87522400AE40CD /* Install.swift */; };
|
ED0F237F1B87522400AE40CD /* Install.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F237E1B87522400AE40CD /* Install.swift */; };
|
||||||
ED0F23831B87533A00AE40CD /* ListInstalled.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F23821B87533A00AE40CD /* ListInstalled.swift */; };
|
ED0F23831B87533A00AE40CD /* ListInstalled.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F23821B87533A00AE40CD /* ListInstalled.swift */; };
|
||||||
|
@ -15,18 +24,9 @@
|
||||||
ED0F23891B87543D00AE40CD /* DownloadQueueObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F23881B87543D00AE40CD /* DownloadQueueObserver.swift */; };
|
ED0F23891B87543D00AE40CD /* DownloadQueueObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F23881B87543D00AE40CD /* DownloadQueueObserver.swift */; };
|
||||||
ED0F238B1B87569C00AE40CD /* Downloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F238A1B87569C00AE40CD /* Downloader.swift */; };
|
ED0F238B1B87569C00AE40CD /* Downloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F238A1B87569C00AE40CD /* Downloader.swift */; };
|
||||||
ED0F238D1B8756E600AE40CD /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F238C1B8756E600AE40CD /* Error.swift */; };
|
ED0F238D1B8756E600AE40CD /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F238C1B8756E600AE40CD /* Error.swift */; };
|
||||||
ED128ECA1B6C2A0B00C4050A /* ArgumentParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED128EC11B6C2A0B00C4050A /* ArgumentParser.swift */; };
|
|
||||||
ED128ECB1B6C2A0B00C4050A /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED128EC21B6C2A0B00C4050A /* Command.swift */; };
|
|
||||||
ED128ECC1B6C2A0B00C4050A /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED128EC41B6C2A0B00C4050A /* Errors.swift */; };
|
|
||||||
ED128ECD1B6C2A0B00C4050A /* HelpCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED128EC51B6C2A0B00C4050A /* HelpCommand.swift */; };
|
|
||||||
ED128ECE1B6C2A0B00C4050A /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED128EC71B6C2A0B00C4050A /* Option.swift */; };
|
|
||||||
ED128ECF1B6C2A0B00C4050A /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED128EC81B6C2A0B00C4050A /* Switch.swift */; };
|
|
||||||
ED128ED31B6C2AA200C4050A /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED128ED21B6C2AA200C4050A /* Result.swift */; };
|
|
||||||
ED128EDC1B6C2B4400C4050A /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED128ED91B6C2B4400C4050A /* Box.swift */; };
|
|
||||||
ED128EDD1B6C2B4400C4050A /* BoxType.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED128EDA1B6C2B4400C4050A /* BoxType.swift */; };
|
|
||||||
ED128EDE1B6C2B4400C4050A /* MutableBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED128EDB1B6C2B4400C4050A /* MutableBox.swift */; };
|
|
||||||
EDEAA0C01B51CE6200F2FC3F /* StoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEAA0BF1B51CE6200F2FC3F /* StoreFoundation.framework */; };
|
EDEAA0C01B51CE6200F2FC3F /* StoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEAA0BF1B51CE6200F2FC3F /* StoreFoundation.framework */; };
|
||||||
EDEAA17D1B5C579100F2FC3F /* CommerceKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEAA17C1B5C579100F2FC3F /* CommerceKit.framework */; };
|
EDEAA17D1B5C579100F2FC3F /* CommerceKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEAA17C1B5C579100F2FC3F /* CommerceKit.framework */; };
|
||||||
|
F5F01044EC3065C6EBAB95D7 /* BoxType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0E87CFA5E6371893D5B1807 /* BoxType.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
@ -42,6 +42,14 @@
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
52882737E43AACD9AAEF5D9D /* ArgumentParser.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ArgumentParser.swift; path = Seeds/Commandant/Commandant/ArgumentParser.swift; sourceTree = "<group>"; };
|
||||||
|
54F23BBFDBCD3D4CAF67DE68 /* Switch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Switch.swift; path = Seeds/Commandant/Commandant/Switch.swift; sourceTree = "<group>"; };
|
||||||
|
9257C5FABA335E5F060CB7F7 /* Result.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Result.swift; path = Seeds/Result/Result/Result.swift; sourceTree = "<group>"; };
|
||||||
|
AECDEA314BB1F1599638884C /* Option.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Option.swift; path = Seeds/Commandant/Commandant/Option.swift; sourceTree = "<group>"; };
|
||||||
|
B7F27132AB0C6BC7BA7078EF /* HelpCommand.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HelpCommand.swift; path = Seeds/Commandant/Commandant/HelpCommand.swift; sourceTree = "<group>"; };
|
||||||
|
B8007A86176C1DC9462A80FA /* MutableBox.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MutableBox.swift; path = Seeds/Box/Box/MutableBox.swift; sourceTree = "<group>"; };
|
||||||
|
C4E553CF8A2DE31278400C3A /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = Seeds/Commandant/Commandant/Errors.swift; sourceTree = "<group>"; };
|
||||||
|
DD1005EEE43D06F809260BEA /* Command.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Command.swift; path = Seeds/Commandant/Commandant/Command.swift; sourceTree = "<group>"; };
|
||||||
ED031A781B5127C00097692E /* mas-cli */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "mas-cli"; sourceTree = BUILT_PRODUCTS_DIR; };
|
ED031A781B5127C00097692E /* mas-cli */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "mas-cli"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
ED031A7B1B5127C00097692E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
ED031A7B1B5127C00097692E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||||
ED0F237E1B87522400AE40CD /* Install.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Install.swift; sourceTree = "<group>"; };
|
ED0F237E1B87522400AE40CD /* Install.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Install.swift; sourceTree = "<group>"; };
|
||||||
|
@ -51,20 +59,6 @@
|
||||||
ED0F23881B87543D00AE40CD /* DownloadQueueObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadQueueObserver.swift; sourceTree = "<group>"; };
|
ED0F23881B87543D00AE40CD /* DownloadQueueObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadQueueObserver.swift; sourceTree = "<group>"; };
|
||||||
ED0F238A1B87569C00AE40CD /* Downloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Downloader.swift; sourceTree = "<group>"; };
|
ED0F238A1B87569C00AE40CD /* Downloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Downloader.swift; sourceTree = "<group>"; };
|
||||||
ED0F238C1B8756E600AE40CD /* Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = "<group>"; };
|
ED0F238C1B8756E600AE40CD /* Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = "<group>"; };
|
||||||
ED128EC11B6C2A0B00C4050A /* ArgumentParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArgumentParser.swift; sourceTree = "<group>"; };
|
|
||||||
ED128EC21B6C2A0B00C4050A /* Command.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; };
|
|
||||||
ED128EC31B6C2A0B00C4050A /* Commandant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Commandant.h; sourceTree = "<group>"; };
|
|
||||||
ED128EC41B6C2A0B00C4050A /* Errors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = "<group>"; };
|
|
||||||
ED128EC51B6C2A0B00C4050A /* HelpCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HelpCommand.swift; sourceTree = "<group>"; };
|
|
||||||
ED128EC61B6C2A0B00C4050A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
|
||||||
ED128EC71B6C2A0B00C4050A /* Option.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Option.swift; sourceTree = "<group>"; };
|
|
||||||
ED128EC81B6C2A0B00C4050A /* Switch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Switch.swift; sourceTree = "<group>"; };
|
|
||||||
ED128ED11B6C2A8B00C4050A /* Result.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Result.h; sourceTree = "<group>"; };
|
|
||||||
ED128ED21B6C2AA200C4050A /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = "<group>"; };
|
|
||||||
ED128ED81B6C2B4400C4050A /* Box.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Box.h; sourceTree = "<group>"; };
|
|
||||||
ED128ED91B6C2B4400C4050A /* Box.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = "<group>"; };
|
|
||||||
ED128EDA1B6C2B4400C4050A /* BoxType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoxType.swift; sourceTree = "<group>"; };
|
|
||||||
ED128EDB1B6C2B4400C4050A /* MutableBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MutableBox.swift; sourceTree = "<group>"; };
|
|
||||||
EDEAA0BF1B51CE6200F2FC3F /* StoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreFoundation.framework; path = /System/Library/PrivateFrameworks/StoreFoundation.framework; sourceTree = "<absolute>"; };
|
EDEAA0BF1B51CE6200F2FC3F /* StoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreFoundation.framework; path = /System/Library/PrivateFrameworks/StoreFoundation.framework; sourceTree = "<absolute>"; };
|
||||||
EDEAA0C31B51CEE400F2FC3F /* CDStructures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDStructures.h; sourceTree = "<group>"; };
|
EDEAA0C31B51CEE400F2FC3F /* CDStructures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDStructures.h; sourceTree = "<group>"; };
|
||||||
EDEAA0C41B51CEE400F2FC3F /* CKBook.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKBook.h; sourceTree = "<group>"; };
|
EDEAA0C41B51CEE400F2FC3F /* CKBook.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKBook.h; sourceTree = "<group>"; };
|
||||||
|
@ -250,6 +244,8 @@
|
||||||
EDEAA17A1B5C576D00F2FC3F /* SSRestoreContentItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSRestoreContentItem.h; sourceTree = "<group>"; };
|
EDEAA17A1B5C576D00F2FC3F /* SSRestoreContentItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSRestoreContentItem.h; sourceTree = "<group>"; };
|
||||||
EDEAA17B1B5C576D00F2FC3F /* SSURLRequestProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSURLRequestProperties.h; sourceTree = "<group>"; };
|
EDEAA17B1B5C576D00F2FC3F /* SSURLRequestProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSURLRequestProperties.h; sourceTree = "<group>"; };
|
||||||
EDEAA17C1B5C579100F2FC3F /* CommerceKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CommerceKit.framework; path = /System/Library/PrivateFrameworks/CommerceKit.framework; sourceTree = "<absolute>"; };
|
EDEAA17C1B5C579100F2FC3F /* CommerceKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CommerceKit.framework; path = /System/Library/PrivateFrameworks/CommerceKit.framework; sourceTree = "<absolute>"; };
|
||||||
|
F0E87CFA5E6371893D5B1807 /* BoxType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BoxType.swift; path = Seeds/Box/Box/BoxType.swift; sourceTree = "<group>"; };
|
||||||
|
FC7B1825DB425D0D3D345597 /* Box.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Box.swift; path = Seeds/Box/Box/Box.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -265,16 +261,55 @@
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
0739FA024AB80925B32D64D1 /* Seeds */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0DBDF2D12EBF050099F36BEE /* Box */,
|
||||||
|
A49C8EB621015CD588C621FD /* Commandant */,
|
||||||
|
6569B225928F21A4A639BB22 /* Result */,
|
||||||
|
);
|
||||||
|
name = Seeds;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
0DBDF2D12EBF050099F36BEE /* Box */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FC7B1825DB425D0D3D345597 /* Box.swift */,
|
||||||
|
F0E87CFA5E6371893D5B1807 /* BoxType.swift */,
|
||||||
|
B8007A86176C1DC9462A80FA /* MutableBox.swift */,
|
||||||
|
);
|
||||||
|
name = Box;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
6569B225928F21A4A639BB22 /* Result */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9257C5FABA335E5F060CB7F7 /* Result.swift */,
|
||||||
|
);
|
||||||
|
name = Result;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
A49C8EB621015CD588C621FD /* Commandant */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
52882737E43AACD9AAEF5D9D /* ArgumentParser.swift */,
|
||||||
|
DD1005EEE43D06F809260BEA /* Command.swift */,
|
||||||
|
C4E553CF8A2DE31278400C3A /* Errors.swift */,
|
||||||
|
B7F27132AB0C6BC7BA7078EF /* HelpCommand.swift */,
|
||||||
|
AECDEA314BB1F1599638884C /* Option.swift */,
|
||||||
|
54F23BBFDBCD3D4CAF67DE68 /* Switch.swift */,
|
||||||
|
);
|
||||||
|
name = Commandant;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
ED031A6F1B5127C00097692E = {
|
ED031A6F1B5127C00097692E = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
ED128ED61B6C2AF200C4050A /* Box */,
|
|
||||||
ED128EC91B6C2A0B00C4050A /* Commandant */,
|
|
||||||
EDFC76381B642A2E00D0DBD7 /* Frameworks */,
|
EDFC76381B642A2E00D0DBD7 /* Frameworks */,
|
||||||
EDEAA0C11B51CEBD00F2FC3F /* Headers */,
|
EDEAA0C11B51CEBD00F2FC3F /* Headers */,
|
||||||
ED031A7A1B5127C00097692E /* mas-cli */,
|
ED031A7A1B5127C00097692E /* mas-cli */,
|
||||||
ED031A791B5127C00097692E /* Products */,
|
ED031A791B5127C00097692E /* Products */,
|
||||||
ED128ED01B6C2A7300C4050A /* Result */,
|
0739FA024AB80925B32D64D1 /* Seeds */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
@ -311,41 +346,6 @@
|
||||||
path = "mas-cli/Commands";
|
path = "mas-cli/Commands";
|
||||||
sourceTree = SOURCE_ROOT;
|
sourceTree = SOURCE_ROOT;
|
||||||
};
|
};
|
||||||
ED128EC91B6C2A0B00C4050A /* Commandant */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
ED128EC11B6C2A0B00C4050A /* ArgumentParser.swift */,
|
|
||||||
ED128EC21B6C2A0B00C4050A /* Command.swift */,
|
|
||||||
ED128EC31B6C2A0B00C4050A /* Commandant.h */,
|
|
||||||
ED128EC41B6C2A0B00C4050A /* Errors.swift */,
|
|
||||||
ED128EC51B6C2A0B00C4050A /* HelpCommand.swift */,
|
|
||||||
ED128EC61B6C2A0B00C4050A /* Info.plist */,
|
|
||||||
ED128EC71B6C2A0B00C4050A /* Option.swift */,
|
|
||||||
ED128EC81B6C2A0B00C4050A /* Switch.swift */,
|
|
||||||
);
|
|
||||||
path = Commandant;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
ED128ED01B6C2A7300C4050A /* Result */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
ED128ED11B6C2A8B00C4050A /* Result.h */,
|
|
||||||
ED128ED21B6C2AA200C4050A /* Result.swift */,
|
|
||||||
);
|
|
||||||
path = Result;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
ED128ED61B6C2AF200C4050A /* Box */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
ED128ED81B6C2B4400C4050A /* Box.h */,
|
|
||||||
ED128ED91B6C2B4400C4050A /* Box.swift */,
|
|
||||||
ED128EDA1B6C2B4400C4050A /* BoxType.swift */,
|
|
||||||
ED128EDB1B6C2B4400C4050A /* MutableBox.swift */,
|
|
||||||
);
|
|
||||||
path = Box;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
EDEAA0C11B51CEBD00F2FC3F /* Headers */ = {
|
EDEAA0C11B51CEBD00F2FC3F /* Headers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -621,23 +621,23 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
ED0F23871B87537200AE40CD /* Account.swift in Sources */,
|
ED0F23871B87537200AE40CD /* Account.swift in Sources */,
|
||||||
ED128ECA1B6C2A0B00C4050A /* ArgumentParser.swift in Sources */,
|
6C2E8E6E36A6598C7DA5BAB5 /* ArgumentParser.swift in Sources */,
|
||||||
ED128EDC1B6C2B4400C4050A /* Box.swift in Sources */,
|
66110A826B78DD6BAEC50E70 /* Box.swift in Sources */,
|
||||||
ED128EDD1B6C2B4400C4050A /* BoxType.swift in Sources */,
|
F5F01044EC3065C6EBAB95D7 /* BoxType.swift in Sources */,
|
||||||
ED128ECB1B6C2A0B00C4050A /* Command.swift in Sources */,
|
21EC092422A3EDFE33B153B8 /* Command.swift in Sources */,
|
||||||
ED0F238B1B87569C00AE40CD /* Downloader.swift in Sources */,
|
ED0F238B1B87569C00AE40CD /* Downloader.swift in Sources */,
|
||||||
ED0F23891B87543D00AE40CD /* DownloadQueueObserver.swift in Sources */,
|
ED0F23891B87543D00AE40CD /* DownloadQueueObserver.swift in Sources */,
|
||||||
ED0F238D1B8756E600AE40CD /* Error.swift in Sources */,
|
ED0F238D1B8756E600AE40CD /* Error.swift in Sources */,
|
||||||
ED128ECC1B6C2A0B00C4050A /* Errors.swift in Sources */,
|
B80C5DDD38A8F7EB6F320697 /* Errors.swift in Sources */,
|
||||||
ED128ECD1B6C2A0B00C4050A /* HelpCommand.swift in Sources */,
|
5918483F96256CDAC88FF450 /* HelpCommand.swift in Sources */,
|
||||||
ED0F237F1B87522400AE40CD /* Install.swift in Sources */,
|
ED0F237F1B87522400AE40CD /* Install.swift in Sources */,
|
||||||
ED0F23831B87533A00AE40CD /* ListInstalled.swift in Sources */,
|
ED0F23831B87533A00AE40CD /* ListInstalled.swift in Sources */,
|
||||||
ED0F23851B87536A00AE40CD /* ListUpdates.swift in Sources */,
|
ED0F23851B87536A00AE40CD /* ListUpdates.swift in Sources */,
|
||||||
ED031A7C1B5127C00097692E /* main.swift in Sources */,
|
ED031A7C1B5127C00097692E /* main.swift in Sources */,
|
||||||
ED128EDE1B6C2B4400C4050A /* MutableBox.swift in Sources */,
|
DE39BCA91D1BC3D876711677 /* MutableBox.swift in Sources */,
|
||||||
ED128ECE1B6C2A0B00C4050A /* Option.swift in Sources */,
|
92828DCD99CED47F54242776 /* Option.swift in Sources */,
|
||||||
ED128ED31B6C2AA200C4050A /* Result.swift in Sources */,
|
1CC607DA6B900AA3FEC3F6D8 /* Result.swift in Sources */,
|
||||||
ED128ECF1B6C2A0B00C4050A /* Switch.swift in Sources */,
|
7858BCFB4D5A4251DE998CE4 /* Switch.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue