PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/rubygems.rb

https://github.com/wanabe/ruby
Ruby | 1358 lines | 670 code | 259 blank | 429 comment | 52 complexity | f3b095e3082e3c913451679449c08f68 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0, 0BSD, Unlicense, GPL-2.0, BSD-3-Clause
  1. # frozen_string_literal: true
  2. #--
  3. # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
  4. # All rights reserved.
  5. # See LICENSE.txt for permissions.
  6. #++
  7. require 'rbconfig'
  8. module Gem
  9. VERSION = "3.3.0.dev".freeze
  10. end
  11. # Must be first since it unloads the prelude from 1.9.2
  12. require_relative 'rubygems/compatibility'
  13. require_relative 'rubygems/defaults'
  14. require_relative 'rubygems/deprecate'
  15. require_relative 'rubygems/errors'
  16. ##
  17. # RubyGems is the Ruby standard for publishing and managing third party
  18. # libraries.
  19. #
  20. # For user documentation, see:
  21. #
  22. # * <tt>gem help</tt> and <tt>gem help [command]</tt>
  23. # * {RubyGems User Guide}[https://guides.rubygems.org/]
  24. # * {Frequently Asked Questions}[https://guides.rubygems.org/faqs]
  25. #
  26. # For gem developer documentation see:
  27. #
  28. # * {Creating Gems}[https://guides.rubygems.org/make-your-own-gem]
  29. # * Gem::Specification
  30. # * Gem::Version for version dependency notes
  31. #
  32. # Further RubyGems documentation can be found at:
  33. #
  34. # * {RubyGems Guides}[https://guides.rubygems.org]
  35. # * {RubyGems API}[https://www.rubydoc.info/github/rubygems/rubygems] (also available from
  36. # <tt>gem server</tt>)
  37. #
  38. # == RubyGems Plugins
  39. #
  40. # RubyGems will load plugins in the latest version of each installed gem or
  41. # $LOAD_PATH. Plugins must be named 'rubygems_plugin' (.rb, .so, etc) and
  42. # placed at the root of your gem's #require_path. Plugins are installed at a
  43. # special location and loaded on boot.
  44. #
  45. # For an example plugin, see the {Graph gem}[https://github.com/seattlerb/graph]
  46. # which adds a `gem graph` command.
  47. #
  48. # == RubyGems Defaults, Packaging
  49. #
  50. # RubyGems defaults are stored in lib/rubygems/defaults.rb. If you're packaging
  51. # RubyGems or implementing Ruby you can change RubyGems' defaults.
  52. #
  53. # For RubyGems packagers, provide lib/rubygems/defaults/operating_system.rb
  54. # and override any defaults from lib/rubygems/defaults.rb.
  55. #
  56. # For Ruby implementers, provide lib/rubygems/defaults/#{RUBY_ENGINE}.rb and
  57. # override any defaults from lib/rubygems/defaults.rb.
  58. #
  59. # If you need RubyGems to perform extra work on install or uninstall, your
  60. # defaults override file can set pre/post install and uninstall hooks.
  61. # See Gem::pre_install, Gem::pre_uninstall, Gem::post_install,
  62. # Gem::post_uninstall.
  63. #
  64. # == Bugs
  65. #
  66. # You can submit bugs to the
  67. # {RubyGems bug tracker}[https://github.com/rubygems/rubygems/issues]
  68. # on GitHub
  69. #
  70. # == Credits
  71. #
  72. # RubyGems is currently maintained by Eric Hodel.
  73. #
  74. # RubyGems was originally developed at RubyConf 2003 by:
  75. #
  76. # * Rich Kilmer -- rich(at)infoether.com
  77. # * Chad Fowler -- chad(at)chadfowler.com
  78. # * David Black -- dblack(at)wobblini.net
  79. # * Paul Brannan -- paul(at)atdesk.com
  80. # * Jim Weirich -- jim(at)weirichhouse.org
  81. #
  82. # Contributors:
  83. #
  84. # * Gavin Sinclair -- gsinclair(at)soyabean.com.au
  85. # * George Marrows -- george.marrows(at)ntlworld.com
  86. # * Dick Davies -- rasputnik(at)hellooperator.net
  87. # * Mauricio Fernandez -- batsman.geo(at)yahoo.com
  88. # * Simon Strandgaard -- neoneye(at)adslhome.dk
  89. # * Dave Glasser -- glasser(at)mit.edu
  90. # * Paul Duncan -- pabs(at)pablotron.org
  91. # * Ville Aine -- vaine(at)cs.helsinki.fi
  92. # * Eric Hodel -- drbrain(at)segment7.net
  93. # * Daniel Berger -- djberg96(at)gmail.com
  94. # * Phil Hagelberg -- technomancy(at)gmail.com
  95. # * Ryan Davis -- ryand-ruby(at)zenspider.com
  96. # * Evan Phoenix -- evan(at)fallingsnow.net
  97. # * Steve Klabnik -- steve(at)steveklabnik.com
  98. #
  99. # (If your name is missing, PLEASE let us know!)
  100. #
  101. # == License
  102. #
  103. # See {LICENSE.txt}[rdoc-ref:lib/rubygems/LICENSE.txt] for permissions.
  104. #
  105. # Thanks!
  106. #
  107. # -The RubyGems Team
  108. module Gem
  109. RUBYGEMS_DIR = File.dirname File.expand_path(__FILE__)
  110. # Taint support is deprecated in Ruby 2.7.
  111. # This allows switching ".untaint" to ".tap(&Gem::UNTAINT)",
  112. # to avoid deprecation warnings in Ruby 2.7.
  113. UNTAINT = RUBY_VERSION < '2.7' ? :untaint.to_sym : proc{}
  114. # When https://bugs.ruby-lang.org/issues/17259 is available, there is no need to override Kernel#warn
  115. KERNEL_WARN_IGNORES_INTERNAL_ENTRIES = RUBY_ENGINE == "truffleruby" ||
  116. (RUBY_ENGINE == "ruby" && RUBY_VERSION >= '3.0')
  117. ##
  118. # An Array of Regexps that match windows Ruby platforms.
  119. WIN_PATTERNS = [
  120. /bccwin/i,
  121. /cygwin/i,
  122. /djgpp/i,
  123. /mingw/i,
  124. /mswin/i,
  125. /wince/i,
  126. ].freeze
  127. GEM_DEP_FILES = %w[
  128. gem.deps.rb
  129. gems.rb
  130. Gemfile
  131. Isolate
  132. ].freeze
  133. ##
  134. # Subdirectories in a gem repository
  135. REPOSITORY_SUBDIRECTORIES = %w[
  136. build_info
  137. cache
  138. doc
  139. extensions
  140. gems
  141. plugins
  142. specifications
  143. ].freeze
  144. ##
  145. # Subdirectories in a gem repository for default gems
  146. REPOSITORY_DEFAULT_GEM_SUBDIRECTORIES = %w[
  147. gems
  148. specifications/default
  149. ].freeze
  150. ##
  151. # Exception classes used in a Gem.read_binary +rescue+ statement
  152. READ_BINARY_ERRORS = [Errno::EACCES, Errno::EROFS, Errno::ENOSYS, Errno::ENOTSUP].freeze
  153. ##
  154. # Exception classes used in Gem.write_binary +rescue+ statement
  155. WRITE_BINARY_ERRORS = [Errno::ENOSYS, Errno::ENOTSUP].freeze
  156. @@win_platform = nil
  157. @configuration = nil
  158. @gemdeps = nil
  159. @loaded_specs = {}
  160. LOADED_SPECS_MUTEX = Thread::Mutex.new
  161. @path_to_default_spec_map = {}
  162. @platforms = []
  163. @ruby = nil
  164. @ruby_api_version = nil
  165. @sources = nil
  166. @post_build_hooks ||= []
  167. @post_install_hooks ||= []
  168. @post_uninstall_hooks ||= []
  169. @pre_uninstall_hooks ||= []
  170. @pre_install_hooks ||= []
  171. @pre_reset_hooks ||= []
  172. @post_reset_hooks ||= []
  173. @default_source_date_epoch = nil
  174. ##
  175. # Try to activate a gem containing +path+. Returns true if
  176. # activation succeeded or wasn't needed because it was already
  177. # activated. Returns false if it can't find the path in a gem.
  178. def self.try_activate(path)
  179. # finds the _latest_ version... regardless of loaded specs and their deps
  180. # if another gem had a requirement that would mean we shouldn't
  181. # activate the latest version, then either it would already be activated
  182. # or if it was ambiguous (and thus unresolved) the code in our custom
  183. # require will try to activate the more specific version.
  184. spec = Gem::Specification.find_by_path path
  185. return false unless spec
  186. return true if spec.activated?
  187. begin
  188. spec.activate
  189. rescue Gem::LoadError => e # this could fail due to gem dep collisions, go lax
  190. spec_by_name = Gem::Specification.find_by_name(spec.name)
  191. if spec_by_name.nil?
  192. raise e
  193. else
  194. spec_by_name.activate
  195. end
  196. end
  197. return true
  198. end
  199. def self.needs
  200. rs = Gem::RequestSet.new
  201. yield rs
  202. finish_resolve rs
  203. end
  204. def self.finish_resolve(request_set=Gem::RequestSet.new)
  205. request_set.import Gem::Specification.unresolved_deps.values
  206. request_set.import Gem.loaded_specs.values.map {|s| Gem::Dependency.new(s.name, s.version) }
  207. request_set.resolve_current.each do |s|
  208. s.full_spec.activate
  209. end
  210. end
  211. ##
  212. # Find the full path to the executable for gem +name+. If the +exec_name+
  213. # is not given, an exception will be raised, otherwise the
  214. # specified executable's path is returned. +requirements+ allows
  215. # you to specify specific gem versions.
  216. def self.bin_path(name, exec_name = nil, *requirements)
  217. requirements = Gem::Requirement.default if
  218. requirements.empty?
  219. find_spec_for_exe(name, exec_name, requirements).bin_file exec_name
  220. end
  221. def self.find_spec_for_exe(name, exec_name, requirements)
  222. raise ArgumentError, "you must supply exec_name" unless exec_name
  223. dep = Gem::Dependency.new name, requirements
  224. loaded = Gem.loaded_specs[name]
  225. return loaded if loaded && dep.matches_spec?(loaded)
  226. specs = dep.matching_specs(true)
  227. specs = specs.find_all do |spec|
  228. spec.executables.include? exec_name
  229. end if exec_name
  230. unless spec = specs.first
  231. msg = "can't find gem #{dep} with executable #{exec_name}"
  232. if dep.filters_bundler? && bundler_message = Gem::BundlerVersionFinder.missing_version_message
  233. msg = bundler_message
  234. end
  235. raise Gem::GemNotFoundException, msg
  236. end
  237. spec
  238. end
  239. private_class_method :find_spec_for_exe
  240. ##
  241. # Find the full path to the executable for gem +name+. If the +exec_name+
  242. # is not given, an exception will be raised, otherwise the
  243. # specified executable's path is returned. +requirements+ allows
  244. # you to specify specific gem versions.
  245. #
  246. # A side effect of this method is that it will activate the gem that
  247. # contains the executable.
  248. #
  249. # This method should *only* be used in bin stub files.
  250. def self.activate_bin_path(name, exec_name = nil, *requirements) # :nodoc:
  251. spec = find_spec_for_exe name, exec_name, requirements
  252. Gem::LOADED_SPECS_MUTEX.synchronize do
  253. spec.activate
  254. finish_resolve
  255. end
  256. spec.bin_file exec_name
  257. end
  258. ##
  259. # The mode needed to read a file as straight binary.
  260. def self.binary_mode
  261. 'rb'
  262. end
  263. ##
  264. # The path where gem executables are to be installed.
  265. def self.bindir(install_dir=Gem.dir)
  266. return File.join install_dir, 'bin' unless
  267. install_dir.to_s == Gem.default_dir.to_s
  268. Gem.default_bindir
  269. end
  270. ##
  271. # The path were rubygems plugins are to be installed.
  272. def self.plugindir(install_dir=Gem.dir)
  273. File.join install_dir, 'plugins'
  274. end
  275. ##
  276. # Reset the +dir+ and +path+ values. The next time +dir+ or +path+
  277. # is requested, the values will be calculated from scratch. This is
  278. # mainly used by the unit tests to provide test isolation.
  279. def self.clear_paths
  280. @paths = nil
  281. @user_home = nil
  282. Gem::Specification.reset
  283. Gem::Security.reset if defined?(Gem::Security)
  284. end
  285. ##
  286. # The standard configuration object for gems.
  287. def self.configuration
  288. @configuration ||= Gem::ConfigFile.new []
  289. end
  290. ##
  291. # Use the given configuration object (which implements the ConfigFile
  292. # protocol) as the standard configuration object.
  293. def self.configuration=(config)
  294. @configuration = config
  295. end
  296. ##
  297. # The path to the data directory specified by the gem name. If the
  298. # package is not available as a gem, return nil.
  299. def self.datadir(gem_name)
  300. spec = @loaded_specs[gem_name]
  301. return nil if spec.nil?
  302. spec.datadir
  303. end
  304. ##
  305. # A Zlib::Deflate.deflate wrapper
  306. def self.deflate(data)
  307. require 'zlib'
  308. Zlib::Deflate.deflate data
  309. end
  310. # Retrieve the PathSupport object that RubyGems uses to
  311. # lookup files.
  312. def self.paths
  313. @paths ||= Gem::PathSupport.new(ENV)
  314. end
  315. # Initialize the filesystem paths to use from +env+.
  316. # +env+ is a hash-like object (typically ENV) that
  317. # is queried for 'GEM_HOME', 'GEM_PATH', and 'GEM_SPEC_CACHE'
  318. # Keys for the +env+ hash should be Strings, and values of the hash should
  319. # be Strings or +nil+.
  320. def self.paths=(env)
  321. clear_paths
  322. target = {}
  323. env.each_pair do |k,v|
  324. case k
  325. when 'GEM_HOME', 'GEM_PATH', 'GEM_SPEC_CACHE'
  326. case v
  327. when nil, String
  328. target[k] = v
  329. when Array
  330. unless Gem::Deprecate.skip
  331. warn <<-EOWARN
  332. Array values in the parameter to `Gem.paths=` are deprecated.
  333. Please use a String or nil.
  334. An Array (#{env.inspect}) was passed in from #{caller[3]}
  335. EOWARN
  336. end
  337. target[k] = v.join File::PATH_SEPARATOR
  338. end
  339. else
  340. target[k] = v
  341. end
  342. end
  343. @paths = Gem::PathSupport.new ENV.to_hash.merge(target)
  344. Gem::Specification.dirs = @paths.path
  345. end
  346. ##
  347. # The path where gems are to be installed.
  348. def self.dir
  349. paths.home
  350. end
  351. def self.path
  352. paths.path
  353. end
  354. def self.spec_cache_dir
  355. paths.spec_cache_dir
  356. end
  357. ##
  358. # Quietly ensure the Gem directory +dir+ contains all the proper
  359. # subdirectories. If we can't create a directory due to a permission
  360. # problem, then we will silently continue.
  361. #
  362. # If +mode+ is given, missing directories are created with this mode.
  363. #
  364. # World-writable directories will never be created.
  365. def self.ensure_gem_subdirectories(dir = Gem.dir, mode = nil)
  366. ensure_subdirectories(dir, mode, REPOSITORY_SUBDIRECTORIES)
  367. end
  368. ##
  369. # Quietly ensure the Gem directory +dir+ contains all the proper
  370. # subdirectories for handling default gems. If we can't create a
  371. # directory due to a permission problem, then we will silently continue.
  372. #
  373. # If +mode+ is given, missing directories are created with this mode.
  374. #
  375. # World-writable directories will never be created.
  376. def self.ensure_default_gem_subdirectories(dir = Gem.dir, mode = nil)
  377. ensure_subdirectories(dir, mode, REPOSITORY_DEFAULT_GEM_SUBDIRECTORIES)
  378. end
  379. def self.ensure_subdirectories(dir, mode, subdirs) # :nodoc:
  380. old_umask = File.umask
  381. File.umask old_umask | 002
  382. require 'fileutils'
  383. options = {}
  384. options[:mode] = mode if mode
  385. subdirs.each do |name|
  386. subdir = File.join dir, name
  387. next if File.exist? subdir
  388. begin
  389. FileUtils.mkdir_p subdir, **options
  390. rescue SystemCallError
  391. end
  392. end
  393. ensure
  394. File.umask old_umask
  395. end
  396. ##
  397. # The extension API version of ruby. This includes the static vs non-static
  398. # distinction as extensions cannot be shared between the two.
  399. def self.extension_api_version # :nodoc:
  400. if 'no' == RbConfig::CONFIG['ENABLE_SHARED']
  401. "#{ruby_api_version}-static"
  402. else
  403. ruby_api_version
  404. end
  405. end
  406. ##
  407. # Returns a list of paths matching +glob+ that can be used by a gem to pick
  408. # up features from other gems. For example:
  409. #
  410. # Gem.find_files('rdoc/discover').each do |path| load path end
  411. #
  412. # if +check_load_path+ is true (the default), then find_files also searches
  413. # $LOAD_PATH for files as well as gems.
  414. #
  415. # Note that find_files will return all files even if they are from different
  416. # versions of the same gem. See also find_latest_files
  417. def self.find_files(glob, check_load_path=true)
  418. files = []
  419. files = find_files_from_load_path glob if check_load_path
  420. gem_specifications = @gemdeps ? Gem.loaded_specs.values : Gem::Specification.stubs
  421. files.concat gem_specifications.map {|spec|
  422. spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}")
  423. }.flatten
  424. # $LOAD_PATH might contain duplicate entries or reference
  425. # the spec dirs directly, so we prune.
  426. files.uniq! if check_load_path
  427. return files
  428. end
  429. def self.find_files_from_load_path(glob) # :nodoc:
  430. glob_with_suffixes = "#{glob}#{Gem.suffix_pattern}"
  431. $LOAD_PATH.map do |load_path|
  432. Gem::Util.glob_files_in_dir(glob_with_suffixes, load_path)
  433. end.flatten.select {|file| File.file? file.tap(&Gem::UNTAINT) }
  434. end
  435. ##
  436. # Returns a list of paths matching +glob+ from the latest gems that can be
  437. # used by a gem to pick up features from other gems. For example:
  438. #
  439. # Gem.find_latest_files('rdoc/discover').each do |path| load path end
  440. #
  441. # if +check_load_path+ is true (the default), then find_latest_files also
  442. # searches $LOAD_PATH for files as well as gems.
  443. #
  444. # Unlike find_files, find_latest_files will return only files from the
  445. # latest version of a gem.
  446. def self.find_latest_files(glob, check_load_path=true)
  447. files = []
  448. files = find_files_from_load_path glob if check_load_path
  449. files.concat Gem::Specification.latest_specs(true).map {|spec|
  450. spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}")
  451. }.flatten
  452. # $LOAD_PATH might contain duplicate entries or reference
  453. # the spec dirs directly, so we prune.
  454. files.uniq! if check_load_path
  455. return files
  456. end
  457. ##
  458. # Top level install helper method. Allows you to install gems interactively:
  459. #
  460. # % irb
  461. # >> Gem.install "minitest"
  462. # Fetching: minitest-5.14.0.gem (100%)
  463. # => [#<Gem::Specification:0x1013b4528 @name="minitest", ...>]
  464. def self.install(name, version = Gem::Requirement.default, *options)
  465. require_relative "rubygems/dependency_installer"
  466. inst = Gem::DependencyInstaller.new(*options)
  467. inst.install name, version
  468. inst.installed_gems
  469. end
  470. ##
  471. # Get the default RubyGems API host. This is normally
  472. # <tt>https://rubygems.org</tt>.
  473. def self.host
  474. @host ||= Gem::DEFAULT_HOST
  475. end
  476. ## Set the default RubyGems API host.
  477. def self.host=(host)
  478. @host = host
  479. end
  480. ##
  481. # The index to insert activated gem paths into the $LOAD_PATH. The activated
  482. # gem's paths are inserted before site lib directory by default.
  483. def self.load_path_insert_index
  484. $LOAD_PATH.each_with_index do |path, i|
  485. return i if path.instance_variable_defined?(:@gem_prelude_index)
  486. end
  487. index = $LOAD_PATH.index RbConfig::CONFIG['sitelibdir']
  488. index || 0
  489. end
  490. ##
  491. # The number of paths in the `$LOAD_PATH` from activated gems. Used to
  492. # prioritize `-I` and `ENV['RUBYLIB`]` entries during `require`.
  493. def self.activated_gem_paths
  494. @activated_gem_paths ||= 0
  495. end
  496. ##
  497. # Add a list of paths to the $LOAD_PATH at the proper place.
  498. def self.add_to_load_path(*paths)
  499. @activated_gem_paths = activated_gem_paths + paths.size
  500. # gem directories must come after -I and ENV['RUBYLIB']
  501. $LOAD_PATH.insert(Gem.load_path_insert_index, *paths)
  502. end
  503. @yaml_loaded = false
  504. ##
  505. # Loads YAML, preferring Psych
  506. def self.load_yaml
  507. return if @yaml_loaded
  508. begin
  509. # Try requiring the gem version *or* stdlib version of psych.
  510. require 'psych'
  511. rescue ::LoadError
  512. # If we can't load psych, that's fine, go on.
  513. else
  514. require_relative 'rubygems/psych_additions'
  515. require_relative 'rubygems/psych_tree'
  516. end
  517. require 'yaml'
  518. require_relative 'rubygems/safe_yaml'
  519. @yaml_loaded = true
  520. end
  521. ##
  522. # The file name and line number of the caller of the caller of this method.
  523. #
  524. # +depth+ is how many layers up the call stack it should go.
  525. #
  526. # e.g.,
  527. #
  528. # def a; Gem.location_of_caller; end
  529. # a #=> ["x.rb", 2] # (it'll vary depending on file name and line number)
  530. #
  531. # def b; c; end
  532. # def c; Gem.location_of_caller(2); end
  533. # b #=> ["x.rb", 6] # (it'll vary depending on file name and line number)
  534. def self.location_of_caller(depth = 1)
  535. caller[depth] =~ /(.*?):(\d+).*?$/i
  536. file = $1
  537. lineno = $2.to_i
  538. [file, lineno]
  539. end
  540. ##
  541. # The version of the Marshal format for your Ruby.
  542. def self.marshal_version
  543. "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
  544. end
  545. ##
  546. # Set array of platforms this RubyGems supports (primarily for testing).
  547. def self.platforms=(platforms)
  548. @platforms = platforms
  549. end
  550. ##
  551. # Array of platforms this RubyGems supports.
  552. def self.platforms
  553. @platforms ||= []
  554. if @platforms.empty?
  555. @platforms = [Gem::Platform::RUBY, Gem::Platform.local]
  556. end
  557. @platforms
  558. end
  559. ##
  560. # Adds a post-build hook that will be passed an Gem::Installer instance
  561. # when Gem::Installer#install is called. The hook is called after the gem
  562. # has been extracted and extensions have been built but before the
  563. # executables or gemspec has been written. If the hook returns +false+ then
  564. # the gem's files will be removed and the install will be aborted.
  565. def self.post_build(&hook)
  566. @post_build_hooks << hook
  567. end
  568. ##
  569. # Adds a post-install hook that will be passed an Gem::Installer instance
  570. # when Gem::Installer#install is called
  571. def self.post_install(&hook)
  572. @post_install_hooks << hook
  573. end
  574. ##
  575. # Adds a post-installs hook that will be passed a Gem::DependencyInstaller
  576. # and a list of installed specifications when
  577. # Gem::DependencyInstaller#install is complete
  578. def self.done_installing(&hook)
  579. @done_installing_hooks << hook
  580. end
  581. ##
  582. # Adds a hook that will get run after Gem::Specification.reset is
  583. # run.
  584. def self.post_reset(&hook)
  585. @post_reset_hooks << hook
  586. end
  587. ##
  588. # Adds a post-uninstall hook that will be passed a Gem::Uninstaller instance
  589. # and the spec that was uninstalled when Gem::Uninstaller#uninstall is
  590. # called
  591. def self.post_uninstall(&hook)
  592. @post_uninstall_hooks << hook
  593. end
  594. ##
  595. # Adds a pre-install hook that will be passed an Gem::Installer instance
  596. # when Gem::Installer#install is called. If the hook returns +false+ then
  597. # the install will be aborted.
  598. def self.pre_install(&hook)
  599. @pre_install_hooks << hook
  600. end
  601. ##
  602. # Adds a hook that will get run before Gem::Specification.reset is
  603. # run.
  604. def self.pre_reset(&hook)
  605. @pre_reset_hooks << hook
  606. end
  607. ##
  608. # Adds a pre-uninstall hook that will be passed an Gem::Uninstaller instance
  609. # and the spec that will be uninstalled when Gem::Uninstaller#uninstall is
  610. # called
  611. def self.pre_uninstall(&hook)
  612. @pre_uninstall_hooks << hook
  613. end
  614. ##
  615. # The directory prefix this RubyGems was installed at. If your
  616. # prefix is in a standard location (ie, rubygems is installed where
  617. # you'd expect it to be), then prefix returns nil.
  618. def self.prefix
  619. prefix = File.dirname RUBYGEMS_DIR
  620. if prefix != File.expand_path(RbConfig::CONFIG['sitelibdir']) and
  621. prefix != File.expand_path(RbConfig::CONFIG['libdir']) and
  622. 'lib' == File.basename(RUBYGEMS_DIR)
  623. prefix
  624. end
  625. end
  626. ##
  627. # Refresh available gems from disk.
  628. def self.refresh
  629. Gem::Specification.reset
  630. end
  631. ##
  632. # Safely read a file in binary mode on all platforms.
  633. def self.read_binary(path)
  634. File.open path, 'rb+' do |f|
  635. f.flock(File::LOCK_EX)
  636. f.read
  637. end
  638. rescue *READ_BINARY_ERRORS
  639. File.open path, 'rb' do |f|
  640. f.read
  641. end
  642. rescue Errno::ENOLCK # NFS
  643. if Thread.main != Thread.current
  644. raise
  645. else
  646. File.open path, 'rb' do |f|
  647. f.read
  648. end
  649. end
  650. end
  651. ##
  652. # Safely write a file in binary mode on all platforms.
  653. def self.write_binary(path, data)
  654. File.open(path, 'wb') do |io|
  655. begin
  656. io.flock(File::LOCK_EX)
  657. rescue *WRITE_BINARY_ERRORS
  658. end
  659. io.write data
  660. end
  661. rescue Errno::ENOLCK # NFS
  662. if Thread.main != Thread.current
  663. raise
  664. else
  665. File.open(path, 'wb') do |io|
  666. io.write data
  667. end
  668. end
  669. end
  670. ##
  671. # The path to the running Ruby interpreter.
  672. def self.ruby
  673. if @ruby.nil?
  674. @ruby = RbConfig.ruby
  675. @ruby = "\"#{@ruby}\"" if @ruby =~ /\s/
  676. end
  677. @ruby
  678. end
  679. ##
  680. # Returns a String containing the API compatibility version of Ruby
  681. def self.ruby_api_version
  682. @ruby_api_version ||= RbConfig::CONFIG['ruby_version'].dup
  683. end
  684. def self.env_requirement(gem_name)
  685. @env_requirements_by_name ||= {}
  686. @env_requirements_by_name[gem_name] ||= begin
  687. req = ENV["GEM_REQUIREMENT_#{gem_name.upcase}"] || '>= 0'.freeze
  688. Gem::Requirement.create(req)
  689. end
  690. end
  691. post_reset { @env_requirements_by_name = {} }
  692. ##
  693. # Returns the latest release-version specification for the gem +name+.
  694. def self.latest_spec_for(name)
  695. dependency = Gem::Dependency.new name
  696. fetcher = Gem::SpecFetcher.fetcher
  697. spec_tuples, = fetcher.spec_for_dependency dependency
  698. spec, = spec_tuples.first
  699. spec
  700. end
  701. ##
  702. # Returns the latest release version of RubyGems.
  703. def self.latest_rubygems_version
  704. latest_version_for('rubygems-update') or
  705. raise "Can't find 'rubygems-update' in any repo. Check `gem source list`."
  706. end
  707. ##
  708. # Returns the version of the latest release-version of gem +name+
  709. def self.latest_version_for(name)
  710. spec = latest_spec_for name
  711. spec and spec.version
  712. end
  713. ##
  714. # A Gem::Version for the currently running Ruby.
  715. def self.ruby_version
  716. return @ruby_version if defined? @ruby_version
  717. version = RUBY_VERSION.dup
  718. if defined?(RUBY_PATCHLEVEL) && RUBY_PATCHLEVEL != -1
  719. version << ".#{RUBY_PATCHLEVEL}"
  720. elsif defined?(RUBY_DESCRIPTION)
  721. if RUBY_ENGINE == "ruby"
  722. desc = RUBY_DESCRIPTION[/\Aruby #{Regexp.quote(RUBY_VERSION)}([^ ]+) /, 1]
  723. else
  724. desc = RUBY_DESCRIPTION[/\A#{RUBY_ENGINE} #{Regexp.quote(RUBY_ENGINE_VERSION)} \(#{RUBY_VERSION}([^ ]+)\) /, 1]
  725. end
  726. version << ".#{desc}" if desc
  727. end
  728. @ruby_version = Gem::Version.new version
  729. end
  730. ##
  731. # A Gem::Version for the currently running RubyGems
  732. def self.rubygems_version
  733. return @rubygems_version if defined? @rubygems_version
  734. @rubygems_version = Gem::Version.new Gem::VERSION
  735. end
  736. ##
  737. # Returns an Array of sources to fetch remote gems from. Uses
  738. # default_sources if the sources list is empty.
  739. def self.sources
  740. source_list = configuration.sources || default_sources
  741. @sources ||= Gem::SourceList.from(source_list)
  742. end
  743. ##
  744. # Need to be able to set the sources without calling
  745. # Gem.sources.replace since that would cause an infinite loop.
  746. #
  747. # DOC: This comment is not documentation about the method itself, it's
  748. # more of a code comment about the implementation.
  749. def self.sources=(new_sources)
  750. if !new_sources
  751. @sources = nil
  752. else
  753. @sources = Gem::SourceList.from(new_sources)
  754. end
  755. end
  756. ##
  757. # Glob pattern for require-able path suffixes.
  758. def self.suffix_pattern
  759. @suffix_pattern ||= "{#{suffixes.join(',')}}"
  760. end
  761. ##
  762. # Regexp for require-able path suffixes.
  763. def self.suffix_regexp
  764. @suffix_regexp ||= /#{Regexp.union(suffixes)}\z/
  765. end
  766. ##
  767. # Glob pattern for require-able plugin suffixes.
  768. def self.plugin_suffix_pattern
  769. @plugin_suffix_pattern ||= "_plugin#{suffix_pattern}"
  770. end
  771. ##
  772. # Regexp for require-able plugin suffixes.
  773. def self.plugin_suffix_regexp
  774. @plugin_suffix_regexp ||= /_plugin#{suffix_regexp}\z/
  775. end
  776. ##
  777. # Suffixes for require-able paths.
  778. def self.suffixes
  779. @suffixes ||= ['',
  780. '.rb',
  781. *%w[DLEXT DLEXT2].map do |key|
  782. val = RbConfig::CONFIG[key]
  783. next unless val and not val.empty?
  784. ".#{val}"
  785. end,
  786. ].compact.uniq
  787. end
  788. ##
  789. # Prints the amount of time the supplied block takes to run using the debug
  790. # UI output.
  791. def self.time(msg, width = 0, display = Gem.configuration.verbose)
  792. now = Time.now
  793. value = yield
  794. elapsed = Time.now - now
  795. ui.say "%2$*1$s: %3$3.3fs" % [-width, msg, elapsed] if display
  796. value
  797. end
  798. ##
  799. # Lazily loads DefaultUserInteraction and returns the default UI.
  800. def self.ui
  801. require_relative 'rubygems/user_interaction'
  802. Gem::DefaultUserInteraction.ui
  803. end
  804. ##
  805. # Use the +home+ and +paths+ values for Gem.dir and Gem.path. Used mainly
  806. # by the unit tests to provide environment isolation.
  807. def self.use_paths(home, *paths)
  808. paths.flatten!
  809. paths.compact!
  810. hash = { "GEM_HOME" => home, "GEM_PATH" => paths.empty? ? home : paths.join(File::PATH_SEPARATOR) }
  811. hash.delete_if {|_, v| v.nil? }
  812. self.paths = hash
  813. end
  814. ##
  815. # Is this a windows platform?
  816. def self.win_platform?
  817. if @@win_platform.nil?
  818. ruby_platform = RbConfig::CONFIG['host_os']
  819. @@win_platform = !!WIN_PATTERNS.find {|r| ruby_platform =~ r }
  820. end
  821. @@win_platform
  822. end
  823. ##
  824. # Is this a java platform?
  825. def self.java_platform?
  826. RUBY_PLATFORM == "java"
  827. end
  828. ##
  829. # Load +plugins+ as Ruby files
  830. def self.load_plugin_files(plugins) # :nodoc:
  831. plugins.each do |plugin|
  832. # Skip older versions of the GemCutter plugin: Its commands are in
  833. # RubyGems proper now.
  834. next if plugin =~ /gemcutter-0\.[0-3]/
  835. begin
  836. load plugin
  837. rescue ::Exception => e
  838. details = "#{plugin.inspect}: #{e.message} (#{e.class})"
  839. warn "Error loading RubyGems plugin #{details}"
  840. end
  841. end
  842. end
  843. ##
  844. # Find rubygems plugin files in the standard location and load them
  845. def self.load_plugins
  846. Gem.path.each do |gem_path|
  847. load_plugin_files Gem::Util.glob_files_in_dir("*#{Gem.plugin_suffix_pattern}", plugindir(gem_path))
  848. end
  849. end
  850. ##
  851. # Find all 'rubygems_plugin' files in $LOAD_PATH and load them
  852. def self.load_env_plugins
  853. load_plugin_files find_files_from_load_path("rubygems_plugin")
  854. end
  855. ##
  856. # Looks for a gem dependency file at +path+ and activates the gems in the
  857. # file if found. If the file is not found an ArgumentError is raised.
  858. #
  859. # If +path+ is not given the RUBYGEMS_GEMDEPS environment variable is used,
  860. # but if no file is found no exception is raised.
  861. #
  862. # If '-' is given for +path+ RubyGems searches up from the current working
  863. # directory for gem dependency files (gem.deps.rb, Gemfile, Isolate) and
  864. # activates the gems in the first one found.
  865. #
  866. # You can run this automatically when rubygems starts. To enable, set
  867. # the <code>RUBYGEMS_GEMDEPS</code> environment variable to either the path
  868. # of your gem dependencies file or "-" to auto-discover in parent
  869. # directories.
  870. #
  871. # NOTE: Enabling automatic discovery on multiuser systems can lead to
  872. # execution of arbitrary code when used from directories outside your
  873. # control.
  874. def self.use_gemdeps(path = nil)
  875. raise_exception = path
  876. path ||= ENV['RUBYGEMS_GEMDEPS']
  877. return unless path
  878. path = path.dup
  879. if path == "-"
  880. Gem::Util.traverse_parents Dir.pwd do |directory|
  881. dep_file = GEM_DEP_FILES.find {|f| File.file?(f) }
  882. next unless dep_file
  883. path = File.join directory, dep_file
  884. break
  885. end
  886. end
  887. path.tap(&Gem::UNTAINT)
  888. unless File.file? path
  889. return unless raise_exception
  890. raise ArgumentError, "Unable to find gem dependencies file at #{path}"
  891. end
  892. ENV["BUNDLE_GEMFILE"] ||= File.expand_path(path)
  893. require_relative 'rubygems/user_interaction'
  894. require "bundler"
  895. begin
  896. Gem::DefaultUserInteraction.use_ui(ui) do
  897. begin
  898. Bundler.ui.silence do
  899. @gemdeps = Bundler.setup
  900. end
  901. ensure
  902. Gem::DefaultUserInteraction.ui.close
  903. end
  904. end
  905. rescue Bundler::BundlerError => e
  906. warn e.message
  907. warn "You may need to `bundle install` to install missing gems"
  908. warn ""
  909. end
  910. end
  911. ##
  912. # If the SOURCE_DATE_EPOCH environment variable is set, returns it's value.
  913. # Otherwise, returns the time that `Gem.source_date_epoch_string` was
  914. # first called in the same format as SOURCE_DATE_EPOCH.
  915. #
  916. # NOTE(@duckinator): The implementation is a tad weird because we want to:
  917. # 1. Make builds reproducible by default, by having this function always
  918. # return the same result during a given run.
  919. # 2. Allow changing ENV['SOURCE_DATE_EPOCH'] at runtime, since multiple
  920. # tests that set this variable will be run in a single process.
  921. #
  922. # If you simplify this function and a lot of tests fail, that is likely
  923. # due to #2 above.
  924. #
  925. # Details on SOURCE_DATE_EPOCH:
  926. # https://reproducible-builds.org/specs/source-date-epoch/
  927. def self.source_date_epoch_string
  928. # The value used if $SOURCE_DATE_EPOCH is not set.
  929. @default_source_date_epoch ||= Time.now.to_i.to_s
  930. specified_epoch = ENV["SOURCE_DATE_EPOCH"]
  931. # If it's empty or just whitespace, treat it like it wasn't set at all.
  932. specified_epoch = nil if !specified_epoch.nil? && specified_epoch.strip.empty?
  933. epoch = specified_epoch || @default_source_date_epoch
  934. epoch.strip
  935. end
  936. ##
  937. # Returns the value of Gem.source_date_epoch_string, as a Time object.
  938. #
  939. # This is used throughout RubyGems for enabling reproducible builds.
  940. def self.source_date_epoch
  941. Time.at(self.source_date_epoch_string.to_i).utc.freeze
  942. end
  943. # FIX: Almost everywhere else we use the `def self.` way of defining class
  944. # methods, and then we switch over to `class << self` here. Pick one or the
  945. # other.
  946. class << self
  947. ##
  948. # RubyGems distributors (like operating system package managers) can
  949. # disable RubyGems update by setting this to error message printed to
  950. # end-users on gem update --system instead of actual update.
  951. attr_accessor :disable_system_update_message
  952. ##
  953. # Hash of loaded Gem::Specification keyed by name
  954. attr_reader :loaded_specs
  955. ##
  956. # GemDependencyAPI object, which is set when .use_gemdeps is called.
  957. # This contains all the information from the Gemfile.
  958. attr_reader :gemdeps
  959. ##
  960. # Register a Gem::Specification for default gem.
  961. #
  962. # Two formats for the specification are supported:
  963. #
  964. # * MRI 2.0 style, where spec.files contains unprefixed require names.
  965. # The spec's filenames will be registered as-is.
  966. # * New style, where spec.files contains files prefixed with paths
  967. # from spec.require_paths. The prefixes are stripped before
  968. # registering the spec's filenames. Unprefixed files are omitted.
  969. #
  970. def register_default_spec(spec)
  971. extended_require_paths = spec.require_paths.map {|f| f + "/" }
  972. new_format = extended_require_paths.any? {|path| spec.files.any? {|f| f.start_with? path } }
  973. if new_format
  974. prefix_group = extended_require_paths.join("|")
  975. prefix_pattern = /^(#{prefix_group})/
  976. end
  977. spec.files.each do |file|
  978. if new_format
  979. file = file.sub(prefix_pattern, "")
  980. next unless $~
  981. end
  982. spec.activate if already_loaded?(file)
  983. @path_to_default_spec_map[file] = spec
  984. @path_to_default_spec_map[file.sub(suffix_regexp, "")] = spec
  985. end
  986. end
  987. ##
  988. # Find a Gem::Specification of default gem from +path+
  989. def find_unresolved_default_spec(path)
  990. default_spec = @path_to_default_spec_map[path]
  991. return default_spec if default_spec && loaded_specs[default_spec.name] != default_spec
  992. end
  993. ##
  994. # Clear default gem related variables. It is for test
  995. def clear_default_specs
  996. @path_to_default_spec_map.clear
  997. end
  998. ##
  999. # The list of hooks to be run after Gem::Installer#install extracts files
  1000. # and builds extensions
  1001. attr_reader :post_build_hooks
  1002. ##
  1003. # The list of hooks to be run after Gem::Installer#install completes
  1004. # installation
  1005. attr_reader :post_install_hooks
  1006. ##
  1007. # The list of hooks to be run after Gem::DependencyInstaller installs a
  1008. # set of gems
  1009. attr_reader :done_installing_hooks
  1010. ##
  1011. # The list of hooks to be run after Gem::Specification.reset is run.
  1012. attr_reader :post_reset_hooks
  1013. ##
  1014. # The list of hooks to be run after Gem::Uninstaller#uninstall completes
  1015. # installation
  1016. attr_reader :post_uninstall_hooks
  1017. ##
  1018. # The list of hooks to be run before Gem::Installer#install does any work
  1019. attr_reader :pre_install_hooks
  1020. ##
  1021. # The list of hooks to be run before Gem::Specification.reset is run.
  1022. attr_reader :pre_reset_hooks
  1023. ##
  1024. # The list of hooks to be run before Gem::Uninstaller#uninstall does any
  1025. # work
  1026. attr_reader :pre_uninstall_hooks
  1027. private
  1028. def already_loaded?(file)
  1029. $LOADED_FEATURES.any? do |feature_path|
  1030. feature_path.end_with?(file) && default_gem_load_paths.any? {|load_path_entry| feature_path == "#{load_path_entry}/#{file}" }
  1031. end
  1032. end
  1033. def default_gem_load_paths
  1034. @default_gem_load_paths ||= $LOAD_PATH[load_path_insert_index..-1]
  1035. end
  1036. end
  1037. ##
  1038. # Location of Marshal quick gemspecs on remote repositories
  1039. MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/".freeze
  1040. autoload :BundlerVersionFinder, File.expand_path('rubygems/bundler_version_finder', __dir__)
  1041. autoload :ConfigFile, File.expand_path('rubygems/config_file', __dir__)
  1042. autoload :Dependency, File.expand_path('rubygems/dependency', __dir__)
  1043. autoload :DependencyList, File.expand_path('rubygems/dependency_list', __dir__)
  1044. autoload :Installer, File.expand_path('rubygems/installer', __dir__)
  1045. autoload :Licenses, File.expand_path('rubygems/util/licenses', __dir__)
  1046. autoload :NameTuple, File.expand_path('rubygems/name_tuple', __dir__)
  1047. autoload :PathSupport, File.expand_path('rubygems/path_support', __dir__)
  1048. autoload :Platform, File.expand_path('rubygems/platform', __dir__)
  1049. autoload :RequestSet, File.expand_path('rubygems/request_set', __dir__)
  1050. autoload :Requirement, File.expand_path('rubygems/requirement', __dir__)
  1051. autoload :Resolver, File.expand_path('rubygems/resolver', __dir__)
  1052. autoload :Source, File.expand_path('rubygems/source', __dir__)
  1053. autoload :SourceList, File.expand_path('rubygems/source_list', __dir__)
  1054. autoload :SpecFetcher, File.expand_path('rubygems/spec_fetcher', __dir__)
  1055. autoload :Specification, File.expand_path('rubygems/specification', __dir__)
  1056. autoload :Util, File.expand_path('rubygems/util', __dir__)
  1057. autoload :Version, File.expand_path('rubygems/version', __dir__)
  1058. end
  1059. require_relative 'rubygems/exceptions'
  1060. # REFACTOR: This should be pulled out into some kind of hacks file.
  1061. begin
  1062. ##
  1063. # Defaults the operating system (or packager) wants to provide for RubyGems.
  1064. require 'rubygems/defaults/operating_system'
  1065. rescue LoadError
  1066. # Ignored
  1067. rescue StandardError => e
  1068. msg = "#{e.message}\n" \
  1069. "Loading the rubygems/defaults/operating_system.rb file caused an error. " \
  1070. "This file is owned by your OS, not by rubygems upstream. " \
  1071. "Please find out which OS package this file belongs to and follow the guidelines from your OS to report " \
  1072. "the problem and ask for help."
  1073. raise e.class, msg
  1074. end
  1075. begin
  1076. ##
  1077. # Defaults the Ruby implementation wants to provide for RubyGems
  1078. require "rubygems/defaults/#{RUBY_ENGINE}"
  1079. rescue LoadError
  1080. end
  1081. ##
  1082. # Loads the default specs.
  1083. Gem::Specification.load_defaults
  1084. require_relative 'rubygems/core_ext/kernel_gem'
  1085. require_relative 'rubygems/core_ext/kernel_require'
  1086. require_relative 'rubygems/core_ext/kernel_warn'