free_mutant/lib/mutant/cli.rb

199 lines
5 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
2018-09-12 13:15:43 +00:00
2012-08-28 18:57:39 +02:00
module Mutant
2016-07-31 12:27:53 +00:00
# Commandline parser / runner
class CLI
include Adamantium::Flat, Equalizer.new(:config), Procto.call(:config)
2012-08-28 18:57:39 +02:00
# Error failed when CLI argv is invalid
Error = Class.new(RuntimeError)
# Run cli with arguments
#
# @param [Array<String>] arguments
#
2015-11-21 22:02:51 +00:00
# @return [Boolean]
def self.run(arguments)
2015-11-21 22:02:51 +00:00
Runner.call(Env::Bootstrap.call(call(arguments))).success?
rescue Error => exception
$stderr.puts(exception.message)
2015-11-21 22:02:51 +00:00
false
end
2015-11-18 15:06:22 -08:00
# Initialize object
#
# @param [Array<String>]
#
# @return [undefined]
def initialize(arguments)
@config = Config::DEFAULT
parse(arguments)
end
2014-06-15 19:30:17 +00:00
# Config parsed from CLI
2014-06-15 19:30:17 +00:00
#
# @return [Config]
attr_reader :config
private
2013-06-15 16:37:43 +02:00
# Parse the command-line options
#
# @param [Array<String>] arguments
# Command-line options and arguments to be parsed.
#
# @fail [Error]
# An error occurred while parsing the options.
#
2013-06-15 16:37:43 +02:00
# @return [undefined]
def parse(arguments)
2013-07-28 19:58:53 +02:00
opts = OptionParser.new do |builder|
2014-07-06 15:00:37 +00:00
builder.banner = 'usage: mutant [options] MATCH_EXPRESSION ...'
2015-11-21 22:02:51 +00:00
%i[add_environment_options add_mutation_options add_filter_options add_debug_options].each do |name|
2015-05-02 22:01:10 +00:00
__send__(name, builder)
2013-06-21 17:21:04 +02:00
end
end
parse_match_expressions(opts.parse!(arguments))
rescue OptionParser::ParseError => error
2015-05-02 22:01:10 +00:00
raise(Error, error)
end
# Parse matchers
#
# @param [Array<String>] expressions
#
2013-06-22 03:47:23 +02:00
# @return [undefined]
def parse_match_expressions(expressions)
expressions.each do |expression|
add_matcher(:match_expressions, config.expression_parser.(expression))
end
end
2013-06-14 20:54:02 +02:00
2013-08-04 23:03:39 +02:00
# Add environmental options
#
# @param [Object] opts
#
# @return [undefined]
#
2014-12-22 01:28:30 +00:00
# rubocop:disable MethodLength
def add_environment_options(opts)
2014-01-19 00:27:56 +01:00
opts.separator('Environment:')
2013-08-04 23:03:39 +02:00
opts.on('--zombie', 'Run mutant zombified') do
2015-09-04 20:20:56 +00:00
with(zombie: true)
end
opts.on('-I', '--include DIRECTORY', 'Add DIRECTORY to $LOAD_PATH') do |directory|
add(:includes, directory)
end
opts.on('-r', '--require NAME', 'Require file with NAME') do |name|
add(:requires, name)
2013-08-04 23:03:39 +02:00
end
opts.on('-j', '--jobs NUMBER', 'Number of kill jobs. Defaults to number of processors.') do |number|
2015-09-04 20:20:56 +00:00
with(jobs: Integer(number))
2014-07-17 13:59:25 +00:00
end
2013-08-04 23:03:39 +02:00
end
# Use integration
2014-01-18 00:25:16 +01:00
#
# @param [String] name
2014-01-18 00:15:42 +01:00
#
# @return [undefined]
def setup_integration(name)
2016-01-10 18:44:01 +00:00
with(integration: Integration.setup(config.kernel, name))
rescue LoadError
2014-12-22 01:28:30 +00:00
raise Error, "Could not load integration #{name.inspect} (you may want to try installing the gem mutant-#{name})"
2014-01-18 00:15:42 +01:00
end
2015-03-06 04:46:03 +00:00
# Add mutation options
2013-06-21 17:21:04 +02:00
#
2014-01-19 00:27:56 +01:00
# @param [OptionParser] opts
2013-06-21 17:21:04 +02:00
#
2013-06-22 03:47:23 +02:00
# @return [undefined]
2014-01-19 00:27:56 +01:00
def add_mutation_options(opts)
2015-05-02 22:01:10 +00:00
opts.separator(nil)
2014-01-19 00:27:56 +01:00
opts.separator('Options:')
2013-06-21 17:21:04 +02:00
2015-06-13 04:26:08 +00:00
opts.on('--use INTEGRATION', 'Use INTEGRATION to kill mutations', &method(:setup_integration))
end
# Add filter options
#
# @param [OptionParser] opts
#
# @return [undefined]
def add_filter_options(opts)
opts.on('--ignore-subject EXPRESSION', 'Ignore subjects that match EXPRESSION as prefix') do |pattern|
add_matcher(:ignore_expressions, config.expression_parser.(pattern))
end
opts.on('--since REVISION', 'Only select subjects touched since REVISION') do |revision|
2015-11-21 22:02:51 +00:00
add_matcher(
:subject_filters,
Repository::SubjectFilter.new(
Repository::Diff.new(
config: config,
from: Repository::Diff::HEAD,
to: revision
)
)
)
end
2014-01-19 00:27:56 +01:00
end
# Add debug options
#
# @param [OptionParser] opts
#
# @return [undefined]
def add_debug_options(opts)
opts.on('--fail-fast', 'Fail fast') do
2015-09-04 20:20:56 +00:00
with(fail_fast: true)
2014-12-22 01:28:30 +00:00
end
opts.on('--version', 'Print mutants version') do
2015-05-02 22:01:10 +00:00
puts("mutant-#{VERSION}")
2015-11-21 22:02:51 +00:00
config.kernel.exit
2014-12-22 01:28:30 +00:00
end
opts.on_tail('-h', '--help', 'Show this message') do
2014-07-06 15:00:37 +00:00
puts(opts.to_s)
2015-11-21 22:02:51 +00:00
config.kernel.exit
2013-06-21 17:21:04 +02:00
end
end
2015-09-04 20:20:56 +00:00
# With configuration
#
# @param [Hash<Symbol, Object>] attributes
#
# @return [undefined]
2015-09-04 20:20:56 +00:00
def with(attributes)
@config = config.with(attributes)
end
# Add configuration
#
# @param [Symbol] attribute
# the attribute to add to
#
# @param [Object] value
# the value to add
#
# @return [undefined]
def add(attribute, value)
2015-09-04 20:20:56 +00:00
with(attribute => config.public_send(attribute) + [value])
end
# Add matcher configuration
#
# @param [Symbol] attribute
# the attribute to add to
#
# @param [Object] value
# the value to add
#
# @return [undefined]
def add_matcher(attribute, value)
2015-09-04 20:20:56 +00:00
with(matcher: config.matcher.add(attribute, value))
end
2013-06-14 20:54:02 +02:00
end # CLI
end # Mutant