require "rubygems"
require "rubygems/config_file"
require "rubygems/gem_runner"

require "log4r"

module VagrantPlugins
  module CommandPlugin
    # This class provides methods to help with calling out to the
    # `gem` command but using the RubyGems API.
    class GemHelper
      def initialize(gem_home)
        @gem_home = gem_home.to_s
        @logger   = Log4r::Logger.new("vagrant::plugins::plugincommand::gemhelper")
      end

      # This will yield the given block with the proper ENV setup so
      # that RubyGems only sees the gems in the Vagrant-managed gem
      # path.
      def with_environment
        old_gem_home = ENV["GEM_HOME"]
        old_gem_path = ENV["GEM_PATH"]
        ENV["GEM_HOME"] = @gem_home
        ENV["GEM_PATH"] = @gem_home
        @logger.debug("Set GEM_* to: #{ENV["GEM_HOME"]}")

        # Clear paths so that it reads the new GEM_HOME setting
        Gem.paths = ENV

        # Set a custom configuration to avoid loading ~/.gemrc loads and
        # /etc/gemrc and so on.
        old_config = Gem.configuration
        Gem.configuration = NilGemConfig.new

        # Clear the sources so that installation uses custom sources
        old_sources = Gem.sources
        Gem.sources = Gem.default_sources
        Gem.sources << "http://gems.hashicorp.com"

        # Use a silent UI so that we have no output
        Gem::DefaultUserInteraction.use_ui(Gem::SilentUI.new) do
          return yield
        end
      ensure
        # Restore the old GEM_* settings
        ENV["GEM_HOME"] = old_gem_home
        ENV["GEM_PATH"] = old_gem_path

        # Reset everything
        Gem.configuration = old_config
        Gem.paths   = ENV
        Gem.sources = old_sources.to_a
      end

      # This is pretty hacky but it is a custom implementatin of
      # Gem::ConfigFile so that we don't load any gemrc files.
      class NilGemConfig < Gem::ConfigFile
        def initialize
          # We _can not_ `super` here because that can really mess up
          # some other configuration state. We need to just set everything
          # directly.

          @api_keys       = {}
          @args           = []
          @backtrace      = false
          @bulk_threshold = 1000
          @hash           = {}
          @update_sources = true
          @verbose        = true
        end
      end
    end
  end
end
