diff options
| author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2023-03-28 20:36:47 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-28 11:36:47 +0000 |
| commit | c3c461c4ff1b998ac49ed1a3ad411d2f0a9123b8 (patch) | |
| tree | 70c8438d980e19d718dc50e04b6221b023e26387 /lib | |
| parent | f8c775cb413724a45bb5641de94f4f9210044116 (diff) | |
Merge RubyGems-3.4.10 and Bundler-2.4.10 (#7479)
* Merge RubyGems-3.4.7 and Bundler-2.4.7
* Merge RubyGems-3.4.8 and Bundler-2.4.8
* Skip failing test on MSWin
* Merge RubyGems-3.4.9 and Bundler-2.4.9
* Merge RubyGems-3.4.10 and Bundler-2.4.10
---------
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Diffstat (limited to 'lib')
103 files changed, 672 insertions, 233 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb index c6a225977f..88f25b523a 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -39,8 +39,8 @@ module Bundler environment_preserver.replace_with_backup SUDO_MUTEX = Thread::Mutex.new - SAFE_MARSHAL_CLASSES = [Symbol, TrueClass, String, Array, Hash].freeze - SAFE_MARSHAL_ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed.".freeze + SAFE_MARSHAL_CLASSES = [Symbol, TrueClass, String, Array, Hash, Gem::Version, Gem::Specification].freeze + SAFE_MARSHAL_ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed." SAFE_MARSHAL_PROC = proc do |object| object.tap do unless SAFE_MARSHAL_CLASSES.include?(object.class) @@ -85,6 +85,7 @@ module Bundler autoload :StubSpecification, File.expand_path("bundler/stub_specification", __dir__) autoload :UI, File.expand_path("bundler/ui", __dir__) autoload :URICredentialsFilter, File.expand_path("bundler/uri_credentials_filter", __dir__) + autoload :URINormalizer, File.expand_path("bundler/uri_normalizer", __dir__) class << self def configure @@ -506,7 +507,7 @@ EOF if File.file?(executable) && File.executable?(executable) executable elsif paths = ENV["PATH"] - quote = '"'.freeze + quote = '"' paths.split(File::PATH_SEPARATOR).find do |path| path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote) executable_path = File.expand_path(executable, path) @@ -525,12 +526,6 @@ EOF load_marshal(data, :marshal_proc => SAFE_MARSHAL_PROC) end - def load_marshal(data, marshal_proc: nil) - Marshal.load(data, marshal_proc) - rescue TypeError => e - raise MarshalError, "#{e.class}: #{e.message}" - end - def load_gemspec(file, validate = false) @gemspec_cache ||= {} key = File.expand_path(file) @@ -619,6 +614,12 @@ EOF private + def load_marshal(data, marshal_proc: nil) + Marshal.load(data, marshal_proc) + rescue TypeError => e + raise MarshalError, "#{e.class}: #{e.message}" + end + def eval_yaml_gemspec(path, contents) Kernel.require "psych" diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index ee73bdb506..a3eb494db2 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -156,6 +156,7 @@ module Bundler dependency listed in the gemspec file to the newly created Gemfile. D method_option "gemspec", :type => :string, :banner => "Use the specified .gemspec to create the Gemfile" + method_option "gemfile", :type => :string, :banner => "Use the specified name for the gemfile instead of 'Gemfile'" def init require_relative "cli/init" Init.new(options.dup).run diff --git a/lib/bundler/cli/init.rb b/lib/bundler/cli/init.rb index bc96507c29..246b9d6460 100644 --- a/lib/bundler/cli/init.rb +++ b/lib/bundler/cli/init.rb @@ -32,7 +32,7 @@ module Bundler file << spec.to_gemfile end else - File.open(File.expand_path("../templates/#{gemfile}", __dir__), "r") do |template| + File.open(File.expand_path("../templates/Gemfile", __dir__), "r") do |template| File.open(gemfile, "wb") do |destination| IO.copy_stream(template, destination) end @@ -45,7 +45,7 @@ module Bundler private def gemfile - @gemfile ||= Bundler.preferred_gemfile_name + @gemfile ||= options[:gemfile] || Bundler.preferred_gemfile_name end end end diff --git a/lib/bundler/current_ruby.rb b/lib/bundler/current_ruby.rb index f9987c4da8..f009b07ad7 100644 --- a/lib/bundler/current_ruby.rb +++ b/lib/bundler/current_ruby.rb @@ -22,6 +22,8 @@ module Bundler 2.7 3.0 3.1 + 3.2 + 3.3 ].freeze KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index e27374f35d..bef86cdd60 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -726,6 +726,8 @@ module Bundler dep.source = sources.get(dep.source) end + next if unlocking? + unless locked_dep = @locked_deps[dep.name] changes = true next @@ -886,8 +888,9 @@ module Bundler end def additional_base_requirements_for_resolve(resolution_packages, last_resolve) - return resolution_packages unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources) + return resolution_packages unless @locked_gems && !sources.expired_sources?(@locked_gems.sources) converge_specs(@originally_locked_specs - last_resolve).each do |locked_spec| + next if locked_spec.source.is_a?(Source::Path) resolution_packages.base_requirements[locked_spec.name] = Gem::Requirement.new(">= #{locked_spec.version}") end resolution_packages @@ -898,6 +901,7 @@ module Bundler Bundler.local_platform == Gem::Platform::RUBY || !platforms.include?(Gem::Platform::RUBY) || (@new_platform && platforms.last == Gem::Platform::RUBY) || + @dependency_changes || !@originally_locked_specs.incomplete_ruby_specs?(dependencies) remove_platform(Gem::Platform::RUBY) diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb index 1f8b9da2eb..5f17943629 100644 --- a/lib/bundler/dependency.rb +++ b/lib/bundler/dependency.rb @@ -9,7 +9,7 @@ module Bundler attr_reader :autorequire attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref - ALL_RUBY_VERSIONS = ((18..27).to_a + (30..31).to_a).freeze + ALL_RUBY_VERSIONS = ((18..27).to_a + (30..33).to_a).freeze PLATFORM_MAP = { :ruby => [Gem::Platform::RUBY, ALL_RUBY_VERSIONS], :mri => [Gem::Platform::RUBY, ALL_RUBY_VERSIONS], diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb index d315d1cc68..863544b1f9 100644 --- a/lib/bundler/endpoint_specification.rb +++ b/lib/bundler/endpoint_specification.rb @@ -26,10 +26,6 @@ module Bundler @platform end - def identifier - @__identifier ||= [name, version, platform.to_s] - end - # needed for standalone, load required_paths from local gemspec # after the gem is installed def require_paths diff --git a/lib/bundler/environment_preserver.rb b/lib/bundler/environment_preserver.rb index 70967522af..57013f5d50 100644 --- a/lib/bundler/environment_preserver.rb +++ b/lib/bundler/environment_preserver.rb @@ -2,7 +2,7 @@ module Bundler class EnvironmentPreserver - INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL".freeze + INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL" BUNDLER_KEYS = %w[ BUNDLE_BIN_PATH BUNDLE_GEMFILE @@ -16,7 +16,7 @@ module Bundler RUBYLIB RUBYOPT ].map(&:freeze).freeze - BUNDLER_PREFIX = "BUNDLER_ORIG_".freeze + BUNDLER_PREFIX = "BUNDLER_ORIG_" def self.from_env new(env_to_hash(ENV), BUNDLER_KEYS) diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb index a073bae278..e12c15af8a 100644 --- a/lib/bundler/fetcher.rb +++ b/lib/bundler/fetcher.rb @@ -102,11 +102,11 @@ module Bundler uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") if uri.scheme == "file" path = Bundler.rubygems.correct_for_windows_path(uri.path) - Bundler.load_marshal Bundler.rubygems.inflate(Gem.read_binary(path)) + Bundler.safe_load_marshal Bundler.rubygems.inflate(Gem.read_binary(path)) elsif cached_spec_path = gemspec_cached_path(spec_file_name) Bundler.load_gemspec(cached_spec_path) else - Bundler.load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) + Bundler.safe_load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) end rescue MarshalError raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ diff --git a/lib/bundler/fetcher/dependency.rb b/lib/bundler/fetcher/dependency.rb index 332f86139d..18b606abb6 100644 --- a/lib/bundler/fetcher/dependency.rb +++ b/lib/bundler/fetcher/dependency.rb @@ -34,14 +34,10 @@ module Bundler returned_gems = spec_list.map(&:first).uniq specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list) - rescue MarshalError + rescue MarshalError, HTTPError, GemspecError Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over Bundler.ui.debug "could not fetch from the dependency API, trying the full index" nil - rescue HTTPError, GemspecError - Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over - Bundler.ui.debug "could not fetch from the dependency API\nit's suggested to retry using the full index via `bundle install --full-index`" - nil end def dependency_specs(gem_names) diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index 0301986ca9..b8c599f63a 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -13,8 +13,8 @@ module Bundler attr_reader :specs, :all_specs, :sources protected :specs, :all_specs - RUBY = "ruby".freeze - NULL = "\0".freeze + RUBY = "ruby" + NULL = "\0" def initialize @sources = [] diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb index c2edc9b43a..cb644a7f69 100644 --- a/lib/bundler/injector.rb +++ b/lib/bundler/injector.rb @@ -2,7 +2,7 @@ module Bundler class Injector - INJECTED_GEMS = "injected gems".freeze + INJECTED_GEMS = "injected gems" def self.inject(new_deps, options = {}) injector = new(new_deps, options) diff --git a/lib/bundler/installer/parallel_installer.rb b/lib/bundler/installer/parallel_installer.rb index dce7133769..58c5aafa1c 100644 --- a/lib/bundler/installer/parallel_installer.rb +++ b/lib/bundler/installer/parallel_installer.rb @@ -110,12 +110,13 @@ module Bundler warning = [] warning << "Your lockfile doesn't include a valid resolution." - warning << "You can fix this by regenerating your lockfile or trying to manually editing the bad locked gems to a version that satisfies all dependencies." + warning << "You can fix this by regenerating your lockfile or manually editing the bad locked gems to a version that satisfies all dependencies." warning << "The unmet dependencies are:" unmet_dependencies.each do |spec, unmet_spec_dependencies| unmet_spec_dependencies.each do |unmet_spec_dependency| - warning << "* #{unmet_spec_dependency}, depended upon #{spec.full_name}, unsatisfied by #{@specs.find {|s| s.name == unmet_spec_dependency.name && !unmet_spec_dependency.matches_spec?(s.spec) }.full_name}" + found = @specs.find {|s| s.name == unmet_spec_dependency.name && !unmet_spec_dependency.matches_spec?(s.spec) } + warning << "* #{unmet_spec_dependency}, dependency of #{spec.full_name}, unsatisfied by #{found.full_name}" end end diff --git a/lib/bundler/installer/standalone.rb b/lib/bundler/installer/standalone.rb index 2efef61648..2a8c9a432d 100644 --- a/lib/bundler/installer/standalone.rb +++ b/lib/bundler/installer/standalone.rb @@ -52,7 +52,7 @@ module Bundler def gem_path(path, spec) full_path = Pathname.new(path).absolute? ? path : File.join(spec.full_gem_path, path) - if spec.source.instance_of?(Source::Path) + if spec.source.instance_of?(Source::Path) && spec.source.path.absolute? full_path else Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path)).to_s diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index 6749892930..ad8191c55f 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -20,7 +20,7 @@ module Bundler end def full_name - if platform == Gem::Platform::RUBY + @full_name ||= if platform == Gem::Platform::RUBY "#{@name}-#{@version}" else "#{@name}-#{@version}-#{platform}" @@ -28,15 +28,15 @@ module Bundler end def ==(other) - identifier == other.identifier + full_name == other.full_name end def eql?(other) - identifier.eql?(other.identifier) + full_name.eql?(other.full_name) end def hash - identifier.hash + full_name.hash end ## @@ -129,10 +129,6 @@ module Bundler end end - def identifier - @__identifier ||= [name, version, platform.to_s] - end - def git_version return unless source.is_a?(Bundler::Source::Git) " #{source.revision[0..6]}" diff --git a/lib/bundler/lockfile_generator.rb b/lib/bundler/lockfile_generator.rb index 23413dbdd6..a7ee026f67 100644 --- a/lib/bundler/lockfile_generator.rb +++ b/lib/bundler/lockfile_generator.rb @@ -45,7 +45,7 @@ module Bundler # gems with the same name, but different platform # are ordered consistently specs.sort_by(&:full_name).each do |spec| - next if spec.name == "bundler".freeze + next if spec.name == "bundler" out << spec.to_lock end end diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb index 0ec5b7de8a..97cbf211ba 100644 --- a/lib/bundler/lockfile_parser.rb +++ b/lib/bundler/lockfile_parser.rb @@ -4,15 +4,15 @@ module Bundler class LockfileParser attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version - BUNDLED = "BUNDLED WITH".freeze - DEPENDENCIES = "DEPENDENCIES".freeze - PLATFORMS = "PLATFORMS".freeze - RUBY = "RUBY VERSION".freeze - GIT = "GIT".freeze - GEM = "GEM".freeze - PATH = "PATH".freeze - PLUGIN = "PLUGIN SOURCE".freeze - SPECS = " specs:".freeze + BUNDLED = "BUNDLED WITH" + DEPENDENCIES = "DEPENDENCIES" + PLATFORMS = "PLATFORMS" + RUBY = "RUBY VERSION" + GIT = "GIT" + GEM = "GEM" + PATH = "PATH" + PLUGIN = "PLUGIN SOURCE" + SPECS = " specs:" OPTIONS = /^ ([a-z]+): (.*)$/i.freeze SOURCE = [GIT, GEM, PATH, PLUGIN].freeze @@ -86,7 +86,7 @@ module Bundler send("parse_#{@state}", line) end end - @specs = @specs.values.sort_by(&:identifier) + @specs = @specs.values.sort_by(&:full_name) rescue ArgumentError => e Bundler.ui.debug(e) raise LockfileError, "Your lockfile is unreadable. Run `rm #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` " \ @@ -199,7 +199,7 @@ module Bundler @current_spec.source = @current_source @current_source.add_dependency_names(name) - @specs[@current_spec.identifier] = @current_spec + @specs[@current_spec.full_name] = @current_spec elsif spaces.size == 6 version = version.split(",").map(&:strip) if version dep = Gem::Dependency.new(name, version) diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1 index 805bd5450d..0e21c75506 100644 --- a/lib/bundler/man/bundle-add.1 +++ b/lib/bundler/man/bundle-add.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-ADD" "1" "January 2023" "" "" +.TH "BUNDLE\-ADD" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1 index f5efe77e10..2774e9d28a 100644 --- a/lib/bundler/man/bundle-binstubs.1 +++ b/lib/bundler/man/bundle-binstubs.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-BINSTUBS" "1" "January 2023" "" "" +.TH "BUNDLE\-BINSTUBS" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1 index a17f1a6b06..f24b63c6fc 100644 --- a/lib/bundler/man/bundle-cache.1 +++ b/lib/bundler/man/bundle-cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CACHE" "1" "January 2023" "" "" +.TH "BUNDLE\-CACHE" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1 index f1bf0b1821..7679945c48 100644 --- a/lib/bundler/man/bundle-check.1 +++ b/lib/bundler/man/bundle-check.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CHECK" "1" "January 2023" "" "" +.TH "BUNDLE\-CHECK" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1 index b05a8eb0eb..2eb745698c 100644 --- a/lib/bundler/man/bundle-clean.1 +++ b/lib/bundler/man/bundle-clean.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CLEAN" "1" "January 2023" "" "" +.TH "BUNDLE\-CLEAN" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index fdb06c321d..493b57e1de 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CONFIG" "1" "January 2023" "" "" +.TH "BUNDLE\-CONFIG" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options diff --git a/lib/bundler/man/bundle-console.1 b/lib/bundler/man/bundle-console.1 index 6cb0f0f810..ff239004bf 100644 --- a/lib/bundler/man/bundle-console.1 +++ b/lib/bundler/man/bundle-console.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CONSOLE" "1" "January 2023" "" "" +.TH "BUNDLE\-CONSOLE" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-console\fR \- Deprecated way to open an IRB session with the bundle pre\-loaded diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1 index bfe928c9a1..e463b67477 100644 --- a/lib/bundler/man/bundle-doctor.1 +++ b/lib/bundler/man/bundle-doctor.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-DOCTOR" "1" "January 2023" "" "" +.TH "BUNDLE\-DOCTOR" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1 index 281f3faede..9e9efe8b6d 100644 --- a/lib/bundler/man/bundle-exec.1 +++ b/lib/bundler/man/bundle-exec.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-EXEC" "1" "January 2023" "" "" +.TH "BUNDLE\-EXEC" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index 4bac1bf442..ea64871fb6 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-GEM" "1" "January 2023" "" "" +.TH "BUNDLE\-GEM" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem diff --git a/lib/bundler/man/bundle-help.1 b/lib/bundler/man/bundle-help.1 index 47a42a497e..a3b059ea07 100644 --- a/lib/bundler/man/bundle-help.1 +++ b/lib/bundler/man/bundle-help.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-HELP" "1" "January 2023" "" "" +.TH "BUNDLE\-HELP" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-help\fR \- Displays detailed help for each subcommand diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1 index e9f5583e85..5af60c6a77 100644 --- a/lib/bundler/man/bundle-info.1 +++ b/lib/bundler/man/bundle-info.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INFO" "1" "January 2023" "" "" +.TH "BUNDLE\-INFO" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1 index 9e8b059f1f..e93b4fd5e9 100644 --- a/lib/bundler/man/bundle-init.1 +++ b/lib/bundler/man/bundle-init.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INIT" "1" "January 2023" "" "" +.TH "BUNDLE\-INIT" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory @@ -18,6 +18,10 @@ Init generates a default [\fBGemfile(5)\fR][Gemfile(5)] in the current working d \fB\-\-gemspec\fR Use the specified \.gemspec to create the [\fBGemfile(5)\fR][Gemfile(5)] . +.TP +\fB\-\-gemfile\fR +Use the specified name for the gemfile instead of \fBGemfile\fR +. .SH "FILES" Included in the default [\fBGemfile(5)\fR][Gemfile(5)] generated is the line \fB# frozen_string_literal: true\fR\. This is a magic comment supported for the first time in Ruby 2\.3\. The presence of this line results in all string literals in the file being implicitly frozen\. . diff --git a/lib/bundler/man/bundle-init.1.ronn b/lib/bundler/man/bundle-init.1.ronn index 9d3d97deea..7d3cede1f6 100644 --- a/lib/bundler/man/bundle-init.1.ronn +++ b/lib/bundler/man/bundle-init.1.ronn @@ -16,6 +16,8 @@ created [`Gemfile(5)`][Gemfile(5)]. * `--gemspec`: Use the specified .gemspec to create the [`Gemfile(5)`][Gemfile(5)] +* `--gemfile`: + Use the specified name for the gemfile instead of `Gemfile` ## FILES diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1 index 0b0766a40c..657d5ef4a7 100644 --- a/lib/bundler/man/bundle-inject.1 +++ b/lib/bundler/man/bundle-inject.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INJECT" "1" "January 2023" "" "" +.TH "BUNDLE\-INJECT" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1 index fcf6a6a66c..8f144692f3 100644 --- a/lib/bundler/man/bundle-install.1 +++ b/lib/bundler/man/bundle-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INSTALL" "1" "January 2023" "" "" +.TH "BUNDLE\-INSTALL" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1 index 37d2c837e4..f24f62dd38 100644 --- a/lib/bundler/man/bundle-list.1 +++ b/lib/bundler/man/bundle-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LIST" "1" "January 2023" "" "" +.TH "BUNDLE\-LIST" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1 index 422da46d00..55d1035d77 100644 --- a/lib/bundler/man/bundle-lock.1 +++ b/lib/bundler/man/bundle-lock.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LOCK" "1" "January 2023" "" "" +.TH "BUNDLE\-LOCK" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1 index c831bf9ce9..ff44d1224f 100644 --- a/lib/bundler/man/bundle-open.1 +++ b/lib/bundler/man/bundle-open.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OPEN" "1" "January 2023" "" "" +.TH "BUNDLE\-OPEN" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1 index 40fe8a4def..8455b71b45 100644 --- a/lib/bundler/man/bundle-outdated.1 +++ b/lib/bundler/man/bundle-outdated.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OUTDATED" "1" "January 2023" "" "" +.TH "BUNDLE\-OUTDATED" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1 index d0015a80ef..2794878719 100644 --- a/lib/bundler/man/bundle-platform.1 +++ b/lib/bundler/man/bundle-platform.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PLATFORM" "1" "January 2023" "" "" +.TH "BUNDLE\-PLATFORM" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information diff --git a/lib/bundler/man/bundle-plugin.1 b/lib/bundler/man/bundle-plugin.1 index a231bb1e3d..39d3dfa04e 100644 --- a/lib/bundler/man/bundle-plugin.1 +++ b/lib/bundler/man/bundle-plugin.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PLUGIN" "1" "January 2023" "" "" +.TH "BUNDLE\-PLUGIN" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-plugin\fR \- Manage Bundler plugins diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1 index 8f4bad3db6..f42c7ce156 100644 --- a/lib/bundler/man/bundle-pristine.1 +++ b/lib/bundler/man/bundle-pristine.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PRISTINE" "1" "January 2023" "" "" +.TH "BUNDLE\-PRISTINE" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1 index 97a65016ac..b18d80554d 100644 --- a/lib/bundler/man/bundle-remove.1 +++ b/lib/bundler/man/bundle-remove.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-REMOVE" "1" "January 2023" "" "" +.TH "BUNDLE\-REMOVE" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1 index 82706d45f3..efd9ccb0e0 100644 --- a/lib/bundler/man/bundle-show.1 +++ b/lib/bundler/man/bundle-show.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-SHOW" "1" "January 2023" "" "" +.TH "BUNDLE\-SHOW" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1 index 65448f4806..c67c44ff86 100644 --- a/lib/bundler/man/bundle-update.1 +++ b/lib/bundler/man/bundle-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-UPDATE" "1" "January 2023" "" "" +.TH "BUNDLE\-UPDATE" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions diff --git a/lib/bundler/man/bundle-version.1 b/lib/bundler/man/bundle-version.1 index bb03e8b5d6..9a3820f3e6 100644 --- a/lib/bundler/man/bundle-version.1 +++ b/lib/bundler/man/bundle-version.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-VERSION" "1" "January 2023" "" "" +.TH "BUNDLE\-VERSION" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-version\fR \- Prints Bundler version information diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1 index 23fb95b738..3a07010309 100644 --- a/lib/bundler/man/bundle-viz.1 +++ b/lib/bundler/man/bundle-viz.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-VIZ" "1" "January 2023" "" "" +.TH "BUNDLE\-VIZ" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1 index 39f3807f30..873ba566b1 100644 --- a/lib/bundler/man/bundle.1 +++ b/lib/bundler/man/bundle.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE" "1" "January 2023" "" "" +.TH "BUNDLE" "1" "February 2023" "" "" . .SH "NAME" \fBbundle\fR \- Ruby Dependency Management diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5 index 740a01e0cc..a9124d26ea 100644 --- a/lib/bundler/man/gemfile.5 +++ b/lib/bundler/man/gemfile.5 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GEMFILE" "5" "January 2023" "" "" +.TH "GEMFILE" "5" "February 2023" "" "" . .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb index 26458bd596..f3caff8963 100644 --- a/lib/bundler/plugin.rb +++ b/lib/bundler/plugin.rb @@ -15,7 +15,7 @@ module Bundler class UnknownSourceError < PluginError; end class PluginInstallError < PluginError; end - PLUGIN_FILE_NAME = "plugins.rb".freeze + PLUGIN_FILE_NAME = "plugins.rb" module_function diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb index 81ecafa470..c9ff12ce4b 100644 --- a/lib/bundler/plugin/installer.rb +++ b/lib/bundler/plugin/installer.rb @@ -83,8 +83,11 @@ module Bundler Bundler.configure_gem_home_and_path(Plugin.root) - definition = Definition.new(nil, deps, source_list, true) - install_definition(definition) + Bundler.settings.temporary(:deployment => false, :frozen => false) do + definition = Definition.new(nil, deps, source_list, true) + + install_definition(definition) + end end # Installs the plugins and deps from the provided specs and returns map of diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb index 34d7fd116c..f626a3218e 100644 --- a/lib/bundler/remote_specification.rb +++ b/lib/bundler/remote_specification.rb @@ -29,12 +29,8 @@ module Bundler @platform = _remote_specification.platform end - def identifier - @__identifier ||= [name, version, @platform.to_s] - end - def full_name - if @platform == Gem::Platform::RUBY + @full_name ||= if @platform == Gem::Platform::RUBY "#{@name}-#{@version}" else "#{@name}-#{@version}-#{@platform}" @@ -106,7 +102,7 @@ module Bundler def _remote_specification @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @original_platform]) @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \ - " missing from the server! Try installing with `--full-index` as a workaround.") + " missing from the server!") end def method_missing(method, *args, &blk) diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 8237ff53fe..c8cc88a3ee 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -37,7 +37,9 @@ module Bundler root_version = Resolver::Candidate.new(0) @all_specs = Hash.new do |specs, name| - specs[name] = source_for(name).specs.search(name).sort_by {|s| [s.version, s.platform.to_s] } + specs[name] = source_for(name).specs.search(name).reject do |s| + s.dependencies.any? {|d| d.name == name && !d.requirement.satisfied_by?(s.version) } # ignore versions that depend on themselves incorrectly + end.sort_by {|s| [s.version, s.platform.to_s] } end @sorted_versions = Hash.new do |candidates, package| @@ -55,7 +57,7 @@ module Bundler { root_version => root_dependencies } else Hash.new do |versions, version| - versions[version] = to_dependency_hash(version.dependencies, @packages) + versions[version] = to_dependency_hash(version.dependencies.reject {|d| d.name == package.name }, @packages) end end end @@ -186,11 +188,6 @@ module Bundler package_deps = @cached_dependencies[package] sorted_versions = @sorted_versions[package] package_deps[version].map do |dep_package, dep_constraint| - if package == dep_package - cause = PubGrub::Incompatibility::CircularDependency.new(dep_package, dep_constraint.constraint_string) - return [PubGrub::Incompatibility.new([PubGrub::Term.new(dep_constraint, true)], :cause => cause)] - end - low = high = sorted_versions.index(version) # find version low such that all >= low share the same dep @@ -243,7 +240,7 @@ module Bundler ruby_specs = select_best_platform_match(specs, Gem::Platform::RUBY) groups << Resolver::Candidate.new(version, :specs => ruby_specs) if ruby_specs.any? - next groups if platform_specs == ruby_specs + next groups if platform_specs == ruby_specs || package.force_ruby_platform? groups << Resolver::Candidate.new(version, :specs => platform_specs) @@ -302,7 +299,7 @@ module Bundler end def filter_prereleases(specs, package) - return specs unless package.ignores_prereleases? + return specs unless package.ignores_prereleases? && specs.size > 1 specs.reject {|s| s.version.prerelease? } end diff --git a/lib/bundler/resolver/base.rb b/lib/bundler/resolver/base.rb index 6921c047a7..c6afa82056 100644 --- a/lib/bundler/resolver/base.rb +++ b/lib/bundler/resolver/base.rb @@ -49,10 +49,18 @@ module Bundler end def unlock_names(names) - names.each do |name| - @base.delete_by_name(name) - - @base_requirements.delete(name) + indirect_pins = indirect_pins(names) + + if indirect_pins.any? + loosen_names(indirect_pins) + else + pins = pins(names) + + if pins.any? + loosen_names(pins) + else + unrestrict_names(names) + end end end @@ -64,6 +72,30 @@ module Bundler private + def indirect_pins(names) + names.select {|name| @base_requirements[name].exact? && @requirements.none? {|dep| dep.name == name } } + end + + def pins(names) + names.select {|name| @base_requirements[name].exact? } + end + + def loosen_names(names) + names.each do |name| + version = @base_requirements[name].requirements.first[1] + + @base_requirements[name] = Gem::Requirement.new(">= #{version}") + + @base.delete_by_name(name) + end + end + + def unrestrict_names(names) + names.each do |name| + @base_requirements.delete(name) + end + end + def build_base_requirements base_requirements = {} @base.each do |ls| diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb index 3857948511..72016e848b 100644 --- a/lib/bundler/rubygems_integration.rb +++ b/lib/bundler/rubygems_integration.rb @@ -453,7 +453,7 @@ module Bundler fetcher = gem_remote_fetcher fetcher.headers = { "X-Gemfile-Source" => remote.original_uri.to_s } if remote.original_uri string = fetcher.fetch_path(path) - Bundler.load_marshal(string) + Bundler.safe_load_marshal(string) rescue Gem::RemoteFetcher::FetchError # it's okay for prerelease to fail raise unless name == "prerelease_specs" diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index a76a792743..1139eab503 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -495,7 +495,7 @@ module Bundler uri = $2 suffix = $3 end - uri = "#{uri}/" unless uri.end_with?("/") + uri = URINormalizer.normalize_suffix(uri) require_relative "vendored_uri" uri = Bundler::URI(uri) unless uri.absolute? diff --git a/lib/bundler/setup.rb b/lib/bundler/setup.rb index 32e9b2d7c0..801fd5312a 100644 --- a/lib/bundler/setup.rb +++ b/lib/bundler/setup.rb @@ -12,7 +12,10 @@ if Bundler::SharedHelpers.in_bundle? Bundler.ui.error e.message Bundler.ui.warn e.backtrace.join("\n") if ENV["DEBUG"] if e.is_a?(Bundler::GemNotFound) - Bundler.ui.warn "Run `bundle install` to install missing gems." + suggested_cmd = "bundle install" + original_gemfile = Bundler.original_env["BUNDLE_GEMFILE"] + suggested_cmd += " --gemfile #{original_gemfile}" if original_gemfile + Bundler.ui.warn "Run `#{suggested_cmd}` to install missing gems." end exit e.status_code end diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index 794a03e62d..d1d4e1d07a 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -160,7 +160,7 @@ module Bundler " (was expecting #{old_deps.map(&:to_s)}, but the real spec has #{new_deps.map(&:to_s)})" raise APIResponseMismatchError, "Downloading #{spec.full_name} revealed dependencies not in the API or the lockfile (#{extra_deps.join(", ")})." \ - "\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem." + "\nRunning `bundle update #{spec.name}` should fix the problem." end def pretty_dependency(dep) diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb index b8ee4029b4..42897813b4 100644 --- a/lib/bundler/source/git.rb +++ b/lib/bundler/source/git.rb @@ -19,7 +19,7 @@ module Bundler # Stringify options that could be set as symbols %w[ref branch tag revision].each {|k| options[k] = options[k].to_s if options[k] } - @uri = options["uri"] || "" + @uri = URINormalizer.normalize_suffix(options["uri"] || "", :trailing_slash => false) @safe_uri = URICredentialsFilter.credential_filtered_uri(@uri) @branch = options["branch"] @ref = options["ref"] || options["branch"] || options["tag"] @@ -173,6 +173,7 @@ module Bundler end def install(spec, options = {}) + return if Bundler.settings[:no_install] force = options[:force] print_using_message "Using #{version_message(spec, options[:previous_spec])} from #{self}" diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb index 2a7c8473f5..926c9b8ead 100644 --- a/lib/bundler/source/git/git_proxy.rb +++ b/lib/bundler/source/git/git_proxy.rb @@ -28,8 +28,9 @@ module Bundler def initialize(command, path, extra_info = nil) @command = command - msg = String.new - msg << "Git error: command `#{command}` in directory #{path} has failed." + msg = String.new("Git error: command `#{command}`") + msg << " in directory #{path}" if path + msg << " has failed." msg << "\n#{extra_info}" if extra_info super msg end @@ -139,8 +140,8 @@ module Bundler out, err, status = capture(command, path) return out if status.success? - if err.include?("couldn't find remote ref") - raise MissingGitRevisionError.new(command_with_no_credentials, path, explicit_ref, credential_filtered_uri) + if err.include?("couldn't find remote ref") || err.include?("not our ref") + raise MissingGitRevisionError.new(command_with_no_credentials, path, commit || explicit_ref, credential_filtered_uri) else raise GitCommandError.new(command_with_no_credentials, path, err) end @@ -153,9 +154,20 @@ module Bundler SharedHelpers.filesystem_access(path.dirname) do |p| FileUtils.mkdir_p(p) end - git_retry "clone", "--bare", "--no-hardlinks", "--quiet", *extra_clone_args, "--", configured_uri, path.to_s - extra_ref + command = ["clone", "--bare", "--no-hardlinks", "--quiet", *extra_clone_args, "--", configured_uri, path.to_s] + command_with_no_credentials = check_allowed(command) + + Bundler::Retry.new("`#{command_with_no_credentials}`", [MissingGitRevisionError]).attempts do + _, err, status = capture(command, nil) + return extra_ref if status.success? + + if err.include?("Could not find remote branch") + raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri) + else + raise GitCommandError.new(command_with_no_credentials, path, err) + end + end end def clone_needs_unshallow? @@ -186,8 +198,6 @@ module Bundler end def refspec - commit = pinned_to_full_sha? ? ref : @revision - if commit @commit_ref = "refs/#{commit}-sha" return "#{commit}:#{@commit_ref}" @@ -206,6 +216,10 @@ module Bundler "#{reference}:#{reference}" end + def commit + @commit ||= pinned_to_full_sha? ? ref : @revision + end + def fully_qualified_ref if branch "refs/heads/#{branch}" @@ -352,6 +366,11 @@ module Bundler args += ["--single-branch"] args.unshift("--no-tags") if supports_cloning_with_no_tags? + # If there's a locked revision, no need to clone any specific branch + # or tag, since we will end up checking out that locked revision + # anyways. + return args if @revision + args += ["--branch", branch || tag] if branch || tag args end diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb index 20975e20ca..bdfcf8274a 100644 --- a/lib/bundler/source/path.rb +++ b/lib/bundler/source/path.rb @@ -11,7 +11,7 @@ module Bundler protected :original_path - DEFAULT_GLOB = "{,*,*/*}.gemspec".freeze + DEFAULT_GLOB = "{,*,*/*}.gemspec" def initialize(options) @options = options.dup diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index c39071705a..8d0c78bd61 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -337,8 +337,7 @@ module Bundler end def normalize_uri(uri) - uri = uri.to_s - uri = "#{uri}/" unless %r{/$}.match?(uri) + uri = URINormalizer.normalize_suffix(uri.to_s) require_relative "../vendored_uri" uri = Bundler::URI(uri) raise ArgumentError, "The source must be an absolute URI. For example:\n" \ diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 7478bd9ca2..cf63c16a70 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -24,6 +24,7 @@ module Bundler name = dep[0].name platform = dep[1] + incomplete = false key = [name, platform] next if handled.key?(key) @@ -36,14 +37,19 @@ module Bundler specs_for_dep.first.dependencies.each do |d| next if d.type == :development + incomplete = true if d.name != "bundler" && lookup[d.name].empty? deps << [d, dep[1]] end - elsif check - @incomplete_specs += lookup[name] + else + incomplete = true + end + + if incomplete && check + @incomplete_specs += lookup[name].any? ? lookup[name] : [LazySpecification.new(name, nil, nil)] end end - specs + specs.uniq end def [](key) @@ -95,6 +101,10 @@ module Bundler end def incomplete_ruby_specs?(deps) + return false if @specs.empty? + + @incomplete_specs = [] + self.for(deps, true, [Gem::Platform::RUBY]) @incomplete_specs.any? diff --git a/lib/bundler/templates/Executable.bundler b/lib/bundler/templates/Executable.bundler index 6dab1688f7..e290fe91eb 100644 --- a/lib/bundler/templates/Executable.bundler +++ b/lib/bundler/templates/Executable.bundler @@ -47,7 +47,7 @@ m = Module.new do def lockfile lockfile = case File.basename(gemfile) - when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, ".locked") else "#{gemfile}.lock" end File.expand_path(lockfile) diff --git a/lib/bundler/templates/gems.rb b/lib/bundler/templates/gems.rb deleted file mode 100644 index d2403f18b2..0000000000 --- a/lib/bundler/templates/gems.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -source "https://rubygems.org" - -# gem "rails" diff --git a/lib/bundler/templates/newgem/Gemfile.tt b/lib/bundler/templates/newgem/Gemfile.tt index 41c95677a3..a0d2ac2826 100644 --- a/lib/bundler/templates/newgem/Gemfile.tt +++ b/lib/bundler/templates/newgem/Gemfile.tt @@ -10,7 +10,7 @@ gem "rake", "~> 13.0" gem "rake-compiler" <%- if config[:ext] == 'rust' -%> -gem "rb_sys" +gem "rb_sys", "~> 0.9.63" <%- end -%> <%- end -%> <%- if config[:test] -%> diff --git a/lib/bundler/templates/newgem/Rakefile.tt b/lib/bundler/templates/newgem/Rakefile.tt index ac14545126..b5a5c4e392 100644 --- a/lib/bundler/templates/newgem/Rakefile.tt +++ b/lib/bundler/templates/newgem/Rakefile.tt @@ -41,6 +41,15 @@ require "standard/rake" <% if config[:ext] -%> <% default_task_names.unshift(:compile) -%> <% default_task_names.unshift(:clobber) unless config[:ext] == 'rust' -%> +<% if config[:ext] == 'rust' -%> +require "rb_sys/extensiontask" + +task build: :compile + +RbSys::ExtensionTask.new(<%= config[:name].inspect %>) do |ext| + ext.lib_dir = "lib/<%= config[:namespaced_path] %>" +end +<% else -%> require "rake/extensiontask" task build: :compile @@ -48,6 +57,7 @@ task build: :compile Rake::ExtensionTask.new("<%= config[:underscored_name] %>") do |ext| ext.lib_dir = "lib/<%= config[:namespaced_path] %>" end +<% end -%> <% end -%> <% if default_task_names.size == 1 -%> diff --git a/lib/bundler/templates/newgem/github/workflows/main.yml.tt b/lib/bundler/templates/newgem/github/workflows/main.yml.tt index d4021980b4..be58dd8156 100644 --- a/lib/bundler/templates/newgem/github/workflows/main.yml.tt +++ b/lib/bundler/templates/newgem/github/workflows/main.yml.tt @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v3 <%- if config[:ext] == 'rust' -%> - name: Set up Ruby & Rust - uses: oxidize-rb/actions/setup-ruby-and-rust@main + uses: oxidize-rb/actions/setup-ruby-and-rust@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt index e35a121245..da81f046d4 100644 --- a/lib/bundler/templates/newgem/newgem.gemspec.tt +++ b/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -29,7 +29,7 @@ Gem::Specification.new do |spec| # The `git ls-files -z` loads the files in the RubyGem that have been added into git. spec.files = Dir.chdir(__dir__) do `git ls-files -z`.split("\x0").reject do |f| - (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)}) + (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor]) end end spec.bindir = "exe" diff --git a/lib/bundler/uri_normalizer.rb b/lib/bundler/uri_normalizer.rb new file mode 100644 index 0000000000..ad08593256 --- /dev/null +++ b/lib/bundler/uri_normalizer.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Bundler + module URINormalizer + module_function + + # Normalizes uri to a consistent version, either with or without trailing + # slash. + # + # TODO: Currently gem sources are locked with a trailing slash, while git + # sources are locked without a trailing slash. This should be normalized but + # the inconsistency is there for now to avoid changing all lockfiles + # including GIT sources. We could normalize this on the next major. + # + def normalize_suffix(uri, trailing_slash: true) + if trailing_slash + uri.end_with?("/") ? uri : "#{uri}/" + else + uri.end_with?("/") ? uri.delete_suffix("/") : uri + end + end + end +end diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb index dab58ecdf7..239eaf3401 100644 --- a/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb +++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb @@ -8,9 +8,6 @@ module Bundler::PubGrub InvalidDependency = Struct.new(:package, :constraint) do end - CircularDependency = Struct.new(:package, :constraint) do - end - NoVersions = Struct.new(:constraint) do end @@ -66,8 +63,6 @@ module Bundler::PubGrub "#{terms[0].to_s(allow_every: true)} depends on #{terms[1].invert}" when Bundler::PubGrub::Incompatibility::InvalidDependency "#{terms[0].to_s(allow_every: true)} depends on unknown package #{cause.package}" - when Bundler::PubGrub::Incompatibility::CircularDependency - "#{terms[0].to_s(allow_every: true)} depends on itself" when Bundler::PubGrub::Incompatibility::NoVersions "no versions satisfy #{cause.constraint}" when Bundler::PubGrub::Incompatibility::ConflictCause @@ -76,9 +71,13 @@ module Bundler::PubGrub elsif terms.length == 1 term = terms[0] if term.positive? - "#{terms[0].to_s(allow_every: true)} is forbidden" + if term.constraint.any? + "#{term.package} cannot be used" + else + "#{term.to_s(allow_every: true)} cannot be used" + end else - "#{terms[0].invert} is required" + "#{term.invert} is required" end else if terms.all?(&:positive?) diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb index e895812bed..4bf61461b2 100644 --- a/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb +++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb @@ -19,7 +19,14 @@ module Bundler::PubGrub version = Gem::Version.new(version) @packages[name] ||= {} raise ArgumentError, "#{name} #{version} declared twice" if @packages[name].key?(version) - @packages[name][version] = deps + @packages[name][version] = clean_deps(name, version, deps) + end + + private + + # Exclude redundant self-referencing dependencies + def clean_deps(name, version, deps) + deps.reject {|dep_name, req| name == dep_name && Bundler::PubGrub::RubyGems.parse_range(req).include?(version) } end end diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb index 9133332d01..b71f3eaf53 100644 --- a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb +++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb @@ -15,15 +15,16 @@ module Bundler::PubGrub package.hash ^ range.hash end + def ==(other) + package == other.package && + range == other.range + end + def eql?(other) package.eql?(other.package) && range.eql?(other.range) end - def ==(other) - package == other.package && range == other.range - end - class << self def exact(package, version) range = VersionRange.new(min: version, max: version, include_min: true, include_max: true) diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb index 506b447b36..8d73c3f7b5 100644 --- a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb +++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb @@ -19,7 +19,7 @@ module Bundler::PubGrub true end - def eql? + def eql?(other) other.empty? end @@ -65,6 +65,7 @@ module Bundler::PubGrub end EMPTY = Empty.new + Empty.singleton_class.undef_method(:new) def self.empty EMPTY @@ -88,7 +89,8 @@ module Bundler::PubGrub def eql?(other) if other.is_a?(VersionRange) - min.eql?(other.min) && + !other.empty? && + min.eql?(other.min) && max.eql?(other.max) && include_min.eql?(other.include_min) && include_max.eql?(other.include_max) diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb index ea5e455968..2cb8412cf3 100644 --- a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb +++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb @@ -125,6 +125,7 @@ module Bundler::PubGrub package = next_package_to_try unsatisfied_term = solution.unsatisfied.find { |t| t.package == package } version = source.versions_for(package, unsatisfied_term.constraint.range).first + logger.debug { "attempting #{package} #{version}" } if version.nil? add_incompatibility source.no_versions_incompatibility_for(package, unsatisfied_term) @@ -148,9 +149,11 @@ module Bundler::PubGrub end unless conflict - logger.info { "selecting #{package} #{version}" } + logger.info { "selected #{package} #{version}" } solution.decide(package, version) + else + logger.info { "conflict: #{conflict.inspect}" } end package diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index d3bd162e48..bc9f8d22cd 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.4.6".freeze + VERSION = "2.4.10".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 26b0b1da7e..ef5f079a80 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require "rbconfig" module Gem - VERSION = "3.4.6".freeze + VERSION = "3.4.10" end # Must be first since it unloads the prelude from 1.9.2 @@ -824,7 +824,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} def self.env_requirement(gem_name) @env_requirements_by_name ||= {} @env_requirements_by_name[gem_name] ||= begin - req = ENV["GEM_REQUIREMENT_#{gem_name.upcase}"] || ">= 0".freeze + req = ENV["GEM_REQUIREMENT_#{gem_name.upcase}"] || ">= 0" Gem::Requirement.create(req) end end @@ -1301,7 +1301,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} ## # Location of Marshal quick gemspecs on remote repositories - MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/".freeze + MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/" autoload :ConfigFile, File.expand_path("rubygems/config_file", __dir__) autoload :Dependency, File.expand_path("rubygems/dependency", __dir__) diff --git a/lib/rubygems/bundler_version_finder.rb b/lib/rubygems/bundler_version_finder.rb index f6fad0bd83..2cbc4ff624 100644 --- a/lib/rubygems/bundler_version_finder.rb +++ b/lib/rubygems/bundler_version_finder.rb @@ -21,7 +21,7 @@ module Gem::BundlerVersionFinder end def self.bundle_update_bundler_version - return unless File.basename($0) == "bundle".freeze + return unless File.basename($0) == "bundle" return unless "update".start_with?(ARGV.first || " ") bundler_version = nil update_index = nil diff --git a/lib/rubygems/command.rb b/lib/rubygems/command.rb index f4688d793b..1e15f612de 100644 --- a/lib/rubygems/command.rb +++ b/lib/rubygems/command.rb @@ -201,11 +201,15 @@ class Gem::Command # respectively. def get_all_gem_names_and_versions get_all_gem_names.map do |name| - if /\A(.*):(#{Gem::Requirement::PATTERN_RAW})\z/ =~ name - [$1, $2] - else - [name] - end + extract_gem_name_and_version(name) + end + end + + def extract_gem_name_and_version(name) # :nodoc: + if /\A(.*):(#{Gem::Requirement::PATTERN_RAW})\z/ =~ name + [$1, $2] + else + [name] end end @@ -624,7 +628,7 @@ class Gem::Command # :stopdoc: - HELP = <<-HELP.freeze + HELP = <<-HELP RubyGems is a package manager for Ruby. Usage: diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb index 1bdbd50530..0a4b53abe5 100644 --- a/lib/rubygems/command_manager.rb +++ b/lib/rubygems/command_manager.rb @@ -43,6 +43,7 @@ class Gem::CommandManager :contents, :dependency, :environment, + :exec, :fetch, :generate_index, :help, diff --git a/lib/rubygems/commands/exec_command.rb b/lib/rubygems/commands/exec_command.rb new file mode 100644 index 0000000000..1d7e836ed0 --- /dev/null +++ b/lib/rubygems/commands/exec_command.rb @@ -0,0 +1,248 @@ +# frozen_string_literal: true +require_relative "../command" +require_relative "../dependency_installer" +require_relative "../gem_runner" +require_relative "../package" +require_relative "../version_option" + +class Gem::Commands::ExecCommand < Gem::Command + include Gem::VersionOption + + def initialize + super "exec", "Run a command from a gem", { + version: Gem::Requirement.default, + } + + add_version_option + add_prerelease_option "to be installed" + + add_option "-g", "--gem GEM", "run the executable from the given gem" do |value, options| + options[:gem_name] = value + end + + add_option(:"Install/Update", "--conservative", + "Prefer the most recent installed version, ", + "rather than the latest version overall") do |value, options| + options[:conservative] = true + end + end + + def arguments # :nodoc: + "COMMAND the executable command to run" + end + + def defaults_str # :nodoc: + "--version '#{Gem::Requirement.default}'" + end + + def description # :nodoc: + <<-EOF +The exec command handles installing (if necessary) and running an executable +from a gem, regardless of whether that gem is currently installed. + +The exec command can be thought of as a shortcut to running `gem install` and +then the executable from the installed gem. + +For example, `gem exec rails new .` will run `rails new .` in the current +directory, without having to manually run `gem install rails`. +Additionally, the exec command ensures the most recent version of the gem +is used (unless run with `--conservative`), and that the gem is not installed +to the same gem path as user-installed gems. + EOF + end + + def usage # :nodoc: + "#{program_name} [options --] COMMAND [args]" + end + + def execute + gem_paths = { "GEM_HOME" => Gem.paths.home, "GEM_PATH" => Gem.paths.path.join(File::PATH_SEPARATOR), "GEM_SPEC_CACHE" => Gem.paths.spec_cache_dir }.compact + + check_executable + + print_command + if options[:gem_name] == "gem" && options[:executable] == "gem" + set_gem_exec_install_paths + Gem::GemRunner.new.run options[:args] + return + elsif options[:conservative] + install_if_needed + else + install + activate! + end + + load! + ensure + ENV.update(gem_paths) if gem_paths + Gem.clear_paths + end + + private + + def handle_options(args) + args = add_extra_args(args) + check_deprecated_options(args) + @options = Marshal.load Marshal.dump @defaults # deep copy + parser.order!(args) do |v| + # put the non-option back at the front of the list of arguments + args.unshift(v) + + # stop parsing once we hit the first non-option, + # so you can call `gem exec rails --version` and it prints the rails + # version rather than rubygem's + break + end + @options[:args] = args + + options[:executable], gem_version = extract_gem_name_and_version(options[:args].shift) + options[:gem_name] ||= options[:executable] + + if gem_version + if options[:version].none? + options[:version] = Gem::Requirement.new(gem_version) + else + options[:version].concat [gem_version] + end + end + + if options[:prerelease] && !options[:version].prerelease? + if options[:version].none? + options[:version] = Gem::Requirement.default_prerelease + else + options[:version].concat [Gem::Requirement.default_prerelease] + end + end + end + + def check_executable + if options[:executable].nil? + raise Gem::CommandLineError, + "Please specify an executable to run (e.g. #{program_name} COMMAND)" + end + end + + def print_command + verbose "running #{program_name} with:\n" + opts = options.reject {|_, v| v.nil? || Array(v).empty? } + max_length = opts.map {|k, _| k.size }.max + opts.each do |k, v| + next if v.nil? + verbose "\t#{k.to_s.rjust(max_length)}: #{v}" + end + verbose "" + end + + def install_if_needed + activate! + rescue Gem::MissingSpecError + verbose "#{Gem::Dependency.new(options[:gem_name], options[:version])} not available locally, installing from remote" + install + activate! + end + + def set_gem_exec_install_paths + home = File.join(Gem.dir, "gem_exec") + + ENV["GEM_PATH"] = ([home] + Gem.path).join(File::PATH_SEPARATOR) + ENV["GEM_HOME"] = home + Gem.clear_paths + end + + def install + set_gem_exec_install_paths + + gem_name = options[:gem_name] + gem_version = options[:version] + + install_options = options.merge( + minimal_deps: false, + wrappers: true + ) + + suppress_always_install do + dep_installer = Gem::DependencyInstaller.new install_options + + request_set = dep_installer.resolve_dependencies gem_name, gem_version + + verbose "Gems to install:" + request_set.sorted_requests.each do |activation_request| + verbose "\t#{activation_request.full_name}" + end + + request_set.install install_options + end + + Gem::Specification.reset + rescue Gem::InstallError => e + alert_error "Error installing #{gem_name}:\n\t#{e.message}" + terminate_interaction 1 + rescue Gem::GemNotFoundException => e + show_lookup_failure e.name, e.version, e.errors, false + + terminate_interaction 2 + rescue Gem::UnsatisfiableDependencyError => e + show_lookup_failure e.name, e.version, e.errors, false, + "'#{gem_name}' (#{gem_version})" + + terminate_interaction 2 + end + + def activate! + gem(options[:gem_name], options[:version]) + Gem.finish_resolve + + verbose "activated #{options[:gem_name]} (#{Gem.loaded_specs[options[:gem_name]].version})" + end + + def load! + argv = ARGV.clone + ARGV.replace options[:args] + + exe = executable = options[:executable] + + contains_executable = Gem.loaded_specs.values.select do |spec| + spec.executables.include?(executable) + end + + if contains_executable.any? {|s| s.name == executable } + contains_executable.select! {|s| s.name == executable } + end + + if contains_executable.empty? + if (spec = Gem.loaded_specs[executable]) && (exe = spec.executable) + contains_executable << spec + else + alert_error "Failed to load executable `#{executable}`," \ + " are you sure the gem `#{options[:gem_name]}` contains it?" + terminate_interaction 1 + end + end + + if contains_executable.size > 1 + alert_error "Ambiguous which gem `#{executable}` should come from: " \ + "the options are #{contains_executable.map(&:name)}, " \ + "specify one via `-g`" + terminate_interaction 1 + end + + load Gem.activate_bin_path(contains_executable.first.name, exe, ">= 0.a") + ensure + ARGV.replace argv + end + + def suppress_always_install + name = :always_install + cls = ::Gem::Resolver::InstallerSet + method = cls.instance_method(name) + cls.remove_method(name) + cls.define_method(name) { [] } + + begin + yield + ensure + cls.remove_method(name) + cls.define_method(name, method) + end + end +end diff --git a/lib/rubygems/commands/help_command.rb b/lib/rubygems/commands/help_command.rb index 8bfb4458ff..bf4ffefbb7 100644 --- a/lib/rubygems/commands/help_command.rb +++ b/lib/rubygems/commands/help_command.rb @@ -3,7 +3,7 @@ require_relative "../command" class Gem::Commands::HelpCommand < Gem::Command # :stopdoc: - EXAMPLES = <<-EOF.freeze + EXAMPLES = <<-EOF Some examples of 'gem' usage. * Install 'rake', either from local directory or remote server: @@ -52,7 +52,7 @@ Some examples of 'gem' usage. gem update --system EOF - GEM_DEPENDENCIES = <<-EOF.freeze + GEM_DEPENDENCIES = <<-EOF A gem dependencies file allows installation of a consistent set of gems across multiple environments. The RubyGems implementation is designed to be compatible with Bundler's Gemfile format. You can see additional @@ -229,7 +229,7 @@ default. This may be overridden with the :development_group option: EOF - PLATFORMS = <<-'EOF'.freeze + PLATFORMS = <<-'EOF' RubyGems platforms are composed of three parts, a CPU, an OS, and a version. These values are taken from values in rbconfig.rb. You can view your current platform by running `gem environment`. diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb index 72db53ef37..d7c78ba13d 100644 --- a/lib/rubygems/commands/pristine_command.rb +++ b/lib/rubygems/commands/pristine_command.rb @@ -34,6 +34,11 @@ class Gem::Commands::PristineCommand < Gem::Command options[:extensions] = value end + add_option("--only-missing-extensions", + "Only restore gems with missing extensions") do |value, options| + options[:only_missing_extensions] = value + end + add_option("--only-executables", "Only restore executables") do |value, options| options[:only_executables] = value @@ -107,6 +112,10 @@ extensions will be restored. Gem::Specification.select do |spec| spec.extensions && !spec.extensions.empty? end + elsif options[:only_missing_extensions] + Gem::Specification.select do |spec| + spec.missing_extensions? + end else get_all_gem_names.sort.map do |gem_name| Gem::Specification.find_all_by_name(gem_name, options[:version]).reverse diff --git a/lib/rubygems/commands/uninstall_command.rb b/lib/rubygems/commands/uninstall_command.rb index 3c520826e5..29f6013c59 100644 --- a/lib/rubygems/commands/uninstall_command.rb +++ b/lib/rubygems/commands/uninstall_command.rb @@ -125,6 +125,9 @@ that is a dependency of an existing gem. You can use the def execute check_version + # Consider only gem specifications installed at `--install-dir` + Gem::Specification.dirs = options[:install_dir] if options[:install_dir] + if options[:all] && !options[:args].empty? uninstall_specific elsif options[:all] diff --git a/lib/rubygems/core_ext/kernel_require.rb b/lib/rubygems/core_ext/kernel_require.rb index 6dcc4a06e4..568ac347b4 100644 --- a/lib/rubygems/core_ext/kernel_require.rb +++ b/lib/rubygems/core_ext/kernel_require.rb @@ -37,9 +37,6 @@ module Kernel return gem_original_require(path) unless Gem.discover_gems_on_require begin - if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?) - monitor_owned = RUBYGEMS_ACTIVATION_MONITOR.mon_owned? - end RUBYGEMS_ACTIVATION_MONITOR.enter path = path.to_path if path.respond_to? :to_path @@ -163,13 +160,6 @@ module Kernel end raise load_error - ensure - if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?) - if monitor_owned != (ow = RUBYGEMS_ACTIVATION_MONITOR.mon_owned?) - STDERR.puts [$$, Thread.current, $!, $!.backtrace].inspect if $! - raise "CRITICAL: RUBYGEMS_ACTIVATION_MONITOR.owned?: before #{monitor_owned} -> after #{ow}" - end - end end end diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb index 8daff0bc30..b186375f69 100644 --- a/lib/rubygems/defaults.rb +++ b/lib/rubygems/defaults.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true module Gem - DEFAULT_HOST = "https://rubygems.org".freeze + DEFAULT_HOST = "https://rubygems.org" @post_install_hooks ||= [] @done_installing_hooks ||= [] @@ -158,7 +158,7 @@ module Gem # The path to standard location of the user's state directory. def self.state_home - @data_home ||= (ENV["XDG_STATE_HOME"] || File.join(Gem.user_home, ".local", "state")) + @state_home ||= (ENV["XDG_STATE_HOME"] || File.join(Gem.user_home, ".local", "state")) end ## diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb index 7fa0f91bd4..cd03e7e299 100644 --- a/lib/rubygems/dependency.rb +++ b/lib/rubygems/dependency.rb @@ -299,7 +299,7 @@ class Gem::Dependency end def prioritizes_bundler? - name == "bundler".freeze && !specific? + name == "bundler" && !specific? end def to_specs diff --git a/lib/rubygems/deprecate.rb b/lib/rubygems/deprecate.rb index 5fe0afb6b0..56505512c3 100644 --- a/lib/rubygems/deprecate.rb +++ b/lib/rubygems/deprecate.rb @@ -143,7 +143,7 @@ module Gem::Deprecate end # Deprecation method to deprecate Rubygems commands - def rubygems_deprecate_command + def rubygems_deprecate_command(version = Gem::Deprecate.next_rubygems_major_version) class_eval do define_method "deprecated?" do true @@ -151,7 +151,7 @@ module Gem::Deprecate define_method "deprecation_warning" do msg = [ "#{self.command} command is deprecated", - ". It will be removed in Rubygems #{Gem::Deprecate.next_rubygems_major_version}.\n", + ". It will be removed in Rubygems #{version}.\n", ] alert_warning "#{msg.join}" unless Gem::Deprecate.skip diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index 7fb8958d7f..43ea207b23 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -55,6 +55,23 @@ class Gem::Ext::Builder end end + def self.ruby + require "shellwords" + # Gem.ruby is quoted if it contains whitespace + cmd = Gem.ruby.shellsplit + + # This load_path is only needed when running rubygems test without a proper installation. + # Prepending it in a normal installation will cause problem with order of $LOAD_PATH. + # Therefore only add load_path if it is not present in the default $LOAD_PATH. + load_path = File.expand_path("../..", __dir__) + case load_path + when RbConfig::CONFIG["sitelibdir"], RbConfig::CONFIG["vendorlibdir"], RbConfig::CONFIG["rubylibdir"] + cmd + else + cmd << "-I#{load_path}" + end + end + def self.run(command, results, command_name = nil, dir = Dir.pwd, env = {}) verbose = Gem.configuration.really_verbose diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb index 27ebd8c62b..2f4193d697 100644 --- a/lib/rubygems/ext/ext_conf_builder.rb +++ b/lib/rubygems/ext/ext_conf_builder.rb @@ -21,8 +21,7 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder destdir = ENV["DESTDIR"] begin - require "shellwords" - cmd = Gem.ruby.shellsplit << "-I" << File.expand_path("../..", __dir__) << File.basename(extension) + cmd = ruby << File.basename(extension) cmd.push(*args) run(cmd, results, class_name, extension_dir) do |s, r| diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb index 9f2e099d40..e74ec8750f 100644 --- a/lib/rubygems/ext/rake_builder.rb +++ b/lib/rubygems/ext/rake_builder.rb @@ -18,7 +18,7 @@ class Gem::Ext::RakeBuilder < Gem::Ext::Builder rake = rake.shellsplit else begin - rake = [Gem.ruby, "-I#{File.expand_path("../..", __dir__)}", "-rrubygems", Gem.bin_path("rake", "rake")] + rake = ruby << "-rrubygems" << Gem.bin_path("rake", "rake") rescue Gem::Exception rake = [Gem.default_exec_format % "rake"] end diff --git a/lib/rubygems/package/tar_header.rb b/lib/rubygems/package/tar_header.rb index 590a2f0315..31566e5865 100644 --- a/lib/rubygems/package/tar_header.rb +++ b/lib/rubygems/package/tar_header.rb @@ -208,7 +208,7 @@ class Gem::Package::TarHeader private def calculate_checksum(header) - header.unpack("C*").inject {|a, b| a + b } + header.sum(0) end def header(checksum = @checksum) diff --git a/lib/rubygems/package/tar_reader.rb b/lib/rubygems/package/tar_reader.rb index cdc3fdc015..9f1d49035b 100644 --- a/lib/rubygems/package/tar_reader.rb +++ b/lib/rubygems/package/tar_reader.rb @@ -53,39 +53,11 @@ class Gem::Package::TarReader def each return enum_for __method__ unless block_given? - use_seek = @io.respond_to?(:seek) - until @io.eof? do header = Gem::Package::TarHeader.from @io return if header.empty? - entry = Gem::Package::TarReader::Entry.new header, @io - size = entry.header.size - yield entry - - skip = (512 - (size % 512)) % 512 - pending = size - entry.bytes_read - - if use_seek - begin - # avoid reading if the @io supports seeking - @io.seek pending, IO::SEEK_CUR - pending = 0 - rescue Errno::EINVAL - end - end - - # if seeking isn't supported or failed - while pending > 0 do - bytes_read = @io.read([pending, 4096].min).size - raise UnexpectedEOF if @io.eof? - pending -= bytes_read - end - - @io.read skip # discard trailing zeros - - # make sure nobody can use #read, #getc or #rewind anymore entry.close end end diff --git a/lib/rubygems/package/tar_reader/entry.rb b/lib/rubygems/package/tar_reader/entry.rb index 8634381c18..9e7b327431 100644 --- a/lib/rubygems/package/tar_reader/entry.rb +++ b/lib/rubygems/package/tar_reader/entry.rb @@ -9,6 +9,20 @@ class Gem::Package::TarReader::Entry ## + # Creates a new tar entry for +header+ that will be read from +io+ + # If a block is given, the entry is yielded and then closed. + + def self.open(header, io, &block) + entry = new header, io + return entry unless block_given? + begin + yield entry + ensure + entry.close + end + end + + ## # Header for this tar entry attr_reader :header @@ -21,6 +35,7 @@ class Gem::Package::TarReader::Entry @header = header @io = io @orig_pos = @io.pos + @end_pos = @orig_pos + @header.size @read = 0 end @@ -39,7 +54,14 @@ class Gem::Package::TarReader::Entry # Closes the tar entry def close + return if closed? + # Seek to the end of the entry if it wasn't fully read + seek(0, IO::SEEK_END) + # discard trailing zeros + skip = (512 - (@header.size % 512)) % 512 + @io.read(skip) @closed = true + nil end ## @@ -117,6 +139,14 @@ class Gem::Package::TarReader::Entry bytes_read end + ## + # Seek to the position in the tar entry + + def pos=(new_pos) + seek(new_pos, IO::SEEK_SET) + new_pos + end + def size @header.size end @@ -130,9 +160,10 @@ class Gem::Package::TarReader::Entry def read(len = nil) check_closed - return nil if @read >= @header.size - len ||= @header.size - @read + + return nil if len > 0 && @read >= @header.size + max_read = [len, @header.size - @read].min ret = @io.read max_read @@ -144,9 +175,10 @@ class Gem::Package::TarReader::Entry def readpartial(maxlen = nil, outbuf = "".b) check_closed - raise EOFError if @read >= @header.size - maxlen ||= @header.size - @read + + raise EOFError if maxlen > 0 && @read >= @header.size + max_read = [maxlen, @header.size - @read].min @io.readpartial(max_read, outbuf) @@ -156,12 +188,61 @@ class Gem::Package::TarReader::Entry end ## + # Seeks to +offset+ bytes into the tar file entry + # +whence+ can be IO::SEEK_SET, IO::SEEK_CUR, or IO::SEEK_END + + def seek(offset, whence = IO::SEEK_SET) + check_closed + + new_pos = + case whence + when IO::SEEK_SET then @orig_pos + offset + when IO::SEEK_CUR then @io.pos + offset + when IO::SEEK_END then @end_pos + offset + else + raise ArgumentError, "invalid whence" + end + + if new_pos < @orig_pos + new_pos = @orig_pos + elsif new_pos > @end_pos + new_pos = @end_pos + end + + pending = new_pos - @io.pos + + if @io.respond_to?(:seek) + begin + # avoid reading if the @io supports seeking + @io.seek new_pos, IO::SEEK_SET + pending = 0 + rescue Errno::EINVAL + end + end + + # if seeking isn't supported or failed + # negative seek requires that we rewind and read + if pending < 0 + @io.rewind + pending = new_pos + end + + while pending > 0 do + size_read = @io.read([pending, 4096].min).size + raise UnexpectedEOF if @io.eof? + pending -= size_read + end + + @read = @io.pos - @orig_pos + + 0 + end + + ## # Rewinds to the beginning of the tar file entry def rewind check_closed - - @io.pos = @orig_pos - @read = 0 + seek(0, IO::SEEK_SET) end end diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb index 128871f2bf..f4983c1153 100644 --- a/lib/rubygems/platform.rb +++ b/lib/rubygems/platform.rb @@ -235,11 +235,11 @@ class Gem::Platform # A pure-Ruby gem that may use Gem::Specification#extensions to build # binary files. - RUBY = "ruby".freeze + RUBY = "ruby" ## # A platform-specific gem that is built for the packaging Ruby's platform. # This will be replaced with Gem::Platform::local. - CURRENT = "current".freeze + CURRENT = "current" end diff --git a/lib/rubygems/request_set/gem_dependency_api.rb b/lib/rubygems/request_set/gem_dependency_api.rb index ad6e45005b..0681f8802a 100644 --- a/lib/rubygems/request_set/gem_dependency_api.rb +++ b/lib/rubygems/request_set/gem_dependency_api.rb @@ -435,7 +435,6 @@ Gem dependencies file #{@path} requires #{name} more than once. reference ||= ref reference ||= branch reference ||= tag - reference ||= "master" if ref && branch warn <<-WARNING diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb index 64f9ac3465..bc2fd9af55 100644 --- a/lib/rubygems/requirement.rb +++ b/lib/rubygems/requirement.rb @@ -22,7 +22,7 @@ class Gem::Requirement SOURCE_SET_REQUIREMENT = Struct.new(:for_lockfile).new "!" # :nodoc: quoted = OPS.keys.map {|k| Regexp.quote k }.join "|" - PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*".freeze # :nodoc: + PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*" # :nodoc: ## # A regular expression that matches a requirement diff --git a/lib/rubygems/resolver/stats.rb b/lib/rubygems/resolver/stats.rb index 64b458f504..3b95efebf7 100644 --- a/lib/rubygems/resolver/stats.rb +++ b/lib/rubygems/resolver/stats.rb @@ -32,7 +32,7 @@ class Gem::Resolver::Stats @iterations += 1 end - PATTERN = "%20s: %d\n".freeze + PATTERN = "%20s: %d\n" def display $stdout.puts "=== Resolver Statistics ===" diff --git a/lib/rubygems/source/git.rb b/lib/rubygems/source/git.rb index 2609a309e8..7ac685f978 100644 --- a/lib/rubygems/source/git.rb +++ b/lib/rubygems/source/git.rb @@ -53,7 +53,7 @@ class Gem::Source::Git < Gem::Source @uri = Gem::Uri.parse(repository) @name = name @repository = repository - @reference = reference + @reference = reference || "HEAD" @need_submodules = submodules @remote = true diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 5175db2d84..b8aa43bf81 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -338,7 +338,7 @@ class Gem::Specification < Gem::BasicSpecification # The simplest way is to specify the standard SPDX ID # https://spdx.org/licenses/ for the license. # Ideally, you should pick one that is OSI (Open Source Initiative) - # http://opensource.org/licenses/alphabetical approved. + # https://opensource.org/licenses/ approved. # # The most commonly used OSI-approved licenses are MIT and Apache-2.0. # GitHub also provides a license picker at http://choosealicense.com/. @@ -1022,6 +1022,12 @@ class Gem::Specification < Gem::BasicSpecification end ## + # Find the best specification matching a +full_name+. + def self.find_by_full_name(full_name) + stubs.find {|s| s.full_name == full_name }&.to_spec + end + + ## # Return the best specification that contains the file matching +path+. def self.find_by_path(path) @@ -1606,6 +1612,8 @@ class Gem::Specification < Gem::BasicSpecification def build_extensions # :nodoc: return if extensions.empty? return if default_gem? + # we need to fresh build when same name and version of default gems + return if self.class.find_by_full_name(full_name)&.default_gem? return if File.exist? gem_build_complete_path return if !File.writable?(base_dir) return if !File.exist?(File.join(base_dir, "extensions")) diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb index 6f4d79cdcf..c7e2edc2bf 100644 --- a/lib/rubygems/specification_policy.rb +++ b/lib/rubygems/specification_policy.rb @@ -173,6 +173,7 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use: end ## + # Checks that the gem does not depend on itself. # Checks that dependencies use requirements as we recommend. Warnings are # issued when dependencies are open-ended or overly strict for semantic # versioning. @@ -180,6 +181,10 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use: def validate_dependencies # :nodoc: warning_messages = [] @specification.dependencies.each do |dep| + if dep.name == @specification.name # warn on self reference + warning_messages << "Self referencing dependency is unnecessary and strongly discouraged." + end + prerelease_dep = dep.requirements_list.any? do |req| Gem::Requirement.new(req).prerelease? end diff --git a/lib/rubygems/stub_specification.rb b/lib/rubygems/stub_specification.rb index 512ca9143d..d87abdd993 100644 --- a/lib/rubygems/stub_specification.rb +++ b/lib/rubygems/stub_specification.rb @@ -6,10 +6,10 @@ class Gem::StubSpecification < Gem::BasicSpecification # :nodoc: - PREFIX = "# stub: ".freeze + PREFIX = "# stub: " # :nodoc: - OPEN_MODE = "r:UTF-8:-".freeze + OPEN_MODE = "r:UTF-8:-" class StubLine # :nodoc: all attr_reader :name, :version, :platform, :require_paths, :extensions, @@ -19,9 +19,9 @@ class Gem::StubSpecification < Gem::BasicSpecification # These are common require paths. REQUIRE_PATHS = { # :nodoc: - "lib" => "lib".freeze, - "test" => "test".freeze, - "ext" => "ext".freeze, + "lib" => "lib", + "test" => "test", + "ext" => "ext", }.freeze # These are common require path lists. This hash is used to optimize @@ -33,7 +33,7 @@ class Gem::StubSpecification < Gem::BasicSpecification }.freeze def initialize(data, extensions) - parts = data[PREFIX.length..-1].split(" ".freeze, 4) + parts = data[PREFIX.length..-1].split(" ", 4) @name = parts[0].freeze @version = if Gem::Version.correct?(parts[1]) Gem::Version.new(parts[1]) @@ -50,7 +50,7 @@ class Gem::StubSpecification < Gem::BasicSpecification end path_list = parts.last - @require_paths = REQUIRE_PATH_LIST[path_list] || path_list.split("\0".freeze).map! do |x| + @require_paths = REQUIRE_PATH_LIST[path_list] || path_list.split("\0").map! do |x| REQUIRE_PATHS[x] || x end end diff --git a/lib/rubygems/text.rb b/lib/rubygems/text.rb index d6b891380e..be811525f2 100644 --- a/lib/rubygems/text.rb +++ b/lib/rubygems/text.rb @@ -9,7 +9,7 @@ module Gem::Text # Remove any non-printable characters and make the text suitable for # printing. def clean_text(text) - text.gsub(/[\000-\b\v-\f\016-\037\177]/, ".".freeze) + text.gsub(/[\000-\b\v-\f\016-\037\177]/, ".") end def truncate_text(text, description, max_length = 100_000) diff --git a/lib/rubygems/util/licenses.rb b/lib/rubygems/util/licenses.rb index 96f47781c0..a823521d10 100644 --- a/lib/rubygems/util/licenses.rb +++ b/lib/rubygems/util/licenses.rb @@ -4,8 +4,8 @@ require_relative "../text" class Gem::Licenses extend Gem::Text - NONSTANDARD = "Nonstandard".freeze - LICENSE_REF = "LicenseRef-.+".freeze + NONSTANDARD = "Nonstandard" + LICENSE_REF = "LicenseRef-.+" # Software Package Data Exchange (SPDX) standard open-source software # license identifiers diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb index f67889ef1a..c319e1f820 100644 --- a/lib/rubygems/version.rb +++ b/lib/rubygems/version.rb @@ -155,7 +155,7 @@ require_relative "deprecate" class Gem::Version include Comparable - VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?'.freeze # :nodoc: + VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?' # :nodoc: ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/.freeze # :nodoc: ## @@ -272,7 +272,7 @@ class Gem::Version # string for backwards (RubyGems 1.3.5 and earlier) compatibility. def marshal_dump - [version] + [@version] end ## |
