module SimpleCov::CLI::Dotfile

def coverage_dir

def coverage_dir
  dotfile = find
  return "coverage" unless dotfile
  with_simplecov_loaded { read_from(dotfile) }
rescue LoadError, StandardError => e
  # simplecov:disable — defensive fallback for a bad dotfile (parse
  # error, EACCES, etc.); never fires in the project's own dogfood run
  warn "simplecov: failed to read coverage_dir from #{dotfile}: #{e.class}: #{e.message}"
  "coverage"
  # simplecov:enable
end

def find

def find
  dir = Pathname.new(Dir.pwd)
  loop do
    candidate = dir.join(".simplecov")
    return candidate.to_s if candidate.exist?
    break if dir.root?
    dir = dir.parent
  end
  nil
end

def load_with_start_neutered(path)

block still runs.
for `coverage_dir`. Config inside any `SimpleCov.start { ... }`
`SimpleCov.start` doesn't trigger Coverage just because we asked
turned into no-ops, so a project whose dotfile calls
Load `path` with `SimpleCov.start` and the at_exit installer
def load_with_start_neutered(path)
  klass = SimpleCov.singleton_class
  names = %i[start_tracking install_at_exit_hook]
  stash = names.to_h { |name| [name, klass.instance_method(name)] } #: Hash[Symbol, UnboundMethod]
  # define_method over an existing method emits a "method redefined"
  # warning under $VERBOSE; the override and restore are intentional.
  silence_verbose { names.each { |name| klass.define_method(name) { nil } } }
  load path
ensure
  # @type var stash: Hash[Symbol, UnboundMethod]
  # @type var klass: Class
  silence_verbose { stash.each { |name, method| klass.define_method(name, method) } }
end

def read_from(dotfile)

themselves.
inside a Ruby host that cares about isolation should arrange that
top-level process where that's harmless; callers driving it from
`SimpleCov.start { ... }` blocks. The CLI normally runs as a
formatters, command_name, ...) via `SimpleCov.configure` or
can still mutate other SimpleCov configuration (filters, groups,
own spec suite). The snapshot is intentionally narrow: a dotfile
configured (e.g. when the CLI is exercised inline by simplecov's
don't quietly clobber it in a host process that's already
Load the dotfile, snapshot+restore `SimpleCov.coverage_dir` so we
def read_from(dotfile)
  snapshot = SimpleCov.instance_variable_get(:@coverage_dir)
  load_with_start_neutered(dotfile)
  dir = SimpleCov.coverage_dir
  SimpleCov.instance_variable_set(:@coverage_dir, snapshot)
  dir
end

def silence_verbose

def silence_verbose
  previous = $VERBOSE #: bool?
  $VERBOSE = nil
  yield
ensure
  # @type var previous: bool?
  $VERBOSE = previous
end

def with_simplecov_loaded

def with_simplecov_loaded
  previous_no_defaults = ENV.fetch("SIMPLECOV_NO_DEFAULTS", nil) #: String?
  previous_cli         = ENV.fetch("SIMPLECOV_CLI", nil) #: String?
  ENV["SIMPLECOV_NO_DEFAULTS"] = "1"
  # SIMPLECOV_CLI lets a project's `.simplecov` opt some config into
  # CLI-only behavior — e.g. simplecov itself sets `coverage_dir`
  # to the dogfood path here but skips that for descendants.
  ENV["SIMPLECOV_CLI"] = "1"
  require "simplecov"
  yield
ensure
  # @type var previous_no_defaults: String?
  # @type var previous_cli: String?
  ENV["SIMPLECOV_NO_DEFAULTS"] = previous_no_defaults
  ENV["SIMPLECOV_CLI"]         = previous_cli
end