123456789_123456789_123456789_123456789_123456789_

Class: Gem::ConfigFile

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
Inherits: Object
Defined in: lib/rubygems/config_file.rb

Overview

ConfigFile RubyGems options and gem command options from gemrc.

gemrc is a YAML file that uses strings to match gem command arguments and symbols to match RubyGems options.

::Gem command arguments use a String key that matches the command name and allow you to specify default arguments:

install: --no-rdoc --no-ri
update: --no-rdoc --no-ri

You can use gem: to set default arguments for all commands.

RubyGems options use symbol keys. Valid options are:

:backtrace:: See #backtrace :bulk_threshold:: See #bulk_threshold :cooldown:: See #cooldown :verbose:: See #verbose :update_sources:: See #update_sources :concurrent_downloads:: See #concurrent_downloads :cert_expiration_length_days:: See #cert_expiration_length_days :install_extension_in_lib:: See #install_extension_in_lib :ipv4_fallback_enabled:: See #ipv4_fallback_enabled :global_gem_cache:: See #global_gem_cache :use_psych:: See #use_psych :credential_store:: See #credential_store :gemhome:: See #home :gempath:: See #path :sources:: Sets sources :disable_default_gem_server:: See #disable_default_gem_server :ssl_verify_mode:: See #ssl_verify_mode :ssl_ca_cert:: See #ssl_ca_cert :ssl_client_cert:: See #ssl_client_cert

gemrc files may exist in various locations and are read and merged in the following order:

  • system wide (/etc/gemrc)
  • per user (~/.gemrc)
  • per environment (gemrc files listed in the GEMRC environment variable)

Constant Summary

Class Method Summary

Instance Attribute Summary

DefaultUserInteraction - Included

Instance Method Summary

UserInteraction - Included

#alert

Displays an alert statement.

#alert_error

Displays an error statement to the error output location.

#alert_warning

Displays a warning statement to the warning output location.

#ask

Asks a question and returns the answer.

#ask_for_password

Asks for a password with a prompt

#ask_yes_no

Asks a yes or no question.

#choose_from_list

Asks the user to answer question with an answer from the given list.

#say

Displays the given statement on the standard output (or equivalent).

#terminate_interaction

Terminates the RubyGems process with the given exit_code

#verbose

Calls say with msg or the results of the block if really_verbose is true.

DefaultUserInteraction - Included

Text - Included

#clean_text

Remove any non-printable characters and make the text suitable for printing.

#format_text

Wraps text to wrap characters and optionally indents by indent characters.

#levenshtein_distance

Returns a value representing the "cost" of transforming str1 into str2 Vendored version of DidYouMean::Levenshtein.distance from the ruby/did_you_mean gem @ 1.4.0 https://github.com/ruby/did_you_mean/blob/2ddf39b874808685965dbc47d344cf6c7651807c/lib/did_you_mean/levenshtein.rb#L7-L37.

#truncate_text, #min3

Constructor Details

.new(args) ⇒ ConfigFile

Create the config file object. #args is the list of arguments from the command line.

The following command line options are handled early here rather than later at the time most command options are processed.

--config-file, --config-file==NAME

Obviously these need to be handled by the ConfigFile object to ensure we get the right config file.

--backtrace

Backtrace needs to be turned on early so that errors before normal option parsing can be properly handled.

--debug

Enable Ruby level debug messages. Handled early for the same reason as --backtrace.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 250

def initialize(args)
  set_config_file_name(args)

  @backtrace = DEFAULT_BACKTRACE
  @bulk_threshold = DEFAULT_BULK_THRESHOLD
  @cooldown = DEFAULT_COOLDOWN
  @verbose = DEFAULT_VERBOSITY
  @update_sources = DEFAULT_UPDATE_SOURCES
  @concurrent_downloads = DEFAULT_CONCURRENT_DOWNLOADS
  @cert_expiration_length_days = DEFAULT_CERT_EXPIRATION_LENGTH_DAYS
  @install_extension_in_lib = DEFAULT_INSTALL_EXTENSION_IN_LIB
  @ipv4_fallback_enabled = ENV["IPV4_FALLBACK_ENABLED"] == "true" || DEFAULT_IPV4_FALLBACK_ENABLED
  @global_gem_cache = ENV["RUBYGEMS_GLOBAL_GEM_CACHE"] == "true" || DEFAULT_GLOBAL_GEM_CACHE
  @use_psych = ENV["RUBYGEMS_USE_PSYCH"] == "true" || DEFAULT_USE_PSYCH
  @credential_store = normalize_credential_store(ENV["RUBYGEMS_CREDENTIAL_STORE"], DEFAULT_CREDENTIAL_STORE)

  operating_system_config = Gem::Util.deep_dup(OPERATING_SYSTEM_DEFAULTS)
  platform_config = Gem::Util.deep_dup(PLATFORM_DEFAULTS)
  system_config = load_file SYSTEM_WIDE_CONFIG_FILE
  user_config = load_file config_file_name

  environment_config = (ENV["GEMRC"] || "").
    split(File::PATH_SEPARATOR).inject({}) do |result, file|
      result.merge load_file file
    end

  @hash = operating_system_config.merge platform_config
  unless args.index "--norc"
    @hash = @hash.merge system_config
    @hash = @hash.merge user_config
    @hash = @hash.merge environment_config
  end

  @hash.transform_keys! do |k|
    # gemhome and gempath are not working with symbol keys
    if %w[backtrace bulk_threshold cooldown verbose update_sources cert_expiration_length_days
          concurrent_downloads install_extension_in_lib ipv4_fallback_enabled
          global_gem_cache use_psych credential_store sources
          disable_default_gem_server ssl_verify_mode ssl_ca_cert ssl_client_cert].include?(k)
      k.to_sym
    else
      k
    end
  end

  # HACK: these override command-line args, which is bad
  @backtrace                   = @hash[:backtrace]                   if @hash.key? :backtrace
  @bulk_threshold              = @hash[:bulk_threshold]              if @hash.key? :bulk_threshold
  @cooldown                    = @hash[:cooldown]                    if @hash.key? :cooldown
  @verbose                     = @hash[:verbose]                     if @hash.key? :verbose
  @update_sources              = @hash[:update_sources]              if @hash.key? :update_sources
  @concurrent_downloads        = @hash[:concurrent_downloads]        if @hash.key? :concurrent_downloads
  @cert_expiration_length_days = @hash[:cert_expiration_length_days] if @hash.key? :cert_expiration_length_days
  @install_extension_in_lib    = @hash[:install_extension_in_lib]    if @hash.key? :install_extension_in_lib
  @ipv4_fallback_enabled       = @hash[:ipv4_fallback_enabled]       if @hash.key? :ipv4_fallback_enabled
  @global_gem_cache            = @hash[:global_gem_cache]            if @hash.key? :global_gem_cache
  @use_psych                   = @hash[:use_psych]                   if @hash.key? :use_psych
  @credential_store            = normalize_credential_store(@hash[:credential_store], @credential_store) if @hash.key? :credential_store

  @home                        = @hash[:gemhome]                     if @hash.key? :gemhome
  @path                        = @hash[:gempath]                     if @hash.key? :gempath
  @sources                     = @hash[:sources]                     if @hash.key? :sources
  @disable_default_gem_server  = @hash[:disable_default_gem_server]  if @hash.key? :disable_default_gem_server
  @ssl_verify_mode             = @hash[:ssl_verify_mode]             if @hash.key? :ssl_verify_mode
  @ssl_ca_cert                 = @hash[:ssl_ca_cert]                 if @hash.key? :ssl_ca_cert
  @ssl_client_cert             = @hash[:ssl_client_cert]             if @hash.key? :ssl_client_cert

  @api_keys         = nil
  @rubygems_api_key = nil

  handle_arguments args
end

Class Method Details

.credential_store_account(host) (private)

Built on the same normalized form the credentials file uses, so the two never disagree about which host a spelling refers to. Userinfo is dropped because the account reaches the backend as a command argument, where any other user on the machine can read it.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 752

def self.(host)
  host = normalize_credentials_key(host).to_s
  return host unless host.match?(%r{\Ahttps?://}i)

  require_relative "vendor/uri/lib/uri"
  uri = Gem::URI(host)
  return host unless uri.userinfo

  uri = uri.dup
  uri.user = uri.password = nil
  uri.to_s
rescue Gem::URI::Error
  host
end

.deep_transform_config_keys!(config) (private)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 775

def self.deep_transform_config_keys!(config)
  config.transform_keys! do |k|
    if k.match?(/\A:(.*)\z/)
      k[1..-1].to_sym
    elsif k.include?("__") || k.end_with?("/")
      if k.is_a?(Symbol)
        k.to_s.gsub(/__/,".").delete_suffix("/").to_sym
      else
        k.dup.gsub(/__/,".").delete_suffix("/")
      end
    else
      k
    end
  end

  config.transform_values! do |v|
    if v.is_a?(String)
      if v.match?(/\A:(.*)\z/)
        v[1..-1].to_sym
      elsif v.match?(/\A[-]?\d\z/)
        v.to_i
      elsif v.match?(/\A(?:true|false)\z/)
        v == "true"
      elsif v.empty?
        nil
      else
        v
      end
    elsif v.respond_to?(:empty?) && v.empty?
      nil
    elsif v.is_a?(Hash)
      deep_transform_config_keys!(v)
    else
      v
    end
  end

  config
end

.dump_with_rubygems_yaml(content)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 728

def self.dump_with_rubygems_yaml(content)
  content.transform_keys! do |k|
    k.is_a?(Symbol) ? ":#{k}" : k
  end

  require_relative "yaml_serializer"
  Gem::YAMLSerializer.dump(content)
end

.load_with_rubygems_config_hash(yaml)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 737

def self.load_with_rubygems_config_hash(yaml)
  require_relative "yaml_serializer"

  content = Gem::YAMLSerializer.load(yaml, permitted_classes: [])
  return {} unless content.is_a?(Hash)

  deep_transform_config_keys!(content)
end

.normalize_credentials_key(host) (private)

A trailing slash, or the underscore pair standing in for a dot, comes back rewritten from #load_file, so a raw host would silently miss.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 769

def self.normalize_credentials_key(host)
  return host unless host.is_a?(String)

  deep_transform_config_keys!(host => nil).keys.first
end

Instance Attribute Details

#args (readonly)

List of arguments supplied to the config file object.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 107

attr_reader :args

#backtrace (rw)

True if the backtrace option has been specified, or debug is on.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 571

def backtrace
  @backtrace || $DEBUG
end

#backtrace=(value) (rw)

True if we print backtraces on errors.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 122

attr_writer :backtrace

#bulk_threshold (rw)

Bulk threshold value. If the number of missing gems are above this threshold value, then a bulk download technique is used. (deprecated)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 128

attr_accessor :bulk_threshold

#cert_expiration_length_days (rw)

Expiration length to sign a certificate

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 184

attr_accessor :cert_expiration_length_days

#concurrent_downloads (rw)

Number of gem downloads that should be performed concurrently.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 155

attr_accessor :concurrent_downloads

#cooldown (rw)

Number of days a newly published gem version must wait before it is considered for installation or update (the cooldown period). 0 disables the cooldown, unless Bundler is configured with a longer one: this setting and Bundler's own cooldown setting are both read, and the longer of the two applies, so a cooldown configured for only one of the two tools still covers both. --cooldown overrides both.

A value that cannot be read as a non-negative integer warns and takes no part in that resolution, so a typo in the gemrc file does not make every command fail.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 142

attr_accessor :cooldown

#credential_store (rw)

Experimental ==

Store and read push/authentication credentials in a credential store instead of the plain text credentials file. true selects the operating system's native store (macOS Keychain, Linux Secret Service, Windows Credential Manager) when one is available on this platform. A string selects a named backend registered by a third-party gem, such as "1password". false (the default) keeps using the credentials file.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 227

attr_accessor :credential_store

#disable_default_gem_server (rw)

True if we want to force specification of gem server when pushing a gem

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 165

attr_accessor :disable_default_gem_server

#global_gem_cache (rw)

Use a global cache for .gem files shared across all Ruby installations. When enabled, gems fetched from a remote source are cached to ~/.cache/gem/gems (or XDG_CACHE_HOME/gem/gems). Gems installed from a local path are not, since a cached copy is later reused without being verified again. gem fetch still writes to the working directory, and an unwritable cache directory falls back to the cache of the installation.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 206

attr_accessor :global_gem_cache

#hash (readonly, protected)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 725

attr_reader :hash

#home (rw)

Where to install gems (deprecated)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 117

attr_accessor :home

#install_extension_in_lib (rw)

Install extensions into lib as well as into the extension directory.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 189

attr_accessor :install_extension_in_lib

#ipv4_fallback_enabled (rw)

Experimental ==

Fallback to IPv4 when IPv6 is not reachable or slow (default: false)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 195

attr_accessor :ipv4_fallback_enabled

#last_update_check (rw)

Reads time of last update check from state file

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 600

def last_update_check
  if File.readable?(state_file_name)
    File.read(state_file_name).to_i
  else
    0
  end
end

#last_update_check=(timestamp) (rw)

Writes time of last update check to state file

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 609

def last_update_check=(timestamp)
  File.write(state_file_name, timestamp.to_s) if state_file_writable?
end

#path (rw)

Where to look for gems (deprecated)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 112

attr_accessor :path

#rubygems_api_key (rw)

Returns the RubyGems.org API key

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 400

def rubygems_api_key
  load_api_keys unless @rubygems_api_key

  # #load_api_keys only reads the credentials file, which no longer holds the
  # key once it is stored. A copy left there after the move is stale.
  credential_store_default_api_key || @rubygems_api_key
end

#rubygems_api_key=(api_key) (rw)

Sets the RubyGems.org API key to api_key

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 411

def rubygems_api_key=(api_key)
  if credential_store
    store = active_credential_store

    if api_key.to_s.empty?
      warn_unremoved_credential(CREDENTIAL_STORE_DEFAULT_ACCOUNT) if store&.available? && !store.delete(CREDENTIAL_STORE_DEFAULT_ACCOUNT)
    elsif store&.set(CREDENTIAL_STORE_DEFAULT_ACCOUNT, api_key)
      remove_api_key_from_file(:rubygems_api_key)
      @rubygems_api_key = api_key
      return
    else
      warn_unremoved_credential(CREDENTIAL_STORE_DEFAULT_ACCOUNT) if store&.available? && !store.delete(CREDENTIAL_STORE_DEFAULT_ACCOUNT)
      warn_credential_store_fallback
    end
  end

  set_api_key :rubygems_api_key, api_key

  @rubygems_api_key = api_key
end

#sources (rw)

sources to look for gems

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 179

attr_accessor :sources

#ssl_ca_cert (rw)

Path name of directory or file of openssl CA certificate, used for remote https connection

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 175

attr_accessor :ssl_ca_cert

#ssl_client_cert (readonly)

Path name of directory or file of openssl client certificate, used for remote https connection with client authentication

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 216

attr_reader :ssl_client_cert

#ssl_verify_mode (readonly)

openssl verify mode value, used for remote https connection

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 169

attr_reader :ssl_verify_mode

#state_file_writable?Boolean (readonly)

Check state file is writable. Creates empty file if not present to ensure we can write to it.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 576

def state_file_writable?
  if File.exist?(state_file_name)
    File.writable?(state_file_name)
  else
    require "fileutils"
    FileUtils.mkdir_p File.dirname(state_file_name)
    File.open(state_file_name, "w") {}
    true
  end
rescue Errno::EACCES
  false
end

#update_sources (rw)

True if we want to update the SourceInfoCache every time, false otherwise

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 160

attr_accessor :update_sources

#use_psych (rw)

Use Psych (C extension YAML parser) instead of the pure Ruby YAMLSerializer.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 211

attr_accessor :use_psych

#verbose (rw)

Verbose level of output:

  • false -- No output
  • true -- Normal output
  • :loud -- Extra output
[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 150

attr_accessor :verbose

Instance Method Details

#==(other)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 716

def ==(other) # :nodoc:
  self.class === other &&
    @backtrace == other.backtrace &&
    @bulk_threshold == other.bulk_threshold &&
    @verbose == other.verbose &&
    @update_sources == other.update_sources &&
    @hash == other.hash
end

#[](key)

Return the configuration information for key.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 707

def [](key)
  @hash[key] || @hash[key.to_s]
end

#[]=(key, value)

Set configuration option key to value.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 712

def []=(key, value)
  @hash[key] = value
end

#active_credential_store (private)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 815

def active_credential_store
  return nil unless credential_store

  require_relative "credential_store"
  Gem::CredentialStore.for(credential_store)
end

#api_keys

Hash of RubyGems.org and alternate API keys, as they appear in the credentials file. Keys held in the credential store are not included, so this is not the full set of keys a command can authenticate with. Use #credential_store_api_key_for or #credential_store_default_api_key to reach those.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 330

def api_keys
  load_api_keys unless @api_keys

  @api_keys
end

#check_credentials_permissions

Checks the permissions of the credentials file. If they are not 0600 an error message is displayed and RubyGems aborts.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 340

def check_credentials_permissions
  return if Gem.win_platform? # windows doesn't write 0600 as 0600
  return unless File.exist? credentials_path

  existing_permissions = File.stat(credentials_path).mode & 0o777

  return if existing_permissions == 0o600

  alert_error <<-ERROR
Your gem push credentials file located at:

\t#{credentials_path}

has file permissions of 0#{existing_permissions.to_s 8} but 0600 is required.

To fix this error run:

\tchmod 0600 #{credentials_path}

You should reset your credentials at:

\thttps://rubygems.org/profile/edit

if you believe they were disclosed to a third party.
  ERROR

  terminate_interaction 1
end

#config_file_name

The name of the configuration file.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 590

def config_file_name
  @config_file_name || Gem.config_file
end

#credential_store_api_key_for(host)

Looks up Gem.host's own API key from the credential store, when the #credential_store setting is on. Only the host-specific account is consulted: falling back to the default account here would send the RubyGems.org key to whatever host was asked for, ahead of that host's own key in the credentials file. #credential_store_default_api_key covers the default account, at the precedence the credentials file uses for it.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 440

def credential_store_api_key_for(host)
  return nil if host.nil? || host.to_s.empty?
  return nil unless credential_store
  return nil unless store = active_credential_store

  store.get(self.class.(host))
end

#credential_store_default_api_key

The default RubyGems.org API key from the credential store, or nil. This is the stored counterpart of #rubygems_api_key, and belongs at the same point in the lookup order.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 471

def credential_store_default_api_key
  return nil unless credential_store
  return nil unless store = active_credential_store

  store.get(CREDENTIAL_STORE_DEFAULT_ACCOUNT)
end

#credential_store_read_failed_for?(host) ⇒ Boolean

True when a read for Gem.host failed rather than finding nothing. Whether the store holds a key for it is unknowable once the read fails, which is the point: a caller that would otherwise fall through to a key belonging to a different host has to treat "unknown" differently from "absent".

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 454

def credential_store_read_failed_for?(host)
  return false unless credential_store
  return false unless store = active_credential_store

  # #rubygems_api_key reads the default account on the way to answering, and
  # for the default host that is the only failure that can happen.
  return true if store.read_failed?(CREDENTIAL_STORE_DEFAULT_ACCOUNT)
  return false if host.nil? || host.to_s.empty?

  store.read_failed?(self.class.(host))
end

#credentials_path

Location of RubyGems.org credentials

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 372

def credentials_path
  credentials = File.join Gem.user_home, ".gem", "credentials"
  if File.exist? credentials
    credentials
  else
    File.join Gem.data_home, "gem", "credentials"
  end
end

#delete_stored_key(store, host) (private)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 851

def delete_stored_key(store, host)
   = self.class.(host)
  warn_unremoved_credential() if store&.available? && !store.delete()
end

#each {|:update_sources, @update_sources| ... }

Delegates to @hash

Yields:

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 614

def each(&block)
  hash = @hash.dup
  hash.delete :update_sources
  hash.delete :verbose
  hash.delete :backtrace
  hash.delete :bulk_threshold

  yield :update_sources, @update_sources
  yield :verbose, @verbose
  yield :backtrace, @backtrace
  yield :bulk_threshold, @bulk_threshold

  yield "config_file_name", @config_file_name if @config_file_name

  hash.each(&block)
end

#handle_arguments(arg_list)

Handle the command arguments.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 632

def handle_arguments(arg_list)
  @args = []

  arg_list.each do |arg|
    case arg
    when /^--(backtrace|traceback)$/ then
      @backtrace = true
    when /^--debug$/ then
      $DEBUG = true

      warn "NOTE:  Debugging mode prints all exceptions even when rescued"
    else
      @args << arg
    end
  end
end

#load_api_keys

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 381

def load_api_keys
  check_credentials_permissions

  @api_keys = if File.exist? credentials_path
    load_file(credentials_path)
  else
    @hash
  end

  if @api_keys.key? :rubygems_api_key
    @rubygems_api_key    = @api_keys[:rubygems_api_key]
    @api_keys[:rubygems] = @api_keys.delete :rubygems_api_key unless
      @api_keys.key? :rubygems
  end
end

#load_file(filename)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 546

def load_file(filename)
  yaml_errors = [ArgumentError]

  return {} unless filename && !filename.empty? && File.exist?(filename)

  begin
    config = self.class.load_with_rubygems_config_hash(File.read(filename))
    has_invalid_keys = config.keys.any? {|k| k.to_s.gsub(%r{https?:\/\/}, "").include?(": ") }
    has_invalid_values = config.values.any? {|v| v.is_a?(String) && v.gsub(%r{https?:\/\/}, "").match?(/\A\S+: /) }
    if has_invalid_keys || has_invalid_values
      warn "Failed to load #{filename} because it doesn't contain valid YAML hash"
      return {}
    else
      return config
    end
  rescue *yaml_errors => e
    warn "Failed to load #{filename}, #{e}"
  rescue Errno::EACCES
    warn "Failed to load #{filename} due to permissions problem."
  end

  {}
end

#normalize_credential_store(value, default) (private)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 881

def normalize_credential_store(value, default)
  # An environment variable can carry bytes String#downcase would reject.
  normalized = value.to_s.b.downcase

  if normalized.empty?
    default
  elsif CREDENTIAL_STORE_OFF.include?(normalized)
    false
  elsif CREDENTIAL_STORE_ON.include?(normalized)
    true
  else
    value
  end
end

#really_verbose

Really verbose mode gives you extra output.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 650

def really_verbose
  case verbose
  when true, false, nil then
    false
  else
    true
  end
end

#remove_api_key_from_file(host) (private)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 833

def remove_api_key_from_file(host)
  return unless File.exist?(credentials_path)

  unless File.writable?(credentials_path)
    alert_warning "The API key moved to the credential store but the plain text copy " \
                  "in #{credentials_path} could not be removed. Delete it yourself."
    return
  end

  key = self.class.normalize_credentials_key(host)
  config = load_file(credentials_path)
  return unless config.key?(key)

  config.delete(key)
  write_credentials(config)
  load_api_keys
end

#set_api_key(host, api_key)

Set a specific host's API key to api_key

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 481

def set_api_key(host, api_key)
  if credential_store && host != :rubygems_api_key
    store = active_credential_store

    if api_key.to_s.empty?
      delete_stored_key(store, host)
    elsif store&.set(self.class.(host), api_key)
      remove_api_key_from_file(host)
      return
    else
      delete_stored_key(store, host)
      warn_credential_store_fallback
    end
  end

  check_credentials_permissions

  config = load_file(credentials_path).merge(self.class.normalize_credentials_key(host) => api_key)

  write_credentials(config)

  load_api_keys # reload
end

#set_config_file_name(args) (private)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 896

def set_config_file_name(args)
  @config_file_name = ENV["GEMRC"]
  need_config_file_name = false

  args.each do |arg|
    if need_config_file_name
      @config_file_name = arg
      need_config_file_name = false
    elsif arg =~ /^--config-file=(.*)/
      @config_file_name = $1
    elsif /^--config-file$/.match?(arg)
      need_config_file_name = true
    end
  end
end

#state_file_name

The name of the state file.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 595

def state_file_name
  Gem.state_file
end

#to_yaml

This method is for internal use only.

to_yaml only overwrites things you can't override on the command line.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 660

def to_yaml # :nodoc:
  yaml_hash = {}
  yaml_hash[:backtrace] = @hash.fetch(:backtrace, DEFAULT_BACKTRACE)
  yaml_hash[:bulk_threshold] = @hash.fetch(:bulk_threshold, DEFAULT_BULK_THRESHOLD)
  yaml_hash[:sources] = Gem.sources.to_a
  yaml_hash[:update_sources] = @hash.fetch(:update_sources, DEFAULT_UPDATE_SOURCES)
  yaml_hash[:verbose] = @hash.fetch(:verbose, DEFAULT_VERBOSITY)

  yaml_hash[:concurrent_downloads] =
    @hash.fetch(:concurrent_downloads, DEFAULT_CONCURRENT_DOWNLOADS)

  yaml_hash[:install_extension_in_lib] =
    @hash.fetch(:install_extension_in_lib, DEFAULT_INSTALL_EXTENSION_IN_LIB)

  yaml_hash[:ssl_verify_mode] =
    @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode

  yaml_hash[:ssl_ca_cert] =
    @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert

  yaml_hash[:ssl_client_cert] =
    @hash[:ssl_client_cert] if @hash.key? :ssl_client_cert

  keys = yaml_hash.keys.map(&:to_s)
  keys << "debug"
  re = Regexp.union(*keys)

  @hash.each do |key, value|
    key = key.to_s
    next if key&.match?(re)
    yaml_hash[key.to_s] = value
  end

  self.class.dump_with_rubygems_yaml(yaml_hash)
end

#unset_api_key!

Remove the ~/.gem/credentials file to clear all the current sessions, and every RubyGems key from the credential store when the #credential_store setting is on, including keys saved for other hosts with gem signin --host.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 511

def unset_api_key!
  store = active_credential_store
  store_cleared =
    if store.nil?
      true
    elsif store.available?
      store.delete_all
    else
      # Failing here would make signout exit 1 on every platform without a
      # native store, and plain success would claim a removal nobody made.
      Gem::CredentialStore.warn_once "The credential store is enabled but unavailable, so any key it holds was left in place."
      true
    end

  file_removed =
    if File.exist?(credentials_path)
      # POSIX deletes a read-only file whenever the directory is writable, so
      # the marking has to be honored explicitly.
      if File.writable?(credentials_path)
        begin
          File.delete(credentials_path)
          true
        rescue SystemCallError
          false
        end
      else
        false
      end
    else
      false
    end

  [store_cleared, file_removed]
end

#warn_credential_store_fallback (private)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 862

def warn_credential_store_fallback
  alert_warning "Could not write the API key to the credential store, so it was written to #{credentials_path} in plain text."
end

#warn_unremoved_credential(account) (private)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 856

def warn_unremoved_credential()
  alert_warning "Could not remove the API key for #{} from the credential store. " \
                "It is still there and will be used instead of the one just set. " \
                "Remove it with your platform's credential manager."
end

#write

Writes out this config file, replacing its source.

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 697

def write
  require "fileutils"
  FileUtils.mkdir_p File.dirname(config_file_name)

  File.open config_file_name, "w" do |io|
    io.write to_yaml
  end
end

#write_credentials(config) (private)

[ GitHub ]

  
# File 'lib/rubygems/config_file.rb', line 822

def write_credentials(config)
  dirname = File.dirname credentials_path
  require "fileutils"
  FileUtils.mkdir_p(dirname)

  permissions = 0o600 & ~File.umask
  File.open(credentials_path, "w", permissions) do |f|
    f.write self.class.dump_with_rubygems_yaml(config)
  end
end