0001    //
0002    //  Command.swift
0003    //  Commandant
0004    //
0005    //  Created by Justin Spahr-Summers on 2014-10-10.
0006    //  Copyright (c) 2014 Carthage. All rights reserved.
0007    //
0008    
0009    import Foundation
0010    import Result
0011    
0012    /// Represents a subcommand that can be executed with its own set of arguments.
0013    public protocol CommandType
Command.swift:42
	private init<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(_ command: C) {
Command.swift:93
	public func register<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(command: C) {
HelpCommand.swift:21
public struct HelpCommand<ClientError: ErrorType>: CommandType {
{ 0014 0015 /// The command's options type. 0016 typealias Options
Command.swift:29
	func run(options: Options) -> Result<(), ClientError>
Command.swift:42
	private init<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(_ command: C) {
Command.swift:93
	public func register<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(command: C) {
: OptionsType 0017 0018 typealias ClientError
Command.swift:42
	private init<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(_ command: C) {
Command.swift:93
	public func register<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(command: C) {
: ErrorType = Options.ClientError 0019 0020 /// The action that users should specify to use this subcommand (e.g., 0021 /// `help`). 0022 var verb
Command.swift:43
		verb = command.verb
Command.swift:94
		commandsByVerb[command.verb] = CommandWrapper(command)
: String { get } 0023 0024 /// A human-readable, high-level description of what this command is used 0025 /// for. 0026 var function
Command.swift:44
		function = command.function
: String { get } 0027 0028 /// Runs this subcommand with the given options. 0029 func run(options: Options) -> Result<(), ClientError> 0030 } 0031 0032 /// A type-erased command. 0033 public struct CommandWrapper
Command.swift:80
	private var commandsByVerb: [String: CommandWrapper<ClientError>] = [:]
Command.swift:83
	public var commands: [CommandWrapper<ClientError>] {
Command.swift:94
		commandsByVerb[command.verb] = CommandWrapper(command)
<ClientError
Command.swift:39
	public let usage: () -> CommandantError<ClientError>?
Command.swift:42
	private init<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(_ command: C) {
Command.swift:42
	private init<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(_ command: C) {
Command.swift:62
		usage = { () -> CommandantError<ClientError>? in
: ErrorType> { 0034 public let verb
Command.swift:43
		verb = command.verb
Command.swift:84
		return commandsByVerb.values.sort { return $0.verb < $1.verb }
Command.swift:84
		return commandsByVerb.values.sort { return $0.verb < $1.verb }
HelpCommand.swift:50
		let maxVerbLength = self.registry.commands.map { $0.verb.characters.count }.maxElement() ?? 0
HelpCommand.swift:53
			let padding = Repeat<Character>(count: maxVerbLength - command.verb.characters.count, repeatedValue: " ")
HelpCommand.swift:54
			print("   \(command.verb)\(String(padding))   \(command.function)")
: String 0035 public let function
Command.swift:44
		function = command.function
HelpCommand.swift:54
			print("   \(command.verb)\(String(padding))   \(command.function)")
: String 0036 0037 public let run: ArgumentParser -> Result<(), CommandantError<ClientError>> 0038 0039 public let usage: () -> CommandantError<ClientError>? 0040 0041 /// Creates a command that wraps another. 0042 private init
Command.swift:94
		commandsByVerb[command.verb] = CommandWrapper(command)
<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(_ command: C) { 0043 verb = command.verb 0044 function = command.function 0045 run = { (arguments: ArgumentParser) -> Result<(), CommandantError<ClientError>> in 0046 let options = C.Options.evaluate(.Arguments(arguments)) 0047 0048 if let remainingArguments = arguments.remainingArguments { 0049 return .Failure(unrecognizedArgumentsError(remainingArguments)) 0050 } 0051 0052 switch options { 0053 case let .Success(options): 0054 return command 0055 .run(options) 0056 .mapError(CommandantError.CommandError) 0057 0058 case let .Failure(error): 0059 return .Failure(error) 0060 } 0061 } 0062 usage = { () -> CommandantError<ClientError>? in 0063 return C.Options.evaluate(.Usage).error 0064 } 0065 } 0066 } 0067 0068 /// Describes the "mode" in which a command should run. 0069 public enum CommandMode
Argument.swift:38
public func <| <T: ArgumentType, ClientError>(mode: CommandMode, argument: Argument<T>) -> Result<T, CommandantError<ClientError>> {
Argument.swift:64
public func <| <T: ArgumentType, ClientError>(mode: CommandMode, argument: Argument<[T]>) -> Result<[T], CommandantError<ClientError>> {
HelpCommand.swift:72
	public static func evaluate(m: CommandMode) -> Result<HelpOptions, CommandantError<ClientError>> {
Option.swift:43
	static func evaluate(m: CommandMode) -> Result<Self, CommandantError<ClientError>>
Option.swift:50
	public static func evaluate(m: CommandMode) -> Result<NoOptions, CommandantError<ClientError>> {
Option.swift:163
public func <| <T: ArgumentType, ClientError>(mode: CommandMode, option: Option<T>) -> Result<T, CommandantError<ClientError>> {
Option.swift:202
public func <| <ClientError>(mode: CommandMode, option: Option<Bool>) -> Result<Bool, CommandantError<ClientError>> {
Switch.swift:52
public func <| <ClientError> (mode: CommandMode, option: Switch) -> Result<Bool, CommandantError<ClientError>> {
{ 0070 /// Options should be parsed from the given command-line arguments. 0071 case Arguments
Argument.swift:40
	case let .Arguments(arguments):
Argument.swift:66
	case let .Arguments(arguments):
Option.swift:165
	case let .Arguments(arguments):
Option.swift:204
	case let .Arguments(arguments):
Switch.swift:54
	case let .Arguments(arguments):
(ArgumentParser) 0072 0073 /// Each option should record its usage information in an error, for 0074 /// presentation to the user. 0075 case Usage
Argument.swift:55
	case .Usage:
Argument.swift:93
	case .Usage:
Option.swift:193
	case .Usage:
Option.swift:213
	case .Usage:
Switch.swift:61
	case .Usage:
0076 } 0077 0078 /// Maintains the list of commands available to run. 0079 public final class CommandRegistry
Command.swift:112
extension CommandRegistry {
HelpCommand.swift:27
	private let registry: CommandRegistry<ClientError>
HelpCommand.swift:31
	public init(registry: CommandRegistry<ClientError>) {
<ClientError
Command.swift:80
	private var commandsByVerb: [String: CommandWrapper<ClientError>] = [:]
Command.swift:83
	public var commands: [CommandWrapper<ClientError>] {
Command.swift:93
	public func register<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(command: C) {
Command.swift:93
	public func register<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(command: C) {
: ErrorType> { 0080 private var commandsByVerb
Command.swift:84
		return commandsByVerb.values.sort { return $0.verb < $1.verb }
Command.swift:94
		commandsByVerb[command.verb] = CommandWrapper(command)
Command.swift:108
		return commandsByVerb[verb]
: [String: CommandWrapper<ClientError>] = [:] 0081 0082 /// All available commands. 0083 public var commands
HelpCommand.swift:50
		let maxVerbLength = self.registry.commands.map { $0.verb.characters.count }.maxElement() ?? 0
HelpCommand.swift:52
		for command in self.registry.commands {
: [CommandWrapper<ClientError>] { 0084 return commandsByVerb.values.sort { return $0.verb < $1.verb } 0085 } 0086 0087 public init() {} 0088 0089 /// Registers the given command, making it available to run. 0090 /// 0091 /// If another command was already registered with the same `verb`, it will 0092 /// be overwritten. 0093 public func register<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(command: C) { 0094 commandsByVerb[command.verb] = CommandWrapper(command) 0095 } 0096 0097 /// Runs the command corresponding to the given verb, passing it the given 0098 /// arguments. 0099 /// 0100 /// Returns the results of the execution, or nil if no such command exists. 0101 public func runCommand(verb: String, arguments: [String]) -> Result<(), CommandantError<ClientError>>? { 0102 return self[verb]?.run(ArgumentParser(arguments)) 0103 } 0104 0105 /// Returns the command matching the given verb, or nil if no such command 0106 /// is registered. 0107 public subscript(verb: String) -> CommandWrapper<ClientError>? { 0108 return commandsByVerb[verb] 0109 } 0110 } 0111 0112 extension CommandRegistry { 0113 /// Hands off execution to the CommandRegistry, by parsing Process.arguments 0114 /// and then running whichever command has been identified in the argument 0115 /// list. 0116 /// 0117 /// If the chosen command executes successfully, the process will exit with 0118 /// a successful exit code. 0119 /// 0120 /// If the chosen command fails, the provided error handler will be invoked, 0121 /// then the process will exit with a failure exit code. 0122 /// 0123 /// If a matching command could not be found but there is any `executable-verb` 0124 /// style subcommand executable in the caller's `$PATH`, the subcommand will 0125 /// be executed. 0126 /// 0127 /// If a matching command could not be found or a usage error occurred, 0128 /// a helpful error message will be written to `stderr`, then the process 0129 /// will exit with a failure error code. 0130 @noreturn public func main(defaultVerb defaultVerb: String, errorHandler: ClientError -> ()) { 0131 main(arguments: Process.arguments, defaultVerb: defaultVerb, errorHandler: errorHandler) 0132 } 0133 0134 /// Hands off execution to the CommandRegistry, by parsing `arguments` 0135 /// and then running whichever command has been identified in the argument 0136 /// list. 0137 /// 0138 /// If the chosen command executes successfully, the process will exit with 0139 /// a successful exit code. 0140 /// 0141 /// If the chosen command fails, the provided error handler will be invoked, 0142 /// then the process will exit with a failure exit code. 0143 /// 0144 /// If a matching command could not be found but there is any `executable-verb` 0145 /// style subcommand executable in the caller's `$PATH`, the subcommand will 0146 /// be executed. 0147 /// 0148 /// If a matching command could not be found or a usage error occurred, 0149 /// a helpful error message will be written to `stderr`, then the process 0150 /// will exit with a failure error code. 0151 @noreturn public func main
Command.swift:131
		main(arguments: Process.arguments, defaultVerb: defaultVerb, errorHandler: errorHandler)
(arguments arguments: [String], defaultVerb: String, errorHandler: ClientError -> ()) { 0152 assert(arguments.count >= 1) 0153 0154 var arguments = arguments 0155 0156 // Extract the executable name. 0157 let executableName = arguments.removeAtIndex(0) 0158 0159 let verb = arguments.first ?? defaultVerb 0160 if arguments.count > 0 { 0161 // Remove the command name. 0162 arguments.removeAtIndex(0) 0163 } 0164 0165 switch runCommand(verb, arguments: arguments) { 0166 case .Success?: 0167 exit(EXIT_SUCCESS) 0168 0169 case let .Failure(error)?: 0170 switch error { 0171 case let .UsageError(description): 0172 fputs(description + "\n", stderr) 0173 0174 case let .CommandError(error): 0175 errorHandler(error) 0176 } 0177 0178 exit(EXIT_FAILURE) 0179 0180 case nil: 0181 if let subcommandExecuted = executeSubcommandIfExists(executableName, verb: verb, arguments: arguments) { 0182 exit(subcommandExecuted) 0183 } 0184 0185 fputs("Unrecognized command: '\(verb)'. See `\(executableName) help`.\n", stderr) 0186 exit(EXIT_FAILURE) 0187 } 0188 } 0189 0190 /// Finds and executes a subcommand which exists in your $PATH. The executable 0191 /// name must be in the form of `executable-verb`. 0192 /// 0193 /// - Returns: The exit status of found subcommand or nil. 0194 private func executeSubcommandIfExists
Command.swift:181
			if let subcommandExecuted = executeSubcommandIfExists(executableName, verb: verb, arguments: arguments) {
(executableName: String, verb: String, arguments: [String]) -> Int32? { 0195 let subcommand = "\((executableName as NSString).lastPathComponent)-\(verb)" 0196 0197 func launchTask(path: String, arguments: [String]) -> Int32 { 0198 let task = NSTask() 0199 task.launchPath = path 0200 task.arguments = arguments 0201 0202 task.launch() 0203 task.waitUntilExit() 0204 0205 return task.terminationStatus 0206 } 0207 0208 guard launchTask("/usr/bin/which", arguments: [ "-s", subcommand ]) == 0 else { 0209 return nil 0210 } 0211 0212 return launchTask("/usr/bin/env", arguments: [ subcommand ] + arguments) 0213 } 0214 } 0215