diff options
83 files changed, 1124 insertions, 511 deletions
@@ -73,7 +73,7 @@ class Gem::AvailableSet end def match_platform! - @set.reject! {|t| !Gem::Platform.match(t.spec.platform) } @sorted = nil self end @@ -73,7 +73,7 @@ class Gem::CommandManager ].freeze ALIAS_COMMANDS = { - 'i' => 'install' }.freeze ## @@ -174,8 +174,8 @@ class Gem::CommandManager else cmd_name = args.shift.downcase cmd = find_command cmd_name - cmd.invoke_with_build_args args, build_args cmd.deprecation_warning if cmd.deprecated? end end @@ -61,14 +61,18 @@ Gems can be saved to a specified filename with the output option: end def execute - gem_name = get_one_optional_argument || find_gemspec - build_gem(gem_name) end private - def find_gemspec - gemspecs = Dir.glob("*.gemspec").sort if gemspecs.size > 1 alert_error "Multiple gemspecs found: #{gemspecs}, please specify one" @@ -78,28 +82,19 @@ Gems can be saved to a specified filename with the output option: gemspecs.first end - def build_gem(gem_name) - gemspec = File.exist?(gem_name) ? gem_name : "#{gem_name}.gemspec" - - if File.exist?(gemspec) - spec = Gem::Specification.load(gemspec) - - if options[:build_path] - Dir.chdir(File.dirname(gemspec)) do - spec = Gem::Specification.load(File.basename(gemspec)) - build_package(spec) - end - else - build_package(spec) - end else - alert_error "Gemspec file not found: #{gemspec}" terminate_interaction(1) end end - def build_package(spec) if spec Gem::Package.build( spec, @@ -112,4 +107,26 @@ Gems can be saved to a specified filename with the output option: terminate_interaction 1 end end end @@ -311,4 +311,4 @@ For further reading on signing gems see `ri Gem::Security`. # It's simple, but is all we need email =~ /\A.+@.+\z/ end -end if defined?(OpenSSL::SSL) @@ -332,6 +332,8 @@ platform. @command_manager.command_names.each do |cmd_name| command = @command_manager[cmd_name] summary = if command command.summary @@ -53,7 +53,7 @@ permission to. def execute @host = options[:host] - sign_in name = get_one_gem_name add_owners name, options[:add] @@ -102,10 +102,18 @@ permission to. private def send_owner_request(method, name, owner) - rubygems_api_request method, "api/v1/gems/#{name}/owners" do |request| request.set_form_data 'email' => owner request.add_field "Authorization", api_key request.add_field "OTP", options[:otp] if options[:otp] end end end @@ -170,7 +170,7 @@ extensions will be restored. :install_dir => spec.base_dir, :env_shebang => env_shebang, :build_args => spec.build_args, - :bin_dir => bin_dir } if options[:only_executables] @@ -61,7 +61,7 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo options[:host] end - sign_in @host send_gem(gem_name) end @@ -86,7 +86,7 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo private def send_push_request(name, args) - rubygems_api_request(*args) do |request| request.body = Gem.read_binary name request.add_field "Content-Length", request.body.size request.add_field "Content-Type", "application/octet-stream" @@ -100,7 +100,11 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo [ gem_metadata["default_gem_server"], - gem_metadata["allowed_push_host"] ] end end @@ -9,6 +9,14 @@ class Gem::Commands::QueryCommand < Gem::Command include Gem::QueryUtils def initialize(name = 'query', summary = 'Query gem information in local or remote repositories') super name, summary, @@ -23,4 +31,13 @@ class Gem::Commands::QueryCommand < Gem::Command add_query_options end end @@ -1,8 +1,12 @@ # frozen_string_literal: true require 'rubygems/command' require 'rubygems/server' class Gem::Commands::ServerCommand < Gem::Command def initialize super 'server', 'Documentation and gem repository HTTP server', :port => 8808, :gemdir => [], :daemon => false @@ -322,13 +322,10 @@ By default, this RubyGems will install gem as: libs.each do |tool, path| say "Installing #{tool}" if @verbose - lib_files = rb_files_in path - lib_files.concat(bundler_template_files) if tool == 'Bundler' - - pem_files = pem_files_in path Dir.chdir path do - install_file_list(lib_files + pem_files, lib_dir) end end end @@ -394,10 +391,6 @@ By default, this RubyGems will install gem as: specs_dir = File.join(options[:destdir], specs_dir) unless Gem.win_platform? mkdir_p specs_dir, :mode => 0755 - # Workaround for non-git environment. - gemspec = File.open('bundler/bundler.gemspec', 'rb'){|f| f.read.gsub(/`git ls-files -z`/, "''") } - File.open('bundler/bundler.gemspec', 'w'){|f| f.write gemspec } - bundler_spec = Gem::Specification.load("bundler/bundler.gemspec") bundler_spec.files = Dir.chdir("bundler") { Dir["{*.md,{lib,exe,man}/**/*}"] } bundler_spec.executables -= %w[bundler bundle_ruby] @@ -518,44 +511,24 @@ By default, this RubyGems will install gem as: [lib_dir, bin_dir] end - def pem_files_in(dir) - Dir.chdir dir do - Dir[File.join('**', '*pem')] - end - end - - def rb_files_in(dir) Dir.chdir dir do - Dir[File.join('**', '*rb')] end end # for installation of bundler as default gems def bundler_man1_files_in(dir) Dir.chdir dir do - Dir['bundle*.1{,.txt,.ronn}'] end end # for installation of bundler as default gems def bundler_man5_files_in(dir) Dir.chdir dir do - Dir['gemfile.5{,.txt,.ronn}'] - end - end - - def bundler_template_files - Dir.chdir "bundler/lib" do - Dir.glob(File.join('bundler', 'templates', '**', '*'), File::FNM_DOTMATCH). - select{|f| !File.directory?(f) } - end - end - - # for cleanup old bundler files - def template_files_in(dir) - Dir.chdir dir do - Dir.glob(File.join('templates', '**', '*'), File::FNM_DOTMATCH). - select{|f| !File.directory?(f) } end end @@ -595,11 +568,9 @@ abort "#{deprecation_message}" lib_dirs = { File.join(lib_dir, 'rubygems') => 'lib/rubygems' } lib_dirs[File.join(lib_dir, 'bundler')] = 'bundler/lib/bundler' lib_dirs.each do |old_lib_dir, new_lib_dir| - lib_files = rb_files_in(new_lib_dir) - lib_files.concat(template_files_in(new_lib_dir)) if new_lib_dir =~ /bundler/ - old_lib_files = rb_files_in(old_lib_dir) - old_lib_files.concat(template_files_in(old_lib_dir)) if old_lib_dir =~ /bundler/ to_remove = old_lib_files - lib_files @@ -617,16 +588,25 @@ abort "#{deprecation_message}" def remove_old_man_files(man_dir) man_dirs = { man_dir => "bundler/man" } man_dirs.each do |old_man_dir, new_man_dir| - ["1", "5"].each do |section| - man_files = send(:"bundler_man#{section}_files_in", new_man_dir) - old_man_dir_with_section = "#{old_man_dir}/man#{section}" - old_man_files = send(:"bundler_man#{section}_files_in", old_man_dir_with_section) - man_to_remove = old_man_files - man_files - remove_file_list(man_to_remove, old_man_dir_with_section) - end end end @@ -34,6 +34,10 @@ class Gem::Commands::SourcesCommand < Gem::Command options[:update] = value end add_proxy_option end @@ -71,7 +75,7 @@ class Gem::Commands::SourcesCommand < Gem::Command Do you want to add this source? QUESTION - terminate_interaction 1 unless ask_yes_no question end end @@ -86,7 +90,7 @@ https://rubygems.org is recommended for security over #{uri} Do you want to add this insecure source? QUESTION - terminate_interaction 1 unless ask_yes_no question end end @@ -126,6 +126,12 @@ Specific fields in the specification can be extracted in YAML format: terminate_interaction 1 end unless options[:all] specs = [specs.max_by {|s| s.version }] end @@ -47,7 +47,7 @@ data you will need to change them immediately and yank your gem. def execute @host = options[:host] - sign_in @host version = get_version_from_requirements(options[:version]) platform = get_platform_from_requirements(options) @@ -72,7 +72,7 @@ data you will need to change them immediately and yank your gem. def yank_api_request(method, version, platform, api) name = get_one_gem_name - response = rubygems_api_request(method, api, host) do |request| request.add_field("Authorization", api_key) request.add_field("OTP", options[:otp]) if options[:otp] @@ -93,7 +93,7 @@ data you will need to change them immediately and yank your gem. nil end - def get_platform_from_requirements(requirements) - Gem.platforms[1].to_s if requirements.key? :added_platform end end @@ -17,6 +17,8 @@ module Kernel private :gem_original_require end ## # When RubyGems is required, Kernel#require is replaced with our own which # is capable of loading gems on demand. @@ -166,6 +168,7 @@ module Kernel end end end private :require @@ -1,12 +1,12 @@ # frozen_string_literal: true # `uplevel` keyword argument of Kernel#warn is available since ruby 2.5. -if RUBY_VERSION >= "2.5" module Kernel rubygems_path = "#{__dir__}/" # Frames to be skipped start with this path. - original_warn = method(:warn) remove_method :warn @@ -17,9 +17,9 @@ if RUBY_VERSION >= "2.5" module_function define_method(:warn) {|*messages, **kw| unless uplevel = kw[:uplevel] if Gem.java_platform? - return original_warn.call(*messages) else - return original_warn.call(*messages, **kw) end end @@ -45,11 +45,10 @@ if RUBY_VERSION >= "2.5" end end end - uplevel = start end - kw[:uplevel] = uplevel - original_warn.call(*messages, **kw) } end end @@ -38,13 +38,13 @@ module Gem [ File.dirname(RbConfig::CONFIG['sitedir']), 'Gems', - RbConfig::CONFIG['ruby_version'] ] else [ RbConfig::CONFIG['rubylibprefix'], 'gems', - RbConfig::CONFIG['ruby_version'] ] end @@ -281,7 +281,7 @@ class Gem::Dependency if platform_only matches.reject! do |spec| - spec.nil? || !Gem::Platform.match(spec.platform) end end @@ -27,7 +27,7 @@ class Gem::DependencyInstaller :wrappers => true, :build_args => nil, :build_docs_in_background => false, - :install_as_default => false }.freeze ## @@ -283,10 +283,9 @@ class Gem::DependencyInstaller request_set.development_shallow = @dev_shallow request_set.soft_missing = @force request_set.prerelease = @prerelease - request_set.remote = false unless consider_remote? installer_set = Gem::Resolver::InstallerSet.new @domain - installer_set.ignore_installed = @only_install_dir if consider_local? if dep_or_name =~ /\.gem$/ and File.file? dep_or_name @@ -307,6 +306,7 @@ class Gem::DependencyInstaller dependency = if spec = installer_set.local?(dep_or_name) Gem::Dependency.new spec.name, version elsif String === dep_or_name Gem::Dependency.new dep_or_name, version @@ -321,6 +321,7 @@ class Gem::DependencyInstaller installer_set.add_always_install dependency request_set.always_install = installer_set.always_install if @ignore_dependencies installer_set.ignore_dependencies = true @@ -10,14 +10,6 @@ require_relative '../user_interaction' class Gem::Ext::Builder include Gem::UserInteraction - ## - # The builder shells-out to run various commands after changing the - # directory. This means multiple installations cannot be allowed to build - # extensions in parallel as they may change each other's directories leading - # to broken extensions or failed installations. - - CHDIR_MUTEX = Mutex.new # :nodoc: - attr_accessor :build_args # :nodoc: def self.class_name @@ -25,8 +17,8 @@ class Gem::Ext::Builder $1.downcase end - def self.make(dest_path, results) - unless File.exist? 'Makefile' raise Gem::InstallError, 'Makefile not found' end @@ -44,32 +36,32 @@ class Gem::Ext::Builder cmd = [ make_program, destdir, - target ].join(' ').rstrip begin - run(cmd, results, "make #{target}".rstrip) rescue Gem::InstallError raise unless target == 'clean' # ignore clean failure end end end - def self.run(command, results, command_name = nil) verbose = Gem.configuration.really_verbose begin rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], nil if verbose - puts("current directory: #{Dir.pwd}") p(command) end - results << "current directory: #{Dir.pwd}" results << (command.respond_to?(:shelljoin) ? command.shelljoin : command) require "open3" # Set $SOURCE_DATE_EPOCH for the subprocess. env = {'SOURCE_DATE_EPOCH' => Gem.source_date_epoch_string} - output, status = Open3.capture2e(env, *command) if verbose puts output else @@ -161,22 +153,10 @@ EOF begin FileUtils.mkdir_p dest_path - CHDIR_MUTEX.synchronize do - pwd = Dir.getwd - Dir.chdir extension_dir - begin - results = builder.build(extension, dest_path, - results, @build_args, lib_dir) - - verbose { results.join("\n") } - ensure - begin - Dir.chdir pwd - rescue SystemCallError - Dir.chdir dest_path - end - end - end write_gem_make_out results.join "\n" rescue => e @@ -201,6 +181,7 @@ EOF dest_path = @spec.extension_dir FileUtils.rm_f @spec.gem_build_complete_path @spec.extensions.each do |extension| @@ -2,15 +2,15 @@ require_relative '../command' class Gem::Ext::CmakeBuilder < Gem::Ext::Builder - def self.build(extension, dest_path, results, args=[], lib_dir=nil) - unless File.exist?('Makefile') cmd = "cmake . -DCMAKE_INSTALL_PREFIX=#{dest_path}" cmd << " #{Gem::Command.build_args.join ' '}" unless Gem::Command.build_args.empty? - run cmd, results end - make dest_path, results results end @@ -6,15 +6,15 @@ #++ class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder - def self.build(extension, dest_path, results, args=[], lib_dir=nil) - unless File.exist?('Makefile') cmd = "sh ./configure --prefix=#{dest_path}" cmd << " #{args.join ' '}" unless args.empty? - run cmd, results end - make dest_path, results results end @@ -8,11 +8,11 @@ require 'shellwords' class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder - def self.build(extension, dest_path, results, args=[], lib_dir=nil) require 'fileutils' require 'tempfile' - tmp_dest = Dir.mktmpdir(".gem.", ".") # Some versions of `mktmpdir` return absolute paths, which will break make # if the paths contain spaces. However, on Ruby 1.9.x on Windows, relative @@ -23,9 +23,9 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder # spaces do not work. # # Details: https://.com/rubygems/rubygems/issues/977#issuecomment-171544940 - tmp_dest = get_relative_path(tmp_dest) - Tempfile.open %w[siteconf .rb], "." do |siteconf| siteconf.puts "require 'rbconfig'" siteconf.puts "dest_path = #{tmp_dest.dump}" %w[sitearchdir sitelibdir].each do |dir| @@ -38,19 +38,22 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder destdir = ENV["DESTDIR"] begin cmd = Gem.ruby.shellsplit << "-I" << File.expand_path("../../..", __FILE__) << - "-r" << get_relative_path(siteconf.path) << File.basename(extension) cmd.push(*args) begin - run(cmd, results) do |s, r| - if File.exist? 'mkmf.log' unless s.success? r << "To see why this extension failed to compile, please check" \ " the mkmf.log which can be found here:\n" r << " " + File.join(dest_path, 'mkmf.log') + "\n" end - FileUtils.mv 'mkmf.log', dest_path end end siteconf.unlink @@ -58,18 +61,20 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder ENV["DESTDIR"] = nil - make dest_path, results if tmp_dest # TODO remove in RubyGems 3 if Gem.install_extension_in_lib and lib_dir FileUtils.mkdir_p lib_dir - entries = Dir.entries(tmp_dest) - %w[. ..] - entries = entries.map {|entry| File.join tmp_dest, entry } FileUtils.cp_r entries, lib_dir, :remove_destination => true end - FileUtils::Entry_.new(tmp_dest).traverse do |ent| destent = ent.class.new(dest_path, ent.rel) destent.exist? or FileUtils.mv(ent.path, destent.path) end @@ -87,8 +92,8 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder private - def self.get_relative_path(path) - path[0..Dir.pwd.length - 1] = '.' if path.start_with?(Dir.pwd) path end end @@ -8,9 +8,9 @@ require "shellwords" class Gem::Ext::RakeBuilder < Gem::Ext::Builder - def self.build(extension, dest_path, results, args=[], lib_dir=nil) if File.basename(extension) =~ /mkrf_conf/i - run([Gem.ruby, File.basename(extension), *args], results) end rake = ENV['rake'] @@ -26,7 +26,7 @@ class Gem::Ext::RakeBuilder < Gem::Ext::Builder end rake_args = ["RUBYARCHDIR=#{dest_path}", "RUBYLIBDIR=#{dest_path}", *args] - run(rake + rake_args, results) results end @@ -8,10 +8,12 @@ require 'rubygems/text' module Gem::GemcutterUtilities ERROR_CODE = 1 include Gem::Text attr_writer :host ## # Add the --key option @@ -72,7 +74,7 @@ module Gem::GemcutterUtilities # # If +allowed_push_host+ metadata is present, then it will only allow that host. - def rubygems_api_request(method, path, host = nil, allowed_push_host = nil, &block) require 'net/http' self.host = host if host @@ -95,11 +97,19 @@ module Gem::GemcutterUtilities request_method = Net::HTTP.const_get method.to_s.capitalize response = Gem::RemoteFetcher.fetcher.request(uri, request_method, &block) - return response unless mfa_unauthorized?(response) - Gem::RemoteFetcher.fetcher.request(uri, request_method) do |req| - req.add_field "OTP", get_otp - block.call(req) end end @@ -112,19 +122,37 @@ module Gem::GemcutterUtilities ask 'Code: ' end ## # Signs in with the RubyGems API at +sign_in_host+ and sets the rubygems API # key. - def sign_in(sign_in_host = nil) sign_in_host ||= self.host return if api_key - pretty_host = if Gem::DEFAULT_HOST == sign_in_host - 'RubyGems.org' - else - sign_in_host - end say "Enter your #{pretty_host} credentials." say "Don't have an account yet? " + @@ -134,14 +162,18 @@ module Gem::GemcutterUtilities password = ask_for_password "Password: " say "\n" - response = rubygems_api_request(:get, "api/v1/api_key", - sign_in_host) do |request| request.basic_auth email, password request.add_field "OTP", options[:otp] if options[:otp] end with_response response do |resp| - say "Signed in." set_api_key host, resp.body end end @@ -195,4 +227,48 @@ module Gem::GemcutterUtilities end end end @@ -1,7 +1,6 @@ # frozen_string_literal: true require 'rubygems' require 'rubygems/package' -require 'time' require 'tmpdir' ## @@ -122,10 +122,10 @@ module Gem::InstallUpdateOptions options[:minimal_deps] = true end - add_option(:"Install/Update", "--minimal-deps", "Don't upgrade any dependencies that already", "meet version requirements") do |value, options| - options[:minimal_deps] = true end add_option(:"Install/Update", "--[no-]post-install-message", @@ -12,7 +12,6 @@ require 'rubygems/deprecate' require 'rubygems/package' require 'rubygems/ext' require 'rubygems/user_interaction' -require 'fileutils' ## # The installer installs the files contained in the .gem into the Gem.home. @@ -433,7 +432,7 @@ class Gem::Installer # def default_spec_file - File.join Gem.default_specifications_dir, "#{spec.full_name}.gemspec" end ## @@ -492,7 +491,11 @@ class Gem::Installer mode = File.stat(bin_path).mode dir_mode = options[:prog_mode] || (mode | 0111) - FileUtils.chmod dir_mode, bin_path unless dir_mode == mode check_executable_overwrite filename @@ -527,6 +530,7 @@ class Gem::Installer def generate_bin_script(filename, bindir) bin_script_path = File.join bindir, formatted_program_filename(filename) FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers File.open bin_script_path, 'wb', 0755 do |file| @@ -670,7 +674,7 @@ class Gem::Installer :env_shebang => false, :force => false, :only_install_dir => false, - :post_install_message => true }.merge options @env_shebang = options[:env_shebang] @@ -693,11 +697,10 @@ class Gem::Installer @build_args = options[:build_args] || Gem::Command.build_args unless @build_root.nil? - require 'pathname' - @build_root = Pathname.new(@build_root).expand_path - @bin_dir = File.join(@build_root, options[:bin_dir] || Gem.bindir(@gem_home)) - @gem_home = File.join(@build_root, @gem_home) - alert_warning "You build with buildroot.\n Build root: #{@build_root}\n Bin dir: #{@bin_dir}\n Gem home: #{@gem_home}" end end @@ -108,9 +108,9 @@ class Gem::InstallerTestCase < Gem::TestCase # # And returns a Gem::Installer for the @spec that installs into @gemhome - def setup_base_installer @gem = setup_base_gem - util_installer @spec, @gemhome end ## @@ -182,7 +182,7 @@ class Gem::InstallerTestCase < Gem::TestCase # lib/code.rb # ext/a/mkrf_conf.rb - def util_setup_gem(ui = @ui) @spec.files << File.join('lib', 'code.rb') @spec.extensions << File.join('ext', 'a', 'mkrf_conf.rb') @@ -214,17 +214,18 @@ class Gem::InstallerTestCase < Gem::TestCase end end - Gem::Installer.at @gem end ## # Creates an installer for +spec+ that will install into +gem_home+. If # +user+ is true a user-install will be performed. - def util_installer(spec, gem_home, user=false) Gem::Installer.at(spec.cache_file, :install_dir => gem_home, - :user_install => user) end @@symlink_supported = nil @@ -59,7 +59,7 @@ class Gem::NameTuple # Indicate if this NameTuple matches the current platform. def match_platform? - Gem::Platform.match @platform end ## @@ -1,7 +1,7 @@ # frozen_string_literal: true -begin - require "openssl" -rescue LoadError => e - raise unless e.path == 'openssl' end @@ -44,7 +44,6 @@ require "rubygems" require 'rubygems/security' require 'rubygems/user_interaction' -require 'zlib' class Gem::Package include Gem::UserInteraction @@ -186,6 +185,8 @@ class Gem::Package # Creates a new package that will read or write to the file +gem+. def initialize(gem, security_policy) # :notnew: @gem = gem @build_time = Gem.source_date_epoch @@ -297,7 +298,7 @@ class Gem::Package setup_signer( signer_options: { - expiration_length_days: Gem.configuration.cert_expiration_length_days } ) @@ -229,7 +229,7 @@ class Gem::Package::TarHeader gname, oct(devmajor, 7), oct(devminor, 7), - prefix ] header = header.pack PACK_FORMAT @@ -90,7 +90,7 @@ class Gem::Package::TarTestCase < Gem::TestCase ASCIIZ("wheel", 32), # char gname[32]; ASCIIZ Z(to_oct(0, 7)), # char devmajor[8]; 0 padded, octal, null Z(to_oct(0, 7)), # char devminor[8]; 0 padded, octal, null - ASCIIZ(dname, 155) # char prefix[155]; ASCII + (Z unless filled) ] h = arr.join @@ -9,11 +9,7 @@ require "rubygems/deprecate" class Gem::Platform @local = nil - attr_accessor :cpu - - attr_accessor :os - - attr_accessor :version def self.local arch = RbConfig::CONFIG['arch'] @@ -22,18 +18,33 @@ class Gem::Platform end def self.match(platform) - Gem.platforms.any? do |local_platform| platform.nil? or local_platform == platform or (local_platform != Gem::Platform::RUBY and local_platform =~ platform) end end def self.installable?(spec) if spec.respond_to? :installable_platform? spec.installable_platform? else - match spec.platform end end @@ -57,15 +57,6 @@ module Gem::QueryUtils "--local --name-matches // --no-details --versions --no-installed" end - def description # :nodoc: - <<-EOF -The query command is the basis for the list and search commands. - -You should really use the list and search commands instead. This command -is too hard to use. - EOF - end - def execute gem_names = Array(options[:name]) @@ -78,7 +78,6 @@ class Gem::RemoteFetcher def initialize(proxy=nil, dns=nil, headers={}) require 'net/http' require 'stringio' - require 'time' require 'uri' Socket.do_not_reverse_lookup = true @@ -263,7 +262,7 @@ class Gem::RemoteFetcher rescue Timeout::Error raise UnknownHostError.new('timed out', uri) rescue IOError, SocketError, SystemCallError, - *(OpenSSL::SSL::SSLError if defined?(OpenSSL)) => e if e.message =~ /getaddrinfo/ raise UnknownHostError.new('no such name', uri) else @@ -1,6 +1,5 @@ # frozen_string_literal: true require 'net/http' -require 'time' require 'rubygems/user_interaction' class Gem::Request @@ -45,7 +44,8 @@ class Gem::Request end def self.configure_connection_for_https(connection, cert_files) - require 'openssl' connection.use_ssl = true connection.verify_mode = Gem.configuration.ssl_verify_mode || OpenSSL::SSL::VERIFY_PEER @@ -125,7 +125,7 @@ class Gem::Request def connection_for(uri) @connection_pool.checkout - rescue defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : Errno::EHOSTDOWN, Errno::EHOSTDOWN => e raise Gem::RemoteFetcher::FetchError.new(e.message, uri) end @@ -143,6 +143,7 @@ class Gem::Request request.add_field 'Keep-Alive', '30' if @last_modified request.add_field 'If-Modified-Since', @last_modified.httpdate end @@ -88,7 +88,7 @@ class Gem::RequestSet::GemDependencyAPI :truffleruby => Gem::Platform::RUBY, :x64_mingw => x64_mingw, :x64_mingw_20 => x64_mingw, - :x64_mingw_21 => x64_mingw }.freeze gt_eq_0 = Gem::Requirement.new '>= 0' @@ -379,7 +379,7 @@ class Gem::RequestSet::GemDependencyAPI Gem::Requirement.create requirements end - return unless gem_platforms options groups = gem_group name, options @@ -532,7 +532,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta # Handles the platforms: option from +options+. Returns true if the # platform matches the current platform. - def gem_platforms(options) # :nodoc: platform_names = Array(options.delete :platform) platform_names.concat Array(options.delete :platforms) platform_names.concat @current_platforms if @current_platforms @@ -543,7 +543,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta raise ArgumentError, "unknown platform #{platform_name.inspect}" unless platform = PLATFORM_MAP[platform_name] - next false unless Gem::Platform.match platform if engines = ENGINE_MAP[platform_name] next false unless engines.include? Gem.ruby_engine @@ -16,7 +16,7 @@ class Gem::Requirement "<" => lambda {|v, r| v < r }, ">=" => lambda {|v, r| v >= r }, "<=" => lambda {|v, r| v <= r }, - "~>" => lambda {|v, r| v >= r && v.release < r.bump } }.freeze SOURCE_SET_REQUIREMENT = Struct.new(:for_lockfile).new "!" # :nodoc: @@ -281,7 +281,7 @@ class Gem::Resolver amount_constrained(dependency), conflicts[name] ? 0 : 1, activated.vertex_named(name).payload ? 0 : search_for(dependency).count, - i # for stable sort ] end end @@ -28,12 +28,20 @@ class Gem::Resolver::ActivationRequest when Gem::Specification @spec == other when Gem::Resolver::ActivationRequest - @spec == other.spec && @request == other.request else false end end ## # Is this activation request for a development dependency? @@ -46,6 +46,10 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification @dependencies == other.dependencies end def fetch_development_dependencies # :nodoc: spec = source.fetch_spec Gem::NameTuple.new @name, @version, @platform @@ -53,7 +57,7 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification end def installable_platform? # :nodoc: - Gem::Platform.match @platform end def pretty_print(q) # :nodoc: @@ -85,7 +85,7 @@ class Gem::Resolver::Conflict activated, requirement, request_path(@activated).reverse.join(", depends on\n "), request_path(@failed_dep).reverse.join(", depends on\n "), - matching, ] end @@ -28,7 +28,7 @@ class Gem::Resolver::DependencyRequest when Gem::Dependency @dependency == other when Gem::Resolver::DependencyRequest - @dependency == other.dependency && @requester == other.requester else false end @@ -33,6 +33,17 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification spec.dependencies end def inspect # :nodoc: '#<%s %s source %s>' % [self.class, full_name, @source] end @@ -32,7 +32,6 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set super() @domain = domain - @remote = consider_remote? @f = Gem::SpecFetcher.fetcher @@ -170,7 +169,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set always_install = @always_install.map {|s| s.full_name } '#<%s domain: %s specs: %p always install: %p>' % [ - self.class, @domain, @specs.keys, always_install, ] end @@ -28,7 +28,7 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set def add(name, version, platform) # :nodoc: version = Gem::Version.new version specs = [ - Gem::Resolver::LockSpecification.new(self, name, version, @sources, platform) ] @specs.concat specs @@ -1,9 +1,10 @@ # frozen_string_literal: true -require 'rubygems/resolver/molinillo/lib/molinillo/gem_metadata' -require 'rubygems/resolver/molinillo/lib/molinillo/errors' -require 'rubygems/resolver/molinillo/lib/molinillo/resolver' -require 'rubygems/resolver/molinillo/lib/molinillo/modules/ui' -require 'rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider' # Gem::Resolver::Molinillo is a generic dependency resolution algorithm. module Gem::Resolver::Molinillo @@ -1,4 +1,5 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo # @!visibility private module Delegates @@ -45,6 +46,12 @@ module Gem::Resolver::Molinillo current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty current_state.conflicts end end end end @@ -1,4 +1,5 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo module Delegates # Delegates all {Gem::Resolver::Molinillo::SpecificationProvider} methods to a @@ -1,9 +1,10 @@ # frozen_string_literal: true require 'set' require 'tsort' -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log' -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex' module Gem::Resolver::Molinillo # A directed acyclic graph that is tuned to hold named dependencies @@ -123,6 +124,7 @@ module Gem::Resolver::Molinillo dot.join("\n") end # @return [Boolean] whether the two dependency graphs are equal, determined # by a recursive traversal of each {#root_vertices} and its # {Vertex#successors} @@ -147,8 +149,8 @@ module Gem::Resolver::Molinillo vertex = add_vertex(name, payload, root) vertex.explicit_requirements << requirement if root parent_names.each do |parent_name| - parent_node = vertex_named(parent_name) - add_edge(parent_node, vertex, requirement) end vertex end @@ -189,7 +191,7 @@ module Gem::Resolver::Molinillo # @return [Edge] the added edge def add_edge(origin, destination, requirement) if destination.path_to?(origin) - raise CircularDependencyError.new([origin, destination]) end add_edge_no_circular(origin, destination, requirement) end @@ -218,5 +220,37 @@ module Gem::Resolver::Molinillo def add_edge_no_circular(origin, destination, requirement) log.add_edge_no_circular(self, origin.name, destination.name, requirement) end end end @@ -1,4 +1,5 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo class DependencyGraph # An action that modifies a {DependencyGraph} that is reversible. @@ -1,5 +1,6 @@ # frozen_string_literal: true -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action' module Gem::Resolver::Molinillo class DependencyGraph # @!visibility private @@ -1,5 +1,6 @@ # frozen_string_literal: true -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action' module Gem::Resolver::Molinillo class DependencyGraph # @!visibility private @@ -1,5 +1,6 @@ # frozen_string_literal: true -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action' module Gem::Resolver::Molinillo class DependencyGraph # @!visibility private @@ -1,5 +1,6 @@ # frozen_string_literal: true -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action' module Gem::Resolver::Molinillo class DependencyGraph # @!visibility private @@ -1,10 +1,11 @@ # frozen_string_literal: true -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular' -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex' -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge' -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named' -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload' -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag' module Gem::Resolver::Molinillo class DependencyGraph @@ -1,5 +1,6 @@ # frozen_string_literal: true -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action' module Gem::Resolver::Molinillo class DependencyGraph # @!visibility private @@ -1,5 +1,6 @@ # frozen_string_literal: true -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action' module Gem::Resolver::Molinillo class DependencyGraph # @!visibility private @@ -13,11 +14,11 @@ module Gem::Resolver::Molinillo end # (see Action#up) - def up(_graph) end # (see Action#down) - def down(_graph) end # @!group Tag @@ -1,4 +1,5 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo class DependencyGraph # A vertex in a {DependencyGraph} that encapsulates a {#name} and a @@ -32,7 +33,7 @@ module Gem::Resolver::Molinillo # @return [Array<Object>] all of the requirements that required # this vertex def requirements - incoming_edges.map(&:requirement) + explicit_requirements end # @return [Array<Edge>] the edges of {#graph} that have `self` as their @@ -49,14 +50,25 @@ module Gem::Resolver::Molinillo incoming_edges.map(&:origin) end - # @return [Array<Vertex>] the vertices of {#graph} where `self` is a # {#descendent?} def recursive_predecessors - vertices = predecessors - vertices += vertices.map(&:recursive_predecessors).flatten(1) - vertices.uniq! vertices end # @return [Array<Vertex>] the vertices of {#graph} that have an edge with # `self` as their {Edge#origin} @@ -64,14 +76,25 @@ module Gem::Resolver::Molinillo outgoing_edges.map(&:destination) end - # @return [Array<Vertex>] the vertices of {#graph} where `self` is an # {#ancestor?} def recursive_successors - vertices = successors - vertices += vertices.map(&:recursive_successors).flatten(1) - vertices.uniq! vertices end # @return [String] a string suitable for debugging def inspect @@ -107,11 +130,21 @@ module Gem::Resolver::Molinillo # dependency graph? # @return true iff there is a path following edges within this {#graph} def path_to?(other) - equal?(other) || successors.any? { |v| v.path_to?(other) } end alias descendent? path_to? # Is there a path from `other` to `self` following edges in the # dependency graph? # @return true iff there is a path following edges within this {#graph} @@ -1,4 +1,5 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo # An error that occurred during the resolution process class ResolverError < StandardError; end @@ -17,7 +18,7 @@ module Gem::Resolver::Molinillo # @param [Array<Object>] required_by @see {#required_by} def initialize(dependency, required_by = []) @dependency = dependency - @required_by = required_by super() end @@ -41,11 +42,11 @@ module Gem::Resolver::Molinillo attr_reader :dependencies # Initializes a new error with the given circular vertices. - # @param [Array<DependencyGraph::Vertex>] nodes the nodes in the dependency # that caused the error - def initialize(nodes) - super "There is a circular dependency between #{nodes.map(&:name).join(' and ')}" - @dependencies = nodes.map(&:payload).to_set end end @@ -55,11 +56,16 @@ module Gem::Resolver::Molinillo # resolution to fail attr_reader :conflicts # Initializes a new error with the given version conflicts. # @param [{String => Resolution::Conflict}] conflicts see {#conflicts} - def initialize(conflicts) pairs = [] - conflicts.values.flatten.map(&:requirements).flatten.each do |conflicting| conflicting.each do |source, conflict_requirements| conflict_requirements.each do |c| pairs << [c, source] @@ -69,7 +75,69 @@ module Gem::Resolver::Molinillo super "Unable to satisfy the following requirements:\n\n" \ "#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}" @conflicts = conflicts end end end @@ -1,5 +1,6 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo # The version of Gem::Resolver::Molinillo. - VERSION = '0.5.7'.freeze end @@ -1,4 +1,5 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo # Provides information about specifcations and dependencies to the resolver, # allowing the {Resolver} class to remain generic while still providing power @@ -1,4 +1,5 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo # Conveys information about the resolution process to a user. module UI @@ -48,7 +49,8 @@ module Gem::Resolver::Molinillo if debug? debug_info = yield debug_info = debug_info.inspect unless debug_info.is_a?(String) - output.puts debug_info.split("\n").map { |s| ' ' * depth + s } end end @@ -1,4 +1,5 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo class Resolver # A specific resolution from a given {Resolver} @@ -8,22 +9,125 @@ module Gem::Resolver::Molinillo # @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict # @attr [Object, nil] existing the existing spec that was in conflict with # the {#possibility} - # @attr [Object] possibility the spec that was unable to be activated due - # to a conflict # @attr [Object] locked_requirement the relevant locking requirement. # @attr [Array<Array<Object>>] requirement_trees the different requirement # trees that led to every requirement for the conflicting name. # @attr [{String=>Object}] activated_by_name the already-activated specs. Conflict = Struct.new( :requirement, :requirements, :existing, - :possibility, :locked_requirement, :requirement_trees, - :activated_by_name ) # @return [SpecificationProvider] the provider that knows about # dependencies, requirements, specifications, versions, etc. attr_reader :specification_provider @@ -64,7 +168,7 @@ module Gem::Resolver::Molinillo start_resolution while state - break unless state.requirements.any? || state.requirement indicate_progress if state.respond_to?(:pop_possibility_state) # DependencyState debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" } @@ -78,7 +182,7 @@ module Gem::Resolver::Molinillo process_topmost_state end - activated.freeze ensure end_resolution end @@ -103,12 +207,25 @@ module Gem::Resolver::Molinillo def start_resolution @started_at = Time.now - handle_missing_or_push_dependency_state(initial_state) debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" } resolver_ui.before_resolution end # Ends the resolution process # @return [void] def end_resolution @@ -121,11 +238,11 @@ module Gem::Resolver::Molinillo debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state end - require 'rubygems/resolver/molinillo/lib/molinillo/state' - require 'rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider' - require 'rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state' - require 'rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider' include Gem::Resolver::Molinillo::Delegates::ResolutionState include Gem::Resolver::Molinillo::Delegates::SpecificationProvider @@ -136,9 +253,12 @@ module Gem::Resolver::Molinillo if possibility attempt_to_activate else - create_conflict if state.is_a? PossibilityState - unwind_for_conflict until possibility && state.is_a?(DependencyState) end end # @return [Object] the current possibility that the resolution is trying @@ -153,63 +273,292 @@ module Gem::Resolver::Molinillo states.last end - # Creates the initial state for the resolution, based upon the # {#requested} dependencies - # @return [DependencyState] the initial state for the resolution - def initial_state graph = DependencyGraph.new.tap do |dg| - original_requested.each { |r| dg.add_vertex(name_for(r), nil, true).tap { |v| v.explicit_requirements << r } } dg.tag(:initial_state) end - requirements = sort_dependencies(original_requested, graph, {}) - initial_requirement = requirements.shift - DependencyState.new( - initial_requirement && name_for(initial_requirement), - requirements, - graph, - initial_requirement, - initial_requirement && search_for(initial_requirement), - 0, - {} - ) end # Unwinds the states stack because a conflict has been encountered # @return [void] def unwind_for_conflict - debug(depth) { "Unwinding for conflict: #{requirement} to #{state_index_for_unwind / 2}" } conflicts.tap do |c| - sliced_states = states.slice!((state_index_for_unwind + 1)..-1) - raise VersionConflict.new(c) unless state activated.rewind_to(sliced_states.first || :initial_state) if sliced_states state.conflicts = c index = states.size - 1 @parents_of.each { |_, a| a.reject! { |i| i >= index } } end end - # @return [Integer] The index to which the resolution should unwind in the - # case of conflict. - def state_index_for_unwind - current_requirement = requirement - existing_requirement = requirement_for_existing_name(name) - index = -1 - [current_requirement, existing_requirement].each do |r| - until r.nil? - current_state = find_state_for(r) - if state_any?(current_state) - current_index = states.index(current_state) - index = current_index if current_index > index - break end - r = parent_of(r) end end - index end # @return [Object] the requirement that led to `requirement` being added # to the list of requirements. def parent_of(requirement) @@ -219,29 +568,27 @@ module Gem::Resolver::Molinillo parent_state.requirement end # @return [Object] the requirement that led to a version of a possibility # with the given name being activated. def requirement_for_existing_name(name) - return nil unless activated.vertex_named(name).payload states.find { |s| s.name == name }.requirement end # @return [ResolutionState] the state whose `requirement` is the given # `requirement`. def find_state_for(requirement) return nil unless requirement - states.reverse_each.find { |i| requirement == i.requirement && i.is_a?(DependencyState) } - end - - # @return [Boolean] whether or not the given state has any possibilities - # left. - def state_any?(state) - state && state.possibilities.any? end # @return [Conflict] a {Conflict} that reflects the failure to activate # the {#possibility} in conjunction with the current {#state} - def create_conflict vertex = activated.vertex_named(name) locked_requirement = locked_requirement_named(name) @@ -250,18 +597,21 @@ module Gem::Resolver::Molinillo requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements end requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement - vertex.incoming_edges.each { |edge| (requirements[edge.origin.payload] ||= []).unshift(edge.requirement) } activated_by_name = {} - activated.each { |v| activated_by_name[v.name] = v.payload if v.payload } conflicts[name] = Conflict.new( requirement, requirements, - vertex.payload, possibility, locked_requirement, requirement_trees, - activated_by_name ) end @@ -272,6 +622,7 @@ module Gem::Resolver::Molinillo vertex.requirements.map { |r| requirement_tree_for(r) } end # @return [Array<Object>] the list of requirements that led to # `requirement` being required. def requirement_tree_for(requirement) @@ -311,116 +662,47 @@ module Gem::Resolver::Molinillo # @return [void] def attempt_to_activate debug(depth) { 'Attempting to activate ' + possibility.to_s } - existing_node = activated.vertex_named(name) - if existing_node.payload - debug(depth) { "Found existing spec (#{existing_node.payload})" } - attempt_to_activate_existing_spec(existing_node) else - attempt_to_activate_new_spec - end - end - - # Attempts to activate the current {#possibility} (given that it has - # already been activated) - # @return [void] - def attempt_to_activate_existing_spec(existing_node) - existing_spec = existing_node.payload - if requirement_satisfied_by?(requirement, activated, existing_spec) - new_requirements = requirements.dup - push_state_for_requirements(new_requirements, false) - else - return if attempt_to_swap_possibility - create_conflict - debug(depth) { "Unsatisfied by existing spec (#{existing_node.payload})" } - unwind_for_conflict - end - end - - # Attempts to swp the current {#possibility} with the already-activated - # spec with the given name - # @return [Boolean] Whether the possibility was swapped into {#activated} - def attempt_to_swap_possibility - activated.tag(:swap) - vertex = activated.vertex_named(name) - activated.set_payload(name, possibility) - if !vertex.requirements. - all? { |r| requirement_satisfied_by?(r, activated, possibility) } || - !new_spec_satisfied? - activated.rewind_to(:swap) - return - end - fixup_swapped_children(vertex) - activate_spec - end - - # Ensures there are no orphaned successors to the given {vertex}. - # @param [DependencyGraph::Vertex] vertex the vertex to fix up. - # @return [void] - def fixup_swapped_children(vertex) # rubocop:disable Metrics/CyclomaticComplexity - payload = vertex.payload - deps = dependencies_for(payload).group_by(&method(:name_for)) - vertex.outgoing_edges.each do |outgoing_edge| - requirement = outgoing_edge.requirement - parent_index = @parents_of[requirement].last - succ = outgoing_edge.destination - matching_deps = Array(deps[succ.name]) - dep_matched = matching_deps.include?(requirement) - - # only push the current index when it was originally required by the - # same named spec - if parent_index && states[parent_index].name == name - @parents_of[requirement].push(states.size - 1) end - - if matching_deps.empty? && !succ.root? && succ.predecessors.to_a == [vertex] - debug(depth) { "Removing orphaned spec #{succ.name} after swapping #{name}" } - succ.requirements.each { |r| @parents_of.delete(r) } - - removed_names = activated.detach_vertex_named(succ.name).map(&:name) - requirements.delete_if do |r| - # the only removed vertices are those with no other requirements, - # so it's safe to delete only based upon name here - removed_names.include?(name_for(r)) - end - elsif !dep_matched - debug(depth) { "Removing orphaned dependency #{requirement} after swapping #{name}" } - # also reset if we're removing the edge, but only if its parent has - # already been fixed up - @parents_of[requirement].push(states.size - 1) if @parents_of[requirement].empty? - - activated.delete_edge(outgoing_edge) - requirements.delete(requirement) end end end - # Attempts to activate the current {#possibility} (given that it hasn't - # already been activated) # @return [void] - def attempt_to_activate_new_spec - if new_spec_satisfied? - activate_spec else create_conflict unwind_for_conflict end end - # @return [Boolean] whether the current spec is satisfied as a new - # possibility. - def new_spec_satisfied? - unless requirement_satisfied_by?(requirement, activated, possibility) - debug(depth) { 'Unsatisfied by requested spec' } - return false - end - - locked_requirement = locked_requirement_named(name) - - locked_spec_satisfied = !locked_requirement || - requirement_satisfied_by?(locked_requirement, activated, possibility) - debug(depth) { 'Unsatisfied by locked spec' } unless locked_spec_satisfied - - locked_spec_satisfied end # @param [String] requirement_name the spec name to search for @@ -434,7 +716,7 @@ module Gem::Resolver::Molinillo # Add the current {#possibility} to the dependency graph of the current # {#state} # @return [void] - def activate_spec conflicts.delete(name) debug(depth) { "Activated #{name} at #{possibility}" } activated.set_payload(name, possibility) @@ -442,14 +724,14 @@ module Gem::Resolver::Molinillo end # Requires the dependencies that the recently activated spec has - # @param [Object] activated_spec the specification that has just been # activated # @return [void] - def require_nested_dependencies_for(activated_spec) - nested_dependencies = dependencies_for(activated_spec) debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" } nested_dependencies.each do |d| - activated.add_child_vertex(name_for(d), nil, [name_for(activated_spec)], d) parent_index = states.size - 1 parents = @parents_of[d] parents << parent_index if parents.empty? @@ -461,23 +743,82 @@ module Gem::Resolver::Molinillo # Pushes a new {DependencyState} that encapsulates both existing and new # requirements # @param [Array] new_requirements # @return [void] def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated) new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort - new_requirement = new_requirements.shift new_name = new_requirement ? name_for(new_requirement) : ''.freeze - possibilities = new_requirement ? search_for(new_requirement) : [] handle_missing_or_push_dependency_state DependencyState.new( new_name, new_requirements, new_activated, - new_requirement, possibilities, depth, conflicts.dup ) end # Pushes a new {DependencyState}. # If the {#specification_provider} says to # {SpecificationProvider#allow_missing?} that particular requirement, and # there are no possibilities for that requirement, then `state` is not - # pushed, and the node in {#activated} is removed, and we continue # resolving the remaining requirements. # @param [DependencyState] state # @return [void] @@ -1,5 +1,6 @@ # frozen_string_literal: true -require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph' module Gem::Resolver::Molinillo # This class encapsulates a dependency resolver. @@ -8,7 +9,7 @@ module Gem::Resolver::Molinillo # # class Resolver - require 'rubygems/resolver/molinillo/lib/molinillo/resolution' # @return [SpecificationProvider] the specification provider used # in the resolution process @@ -1,4 +1,5 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo # A state that a {Resolution} can be in # @attr [String] name the name of the current requirement @@ -7,7 +8,8 @@ module Gem::Resolver::Molinillo # @attr [Object] requirement the current requirement # @attr [Object] possibilities the possibilities to satisfy the current requirement # @attr [Integer] depth the depth of the resolution - # @attr [Set<Object>] conflicts unresolved conflicts ResolutionState = Struct.new( :name, :requirements, @@ -15,14 +17,15 @@ module Gem::Resolver::Molinillo :requirement, :possibilities, :depth, - :conflicts ) class ResolutionState # Returns an empty resolution state # @return [ResolutionState] an empty state def self.empty - new(nil, [], DependencyGraph.new, nil, nil, 0, Set.new) end end @@ -40,7 +43,8 @@ module Gem::Resolver::Molinillo requirement, [possibilities.pop], depth + 1, - conflicts.dup ).tap do |state| state.activated.tag(state) end @@ -104,7 +104,7 @@ class Gem::Resolver::Specification # Returns true if this specification is installable on this platform. def installable_platform? - Gem::Platform.match spec.platform end def local? # :nodoc: @@ -88,7 +88,7 @@ class Gem::S3URISigner "AWS4-HMAC-SHA256", date_time, credential_info, - Digest::SHA256.hexdigest(canonical_request) ].join("\n") end @@ -6,7 +6,6 @@ #++ require 'rubygems/exceptions' -require 'fileutils' require_relative 'openssl' ## @@ -592,7 +591,7 @@ module Gem::Security end -if defined?(OpenSSL::SSL) require 'rubygems/security/policy' require 'rubygems/security/policies' require 'rubygems/security/trust_dir' @@ -194,7 +194,7 @@ class Gem::Security::Policy ("[Policy: %s - data: %p signer: %p chain: %p root: %p " + "signed-only: %p trusted-only: %p]") % [ @name, @verify_chain, @verify_data, @verify_root, @verify_signer, - @only_signed, @only_trusted, ] end @@ -34,7 +34,7 @@ class Gem::Security::Signer attr_reader :options DEFAULT_OPTIONS = { - expiration_length_days: 365 }.freeze ## @@ -771,7 +771,7 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } doc_items << { :name => base_name, :url => doc_root(new_path), - :summary => '' } end @@ -79,7 +79,7 @@ class Gem::Source def dependency_resolver_set # :nodoc: return Gem::Resolver::IndexSet.new self if 'file' == uri.scheme - bundler_api_uri = uri + './api/v1/dependencies' begin fetcher = Gem::RemoteFetcher.fetcher @@ -130,7 +130,7 @@ class Gem::Source spec_file_name = name_tuple.spec_name - source_uri = uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}" cache_dir = cache_dir source_uri @@ -174,7 +174,7 @@ class Gem::Source file = FILES[type] fetcher = Gem::RemoteFetcher.fetcher file_name = "#{file}.#{Gem.marshal_version}" - spec_path = uri + "#{file_name}.gz" cache_dir = cache_dir spec_path local_file = File.join(cache_dir, file_name) retried = false @@ -223,7 +223,13 @@ class Gem::Source def typo_squatting?(host, distance_threshold=4) return if @uri.host.nil? - levenshtein_distance(@uri.host, host) <= distance_threshold end end @@ -98,7 +98,7 @@ class Gem::SpecFetcher found[source] = specs.select do |tup| if dependency.match?(tup) - if matching_platform and !Gem::Platform.match(tup.platform) pm = ( rejected_specs[dependency] ||= \ Gem::PlatformMismatch.new(tup.name, tup.version)) @@ -77,18 +77,18 @@ class Gem::Specification < Gem::BasicSpecification -1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'], 1 => [ 'Deprecated "test_suite_file" in favor of the new, but equivalent, "test_files"', - '"test_file=x" is a shortcut for "test_files=[x]"' ], 2 => [ 'Added "required_rubygems_version"', 'Now forward-compatible with future versions', ], 3 => [ - 'Added Fixnum validation to the specification_version' ], 4 => [ - 'Added sandboxed freeform metadata to the specification version.' - ] }.freeze MARSHAL_FIELDS = { # :nodoc: @@ -804,7 +804,7 @@ class Gem::Specification < Gem::BasicSpecification stubs = stubs.uniq {|stub| stub.full_name } _resort!(stubs) - @@stubs_by_name = stubs.select {|s| Gem::Platform.match s.platform }.group_by(&:name) stubs end end @@ -831,7 +831,7 @@ class Gem::Specification < Gem::BasicSpecification @@stubs_by_name[name] else pattern = "#{name}-*.gemspec" - stubs = installed_stubs(dirs, pattern).select {|s| Gem::Platform.match s.platform } + default_stubs(pattern) stubs = stubs.uniq {|stub| stub.full_name }.group_by(&:name) stubs.each_value {|v| _resort!(v) } @@ -1344,7 +1344,7 @@ class Gem::Specification < Gem::BasicSpecification true, # has_rdoc @new_platform, @licenses, - @metadata ] end @@ -2450,7 +2450,7 @@ class Gem::Specification < Gem::BasicSpecification :version, :has_rdoc, :default_executable, - :metadata ] @@attributes.each do |attr_name| @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- @@ -29,7 +29,7 @@ class Gem::StubSpecification < Gem::BasicSpecification # in their require paths, so lets take advantage of that by pre-allocating # a require path list for that case. REQUIRE_PATH_LIST = { # :nodoc: - 'lib' => ['lib'].freeze }.freeze def initialize(data, extensions) @@ -252,14 +252,14 @@ class Gem::TestCase < Minitest::Test msg = message(msg) do 'Expected output containing make command "%s": %s' % [ ('%s %s' % [make_command, target]).rstrip, - output.inspect ] end else msg = message(msg) do 'Expected make command "%s": %s' % [ ('%s %s' % [make_command, target]).rstrip, - output.inspect ] end end @@ -335,6 +335,7 @@ class Gem::TestCase < Minitest::Test @git = ENV['GIT'] || (win_platform? ? 'git.exe' : 'git') Gem.ensure_gem_subdirectories @gemhome @orig_LOAD_PATH = $LOAD_PATH.dup $LOAD_PATH.map! do |s| @@ -360,26 +361,23 @@ class Gem::TestCase < Minitest::Test Gem.send :remove_instance_variable, :@ruby_version if Gem.instance_variables.include? :@ruby_version - FileUtils.mkdir_p @gemhome FileUtils.mkdir_p @userhome ENV['GEM_PRIVATE_KEY_PASSPHRASE'] = PRIVATE_KEY_PASSPHRASE - @default_dir = File.join @tempdir, 'default' - @default_spec_dir = File.join @default_dir, "specifications", "default" if Gem.java_platform? @orig_default_gem_home = RbConfig::CONFIG['default_gem_home'] - RbConfig::CONFIG['default_gem_home'] = @default_dir else - Gem.instance_variable_set(:@default_dir, @default_dir) end - FileUtils.mkdir_p @default_spec_dir Gem::Specification.unresolved_deps.clear Gem.use_paths(@gemhome) - Gem::Security.reset - Gem.loaded_specs.clear Gem.instance_variable_set(:@activated_gem_paths, 0) Gem.clear_default_specs @@ -448,6 +446,8 @@ class Gem::TestCase < Minitest::Test Gem.ruby = @orig_ruby if @orig_ruby if Gem.java_platform? RbConfig::CONFIG['default_gem_home'] = @orig_default_gem_home else @@ -741,7 +741,7 @@ class Gem::TestCase < Minitest::Test def install_specs(*specs) specs.each do |spec| - Gem::Installer.for_spec(spec).install end Gem.searcher = nil @@ -751,19 +751,6 @@ class Gem::TestCase < Minitest::Test # Installs the provided default specs including writing the spec file def install_default_gems(*specs) - install_default_specs(*specs) - - specs.each do |spec| - File.open spec.loaded_from, 'w' do |io| - io.write spec.to_ruby_for_cache - end - end - end - - ## - # Install the provided default specs - - def install_default_specs(*specs) specs.each do |spec| installer = Gem::Installer.for_spec(spec, :install_as_default => true) installer.install @@ -792,7 +779,7 @@ class Gem::TestCase < Minitest::Test def new_default_spec(name, version, deps = nil, *files) spec = util_spec name, version, deps - spec.loaded_from = File.join(@default_spec_dir, spec.spec_name) spec.files = files lib_dir = File.join(@tempdir, "default_gems", "lib") @@ -1517,7 +1504,7 @@ Also, a list: PRIVATE_KEY = nil PUBLIC_KEY = nil PUBLIC_CERT = nil - end if defined?(OpenSSL::SSL) end require 'rubygems/test_utilities' @@ -1,5 +1,4 @@ # frozen_string_literal: true -require 'cgi' ## # The UriFormatter handles URIs from user-input and escaping. @@ -18,6 +17,8 @@ class Gem::UriFormatter # Creates a new URI formatter for +uri+. def initialize(uri) @uri = uri end @@ -73,4 +73,10 @@ module Gem::VersionOption end end end |