class ParallelTests::CLI

def parse_options!(argv)

def parse_options!(argv)
  options = {}
  OptionParser.new do |opts|
    opts.banner = <<-BANNER.gsub(/^          /, '')
      Run all tests in parallel, giving each process ENV['TEST_ENV_NUMBER'] ('', '2', '3', ...)
      [optional] Only selected files & folders:
        parallel_test test/bar test/baz/xxx_text.rb
      [optional] Pass test-options and files via `--`:
        parallel_test -- -t acceptance -f progress -- spec/foo_spec.rb spec/acceptance
      Options are:
    BANNER
    opts.on("-n [PROCESSES]", Integer, "How many processes to use, default: available CPUs") { |n| options[:count] = n }
    opts.on("-p", "--pattern [PATTERN]", "run tests matching this regex pattern") { |pattern| options[:pattern] = /#{pattern}/ }
    opts.on("--exclude-pattern", "--exclude-pattern [PATTERN]", "exclude tests matching this regex pattern") { |pattern| options[:exclude_pattern] = /#{pattern}/ }
    opts.on("--group-by [TYPE]", <<-TEXT.gsub(/^          /, '')
      group tests by:
                found - order of finding files
                steps - number of cucumber/spinach steps
                scenarios - individual cucumber scenarios
                filesize - by size of the file
                runtime - info from runtime log
                default - runtime when runtime log is filled otherwise filesize
      TEXT
      ) { |type| options[:group_by] = type.to_sym }
    opts.on("-m [FLOAT]", "--multiply-processes [FLOAT]", Float, "use given number as a multiplier of processes to run") { |multiply| options[:multiply] = multiply }
    opts.on("-s [PATTERN]", "--single [PATTERN]",
      "Run all matching files in the same process") do |pattern|
      options[:single_process] ||= []
      options[:single_process] << /#{pattern}/
    end
    opts.on("-i", "--isolate",
      "Do not run any other tests in the group used by --single(-s)") do |pattern|
      options[:isolate] = true
    end
    opts.on("--only-group INT[, INT]", Array) { |groups| options[:only_group] = groups.map(&:to_i) }
    opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUMBER']") { |path| options[:execute] = path }
    opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = arg.lstrip }
    opts.on("-t", "--type [TYPE]", "test(default) / rspec / cucumber / spinach") do |type|
      begin
        @runner = load_runner(type)
      rescue NameError, LoadError => e
        puts "Runner for `#{type}` type has not been found! (#{e})"
        abort
      end
    end
    opts.on("--suffix [PATTERN]", <<-TEXT.gsub(/^          /, '')
      override built in test file pattern (should match suffix):
                '_spec\.rb$' - matches rspec files
                '_(test|spec).rb$' - matches test or spec files
      TEXT
      ) { |pattern| options[:suffix] = /#{pattern}/ }
    opts.on("--serialize-stdout", "Serialize stdout output, nothing will be written until everything is done") { options[:serialize_stdout] = true }
    opts.on("--prefix-output-with-test-env-number", "Prefixes test env number to the output when not using --serialize-stdout") { options[:prefix_output_with_test_env_number] = true }
    opts.on("--combine-stderr", "Combine stderr into stdout, useful in conjunction with --serialize-stdout") { options[:combine_stderr] = true }
    opts.on("--non-parallel", "execute same commands but do not in parallel, needs --exec") { options[:non_parallel] = true }
    opts.on("--no-symlinks", "Do not traverse symbolic links to find test files") { options[:symlinks] = false }
    opts.on('--ignore-tags [PATTERN]', 'When counting steps ignore scenarios with tags that match this pattern')  { |arg| options[:ignore_tag_pattern] = arg }
    opts.on("--nice", "execute test commands with low priority.") { options[:nice] = true }
    opts.on("--runtime-log [PATH]", "Location of previously recorded test runtimes") { |path| options[:runtime_log] = path }
    opts.on("--allowed-missing [INT]", Integer, "Allowed percentage of missing runtimes (default = 50)") { |percent| options[:allowed_missing_percent] = percent }
    opts.on("--unknown-runtime [FLOAT]", Float, "Use given number as unknown runtime (otherwise use average time)") { |time| options[:unknown_runtime] = time }
    opts.on("--first-is-1", "Use \"1\" as TEST_ENV_NUMBER to not reuse the default test environment") { options[:first_is_1] = true }
    opts.on("--verbose", "Print debug output") { options[:verbose] = true }
    opts.on("--verbose-process-command", "Displays only the command that will be executed by each process") { options[:verbose_process_command] = true }
    opts.on("--verbose-rerun-command", "When there are failures, displays the command executed by each process that failed") { options[:verbose_rerun_command] = true }
    opts.on("--quiet", "Print only tests output") { options[:quiet] = true }
    opts.on("-v", "--version", "Show Version") { puts ParallelTests::VERSION; exit }
    opts.on("-h", "--help", "Show this.") { puts opts; exit }
  end.parse!(argv)
  if options[:verbose] && options[:quiet]
    raise "Both options are mutually exclusive: verbose & quiet"
  end
  if options[:count] == 0
    options.delete(:count)
    options[:non_parallel] = true
  end
  files, remaining = extract_file_paths(argv)
  unless options[:execute]
    abort "Pass files or folders to run" unless files.any?
    options[:files] = files.map { |file_path| Pathname.new(file_path).cleanpath.to_s }
  end
  append_test_options(options, remaining)
  options[:group_by] ||= :filesize if options[:only_group]
  raise "--group-by found and --single-process are not supported" if options[:group_by] == :found and options[:single_process]
  allowed = [:filesize, :runtime, :found]
  if !allowed.include?(options[:group_by]) && options[:only_group]
    raise "--group-by #{allowed.join(" or ")} is required for --only-group"
  end
  options
end