<commit_before>//
//  Command.swift
//  Carthage
//
//  Created by <NAME> on 2014-10-10.
//  Copyright (c) 2014 Carthage. All rights reserved.
//

import CarthageKit
import Foundation
import LlamaKit

/// Represents a Carthage subcommand that can be executed with its own set of
/// arguments.
public protocol CommandType {
	/// 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<()>
}

/// Maintains the list of commands available to run.
public final class CommandRegistry {
	private var commandsByVerb: [String: CommandType] = [:]

	/// All available commands.
	public var commands: [CommandType] {
		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(command: CommandType) {
		commandsByVerb[command.verb] = 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<()>? {
		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) -> CommandType? {
		return commandsByVerb[verb]
	}
}

/// 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)
}

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

	default:
		return false
	}
}

extension RawArgument: Printable {
	private var description: String {
		switch self {
		case let .Key(key):
			return "--\(key)"

		case let .Value(value):
			return "\"\(value)\""
		}
	}
}

/// Constructs an `InvalidArgument` error that indicates a missing value for
/// the argument by the given name.
private func missingArgumentError(argumentName: String) -> NSError {
	let description = "Missing argument for \(argumentName)"
	return CarthageError.InvalidArgument(description: description).error
}

/// Constructs an `InvalidArgument` error that describes how to use the
/// option.
private func informativeUsageError<T: ArgumentType>(option: Option<T>) -> NSError {
	var description = ""

	if option.defaultValue != nil {
		description += "["
	}

	if let key = option.key {
		description += "--\(key) "
	}

	description += "(\(T.name))"

	if option.defaultValue != nil {
		description += "]"
	}

	description += "\n\t\(option.usage)"
	return CarthageError.InvalidArgument(description: description).error
}

/// Constructs an `InvalidArgument` error that describes how to use the
/// given boolean option.
private func informativeUsageError(option: Option<Bool>) -> NSError {
	precondition(option.key != nil)

	var description = ""

	if option.defaultValue != nil {
		description += "["
	}

	description += "--(no-)\(option.key!)"

	if option.defaultValue != nil {
		description += "]"
	}

	description += "\n\t\(option.usage)"
	return CarthageError.InvalidArgument(description: description).error
}

/// 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]) {
		var permitKeys = true

		for arg in arguments {
			// Check whether this is a keyed argument.<commit_msg>Factor out common bits of informativeUsageError()<commit_after>//
//  Command.swift
//  Carthage
//
//  Created by <NAME> on 2014-10-10.
//  Copyright (c) 2014 Carthage. All rights reserved.
//

import CarthageKit
import Foundation
import LlamaKit

/// Represents a Carthage subcommand that can be executed with its own set of
/// arguments.
public protocol CommandType {
	/// 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<()>
}

/// Maintains the list of commands available to run.
public final class CommandRegistry {
	private var commandsByVerb: [String: CommandType] = [:]

	/// All available commands.
	public var commands: [CommandType] {
		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(command: CommandType) {
		commandsByVerb[command.verb] = 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<()>? {
		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) -> CommandType? {
		return commandsByVerb[verb]
	}
}

/// 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)
}

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

	default:
		return false
	}
}

extension RawArgument: Printable {
	private var description: String {
		switch self {
		case let .Key(key):
			return "--\(key)"

		case let .Value(value):
			return "\"\(value)\""
		}
	}
}

/// Constructs an `InvalidArgument` error that indicates a missing value for
/// the argument by the given name.
private func missingArgumentError(argumentName: String) -> NSError {
	let description = "Missing argument for \(argumentName)"
	return CarthageError.InvalidArgument(description: description).error
}

/// Constructs an `InvalidArgument` error that describes how to use the
/// option, with the given example of key (and value, if applicable) usage.
private func informativeUsageError<T>(keyValueExample: String, option: Option<T>) -> NSError {
	var description = ""

	if option.defaultValue != nil {
		description += "["
	}

	description += keyValueExample

	if option.defaultValue != nil {
		description += "]"
	}

	description += "\n\t\(option.usage)"
	return CarthageError.InvalidArgument(description: description).error
}

/// Constructs an `InvalidArgument` error that describes how to use the
/// option.
private func informativeUsageError<T: ArgumentType>(option: Option<T>) -> NSError {
	var example = ""

	if let key = option.key {
		example += "--\(key) "
	}

	example += "(\(T.name))"

	return informativeUsageError(example, option)
}

/// Constructs an `InvalidArgument` error that describes how to use the
/// given boolean option.
private func informativeUsageError(option: Option<Bool>) -> NSError {
	precondition(option.key != nil)

	return informativeUsageError("--(no-)\(option.key!)", option)
}

/// 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]) {
		var permitKeys = true

		for arg in arguments {
			// Check whether this is a keyed argument.
{'fraction_non_alphanumeric': 0.12408844977652317, 'fraction_numerical': 0.003293342742884027, 'mean_word_length': 3.57396449704142, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6306398', 'n_tokens_mistral': 2581, 'n_tokens_neox': 2427, 'n_words': 908}