diff options
author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2022-08-22 11:50:00 +0900 |
---|---|---|
committer | nagachika <nagachika@ruby-lang.org> | 2022-09-03 15:54:07 +0900 |
commit | 522b75f1b666051f86a3c8961fd4255e560c5020 (patch) | |
tree | 85315021fac815517ce3e68f1883533aa4b35747 /lib/bundler | |
parent | 44c926f3a94346809c68574e0277dae3917992c6 (diff) |
Merge RubyGems-3.3.20 and Bundler-2.3.20
Diffstat (limited to 'lib/bundler')
29 files changed, 244 insertions, 114 deletions
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index e1c284130b..5bf0f4fa3a 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -218,6 +218,8 @@ module Bundler "Specify the number of jobs to run in parallel" method_option "local", :type => :boolean, :banner => "Do not attempt to fetch gems remotely and use the gem cache instead" + method_option "prefer-local", :type => :boolean, :banner => + "Only attempt to fetch gems remotely if not present locally, even if newer versions are available remotely" method_option "no-cache", :type => :boolean, :banner => "Don't update the existing gem cache." method_option "redownload", :type => :boolean, :aliases => "--force", :banner => @@ -236,7 +238,7 @@ module Bundler "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application" method_option "trust-policy", :alias => "P", :type => :string, :banner => "Gem trust policy (like gem install -P). Must be one of " + - Bundler.rubygems.security_policy_keys.join("|") + Bundler.rubygems.security_policy_keys.join("|") method_option "without", :type => :array, :banner => "Exclude gems that are part of the specified named group." method_option "with", :type => :array, :banner => @@ -399,9 +401,9 @@ module Bundler "Do not attempt to fetch gems remotely and use the gem cache instead" method_option "pre", :type => :boolean, :banner => "Check for newer pre-release gems" method_option "source", :type => :array, :banner => "Check against a specific source" - method_option "filter-strict", :type => :boolean, :banner => + method_option "filter-strict", :type => :boolean, :aliases => "--strict", :banner => "Only list newer versions allowed by your Gemfile requirements" - method_option "strict", :type => :boolean, :aliases => "--update-strict", :banner => + method_option "update-strict", :type => :boolean, :banner => "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major" method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version" method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)" diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb index e9b85f7f6f..851ae9b840 100644 --- a/lib/bundler/cli/install.rb +++ b/lib/bundler/cli/install.rb @@ -147,8 +147,11 @@ module Bundler def normalize_settings Bundler.settings.set_command_option :path, nil if options[:system] Bundler.settings.set_command_option_if_given :path, options[:path] - Bundler.settings.temporary(:path_relative_to_cwd => false) do - Bundler.settings.set_command_option :path, "bundle" if options["standalone"] && Bundler.settings[:path].nil? + + if options["standalone"] && Bundler.settings[:path].nil? && !options["local"] + Bundler.settings.temporary(:path_relative_to_cwd => false) do + Bundler.settings.set_command_option :path, "bundle" + end end bin_option = options["binstubs"] diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb index d5183b060b..e9f93fec39 100644 --- a/lib/bundler/cli/outdated.rb +++ b/lib/bundler/cli/outdated.rb @@ -46,7 +46,7 @@ module Bundler Bundler::CLI::Common.configure_gem_version_promoter( Bundler.definition, - options + options.merge(:strict => @strict) ) definition_resolution = proc do @@ -129,6 +129,12 @@ module Bundler private + def loaded_from_for(spec) + return unless spec.respond_to?(:loaded_from) + + spec.loaded_from + end + def groups_text(group_text, groups) "#{group_text}#{groups.split(",").size > 1 ? "s" : ""} \"#{groups}\"" end @@ -184,7 +190,10 @@ module Bundler def print_gem(current_spec, active_spec, dependency, groups) spec_version = "#{active_spec.version}#{active_spec.git_version}" - spec_version += " (from #{active_spec.loaded_from})" if Bundler.ui.debug? && active_spec.loaded_from + if Bundler.ui.debug? + loaded_from = loaded_from_for(active_spec) + spec_version += " (from #{loaded_from})" if loaded_from + end current_version = "#{current_spec.version}#{current_spec.git_version}" if dependency && dependency.specific? @@ -211,7 +220,7 @@ module Bundler dependency = dependency.requirement if dependency ret_val = [active_spec.name, current_version, spec_version, dependency.to_s, groups.to_s] - ret_val << active_spec.loaded_from.to_s if Bundler.ui.debug? + ret_val << loaded_from_for(active_spec).to_s if Bundler.ui.debug? ret_val end diff --git a/lib/bundler/cli/platform.rb b/lib/bundler/cli/platform.rb index 068c765aad..16d4e0145a 100644 --- a/lib/bundler/cli/platform.rb +++ b/lib/bundler/cli/platform.rb @@ -9,7 +9,7 @@ module Bundler def run platforms, ruby_version = Bundler.ui.silence do - locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version + locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version.gsub(/p\d+\Z/, "") gemfile_ruby_version = Bundler.definition.ruby_version && Bundler.definition.ruby_version.single_version_string [Bundler.definition.platforms.map {|p| "* #{p}" }, locked_ruby_version || gemfile_ruby_version] diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index d55ee29ebc..21c06e55ba 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -70,6 +70,7 @@ module Bundler @unlock = unlock @optional_groups = optional_groups @remote = false + @prefer_local = false @specs = nil @ruby_version = ruby_version @gemfiles = gemfiles @@ -170,6 +171,13 @@ module Bundler resolve end + def resolve_prefering_local! + @prefer_local = true + @remote = true + sources.remote! + resolve + end + def resolve_with_cache! sources.cached! resolve @@ -476,6 +484,7 @@ module Bundler def reresolve last_resolve = converge_locked_specs + remove_ruby_from_platforms_if_necessary!(dependencies) expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, true) Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) end @@ -516,10 +525,8 @@ module Bundler end end - unless specs["bundler"].any? - bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last - specs["bundler"] = bundler - end + bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last + specs["bundler"] = bundler specs end @@ -528,6 +535,19 @@ module Bundler @remote && sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source? end + def pin_locally_available_names(source_requirements) + source_requirements.each_with_object({}) do |(name, original_source), new_source_requirements| + local_source = original_source.dup + local_source.local_only! + + new_source_requirements[name] = if local_source.specs.search(name).any? + local_source + else + original_source + end + end + end + def current_ruby_platform_locked? return false unless generic_local_platform == Gem::Platform::RUBY return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY) @@ -719,16 +739,24 @@ module Bundler specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) } end + @specs_that_changed_sources = [] + specs.each do |s| - # Replace the locked dependency's source with the equivalent source from the Gemfile dep = @dependencies.find {|d| s.satisfies?(d) } - s.source = (dep && dep.source) || sources.get(s.source) || sources.default_source + # Replace the locked dependency's source with the equivalent source from the Gemfile + s.source = if dep && dep.source + gemfile_source = dep.source + lockfile_source = s.source - next if @unlock[:sources].include?(s.source.name) + @specs_that_changed_sources << s if gemfile_source != lockfile_source - # If the spec is from a path source and it doesn't exist anymore - # then we unlock it. + gemfile_source + else + sources.get_with_fallback(s.source) + end + + next if @unlock[:sources].include?(s.source.name) # Path sources have special logic if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec) @@ -765,7 +793,7 @@ module Bundler def metadata_dependencies @metadata_dependencies ||= [ - Dependency.new("Ruby\0", RubyVersion.system.gem_version), + Dependency.new("Ruby\0", Gem.ruby_version), Dependency.new("RubyGems\0", Gem::VERSION), ] end @@ -792,7 +820,9 @@ module Bundler # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) source_requirements = if precompute_source_requirements_for_indirect_dependencies? - { :default => sources.default_source }.merge(source_map.all_requirements) + all_requirements = source_map.all_requirements + all_requirements = pin_locally_available_names(all_requirements) if @prefer_local + { :default => sources.default_source }.merge(all_requirements) else { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements) end @@ -802,9 +832,18 @@ module Bundler end source_requirements[:default_bundler] = source_requirements["bundler"] || sources.default_source source_requirements["bundler"] = sources.metadata_source # needs to come last to override + verify_changed_sources! source_requirements end + def verify_changed_sources! + @specs_that_changed_sources.each do |s| + if s.source.specs.search(s.name).empty? + raise GemNotFound, "Could not find gem '#{s.name}' in #{s.source}" + end + end + end + def requested_groups values = groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] values &= Bundler.settings[:only] unless Bundler.settings[:only].empty? @@ -844,6 +883,17 @@ module Bundler end end + def remove_ruby_from_platforms_if_necessary!(dependencies) + return if Bundler.frozen_bundle? || + Bundler.local_platform == Gem::Platform::RUBY || + !platforms.include?(Gem::Platform::RUBY) || + (@new_platform && platforms.last == Gem::Platform::RUBY) || + !@originally_locked_specs.incomplete_ruby_specs?(dependencies) + + remove_platform(Gem::Platform::RUBY) + add_current_platform + end + def source_map @source_map ||= SourceMap.new(sources, dependencies, @locked_specs) end diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb index e9d5dd505c..e399a50cfd 100644 --- a/lib/bundler/fetcher.rb +++ b/lib/bundler/fetcher.rb @@ -240,8 +240,8 @@ module Bundler def connection @connection ||= begin needs_ssl = remote_uri.scheme == "https" || - Bundler.settings[:ssl_verify_mode] || - Bundler.settings[:ssl_client_cert] + Bundler.settings[:ssl_verify_mode] || + Bundler.settings[:ssl_client_cert] raise SSLError if needs_ssl && !defined?(OpenSSL::SSL) con = PersistentHTTP.new :name => "bundler", :proxy => :ENV @@ -256,8 +256,8 @@ module Bundler end ssl_client_cert = Bundler.settings[:ssl_client_cert] || - (Gem.configuration.ssl_client_cert if - Gem.configuration.respond_to?(:ssl_client_cert)) + (Gem.configuration.ssl_client_cert if + Gem.configuration.respond_to?(:ssl_client_cert)) if ssl_client_cert pem = File.read(ssl_client_cert) con.cert = OpenSSL::X509::Certificate.new(pem) @@ -288,8 +288,8 @@ module Bundler def bundler_cert_store store = OpenSSL::X509::Store.new ssl_ca_cert = Bundler.settings[:ssl_ca_cert] || - (Gem.configuration.ssl_ca_cert if - Gem.configuration.respond_to?(:ssl_ca_cert)) + (Gem.configuration.ssl_ca_cert if + Gem.configuration.respond_to?(:ssl_ca_cert)) if ssl_ca_cert if File.directory? ssl_ca_cert store.add_path ssl_ca_cert diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb index 6bc4fb4991..0d50d8687b 100644 --- a/lib/bundler/gem_helpers.rb +++ b/lib/bundler/gem_helpers.rb @@ -44,6 +44,12 @@ module Bundler def select_best_platform_match(specs, platform) matching = specs.select {|spec| spec.match_platform(platform) } + + sort_best_platform_match(matching, platform) + end + module_function :select_best_platform_match + + def sort_best_platform_match(matching, platform) exact = matching.select {|spec| spec.platform == platform } return exact if exact.any? @@ -52,7 +58,7 @@ module Bundler sorted_matching.take_while {|spec| same_specificity(platform, spec, exemplary_spec) && same_deps(spec, exemplary_spec) } end - module_function :select_best_platform_match + module_function :sort_best_platform_match class PlatformMatch def self.specificity_score(spec_platform, user_platform) diff --git a/lib/bundler/incomplete_specification.rb b/lib/bundler/incomplete_specification.rb new file mode 100644 index 0000000000..6d0b9b901c --- /dev/null +++ b/lib/bundler/incomplete_specification.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Bundler + class IncompleteSpecification + attr_reader :name, :platform + + def initialize(name, platform) + @name = name + @platform = platform + end + end +end diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index f195d36600..b7b0e36dfd 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -268,7 +268,14 @@ module Bundler return false if @definition.nothing_changed? && !@definition.missing_specs? end - options["local"] ? @definition.resolve_with_cache! : @definition.resolve_remotely! + if options["local"] + @definition.resolve_with_cache! + elsif options["prefer-local"] + @definition.resolve_prefering_local! + else + @definition.resolve_remotely! + end + true end diff --git a/lib/bundler/installer/standalone.rb b/lib/bundler/installer/standalone.rb index 248b677233..2756626f8a 100644 --- a/lib/bundler/installer/standalone.rb +++ b/lib/bundler/installer/standalone.rb @@ -47,7 +47,7 @@ module Bundler end def bundler_path - Bundler.root.join(Bundler.settings[:path], "bundler") + Bundler.root.join(Bundler.settings[:path].to_s, "bundler") end def gem_path(path, spec) diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index 21e75d2126..5b40bec5a8 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -76,35 +76,35 @@ module Bundler end def materialize_for_installation - __materialize__(ruby_platform_materializes_to_ruby_platform? ? platform : Bundler.local_platform) - end + source.local! + + candidates = if source.is_a?(Source::Path) || !ruby_platform_materializes_to_ruby_platform? + target_platform = ruby_platform_materializes_to_ruby_platform? ? platform : Bundler.local_platform + + source.specs.search(Dependency.new(name, version)).select do |spec| + MatchPlatform.platforms_match?(spec.platform, target_platform) + end + else + source.specs.search(self) + end - def materialize_for_resolution - return self unless Gem::Platform.match_spec?(self) + return self if candidates.empty? - __materialize__(platform) + __materialize__(candidates) end - def __materialize__(platform) - @specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name - source.gemspec.tap {|s| s.source = source } - else - search_object = if source.is_a?(Source::Path) - Dependency.new(name, version) - else - ruby_platform_materializes_to_ruby_platform? ? self : Dependency.new(name, version) - end - candidates = source.specs.search(search_object) - same_platform_candidates = candidates.select do |spec| - MatchPlatform.platforms_match?(spec.platform, platform) - end - installable_candidates = same_platform_candidates.select do |spec| + def __materialize__(candidates) + @specification = begin + search = candidates.reverse.find do |spec| spec.is_a?(StubSpecification) || (spec.required_ruby_version.satisfied_by?(Gem.ruby_version) && spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version)) end - search = installable_candidates.last || same_platform_candidates.last - search.dependencies = dependencies if search && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)) + if search.nil? && Bundler.frozen_bundle? + search = candidates.last + else + search.dependencies = dependencies if search && search.full_name == full_name && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)) + end search end end diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1 index 4903015881..fdaaa3b92a 100644 --- a/lib/bundler/man/bundle-cache.1 +++ b/lib/bundler/man/bundle-cache.1 @@ -9,6 +9,9 @@ .SH "SYNOPSIS" \fBbundle cache\fR . +.P +alias: \fBpackage\fR, \fBpack\fR +. .SH "DESCRIPTION" Copy all of the \fB\.gem\fR files needed to run the application into the \fBvendor/cache\fR directory\. In the future, when running [bundle install(1)][bundle\-install], use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\. . @@ -53,3 +56,6 @@ One way to be sure that you have the right platformed versions of all your gems . .P By default, bundle cache(1) \fIbundle\-cache\.1\.html\fR fetches and also installs the gems to the default location\. To package the dependencies to \fBvendor/cache\fR without installing them to the local install location, you can run \fBbundle cache \-\-no\-install\fR\. +. +.SH "HISTORY" +In Bundler 2\.1, \fBcache\fR took in the functionalities of \fBpackage\fR and now \fBpackage\fR and \fBpack\fR are aliases of \fBcache\fR\. diff --git a/lib/bundler/man/bundle-cache.1.ronn b/lib/bundler/man/bundle-cache.1.ronn index 383adb2ba3..46906d2b48 100644 --- a/lib/bundler/man/bundle-cache.1.ronn +++ b/lib/bundler/man/bundle-cache.1.ronn @@ -5,6 +5,8 @@ bundle-cache(1) -- Package your needed `.gem` files into your application `bundle cache` +alias: `package`, `pack` + ## DESCRIPTION Copy all of the `.gem` files needed to run the application into the @@ -70,3 +72,8 @@ By default, [bundle cache(1)](bundle-cache.1.html) fetches and also installs the gems to the default location. To package the dependencies to `vendor/cache` without installing them to the local install location, you can run `bundle cache --no-install`. + +## HISTORY + +In Bundler 2.1, `cache` took in the functionalities of `package` and now +`package` and `pack` are aliases of `cache`. diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index b5cee57f29..9f7887ca91 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -51,7 +51,7 @@ Executing \fBbundle config unset <name>\fR will delete the configuration in both Executing \fBbundle config unset \-\-global <name>\fR will delete the configuration only from the user configuration\. . .P -Executing \fBbundle config unset \-\-local <name> <value>\fR will delete the configuration only from the local application\. +Executing \fBbundle config unset \-\-local <name>\fR will delete the configuration only from the local application\. . .P Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. @@ -298,7 +298,7 @@ The following is a list of all configuration keys and their purpose\. You can le .IP "" 0 . .P -In general, you should set these settings per\-application by using the applicable flag to the bundle install(1) \fIbundle\-install\.1\.html\fR or bundle package(1) \fIbundle\-package\.1\.html\fR command\. +In general, you should set these settings per\-application by using the applicable flag to the bundle install(1) \fIbundle\-install\.1\.html\fR or bundle cache(1) \fIbundle\-cache\.1\.html\fR command\. . .P You can set them globally either via environment variables or \fBbundle config\fR, whichever is preferable for your setup\. If you use both, environment variables will take preference over global settings\. diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index e2af773141..905c85fcd9 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -43,8 +43,8 @@ local and global sources. Executing `bundle config unset --global <name>` will delete the configuration only from the user configuration. -Executing `bundle config unset --local <name> <value>` will delete the -configuration only from the local application. +Executing `bundle config unset --local <name>` will delete the configuration +only from the local application. Executing bundle with the `BUNDLE_IGNORE_CONFIG` environment variable set will cause it to ignore all configuration. @@ -280,7 +280,7 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). A `:`-separated list of groups whose gems bundler should not install. In general, you should set these settings per-application by using the applicable -flag to the [bundle install(1)](bundle-install.1.html) or [bundle package(1)](bundle-package.1.html) command. +flag to the [bundle install(1)](bundle-install.1.html) or [bundle cache(1)](bundle-cache.1.html) command. You can set them globally either via environment variables or `bundle config`, whichever is preferable for your setup. If you use both, environment variables diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1 index c742efd142..8e94fe2437 100644 --- a/lib/bundler/man/bundle-install.1 +++ b/lib/bundler/man/bundle-install.1 @@ -70,6 +70,10 @@ The maximum number of parallel download and install jobs\. The default is the nu Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. . .TP +\fB\-\-prefer\-local\fR +Force using locally installed gems, or gems already present in Rubygems\' cache or in \fBvendor/cache\fR, when resolving, even if newer versions are available remotely\. Only attempt to connect to \fBrubygems\.org\fR for gems that are not present locally\. +. +.TP \fB\-\-no\-cache\fR Do not update the cache in \fBvendor/cache\fR with the newly bundled gems\. This does not remove any gems in the cache but keeps the newly bundled gems from being cached during the install\. . diff --git a/lib/bundler/man/bundle-install.1.ronn b/lib/bundler/man/bundle-install.1.ronn index bec05187f3..47200ac2d5 100644 --- a/lib/bundler/man/bundle-install.1.ronn +++ b/lib/bundler/man/bundle-install.1.ronn @@ -109,6 +109,12 @@ automatically and that requires `bundler` to silently remember them. Since appropriate platform-specific gem exists on `rubygems.org` it will not be found. +* `--prefer-local`: + Force using locally installed gems, or gems already present in Rubygems' cache + or in `vendor/cache`, when resolving, even if newer versions are available + remotely. Only attempt to connect to `rubygems.org` for gems that are not + present locally. + * `--no-cache`: Do not update the cache in `vendor/cache` with the newly bundled gems. This does not remove any gems in the cache but keeps the newly bundled gems from diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1 index 344ad93083..f5a90c59e9 100644 --- a/lib/bundler/man/bundle-platform.1 +++ b/lib/bundler/man/bundle-platform.1 @@ -10,7 +10,7 @@ \fBbundle platform\fR [\-\-ruby] . .SH "DESCRIPTION" -\fBplatform\fR will display information from your Gemfile, Gemfile\.lock, and Ruby VM about your platform\. +\fBplatform\fR displays information from your Gemfile, Gemfile\.lock, and Ruby VM about your platform\. . .P For instance, using this Gemfile(5): @@ -21,7 +21,7 @@ For instance, using this Gemfile(5): source "https://rubygems\.org" -ruby "1\.9\.3" +ruby "3\.1\.2" gem "rack" . @@ -30,7 +30,7 @@ gem "rack" .IP "" 0 . .P -If you run \fBbundle platform\fR on Ruby 1\.9\.3, it will display the following output: +If you run \fBbundle platform\fR on Ruby 3\.1\.2, it displays the following output: . .IP "" 4 . @@ -39,10 +39,13 @@ If you run \fBbundle platform\fR on Ruby 1\.9\.3, it will display the following Your platform is: x86_64\-linux Your app has gems that work on these platforms: +* arm64\-darwin\-21 * ruby +* x64\-mingw\-ucrt +* x86_64\-linux Your Gemfile specifies a Ruby version requirement: -* ruby 1\.9\.3 +* ruby 3\.1\.2 Your current platform satisfies the Ruby version requirement\. . @@ -51,11 +54,18 @@ Your current platform satisfies the Ruby version requirement\. .IP "" 0 . .P -\fBplatform\fR will list all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It will also let you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn\'t match the running Ruby VM, it will tell you what part does not\. +\fBplatform\fR lists all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It also lets you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn\'t match the running Ruby VM, it tells you what part does not\. . .SH "OPTIONS" . .TP \fB\-\-ruby\fR It will display the ruby directive information, so you don\'t have to parse it from the Gemfile(5)\. +. +.SH "SEE ALSO" +. +.IP "\(bu" 4 +bundle\-lock(1) \fIbundle\-lock\.1\.ronn\fR +. +.IP "" 0 diff --git a/lib/bundler/man/bundle-platform.1.ronn b/lib/bundler/man/bundle-platform.1.ronn index b5d3283fb6..eb9baa1c62 100644 --- a/lib/bundler/man/bundle-platform.1.ronn +++ b/lib/bundler/man/bundle-platform.1.ronn @@ -7,36 +7,43 @@ bundle-platform(1) -- Displays platform compatibility information ## DESCRIPTION -`platform` will display information from your Gemfile, Gemfile.lock, and Ruby +`platform` displays information from your Gemfile, Gemfile.lock, and Ruby VM about your platform. For instance, using this Gemfile(5): source "https://rubygems.org" - ruby "1.9.3" + ruby "3.1.2" gem "rack" -If you run `bundle platform` on Ruby 1.9.3, it will display the following output: +If you run `bundle platform` on Ruby 3.1.2, it displays the following output: Your platform is: x86_64-linux Your app has gems that work on these platforms: + * arm64-darwin-21 * ruby + * x64-mingw-ucrt + * x86_64-linux Your Gemfile specifies a Ruby version requirement: - * ruby 1.9.3 + * ruby 3.1.2 Your current platform satisfies the Ruby version requirement. -`platform` will list all the platforms in your `Gemfile.lock` as well as the -`ruby` directive if applicable from your Gemfile(5). It will also let you know +`platform` lists all the platforms in your `Gemfile.lock` as well as the +`ruby` directive if applicable from your Gemfile(5). It also lets you know if the `ruby` directive requirement has been met. If `ruby` directive doesn't -match the running Ruby VM, it will tell you what part does not. +match the running Ruby VM, it tells you what part does not. ## OPTIONS * `--ruby`: It will display the ruby directive information, so you don't have to parse it from the Gemfile(5). + +## SEE ALSO + +* [bundle-lock(1)](bundle-lock.1.ronn) diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1 index c46c37c708..f683e78cc6 100644 --- a/lib/bundler/man/bundle.1 +++ b/lib/bundler/man/bundle.1 @@ -43,8 +43,8 @@ Install the gems specified by the \fBGemfile\fR or \fBGemfile\.lock\fR Update dependencies to their latest versions . .TP -\fBbundle package(1)\fR \fIbundle\-package\.1\.html\fR -Package the \.gem files required by your application into the \fBvendor/cache\fR directory +\fBbundle cache(1)\fR \fIbundle\-cache\.1\.html\fR +Package the \.gem files required by your application into the \fBvendor/cache\fR directory (aliases: \fBbundle package\fR, \fBbundle pack\fR) . .TP \fBbundle exec(1)\fR \fIbundle\-exec\.1\.html\fR @@ -81,7 +81,7 @@ Show the source location of a particular gem in the bundle Show all of the outdated gems in the current bundle . .TP -\fBbundle console(1)\fR +\fBbundle console(1)\fR (deprecated) Start an IRB session in the current bundle . .TP @@ -127,9 +127,6 @@ When running a command that isn\'t listed in PRIMARY COMMANDS or UTILITIES, Bund These commands are obsolete and should no longer be used: . .IP "\(bu" 4 -\fBbundle cache(1)\fR -. -.IP "\(bu" 4 \fBbundle inject(1)\fR . .IP "" 0 diff --git a/lib/bundler/man/bundle.1.ronn b/lib/bundler/man/bundle.1.ronn index fa247ab365..8f0159eee5 100644 --- a/lib/bundler/man/bundle.1.ronn +++ b/lib/bundler/man/bundle.1.ronn @@ -36,9 +36,9 @@ We divide `bundle` subcommands into primary commands and utilities: * [`bundle update(1)`](bundle-update.1.html): Update dependencies to their latest versions -* [`bundle package(1)`](bundle-package.1.html): +* [`bundle cache(1)`](bundle-cache.1.html): Package the .gem files required by your application into the - `vendor/cache` directory + `vendor/cache` directory (aliases: `bundle package`, `bundle pack`) * [`bundle exec(1)`](bundle-exec.1.html): Execute a script in the current bundle @@ -67,7 +67,7 @@ We divide `bundle` subcommands into primary commands and utilities: * [`bundle outdated(1)`](bundle-outdated.1.html): Show all of the outdated gems in the current bundle -* `bundle console(1)`: +* `bundle console(1)` (deprecated): Start an IRB session in the current bundle * [`bundle open(1)`](bundle-open.1.html): @@ -107,5 +107,4 @@ and execute it, passing down any extra arguments to it. These commands are obsolete and should no longer be used: -* `bundle cache(1)` * `bundle inject(1)` diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 40bc247b32..ca1bdbda7b 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -28,10 +28,11 @@ module Bundler def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms, metadata_requirements) @source_requirements = source_requirements @metadata_requirements = metadata_requirements + @base = base @resolver = Molinillo::Resolver.new(self, self) @search_for = {} @base_dg = Molinillo::DependencyGraph.new - @base = base.materialized_for_resolution do |ls| + base.each do |ls| dep = Dependency.new(ls.name, ls.version) @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true) end diff --git a/lib/bundler/ruby_dsl.rb b/lib/bundler/ruby_dsl.rb index f6ba220cd5..3b3a0583a5 100644 --- a/lib/bundler/ruby_dsl.rb +++ b/lib/bundler/ruby_dsl.rb @@ -9,7 +9,7 @@ module Bundler raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil? if options[:engine] == "ruby" && options[:engine_version] && - ruby_version != Array(options[:engine_version]) + ruby_version != Array(options[:engine_version]) raise GemfileEvalError, "ruby_version must match the :engine_version for MRI" end @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version]) diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb index 3f51cf4528..9161c6afde 100644 --- a/lib/bundler/ruby_version.rb +++ b/lib/bundler/ruby_version.rb @@ -32,12 +32,12 @@ module Bundler @engine = engine && engine.to_s || "ruby" @engine_versions = (engine_version && Array(engine_version)) || @versions @engine_gem_version = Gem::Requirement.create(@engine_versions.first).requirements.first.last - @patchlevel = patchlevel + @patchlevel = patchlevel || (@gem_version.prerelease? ? "-1" : nil) end def to_s(versions = self.versions) output = String.new("ruby #{versions_string(versions)}") - output << "p#{patchlevel}" if patchlevel + output << "p#{patchlevel}" if patchlevel && patchlevel != "-1" output << " (#{engine} #{versions_string(engine_versions)})" unless engine == "ruby" output @@ -46,7 +46,7 @@ module Bundler # @private PATTERN = / ruby\s - ([\d.]+) # ruby version + (\d+\.\d+\.\d+(?:\.\S+)?) # ruby version (?:p(-?\d+))? # optional patchlevel (?:\s\((\S+)\s(.+)\))? # optional engine info /xo.freeze @@ -103,8 +103,8 @@ module Bundler def self.system ruby_engine = RUBY_ENGINE.dup - ruby_version = RUBY_VERSION.dup - ruby_engine_version = RUBY_ENGINE_VERSION.dup + ruby_version = Gem.ruby_version.to_s + ruby_engine_version = RUBY_ENGINE == "ruby" ? ruby_version : RUBY_ENGINE_VERSION.dup patchlevel = RUBY_PATCHLEVEL.to_s @ruby_version ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version) diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb index a47692d1f2..938c58e64d 100644 --- a/lib/bundler/rubygems_ext.rb +++ b/lib/bundler/rubygems_ext.rb @@ -17,6 +17,15 @@ require "rubygems/source" require_relative "match_platform" +# Cherry-pick fixes to `Gem.ruby_version` to be useful for modern Bundler +# versions and ignore patchlevels +# (https://github.com/rubygems/rubygems/pull/5472, +# https://github.com/rubygems/rubygems/pull/5486). May be removed once RubyGems +# 3.3.12 support is dropped. +unless Gem.ruby_version.to_s == RUBY_VERSION || RUBY_PATCHLEVEL == -1 + Gem.instance_variable_set(:@ruby_version, Gem::Version.new(RUBY_VERSION)) +end + module Gem class Specification include ::Bundler::MatchPlatform @@ -146,6 +155,10 @@ module Gem alias_method :eql?, :== + def force_ruby_platform + false + end + def encode_with(coder) to_yaml_properties.each do |ivar| coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar) diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb index 185fe70824..23531b8bd4 100644 --- a/lib/bundler/source/metadata.rb +++ b/lib/bundler/source/metadata.rb @@ -5,7 +5,7 @@ module Bundler class Metadata < Source def specs @specs ||= Index.build do |idx| - idx << Gem::Specification.new("Ruby\0", RubyVersion.system.gem_version) + idx << Gem::Specification.new("Ruby\0", Gem.ruby_version) idx << Gem::Specification.new("RubyGems\0", Gem::VERSION) do |s| s.required_rubygems_version = Gem::Requirement.default end diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index a4773397c7..6ea2910d18 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -101,6 +101,10 @@ module Bundler source_list_for(source).find {|s| equivalent_source?(source, s) } end + def get_with_fallback(source) + get(source) || default_source + end + def lock_sources lock_other_sources + lock_rubygems_sources end diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index a7a95e49bc..14733269d6 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -13,14 +13,16 @@ module Bundler def for(dependencies, check = false, platforms = [nil]) handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h - deps = dependencies.product(platforms).map {|dep, platform| [dep.name, platform && dep.force_ruby_platform ? Gem::Platform::RUBY : platform] } + deps = dependencies.product(platforms) specs = [] loop do break unless dep = deps.shift - next if handled.key?(dep) - handled[dep] = true + key = [dep[0].name, dep[1]] + next if handled.key?(key) + + handled[key] = true specs_for_dep = specs_for_dependency(*dep) if specs_for_dep.any? @@ -28,17 +30,13 @@ module Bundler specs_for_dep.first.dependencies.each do |d| next if d.type == :development - deps << [d.name, dep[1]] + deps << [d, dep[1]] end elsif check - specs << IncompleteSpecification.new(*dep) + specs << IncompleteSpecification.new(*key) end end - if spec = lookup["bundler"].first - specs << spec - end - specs end @@ -66,13 +64,8 @@ module Bundler end def materialize(deps) - materialized = self.for(deps, true).uniq + materialized = self.for(deps, true) - materialized.map! do |s| - next s unless s.is_a?(LazySpecification) - s.source.local! - s.materialize_for_installation || s - end SpecSet.new(materialized) end @@ -82,7 +75,6 @@ module Bundler def materialized_for_all_platforms @specs.map do |s| next s unless s.is_a?(LazySpecification) - s.source.local! s.source.remote! spec = s.materialize_for_installation raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec @@ -90,13 +82,8 @@ module Bundler end end - def materialized_for_resolution - materialized = @specs.map do |s| - spec = s.materialize_for_resolution - yield spec if spec - spec - end.compact - SpecSet.new(materialized) + def incomplete_ruby_specs?(deps) + self.class.new(self.for(deps, true, [Gem::Platform::RUBY])).incomplete_specs.any? end def missing_specs @@ -181,13 +168,13 @@ module Bundler @specs.sort_by(&:name).each {|s| yield s } end - def specs_for_dependency(name, platform) - specs_for_name = lookup[name] + def specs_for_dependency(dep, platform) + specs_for_name = lookup[dep.name] if platform.nil? - GemHelpers.select_best_platform_match(specs_for_name.select {|s| Gem::Platform.match_spec?(s) }, Bundler.local_platform) + matching_specs = specs_for_name.map {|s| s.materialize_for_installation if Gem::Platform.match_spec?(s) }.compact + GemHelpers.sort_best_platform_match(matching_specs, Bundler.local_platform) else - specs_for_name_and_platform = GemHelpers.select_best_platform_match(specs_for_name, platform) - specs_for_name_and_platform.any? ? specs_for_name_and_platform : specs_for_name + GemHelpers.select_best_platform_match(specs_for_name, dep.force_ruby_platform ? Gem::Platform::RUBY : platform) end end diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index f01d90b943..f15165f86d 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.3.19".freeze + VERSION = "2.3.20".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i |