# frozen_string_literal: true
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# See LICENSE.txt for permissions.
# Must be first since it unloads the prelude from 1.9.2
require_relative "rubygems/compatibility"
require_relative "rubygems/defaults"
require_relative "rubygems/deprecate"
require_relative "rubygems/errors"
# RubyGems is the Ruby standard for publishing and managing third party
# For user documentation, see:
# * <tt>gem help</tt> and <tt>gem help [command]</tt>
# * {RubyGems User Guide}[https://guides.rubygems.org/]
# * {Frequently Asked Questions}[https://guides.rubygems.org/faqs]
# For gem developer documentation see:
# * {Creating Gems}[https://guides.rubygems.org/make-your-own-gem]
# * Gem::Version for version dependency notes
# Further RubyGems documentation can be found at:
# * {RubyGems Guides}[https://guides.rubygems.org]
# * {RubyGems API}[https://www.rubydoc.info/github/rubygems/rubygems] (also available from
# RubyGems will load plugins in the latest version of each installed gem or
# $LOAD_PATH. Plugins must be named 'rubygems_plugin' (.rb, .so, etc) and
# placed at the root of your gem's #require_path. Plugins are installed at a
# special location and loaded on boot.
# For an example plugin, see the {Graph gem}[https://github.com/seattlerb/graph]
# which adds a <tt>gem graph</tt> command.
# == RubyGems Defaults, Packaging
# RubyGems defaults are stored in lib/rubygems/defaults.rb. If you're packaging
# RubyGems or implementing Ruby you can change RubyGems' defaults.
# For RubyGems packagers, provide lib/rubygems/defaults/operating_system.rb
# and override any defaults from lib/rubygems/defaults.rb.
# For Ruby implementers, provide lib/rubygems/defaults/#{RUBY_ENGINE}.rb and
# override any defaults from lib/rubygems/defaults.rb.
# If you need RubyGems to perform extra work on install or uninstall, your
# defaults override file can set pre/post install and uninstall hooks.
# See Gem::pre_install, Gem::pre_uninstall, Gem::post_install,
# You can submit bugs to the
# {RubyGems bug tracker}[https://github.com/rubygems/rubygems/issues]
# RubyGems is currently maintained by Eric Hodel.
# RubyGems was originally developed at RubyConf 2003 by:
# * Rich Kilmer -- rich(at)infoether.com
# * Chad Fowler -- chad(at)chadfowler.com
# * David Black -- dblack(at)wobblini.net
# * Paul Brannan -- paul(at)atdesk.com
# * Jim Weirich -- jim(at)weirichhouse.org
# * Gavin Sinclair -- gsinclair(at)soyabean.com.au
# * George Marrows -- george.marrows(at)ntlworld.com
# * Dick Davies -- rasputnik(at)hellooperator.net
# * Mauricio Fernandez -- batsman.geo(at)yahoo.com
# * Simon Strandgaard -- neoneye(at)adslhome.dk
# * Dave Glasser -- glasser(at)mit.edu
# * Paul Duncan -- pabs(at)pablotron.org
# * Ville Aine -- vaine(at)cs.helsinki.fi
# * Eric Hodel -- drbrain(at)segment7.net
# * Daniel Berger -- djberg96(at)gmail.com
# * Phil Hagelberg -- technomancy(at)gmail.com
# * Ryan Davis -- ryand-ruby(at)zenspider.com
# * Evan Phoenix -- evan(at)fallingsnow.net
# * Steve Klabnik -- steve(at)steveklabnik.com
# (If your name is missing, PLEASE let us know!)
# See {LICENSE.txt}[rdoc-ref:lib/rubygems/LICENSE.txt] for permissions.
# An Array of Regexps that match windows Ruby platforms.
# Subdirectories in a gem repository
REPOSITORY_SUBDIRECTORIES = %w[
# Subdirectories in a gem repository for default gems
REPOSITORY_DEFAULT_GEM_SUBDIRECTORIES = %w[
LOADED_SPECS_MUTEX = Thread::Mutex.new
@path_to_default_spec_map = {}
@post_install_hooks ||= []
@post_uninstall_hooks ||= []
@pre_uninstall_hooks ||= []
@pre_install_hooks ||= []
@default_source_date_epoch = nil
@discover_gems_on_require = true
# Try to activate a gem containing +path+. Returns true if
# activation succeeded or wasn't needed because it was already
# activated. Returns false if it can't find the path in a gem.
def self.try_activate(path)
# finds the _latest_ version... regardless of loaded specs and their deps
# if another gem had a requirement that would mean we shouldn't
# activate the latest version, then either it would already be activated
# or if it was ambiguous (and thus unresolved) the code in our custom
# require will try to activate the more specific version.
spec = Gem::Specification.find_by_path path
return true if spec.activated?
rescue Gem::LoadError => e # this could fail due to gem dep collisions, go lax
spec_by_name = Gem::Specification.find_by_name(spec.name)
def self.finish_resolve(request_set=Gem::RequestSet.new)
request_set.import Gem::Specification.unresolved_deps.values
request_set.import Gem.loaded_specs.values.map {|s| Gem::Dependency.new(s.name, s.version) }
request_set.resolve_current.each do |s|
# Find the full path to the executable for gem +name+. If the +exec_name+
# is not given, an exception will be raised, otherwise the
# specified executable's path is returned. +requirements+ allows
# you to specify specific gem versions.
def self.bin_path(name, exec_name = nil, *requirements)
requirements = Gem::Requirement.default if
find_spec_for_exe(name, exec_name, requirements).bin_file exec_name
def self.find_spec_for_exe(name, exec_name, requirements)
raise ArgumentError, "you must supply exec_name" unless exec_name
dep = Gem::Dependency.new name, requirements
loaded = Gem.loaded_specs[name]
return loaded if loaded && dep.matches_spec?(loaded)
specs = dep.matching_specs(true)
specs = specs.find_all do |spec|
spec.executables.include? exec_name
unless spec = specs.first
msg = "can't find gem #{dep} with executable #{exec_name}"
raise Gem::GemNotFoundException, msg
private_class_method :find_spec_for_exe
# Find the full path to the executable for gem +name+. If the +exec_name+
# is not given, an exception will be raised, otherwise the
# specified executable's path is returned. +requirements+ allows
# you to specify specific gem versions.
# A side effect of this method is that it will activate the gem that
# contains the executable.
# This method should *only* be used in bin stub files.
def self.activate_bin_path(name, exec_name = nil, *requirements) # :nodoc:
spec = find_spec_for_exe name, exec_name, requirements
Gem::LOADED_SPECS_MUTEX.synchronize do
# The mode needed to read a file as straight binary.
# The path where gem executables are to be installed.
def self.bindir(install_dir=Gem.dir)
return File.join install_dir, "bin" unless
install_dir.to_s == Gem.default_dir.to_s
# The path were rubygems plugins are to be installed.
def self.plugindir(install_dir=Gem.dir)
File.join install_dir, "plugins"
# Reset the +dir+ and +path+ values. The next time +dir+ or +path+
# is requested, the values will be calculated from scratch. This is
# mainly used by the unit tests to provide test isolation.
Gem::Security.reset if defined?(Gem::Security)
# The standard configuration object for gems.
@configuration ||= Gem::ConfigFile.new []
# Use the given configuration object (which implements the ConfigFile
# protocol) as the standard configuration object.
def self.configuration=(config)
# A Zlib::Deflate.deflate wrapper
Zlib::Deflate.deflate data
# Retrieve the PathSupport object that RubyGems uses to
@paths ||= Gem::PathSupport.new(ENV)
# Initialize the filesystem paths to use from +env+.
# +env+ is a hash-like object (typically ENV) that
# is queried for 'GEM_HOME', 'GEM_PATH', and 'GEM_SPEC_CACHE'
# Keys for the +env+ hash should be Strings, and values of the hash should
when "GEM_HOME", "GEM_PATH", "GEM_SPEC_CACHE"
unless Gem::Deprecate.skip
Array values in the parameter to `Gem.paths=` are deprecated.
Please use a String or nil.
An Array (#{env.inspect}) was passed in from #{caller[3]}
target[k] = v.join File::PATH_SEPARATOR
@paths = Gem::PathSupport.new ENV.to_hash.merge(target)
Gem::Specification.dirs = @paths.path
# The path where gems are to be installed.
# Quietly ensure the Gem directory +dir+ contains all the proper
# subdirectories. If we can't create a directory due to a permission
# problem, then we will silently continue.
# If +mode+ is given, missing directories are created with this mode.
# World-writable directories will never be created.
def self.ensure_gem_subdirectories(dir = Gem.dir, mode = nil)
ensure_subdirectories(dir, mode, REPOSITORY_SUBDIRECTORIES)
# Quietly ensure the Gem directory +dir+ contains all the proper
# subdirectories for handling default gems. If we can't create a
# directory due to a permission problem, then we will silently continue.
# If +mode+ is given, missing directories are created with this mode.
# World-writable directories will never be created.
def self.ensure_default_gem_subdirectories(dir = Gem.dir, mode = nil)
ensure_subdirectories(dir, mode, REPOSITORY_DEFAULT_GEM_SUBDIRECTORIES)
def self.ensure_subdirectories(dir, mode, subdirs) # :nodoc:
File.umask old_umask | 0o002
options[:mode] = mode if mode
subdir = File.join dir, name
next if File.exist? subdir
FileUtils.mkdir_p subdir, **options
# The extension API version of ruby. This includes the static vs non-static
# distinction as extensions cannot be shared between the two.
def self.extension_api_version # :nodoc:
if RbConfig::CONFIG["ENABLE_SHARED"] == "no"
"#{ruby_api_version}-static"
# Returns a list of paths matching +glob+ that can be used by a gem to pick
# up features from other gems. For example:
# Gem.find_files('rdoc/discover').each do |path| load path end
# if +check_load_path+ is true (the default), then find_files also searches
# $LOAD_PATH for files as well as gems.
# Note that find_files will return all files even if they are from different
# versions of the same gem. See also find_latest_files
def self.find_files(glob, check_load_path=true)
files = find_files_from_load_path glob if check_load_path
gem_specifications = @gemdeps ? Gem.loaded_specs.values : Gem::Specification.stubs
files.concat gem_specifications.map {|spec|
spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}")
# $LOAD_PATH might contain duplicate entries or reference
# the spec dirs directly, so we prune.
files.uniq! if check_load_path
def self.find_files_from_load_path(glob) # :nodoc:
glob_with_suffixes = "#{glob}#{Gem.suffix_pattern}"
$LOAD_PATH.map do |load_path|
Gem::Util.glob_files_in_dir(glob_with_suffixes, load_path)
end.flatten.select {|file| File.file? file }
# Returns a list of paths matching +glob+ from the latest gems that can be
# used by a gem to pick up features from other gems. For example: