## Rubygems Customization ##
# Customize rubygems install behavior and locations to keep user gems isolated
# from the stuff we bundle with omnibus and any other ruby installations on the
# system.

# Always install and update new gems in "user install mode"
Gem::ConfigFile::OPERATING_SYSTEM_DEFAULTS["install"] = "--user"
Gem::ConfigFile::OPERATING_SYSTEM_DEFAULTS["update"] = "--user"

# We will inject our hacks in if the user will allow it.
begin
  if ENV["CHEFDK_ENV_FIX"] != "0" && ENV["CHEFWS_ENV_FIX"] != "0"
    # TODO remove support for CHEFDK_ENV_FIX as part of 1.0 bump
    require "env_customization"
  end
rescue
  nil
end

module Gem

  ##
  # Override user_dir to live inside of ~/.chef

  def self.user_dir
    chefdk_home_set = !([nil, ""].include? ENV["CHEF_HOME"])
    # We call expand_path here because it converts \ -> /
    # Rubygems seems to require that we not use \
    default_home = File.join(File.expand_path(ENV["LOCALAPPDATA"]), "cinc-workstation")

    chef_home = if chefdk_home_set
                  ENV["CHEF_HOME"]
                else
                  default_home
                end

    # Prevents multiple warnings
    ENV["CHEF_HOME"] = chef_home

    parts = [chef_home, "gem", ruby_engine]
    parts << RbConfig::CONFIG["ruby_version"] unless RbConfig::CONFIG["ruby_version"].empty?
    File.join parts
  end

end

# Workaround: serialize Gem.load_yaml across threads to close a Ruby 3.4 /
# RubyGems 3.6 / Bundler 2.6 race where the parallel installer can observe a
# partially-loaded Psych module during `bundle install` for cookbook gem
# dependencies:
#   NoMethodError: undefined method 'safe_load' for module Psych
# while one worker thread is mid-`require "psych"` (only psych/versions.rb
# loaded so far) and another worker thread calls Gem.load_yaml ->
# Gem::SafeYAML.safe_load. Wrapping load_yaml in a mutex forces the second
# thread to wait until psych is fully loaded.
#
# We deliberately do NOT `require "psych"` here: that would activate psych's
# runtime deps (date >= 0) at every `require "rubygems"`, before appbundler
# can pin its own gem versions, producing:
#   Gem::LoadError: can't activate date-3.5.0, already activated date-3.4.1
# in cinc-client startup.
#
# Upstream tracking:
#   - https://github.com/rubygems/rubygems/issues/9347
#   - https://github.com/rubygems/rubygems/pull/9352 (replaces Psych with a
#     pure-ruby YAMLSerializer in Gem.load_yaml's default path; merged to
#     master, not yet released)
#
# Remove this block once cinc-workstation ships on a Ruby whose bundled
# RubyGems contains the YAMLSerializer rewrite (post-v4.0.11), or once the
# chef gem version shipped here carries the gem_installer.rb RUBYOPT
# workaround that landed in our chef fork on stable/cinc.
module Gem
  @yaml_load_mutex = Thread::Mutex.new

  class << self
    alias_method :_load_yaml_without_mutex, :load_yaml
    remove_method :load_yaml

    def load_yaml
      return if @yaml_loaded

      @yaml_load_mutex.synchronize { _load_yaml_without_mutex }
    end
  end
end

# :DK-BEG: override 'gem install' to enable RubyInstaller DevKit usage
Gem.pre_install do |gem_installer|
  win_install_dir = "C:\\cinc-project\\cinc-workstation"
  unless gem_installer.spec.extensions.empty?
    unless ENV["PATH"].include?("#{win_install_dir}\\embedded\\mingw\\bin")
      Gem.ui.say "Temporarily enhancing PATH to include DevKit..." if Gem.configuration.verbose
      ENV["PATH"] = "#{win_install_dir}\\embedded\\bin;#{win_install_dir}\\embedded\\mingw\\bin;#{ENV["PATH"]}"
    end
    ENV["RI_DEVKIT"] = "#{win_install_dir}\\embedded"
    ENV["CC"] = "gcc"
    ENV["CXX"] = "g++"
    ENV["CPP"] = "cpp"
  end
end
# :DK-END:
