class RuboCop::Server::Cache

@api private
Caches the states of server process.

def acquire_lock

def acquire_lock
  lock_file = File.open(lock_path, File::CREAT)
  # flock returns 0 if successful, and false if not.
  flock_result = lock_file.flock(File::LOCK_EX | File::LOCK_NB)
  yield flock_result != false
ensure
  lock_file.flock(File::LOCK_UN)
  lock_file.close
end

def cache_path

def cache_path
  cache_root_dir = if cache_root_path
                     File.join(cache_root_path, 'rubocop_cache')
                   else
                     cache_root_dir_from_config
                   end
  File.expand_path(File.join(cache_root_dir, 'server'))
end

def cache_root_dir_from_config

rubocop:disable Metrics/MethodLength
def cache_root_dir_from_config
  CacheConfig.root_dir do
    # `RuboCop::ConfigStore` has heavy dependencies, this is a lightweight implementation
    # so that only the necessary `CacheRootDirectory` can be obtained.
    config_path = ConfigFinder.find_config_path(Dir.pwd)
    file_contents = File.read(config_path)
    # Returns early if `CacheRootDirectory` is not used before requiring `erb` or `yaml`.
    next unless file_contents.include?('CacheRootDirectory')
    require 'erb'
    yaml_code = ERB.new(file_contents).result
    require 'yaml'
    config_yaml = YAML.safe_load(
      yaml_code, permitted_classes: [Regexp, Symbol], aliases: true
    )
    # For compatibility with Ruby 3.0 or lower.
    if Gem::Version.new(Psych::VERSION) < Gem::Version.new('4.0.0')
      config_yaml == false ? nil : config_yaml
    end
    config_yaml&.dig('AllCops', 'CacheRootDirectory')
  end
end

def dir

def dir
  Pathname.new(File.join(cache_path, project_dir_cache_key)).tap do |d|
    d.mkpath unless d.exist?
  end
end

def lock_path

def lock_path
  dir.join('lock')
end

def pid_path

def pid_path
  dir.join('pid')
end

def pid_running?

def pid_running?
  Process.kill(0, pid_path.read.to_i) == 1
rescue Errno::ESRCH, Errno::ENOENT, Errno::EACCES
  false
end

def port_path

def port_path
  dir.join('port')
end

def project_dir

Searches for Gemfile or gems.rb in the current dir or any parent dirs
def project_dir
  current_dir = Dir.pwd
  while current_dir != '/'
    return current_dir if GEMFILE_NAMES.any? do |gemfile|
      File.exist?(File.join(current_dir, gemfile))
    end
    current_dir = File.expand_path('..', current_dir)
  end
  # If we can't find a Gemfile, just use the current directory
  Dir.pwd
end

def project_dir_cache_key

def project_dir_cache_key
  @project_dir_cache_key ||= project_dir[1..].tr('/', '+')
end

def status_path

def status_path
  dir.join('status')
end

def stderr_path

def stderr_path
  dir.join('stderr')
end

def token_path

def token_path
  dir.join('token')
end

def version_path

def version_path
  dir.join('version')
end

def write_pid_file

def write_pid_file
  pid_path.write(Process.pid)
  yield
ensure
  dir.rmtree
end

def write_port_and_token_files(port:, token:)

def write_port_and_token_files(port:, token:)
  port_path.write(port)
  token_path.write(token)
end

def write_status_file(status)

def write_status_file(status)
  status_path.write(status)
end

def write_version_file(version)

def write_version_file(version)
  version_path.write(version)
end