# frozen_string_literal: true#--# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.# All rights reserved.# See LICENSE.txt for permissions.#++require_relative"user_interaction"require"rbconfig"### Gem::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 <tt>gem:</tt> to set default arguments for all commands.## RubyGems options use symbol keys. Valid options are:## +:backtrace+:: See #backtrace# +:sources+:: Sets Gem::sources# +:verbose+:: See #verbose# +:concurrent_downloads+:: See #concurrent_downloads## 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)classGem::ConfigFileincludeGem::UserInteractionDEFAULT_BACKTRACE=trueDEFAULT_BULK_THRESHOLD=1000DEFAULT_VERBOSITY=trueDEFAULT_UPDATE_SOURCES=trueDEFAULT_CONCURRENT_DOWNLOADS=8DEFAULT_CERT_EXPIRATION_LENGTH_DAYS=365DEFAULT_IPV4_FALLBACK_ENABLED=false# TODO: Use false as default value for this option in RubyGems 4.0DEFAULT_INSTALL_EXTENSION_IN_LIB=true### For Ruby packagers to set configuration defaults. Set in# rubygems/defaults/operating_system.rbOPERATING_SYSTEM_DEFAULTS=Gem.operating_system_defaults### For Ruby implementers to set configuration defaults. Set in# rubygems/defaults/#{RUBY_ENGINE}.rbPLATFORM_DEFAULTS=Gem.platform_defaults# :stopdoc:SYSTEM_CONFIG_PATH=beginrequire"etc"Etc.sysconfdirrescueLoadError,NoMethodErrorRbConfig::CONFIG["sysconfdir"]||"/etc"end# :startdoc:SYSTEM_WIDE_CONFIG_FILE=File.joinSYSTEM_CONFIG_PATH,"gemrc"### List of arguments supplied to the config file object.attr_reader:args### Where to look for gems (deprecated)attr_accessor:path### Where to install gems (deprecated)attr_accessor:home### True if we print backtraces on errors.attr_writer:backtrace### Bulk threshold value. If the number of missing gems are above this# threshold value, then a bulk download technique is used. (deprecated)attr_accessor:bulk_threshold### Verbose level of output:# * false -- No output# * true -- Normal output# * :loud -- Extra outputattr_accessor:verbose### Number of gem downloads that should be performed concurrently.attr_accessor:concurrent_downloads### True if we want to update the SourceInfoCache every time, false otherwiseattr_accessor:update_sources### True if we want to force specification of gem server when pushing a gemattr_accessor:disable_default_gem_server# openssl verify mode value, used for remote https connectionattr_reader:ssl_verify_mode### Path name of directory or file of openssl CA certificate, used for remote# https connectionattr_accessor:ssl_ca_cert### sources to look for gemsattr_accessor:sources### Expiration length to sign a certificateattr_accessor:cert_expiration_length_days### Install extensions into lib as well as into the extension directory.attr_accessor:install_extension_in_lib### == Experimental ==# Fallback to IPv4 when IPv6 is not reachable or slow (default: false)attr_accessor:ipv4_fallback_enabled### Path name of directory or file of openssl client certificate, used for remote https connection with client authenticationattr_reader:ssl_client_cert### 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.## <tt>--config-file</tt>, <tt>--config-file==NAME</tt>::# Obviously these need to be handled by the ConfigFile object to ensure we# get the right config file.## <tt>--backtrace</tt>::# Backtrace needs to be turned on early so that errors before normal# option parsing can be properly handled.## <tt>--debug</tt>::# Enable Ruby level debug messages. Handled early for the same reason as# --backtrace.#--# TODO: parse options upstream, pass in options directlydefinitialize(args)set_config_file_name(args)@backtrace=DEFAULT_BACKTRACE@bulk_threshold=DEFAULT_BULK_THRESHOLD@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_ENABLEDoperating_system_config=Marshal.loadMarshal.dump(OPERATING_SYSTEM_DEFAULTS)platform_config=Marshal.loadMarshal.dump(PLATFORM_DEFAULTS)system_config=load_fileSYSTEM_WIDE_CONFIG_FILEuser_config=load_fileconfig_file_nameenvironment_config=(ENV["GEMRC"]||"").split(File::PATH_SEPARATOR).inject({})do|result,file|result.mergeload_filefileend@hash=operating_system_config.mergeplatform_configunlessargs.index"--norc"@hash=@hash.mergesystem_config@hash=@hash.mergeuser_config@hash=@hash.mergeenvironment_configend@hash.transform_keys!do|k|# gemhome and gempath are not working with symbol keysif%w[backtrace bulk_threshold verbose update_sources cert_expiration_length_days
install_extension_in_lib ipv4_fallback_enabled sources disable_default_gem_server
ssl_verify_mode ssl_ca_cert ssl_client_cert].include?(k)k.to_symelsekendend# 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@verbose=@hash[:verbose]if@hash.key?:verbose@update_sources=@hash[:update_sources]if@hash.key?:update_sources# TODO: We should handle concurrent_downloads same as other options@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@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=nilhandle_argumentsargsend### Hash of RubyGems.org and alternate API keysdefapi_keysload_api_keysunless@api_keys@api_keysend### Checks the permissions of the credentials file. If they are not 0600 an# error message is displayed and RubyGems aborts.defcheck_credentials_permissionsreturnifGem.win_platform?# windows doesn't write 0600 as 0600returnunlessFile.exist?credentials_pathexisting_permissions=File.stat(credentials_path).mode&0o777returnifexisting_permissions==0o600alert_error<<-ERROR
Your gem push credentials file located at:
\t#{credentials_path}
has file permissions of 0#{existing_permissions.to_s8} 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.
ERRORterminate_interaction1end### Location of RubyGems.org credentialsdefcredentials_pathcredentials=File.joinGem.user_home,".gem","credentials"ifFile.exist?credentialscredentialselseFile.joinGem.data_home,"gem","credentials"endenddefload_api_keyscheck_credentials_permissions@api_keys=ifFile.exist?credentials_pathload_file(credentials_path)else@hashendif@api_keys.key?:rubygems_api_key@rubygems_api_key=@api_keys[:rubygems_api_key]@api_keys[:rubygems]=@api_keys.delete:rubygems_api_keyunless@api_keys.key?:rubygemsendend### Returns the RubyGems.org API keydefrubygems_api_keyload_api_keysunless@rubygems_api_key@rubygems_api_keyend### Sets the RubyGems.org API key to +api_key+defrubygems_api_key=(api_key)set_api_key:rubygems_api_key,api_key@rubygems_api_key=api_keyend### Set a specific host's API key to +api_key+defset_api_key(host,api_key)check_credentials_permissionsconfig=load_file(credentials_path).merge(host=>api_key)dirname=File.dirnamecredentials_pathrequire"fileutils"FileUtils.mkdir_p(dirname)permissions=0o600&(~File.umask)File.open(credentials_path,"w",permissions)do|f|f.writeself.class.dump_with_rubygems_yaml(config)endload_api_keys# reloadend### Remove the +~/.gem/credentials+ file to clear all the current sessions.defunset_api_key!returnfalseunlessFile.exist?(credentials_path)File.delete(credentials_path)enddefload_file(filename)yaml_errors=[ArgumentError]return{}unlessfilename&&!filename.empty?&&File.exist?(filename)beginconfig=self.class.load_with_rubygems_config_hash(File.read(filename))ifconfig.keys.any?{|k|k.to_s.gsub(%r{https?:\/\/},"").include?(": ")}warn"Failed to load #{filename} because it doesn't contain valid YAML hash"return{}elsereturnconfigendrescue*yaml_errors=>ewarn"Failed to load #{filename}, #{e}"rescueErrno::EACCESwarn"Failed to load #{filename} due to permissions problem."end{}end# True if the backtrace option has been specified, or debug is on.defbacktrace@backtrace||$DEBUGend# Check state file is writable. Creates empty file if not present to ensure we can write to it.defstate_file_writable?ifFile.exist?(state_file_name)File.writable?(state_file_name)elserequire"fileutils"FileUtils.mkdir_pFile.dirname(state_file_name)File.open(state_file_name,"w"){}trueendrescueErrno::EACCESfalseend# The name of the configuration file.defconfig_file_name@config_file_name||Gem.config_fileend# The name of the state file.defstate_file_nameGem.state_fileend# Reads time of last update check from state filedeflast_update_checkifFile.readable?(state_file_name)File.read(state_file_name).to_ielse0endend# Writes time of last update check to state filedeflast_update_check=(timestamp)File.write(state_file_name,timestamp.to_s)ifstate_file_writable?end# Delegates to @hashdefeach(&block)hash=@hash.duphash.delete:update_sourceshash.delete:verbosehash.delete:backtracehash.delete:bulk_thresholdyield:update_sources,@update_sourcesyield:verbose,@verboseyield:backtrace,@backtraceyield:bulk_threshold,@bulk_thresholdyield"config_file_name",@config_file_nameif@config_file_namehash.each(&block)end# Handle the command arguments.defhandle_arguments(arg_list)@args=[]arg_list.eachdo|arg|caseargwhen/^--(backtrace|traceback)$/then@backtrace=truewhen/^--debug$/then$DEBUG=truewarn"NOTE: Debugging mode prints all exceptions even when rescued"else@args<<argendendend# Really verbose mode gives you extra output.defreally_verbosecaseverbosewhentrue,false,nilthenfalseelsetrueendend# to_yaml only overwrites things you can't override on the command line.defto_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_ayaml_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_modeyaml_hash[:ssl_ca_cert]=@hash[:ssl_ca_cert]if@hash.key?:ssl_ca_certyaml_hash[:ssl_client_cert]=@hash[:ssl_client_cert]if@hash.key?:ssl_client_certkeys=yaml_hash.keys.map(&:to_s)keys<<"debug"re=Regexp.union(*keys)@hash.eachdo|key,value|key=key.to_snextifkey&.match?(re)yaml_hash[key.to_s]=valueendself.class.dump_with_rubygems_yaml(yaml_hash)end# Writes out this config file, replacing its source.defwriterequire"fileutils"FileUtils.mkdir_pFile.dirname(config_file_name)File.openconfig_file_name,"w"do|io|io.writeto_yamlendend# Return the configuration information for +key+.def[](key)@hash[key]||@hash[key.to_s]end# Set configuration option +key+ to +value+.def[]=(key,value)@hash[key]=valueenddef==(other)# :nodoc:self.class===other&&@backtrace==other.backtrace&&@bulk_threshold==other.bulk_threshold&&@verbose==other.verbose&&@update_sources==other.update_sources&&@hash==other.hashendattr_reader:hashprotected:hashdefself.dump_with_rubygems_yaml(content)content.transform_keys!do|k|k.is_a?(Symbol)?":#{k}":kendrequire_relative"yaml_serializer"Gem::YAMLSerializer.dump(content)enddefself.load_with_rubygems_config_hash(yaml)require_relative"yaml_serializer"content=Gem::YAMLSerializer.load(yaml)deep_transform_config_keys!(content)endprivatedefself.deep_transform_config_keys!(config)config.transform_keys!do|k|ifk.match?(/\A:(.*)\Z/)k[1..-1].to_symelsifk.include?("__")||k.match?(%r{/\Z})ifk.is_a?(Symbol)k.to_s.gsub(/__/,".").gsub(%r{/\Z},"").to_symelsek.dup.gsub(/__/,".").gsub(%r{/\Z},"")endelsekendendconfig.transform_values!do|v|ifv.is_a?(String)ifv.match?(/\A:(.*)\Z/)v[1..-1].to_symelsifv.match?(/\A[+-]?\d+\Z/)v.to_ielsifv.match?(/\Atrue|false\Z/)v=="true"elsifv.empty?nilelsevendelsifv.empty?nilelsifv.is_a?(Hash)deep_transform_config_keys!(v)elsevendendconfigenddefset_config_file_name(args)@config_file_name=ENV["GEMRC"]need_config_file_name=falseargs.eachdo|arg|ifneed_config_file_name@config_file_name=argneed_config_file_name=falseelsifarg=~/^--config-file=(.*)/@config_file_name=$1elsif/^--config-file$/.match?(arg)need_config_file_name=trueendendendend