diff --git a/lib/bundler/checksum.rb b/lib/bundler/checksum.rb index 60ba93417c..46befe5356 100644 --- a/lib/bundler/checksum.rb +++ b/lib/bundler/checksum.rb @@ -126,7 +126,7 @@ module Bundler end def removable? - type == :lock || type == :gem + [:lock, :gem].include?(type) end def ==(other) diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb index 5365338823..1274630556 100644 --- a/lib/bundler/cli/doctor.rb +++ b/lib/bundler/cli/doctor.rb @@ -99,7 +99,7 @@ module Bundler end end.sort.each {|m| message += m } raise ProductionError, message - elsif !permissions_valid + elsif permissions_valid Bundler.ui.info "No issues found with the installed bundle" end end @@ -108,21 +108,21 @@ module Bundler def check_home_permissions require "find" - files_not_readable_or_writable = [] - files_not_rw_and_owned_by_different_user = [] - files_not_owned_by_current_user_but_still_rw = [] + files_not_readable = [] + files_not_readable_and_owned_by_different_user = [] + files_not_owned_by_current_user_but_still_readable = [] broken_symlinks = [] Find.find(Bundler.bundle_path.to_s).each do |f| if !File.exist?(f) broken_symlinks << f - elsif !File.writable?(f) || !File.readable?(f) + elsif !File.readable?(f) if File.stat(f).uid != Process.uid - files_not_rw_and_owned_by_different_user << f + files_not_readable_and_owned_by_different_user << f else - files_not_readable_or_writable << f + files_not_readable << f end elsif File.stat(f).uid != Process.uid - files_not_owned_by_current_user_but_still_rw << f + files_not_owned_by_current_user_but_still_readable << f end end @@ -134,23 +134,23 @@ module Bundler ok = false end - if files_not_owned_by_current_user_but_still_rw.any? + if files_not_owned_by_current_user_but_still_readable.any? Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ - "user, but are still readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" + "user, but are still readable. These files are:\n - #{files_not_owned_by_current_user_but_still_readable.join("\n - ")}" ok = false end - if files_not_rw_and_owned_by_different_user.any? + if files_not_readable_and_owned_by_different_user.any? Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ - "user, and are not readable/writable. These files are:\n - #{files_not_rw_and_owned_by_different_user.join("\n - ")}" + "user, and are not readable. These files are:\n - #{files_not_readable_and_owned_by_different_user.join("\n - ")}" ok = false end - if files_not_readable_or_writable.any? + if files_not_readable.any? Bundler.ui.warn "Files exist in the Bundler home that are not " \ - "readable/writable by the current user. These files are:\n - #{files_not_readable_or_writable.join("\n - ")}" + "readable by the current user. These files are:\n - #{files_not_readable.join("\n - ")}" ok = false end diff --git a/lib/bundler/cli/inject.rb b/lib/bundler/cli/inject.rb index 4838aba671..a09d5c6bda 100644 --- a/lib/bundler/cli/inject.rb +++ b/lib/bundler/cli/inject.rb @@ -35,8 +35,8 @@ module Bundler Bundler.ui.confirm(added.map do |d| name = "'#{d.name}'" requirement = ", '#{d.requirement}'" - group = ", :group => #{d.groups.inspect}" if d.groups != Array(:default) - source = ", :source => '#{d.source}'" unless d.source.nil? + group = ", group: #{d.groups.inspect}" if d.groups != Array(:default) + source = ", source: '#{d.source}'" unless d.source.nil? %(gem #{name}#{requirement}#{group}#{source}) end.join("\n")) else diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb index ff08927363..b60c82e3a1 100644 --- a/lib/bundler/cli/lock.rb +++ b/lib/bundler/cli/lock.rb @@ -44,7 +44,8 @@ module Bundler Bundler::CLI::Common.configure_gem_version_promoter(definition, options) if options[:update] - options["remove-platform"].each do |platform| + options["remove-platform"].each do |platform_string| + platform = Gem::Platform.new(platform_string) definition.remove_platform(platform) end diff --git a/lib/bundler/compact_index_client/updater.rb b/lib/bundler/compact_index_client/updater.rb index 88c7146900..6066fdc7c4 100644 --- a/lib/bundler/compact_index_client/updater.rb +++ b/lib/bundler/compact_index_client/updater.rb @@ -37,7 +37,8 @@ module Bundler file.digests = parse_digests(response) # server may ignore Range and return the full response if response.is_a?(Gem::Net::HTTPPartialContent) - break false unless file.append(response.body.byteslice(1..-1)) + tail = response.body.byteslice(1..-1) + break false unless tail && file.append(tail) else file.write(response.body) end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 0670b49349..557315af4f 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -94,7 +94,7 @@ module Bundler @locked_ruby_version = nil @new_platforms = [] - @removed_platform = nil + @removed_platforms = [] if lockfile_exists? @lockfile_contents = Bundler.read_file(lockfile) @@ -330,7 +330,7 @@ module Bundler SpecSet.new(filter_specs(@locked_specs, @dependencies - deleted_deps)) else Bundler.ui.debug "Found no changes, using resolution from the lockfile" - if @removed_platform || @locked_gems.may_include_redundant_platform_specific_gems? + if @removed_platforms.any? || @locked_gems.may_include_redundant_platform_specific_gems? SpecSet.new(filter_specs(@locked_specs, @dependencies)) else @locked_specs @@ -412,41 +412,8 @@ module Bundler raise ProductionError, "Frozen mode is set, but there's no lockfile" unless lockfile_exists? - added = [] - deleted = [] - changed = [] - - new_platforms = @platforms - @locked_platforms - deleted_platforms = @locked_platforms - @platforms - added.concat new_platforms.map {|p| "* platform: #{p}" } - deleted.concat deleted_platforms.map {|p| "* platform: #{p}" } - - added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any? - deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any? - - both_sources = Hash.new {|h, k| h[k] = [] } - current_dependencies.each {|d| both_sources[d.name][0] = d } - current_locked_dependencies.each {|d| both_sources[d.name][1] = d } - - both_sources.each do |name, (dep, lock_dep)| - next if dep.nil? || lock_dep.nil? - - gemfile_source = dep.source || default_source - lock_source = lock_dep.source || default_source - next if lock_source.include?(gemfile_source) - - gemfile_source_name = dep.source ? gemfile_source.to_gemfile : "no specified source" - lockfile_source_name = lock_dep.source ? lock_source.to_gemfile : "no specified source" - changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`" - end - - reason = resolve_needed? ? change_reason : "some dependencies were deleted from your gemfile" - msg = String.new - msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because frozen mode is set" - msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? - msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any? - msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? - msg << "\n\nRun `bundle install` elsewhere and add the updated #{SharedHelpers.relative_gemfile_path} to version control.\n" unless unlocking? + msg = lockfile_changes_summary("frozen mode is set") + return unless msg unless explicit_flag suggested_command = unless Bundler.settings.locations("frozen").keys.include?(:env) @@ -456,7 +423,7 @@ module Bundler "freeze by running `#{suggested_command}`." if suggested_command end - raise ProductionError, msg if added.any? || deleted.any? || changed.any? || resolve_needed? + raise ProductionError, msg end def validate_runtime! @@ -511,10 +478,10 @@ module Bundler end def remove_platform(platform) - removed_platform = @platforms.delete(Gem::Platform.new(platform)) - @removed_platform ||= removed_platform - return if removed_platform - raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" + raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" unless @platforms.include?(platform) + + @removed_platforms << platform + @platforms.delete(platform) end def nothing_changed? @@ -541,6 +508,46 @@ module Bundler private + def lockfile_changes_summary(update_refused_reason) + added = [] + deleted = [] + changed = [] + + added.concat @new_platforms.map {|p| "* platform: #{p}" } + deleted.concat @removed_platforms.map {|p| "* platform: #{p}" } + + added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any? + deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any? + + both_sources = Hash.new {|h, k| h[k] = [] } + current_dependencies.each {|d| both_sources[d.name][0] = d } + current_locked_dependencies.each {|d| both_sources[d.name][1] = d } + + both_sources.each do |name, (dep, lock_dep)| + next if dep.nil? || lock_dep.nil? + + gemfile_source = dep.source || default_source + lock_source = lock_dep.source || default_source + next if lock_source.include?(gemfile_source) + + gemfile_source_name = dep.source ? gemfile_source.to_gemfile : "no specified source" + lockfile_source_name = lock_dep.source ? lock_source.to_gemfile : "no specified source" + changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`" + end + + return unless added.any? || deleted.any? || changed.any? || resolve_needed? + + reason = resolve_needed? ? change_reason : "some dependencies were deleted from your gemfile" + + msg = String.new + msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because #{update_refused_reason}" + msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? + msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any? + msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? + msg << "\n\nRun `bundle install` elsewhere and add the updated #{SharedHelpers.relative_gemfile_path} to version control.\n" unless unlocking? + msg + end + def install_needed? resolve_needed? || missing_specs? end @@ -601,8 +608,12 @@ module Bundler return end - SharedHelpers.filesystem_access(file) do |p| - File.open(p, "wb") {|f| f.puts(contents) } + begin + SharedHelpers.filesystem_access(file) do |p| + File.open(p, "wb") {|f| f.puts(contents) } + end + rescue ReadOnlyFileSystemError + raise ProductionError, lockfile_changes_summary("file system is read-only") end end @@ -625,7 +636,8 @@ module Bundler @resolution_packages ||= begin last_resolve = converge_locked_specs remove_invalid_platforms! - packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @unlocking_all || @gems_to_unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: @new_platforms) + new_resolution_platforms = @current_platform_missing ? @new_platforms + [local_platform] : @new_platforms + packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @unlocking_all || @gems_to_unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms) packages = additional_base_requirements_to_prevent_downgrades(packages) packages = additional_base_requirements_to_force_updates(packages) packages @@ -768,7 +780,6 @@ module Bundler @most_specific_non_local_locked_platform = find_most_specific_locked_platform return if @most_specific_non_local_locked_platform - @new_platforms << local_platform @platforms << local_platform true end @@ -799,7 +810,7 @@ module Bundler [@source_changes, "the list of sources changed"], [@dependency_changes, "the dependencies in your gemfile changed"], [@current_platform_missing, "your lockfile does not include the current platform"], - [@new_platforms.any?, "you added a new platform to your gemfile"], + [@new_platforms.any?, "you are adding a new platform to your lockfile"], [@path_changes, "the gemspecs for path gems changed"], [@local_changes, "the gemspecs for git local gems changed"], [@missing_lockfile_dep, "your lock file is missing \"#{@missing_lockfile_dep}\""], diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb index 9d3d89ffeb..4d1bface51 100644 --- a/lib/bundler/errors.rb +++ b/lib/bundler/errors.rb @@ -193,6 +193,24 @@ module Bundler status_code(31) end + class ReadOnlyFileSystemError < PermissionError + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "File system is read-only." + end + + status_code(42) + end + + class OperationNotPermittedError < PermissionError + def message + "There was an error while trying to #{action} `#{@path}`. " \ + "Underlying OS system call raised an EPERM error." + end + + status_code(43) + end + class GenericSystemCallError < BundlerError attr_reader :underlying_error diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb index c0941e9909..21ff90ad13 100644 --- a/lib/bundler/injector.rb +++ b/lib/bundler/injector.rb @@ -108,17 +108,17 @@ module Bundler end if d.groups != Array(:default) - group = d.groups.size == 1 ? ", :group => #{d.groups.first.inspect}" : ", :groups => #{d.groups.inspect}" + group = d.groups.size == 1 ? ", group: #{d.groups.first.inspect}" : ", groups: #{d.groups.inspect}" end - source = ", :source => \"#{d.source}\"" unless d.source.nil? - path = ", :path => \"#{d.path}\"" unless d.path.nil? - git = ", :git => \"#{d.git}\"" unless d.git.nil? - github = ", :github => \"#{d.github}\"" unless d.github.nil? - branch = ", :branch => \"#{d.branch}\"" unless d.branch.nil? - ref = ", :ref => \"#{d.ref}\"" unless d.ref.nil? - glob = ", :glob => \"#{d.glob}\"" unless d.glob.nil? - require_path = ", :require => #{convert_autorequire(d.autorequire)}" unless d.autorequire.nil? + source = ", source: \"#{d.source}\"" unless d.source.nil? + path = ", path: \"#{d.path}\"" unless d.path.nil? + git = ", git: \"#{d.git}\"" unless d.git.nil? + github = ", github: \"#{d.github}\"" unless d.github.nil? + branch = ", branch: \"#{d.branch}\"" unless d.branch.nil? + ref = ", ref: \"#{d.ref}\"" unless d.ref.nil? + glob = ", glob: \"#{d.glob}\"" unless d.glob.nil? + require_path = ", require: #{convert_autorequire(d.autorequire)}" unless d.autorequire.nil? %(gem #{name}#{requirement}#{group}#{source}#{path}#{git}#{github}#{branch}#{ref}#{glob}#{require_path}) end.join("\n") diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1 index 47e4e3482a..176e8b117e 100644 --- a/lib/bundler/man/bundle-add.1 +++ b/lib/bundler/man/bundle-add.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-ADD" "1" "January 2025" "" +.TH "BUNDLE\-ADD" "1" "March 2025" "" .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1 index f175eaa917..146c1c021e 100644 --- a/lib/bundler/man/bundle-binstubs.1 +++ b/lib/bundler/man/bundle-binstubs.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-BINSTUBS" "1" "January 2025" "" +.TH "BUNDLE\-BINSTUBS" "1" "March 2025" "" .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1 index c5ded3ad24..64e806029b 100644 --- a/lib/bundler/man/bundle-cache.1 +++ b/lib/bundler/man/bundle-cache.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-CACHE" "1" "January 2025" "" +.TH "BUNDLE\-CACHE" "1" "March 2025" "" .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1 index f30afeda46..bf16a22461 100644 --- a/lib/bundler/man/bundle-check.1 +++ b/lib/bundler/man/bundle-check.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-CHECK" "1" "January 2025" "" +.TH "BUNDLE\-CHECK" "1" "March 2025" "" .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1 index e7216d3e15..83f7661482 100644 --- a/lib/bundler/man/bundle-clean.1 +++ b/lib/bundler/man/bundle-clean.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-CLEAN" "1" "January 2025" "" +.TH "BUNDLE\-CLEAN" "1" "March 2025" "" .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index fb45e631c5..190177eb37 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-CONFIG" "1" "January 2025" "" +.TH "BUNDLE\-CONFIG" "1" "March 2025" "" .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options .SH "SYNOPSIS" @@ -56,16 +56,16 @@ Creates a directory (defaults to \fB~/bin\fR) and place any executables from the In deployment mode, Bundler will 'roll\-out' the bundle for \fBproduction\fR use\. Please check carefully if you want to have this option enabled in \fBdevelopment\fR or \fBtest\fR environments\. .TP \fBonly\fR -A space\-separated list of groups to install only gems of the specified groups\. +A space\-separated list of groups to install only gems of the specified groups\. Please check carefully if you want to install also gems without a group, cause they get put inside \fBdefault\fR group\. For example \fBonly test:default\fR will install all gems specified in test group and without one\. .TP \fBpath\fR The location to install the specified gems to\. This defaults to Rubygems' setting\. Bundler shares this location with Rubygems, \fBgem install \|\.\|\.\|\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \|\.\|\.\|\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\. .TP \fBwithout\fR -A space\-separated list of groups referencing gems to skip during installation\. +A space\-separated or \fB:\fR\-separated list of groups referencing gems to skip during installation\. .TP \fBwith\fR -A space\-separated list of \fBoptional\fR groups referencing gems to include during installation\. +A space\-separated or \fB:\fR\-separated list of \fBoptional\fR groups referencing gems to include during installation\. .SH "BUILD OPTIONS" You can use \fBbundle config\fR to give Bundler the flags to pass to the gem installer every time bundler tries to install a particular gem\. .P @@ -197,9 +197,9 @@ The following is a list of all configuration keys and their purpose\. You can le .IP "\(bu" 4 \fBversion\fR (\fBBUNDLE_VERSION\fR): The version of Bundler to use when running under Bundler environment\. Defaults to \fBlockfile\fR\. You can also specify \fBsystem\fR or \fBx\.y\.z\fR\. \fBlockfile\fR will use the Bundler version specified in the \fBGemfile\.lock\fR, \fBsystem\fR will use the system version of Bundler, and \fBx\.y\.z\fR will use the specified version of Bundler\. .IP "\(bu" 4 -\fBwith\fR (\fBBUNDLE_WITH\fR): A \fB:\fR\-separated list of groups whose gems bundler should install\. +\fBwith\fR (\fBBUNDLE_WITH\fR): A space\-separated or \fB:\fR\-separated list of groups whose gems bundler should install\. .IP "\(bu" 4 -\fBwithout\fR (\fBBUNDLE_WITHOUT\fR): A \fB:\fR\-separated list of groups whose gems bundler should not install\. +\fBwithout\fR (\fBBUNDLE_WITHOUT\fR): A space\-separated or \fB:\fR\-separated list of groups whose gems bundler should not install\. .IP "" 0 .SH "LOCAL GIT REPOS" Bundler also allows you to work against a git repository locally instead of using the remote version\. This can be achieved by setting up a local override: diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index 00e2081959..44c31cd10d 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -79,6 +79,9 @@ The options that can be configured are: * `only`: A space-separated list of groups to install only gems of the specified groups. + Please check carefully if you want to install also gems without a group, cause + they get put inside `default` group. For example `only test:default` will install + all gems specified in test group and without one. * `path`: The location to install the specified gems to. This defaults to Rubygems' @@ -88,10 +91,12 @@ The options that can be configured are: installed to other locations will not get listed. * `without`: - A space-separated list of groups referencing gems to skip during installation. + A space-separated or `:`-separated list of groups referencing gems to skip during + installation. * `with`: - A space-separated list of **optional** groups referencing gems to include during installation. + A space-separated or `:`-separated list of **optional** groups referencing gems to + include during installation. ## BUILD OPTIONS @@ -280,9 +285,9 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). `system` will use the system version of Bundler, and `x.y.z` will use the specified version of Bundler. * `with` (`BUNDLE_WITH`): - A `:`-separated list of groups whose gems bundler should install. + A space-separated or `:`-separated list of groups whose gems bundler should install. * `without` (`BUNDLE_WITHOUT`): - A `:`-separated list of groups whose gems bundler should not install. + A space-separated or `:`-separated list of groups whose gems bundler should not install. ## LOCAL GIT REPOS diff --git a/lib/bundler/man/bundle-console.1 b/lib/bundler/man/bundle-console.1 index 287c976c2b..de9eeac907 100644 --- a/lib/bundler/man/bundle-console.1 +++ b/lib/bundler/man/bundle-console.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-CONSOLE" "1" "January 2025" "" +.TH "BUNDLE\-CONSOLE" "1" "March 2025" "" .SH "NAME" \fBbundle\-console\fR \- Open an IRB session with the bundle pre\-loaded .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1 index ca385c3b86..cd831f2fee 100644 --- a/lib/bundler/man/bundle-doctor.1 +++ b/lib/bundler/man/bundle-doctor.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-DOCTOR" "1" "January 2025" "" +.TH "BUNDLE\-DOCTOR" "1" "March 2025" "" .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-env.1 b/lib/bundler/man/bundle-env.1 index 45f97c9283..c936294827 100644 --- a/lib/bundler/man/bundle-env.1 +++ b/lib/bundler/man/bundle-env.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-ENV" "1" "January 2025" "" +.TH "BUNDLE\-ENV" "1" "March 2025" "" .SH "NAME" \fBbundle\-env\fR \- Print information about the environment Bundler is running under .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1 index fa02c4234c..0ebbb4c198 100644 --- a/lib/bundler/man/bundle-exec.1 +++ b/lib/bundler/man/bundle-exec.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-EXEC" "1" "January 2025" "" +.TH "BUNDLE\-EXEC" "1" "March 2025" "" .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle .SH "SYNOPSIS" @@ -74,8 +74,8 @@ end Bundler provides convenience helpers that wrap \fBsystem\fR and \fBexec\fR, and they can be used like this: .IP "" 4 .nf -Bundler\.clean_system('brew install wget') -Bundler\.clean_exec('brew install wget') +Bundler\.unbundled_system('brew install wget') +Bundler\.unbundled_exec('brew install wget') .fi .IP "" 0 .SH "RUBYGEMS PLUGINS" diff --git a/lib/bundler/man/bundle-exec.1.ronn b/lib/bundler/man/bundle-exec.1.ronn index 8da1e2348b..3d3f0eed7b 100644 --- a/lib/bundler/man/bundle-exec.1.ronn +++ b/lib/bundler/man/bundle-exec.1.ronn @@ -108,8 +108,8 @@ need to use `with_unbundled_env`. Bundler provides convenience helpers that wrap `system` and `exec`, and they can be used like this: - Bundler.clean_system('brew install wget') - Bundler.clean_exec('brew install wget') + Bundler.unbundled_system('brew install wget') + Bundler.unbundled_exec('brew install wget') ## RUBYGEMS PLUGINS diff --git a/lib/bundler/man/bundle-fund.1 b/lib/bundler/man/bundle-fund.1 index fd6f8f4ac1..641d8cf864 100644 --- a/lib/bundler/man/bundle-fund.1 +++ b/lib/bundler/man/bundle-fund.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-FUND" "1" "January 2025" "" +.TH "BUNDLE\-FUND" "1" "March 2025" "" .SH "NAME" \fBbundle\-fund\fR \- Lists information about gems seeking funding assistance .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index 7840fdda23..65882afa4f 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-GEM" "1" "January 2025" "" +.TH "BUNDLE\-GEM" "1" "March 2025" "" .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-help.1 b/lib/bundler/man/bundle-help.1 index 2ac1c26997..d8dd4660dc 100644 --- a/lib/bundler/man/bundle-help.1 +++ b/lib/bundler/man/bundle-help.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-HELP" "1" "January 2025" "" +.TH "BUNDLE\-HELP" "1" "March 2025" "" .SH "NAME" \fBbundle\-help\fR \- Displays detailed help for each subcommand .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1 index 22a2bae2bd..8124836519 100644 --- a/lib/bundler/man/bundle-info.1 +++ b/lib/bundler/man/bundle-info.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-INFO" "1" "January 2025" "" +.TH "BUNDLE\-INFO" "1" "March 2025" "" .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1 index 4d59572d05..2e4b99b28a 100644 --- a/lib/bundler/man/bundle-init.1 +++ b/lib/bundler/man/bundle-init.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-INIT" "1" "January 2025" "" +.TH "BUNDLE\-INIT" "1" "March 2025" "" .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1 index ab9d5e83f6..54cacaa56d 100644 --- a/lib/bundler/man/bundle-inject.1 +++ b/lib/bundler/man/bundle-inject.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-INJECT" "1" "January 2025" "" +.TH "BUNDLE\-INJECT" "1" "March 2025" "" .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1 index efec8b8d4f..272f4187ed 100644 --- a/lib/bundler/man/bundle-install.1 +++ b/lib/bundler/man/bundle-install.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-INSTALL" "1" "January 2025" "" +.TH "BUNDLE\-INSTALL" "1" "March 2025" "" .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-issue.1 b/lib/bundler/man/bundle-issue.1 index 6fcfc70a80..02d28c91ba 100644 --- a/lib/bundler/man/bundle-issue.1 +++ b/lib/bundler/man/bundle-issue.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-ISSUE" "1" "January 2025" "" +.TH "BUNDLE\-ISSUE" "1" "March 2025" "" .SH "NAME" \fBbundle\-issue\fR \- Get help reporting Bundler issues .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-licenses.1 b/lib/bundler/man/bundle-licenses.1 index 8ac8358906..d0dbf3913c 100644 --- a/lib/bundler/man/bundle-licenses.1 +++ b/lib/bundler/man/bundle-licenses.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-LICENSES" "1" "January 2025" "" +.TH "BUNDLE\-LICENSES" "1" "March 2025" "" .SH "NAME" \fBbundle\-licenses\fR \- Print the license of all gems in the bundle .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1 index 83c246fd99..cd09ccab31 100644 --- a/lib/bundler/man/bundle-list.1 +++ b/lib/bundler/man/bundle-list.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-LIST" "1" "January 2025" "" +.TH "BUNDLE\-LIST" "1" "March 2025" "" .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1 index 60c93dd147..8c9b94e8e2 100644 --- a/lib/bundler/man/bundle-lock.1 +++ b/lib/bundler/man/bundle-lock.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-LOCK" "1" "January 2025" "" +.TH "BUNDLE\-LOCK" "1" "March 2025" "" .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1 index d97a332b02..eb4ac2e859 100644 --- a/lib/bundler/man/bundle-open.1 +++ b/lib/bundler/man/bundle-open.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-OPEN" "1" "January 2025" "" +.TH "BUNDLE\-OPEN" "1" "March 2025" "" .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1 index 0fdc047e6b..4f8a2cc56f 100644 --- a/lib/bundler/man/bundle-outdated.1 +++ b/lib/bundler/man/bundle-outdated.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-OUTDATED" "1" "January 2025" "" +.TH "BUNDLE\-OUTDATED" "1" "March 2025" "" .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1 index 8f9e00cf94..bdac52f937 100644 --- a/lib/bundler/man/bundle-platform.1 +++ b/lib/bundler/man/bundle-platform.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-PLATFORM" "1" "January 2025" "" +.TH "BUNDLE\-PLATFORM" "1" "March 2025" "" .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-plugin.1 b/lib/bundler/man/bundle-plugin.1 index f70557ca4b..ded328dbd8 100644 --- a/lib/bundler/man/bundle-plugin.1 +++ b/lib/bundler/man/bundle-plugin.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-PLUGIN" "1" "January 2025" "" +.TH "BUNDLE\-PLUGIN" "1" "March 2025" "" .SH "NAME" \fBbundle\-plugin\fR \- Manage Bundler plugins .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1 index 4ef23c6d26..294ef179a7 100644 --- a/lib/bundler/man/bundle-pristine.1 +++ b/lib/bundler/man/bundle-pristine.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-PRISTINE" "1" "January 2025" "" +.TH "BUNDLE\-PRISTINE" "1" "March 2025" "" .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1 index 959906a02e..2e42a12de3 100644 --- a/lib/bundler/man/bundle-remove.1 +++ b/lib/bundler/man/bundle-remove.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-REMOVE" "1" "January 2025" "" +.TH "BUNDLE\-REMOVE" "1" "March 2025" "" .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1 index bf228e8498..d460e7a256 100644 --- a/lib/bundler/man/bundle-show.1 +++ b/lib/bundler/man/bundle-show.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-SHOW" "1" "January 2025" "" +.TH "BUNDLE\-SHOW" "1" "March 2025" "" .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1 index a067615150..855a5049aa 100644 --- a/lib/bundler/man/bundle-update.1 +++ b/lib/bundler/man/bundle-update.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-UPDATE" "1" "January 2025" "" +.TH "BUNDLE\-UPDATE" "1" "March 2025" "" .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-version.1 b/lib/bundler/man/bundle-version.1 index 9f41cdc4a3..17add566d8 100644 --- a/lib/bundler/man/bundle-version.1 +++ b/lib/bundler/man/bundle-version.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-VERSION" "1" "January 2025" "" +.TH "BUNDLE\-VERSION" "1" "March 2025" "" .SH "NAME" \fBbundle\-version\fR \- Prints Bundler version information .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1 index 0eb7733d8b..17e6f90cca 100644 --- a/lib/bundler/man/bundle-viz.1 +++ b/lib/bundler/man/bundle-viz.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE\-VIZ" "1" "January 2025" "" +.TH "BUNDLE\-VIZ" "1" "March 2025" "" .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile .SH "SYNOPSIS" diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1 index ed7ad3afa3..3b40f58210 100644 --- a/lib/bundler/man/bundle.1 +++ b/lib/bundler/man/bundle.1 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "BUNDLE" "1" "January 2025" "" +.TH "BUNDLE" "1" "March 2025" "" .SH "NAME" \fBbundle\fR \- Ruby Dependency Management .SH "SYNOPSIS" diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5 index 579c82498a..f52864a2bf 100644 --- a/lib/bundler/man/gemfile.5 +++ b/lib/bundler/man/gemfile.5 @@ -1,6 +1,6 @@ .\" generated with Ronn-NG/v0.10.1 .\" http://github.com/apjanke/ronn-ng/tree/0.10.1 -.TH "GEMFILE" "5" "January 2025" "" +.TH "GEMFILE" "5" "March 2025" "" .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs .SH "SYNOPSIS" diff --git a/lib/bundler/plugin/index.rb b/lib/bundler/plugin/index.rb index 0b1234bbf3..0682d37772 100644 --- a/lib/bundler/plugin/index.rb +++ b/lib/bundler/plugin/index.rb @@ -31,7 +31,7 @@ module Bundler begin load_index(global_index_file, true) - rescue GenericSystemCallError + rescue PermissionError # no need to fail when on a read-only FS, for example nil rescue ArgumentError => e diff --git a/lib/bundler/resolver/candidate.rb b/lib/bundler/resolver/candidate.rb index 30fd6fe2fd..ad280fe82d 100644 --- a/lib/bundler/resolver/candidate.rb +++ b/lib/bundler/resolver/candidate.rb @@ -48,35 +48,38 @@ module Bundler @version.segments end - def sort_obj - [@version, @priority] - end - def <=>(other) return unless other.is_a?(self.class) - sort_obj <=> other.sort_obj + version_comparison = version <=> other.version + return version_comparison unless version_comparison.zero? + + priority <=> other.priority end def ==(other) return unless other.is_a?(self.class) - sort_obj == other.sort_obj + version == other.version && priority == other.priority end def eql?(other) return unless other.is_a?(self.class) - sort_obj.eql?(other.sort_obj) + version.eql?(other.version) && priority.eql?(other.priority) end def hash - sort_obj.hash + [@version, @priority].hash end def to_s @version.to_s end + + protected + + attr_reader :priority end end end diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index 9b398830f7..1ef9d61361 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -115,6 +115,10 @@ module Bundler raise NoSpaceOnDeviceError.new(path, action) rescue Errno::ENOTSUP raise OperationNotSupportedError.new(path, action) + rescue Errno::EPERM + raise OperationNotPermittedError.new(path, action) + rescue Errno::EROFS + raise ReadOnlyFileSystemError.new(path, action) rescue Errno::EEXIST, Errno::ENOENT raise rescue SystemCallError => e diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb index fde05e472b..d57944ee12 100644 --- a/lib/bundler/source/git.rb +++ b/lib/bundler/source/git.rb @@ -360,7 +360,11 @@ module Bundler end def locked_revision_checked_out? - locked_revision && locked_revision == revision && install_path.exist? + locked_revision && locked_revision == revision && installed? + end + + def installed? + git_proxy.installed_to?(install_path) end def base_name diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb index 4eedfc1bff..e01c5876de 100644 --- a/lib/bundler/source/git/git_proxy.rb +++ b/lib/bundler/source/git/git_proxy.rb @@ -147,6 +147,12 @@ module Bundler end end + def installed_to?(destination) + # if copy_to is interrupted, it may leave a partially installed directory that + # contains .git but no other files -- consider this not to be installed + Dir.exist?(destination) && (Dir.children(destination) - [".git"]).any? + end + private def git_remote_fetch(args) @@ -179,8 +185,7 @@ module Bundler _, err, status = capture(command, nil) return extra_ref if status.success? - if err.include?("Could not find remote branch") || # git up to 2.49 - err.include?("Remote branch #{branch_option} not found") # git 2.49 or higher + if err.include?("Could not find remote branch") raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri) else idx = command.index("--depth") @@ -257,7 +262,7 @@ module Bundler end def not_pinned? - branch_option || ref.nil? + branch || tag || ref.nil? end def pinned_to_full_sha? @@ -421,7 +426,7 @@ module Bundler # anyways. return args if @revision - args += ["--branch", branch_option] if branch_option + args += ["--branch", branch || tag] if branch || tag args end @@ -437,10 +442,6 @@ module Bundler extra_args end - def branch_option - branch || tag - end - def full_clone? depth.nil? end diff --git a/lib/bundler/source/rubygems/remote.rb b/lib/bundler/source/rubygems/remote.rb index 9c5c06de24..ed55912a99 100644 --- a/lib/bundler/source/rubygems/remote.rb +++ b/lib/bundler/source/rubygems/remote.rb @@ -16,6 +16,9 @@ module Bundler @anonymized_uri = remove_auth(@uri).freeze end + MAX_CACHE_SLUG_HOST_SIZE = 255 - 1 - 32 # 255 minus dot minus MD5 length + private_constant :MAX_CACHE_SLUG_HOST_SIZE + # @return [String] A slug suitable for use as a cache key for this # remote. # @@ -28,10 +31,15 @@ module Bundler host = cache_uri.to_s.start_with?("file://") ? nil : cache_uri.host uri_parts = [host, cache_uri.user, cache_uri.port, cache_uri.path] - uri_digest = SharedHelpers.digest(:MD5).hexdigest(uri_parts.compact.join(".")) + uri_parts.compact! + uri_digest = SharedHelpers.digest(:MD5).hexdigest(uri_parts.join(".")) - uri_parts[-1] = uri_digest - uri_parts.compact.join(".") + uri_parts.pop + host_parts = uri_parts.join(".") + return uri_digest if host_parts.empty? + + shortened_host_parts = host_parts[0...MAX_CACHE_SLUG_HOST_SIZE] + [shortened_host_parts, uri_digest].join(".") end end diff --git a/lib/bundler/vendor/uri/lib/uri/common.rb b/lib/bundler/vendor/uri/lib/uri/common.rb index 7cf81d27f6..186da24fa8 100644 --- a/lib/bundler/vendor/uri/lib/uri/common.rb +++ b/lib/bundler/vendor/uri/lib/uri/common.rb @@ -13,15 +13,19 @@ require_relative "rfc2396_parser" require_relative "rfc3986_parser" module Bundler::URI + # The default parser instance for RFC 2396. RFC2396_PARSER = RFC2396_Parser.new Ractor.make_shareable(RFC2396_PARSER) if defined?(Ractor) + # The default parser instance for RFC 3986. RFC3986_PARSER = RFC3986_Parser.new Ractor.make_shareable(RFC3986_PARSER) if defined?(Ractor) + # The default parser instance. DEFAULT_PARSER = RFC3986_PARSER Ractor.make_shareable(DEFAULT_PARSER) if defined?(Ractor) + # Set the default parser instance. def self.parser=(parser = RFC3986_PARSER) remove_const(:Parser) if defined?(::Bundler::URI::Parser) const_set("Parser", parser.class) @@ -40,7 +44,7 @@ module Bundler::URI end self.parser = RFC3986_PARSER - def self.const_missing(const) + def self.const_missing(const) # :nodoc: if const == :REGEXP warn "Bundler::URI::REGEXP is obsolete. Use Bundler::URI::RFC2396_REGEXP explicitly.", uplevel: 1 if $VERBOSE Bundler::URI::RFC2396_REGEXP @@ -87,7 +91,7 @@ module Bundler::URI module_function :make_components_hash end - module Schemes + module Schemes # :nodoc: end private_constant :Schemes @@ -305,7 +309,7 @@ module Bundler::URI 256.times do |i| TBLENCWWWCOMP_[-i.chr] = -('%%%02X' % i) end - TBLENCURICOMP_ = TBLENCWWWCOMP_.dup.freeze + TBLENCURICOMP_ = TBLENCWWWCOMP_.dup.freeze # :nodoc: TBLENCWWWCOMP_[' '] = '+' TBLENCWWWCOMP_.freeze TBLDECWWWCOMP_ = {} # :nodoc: diff --git a/lib/bundler/vendor/uri/lib/uri/generic.rb b/lib/bundler/vendor/uri/lib/uri/generic.rb index 8b097fba99..6abb171d14 100644 --- a/lib/bundler/vendor/uri/lib/uri/generic.rb +++ b/lib/bundler/vendor/uri/lib/uri/generic.rb @@ -737,12 +737,12 @@ module Bundler::URI end private :check_registry - def set_registry(v) #:nodoc: + def set_registry(v) # :nodoc: raise InvalidURIError, "cannot set registry" end protected :set_registry - def registry=(v) + def registry=(v) # :nodoc: raise InvalidURIError, "cannot set registry" end @@ -1133,17 +1133,16 @@ module Bundler::URI base.fragment=(nil) # RFC2396, Section 5.2, 4) - if !authority - base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path - else - # RFC2396, Section 5.2, 4) - base.set_path(rel.path) if rel.path + if authority + base.set_userinfo(rel.userinfo) + base.set_host(rel.host) + base.set_port(rel.port || base.default_port) + base.set_path(rel.path) + elsif base.path && rel.path + base.set_path(merge_path(base.path, rel.path)) end # RFC2396, Section 5.2, 7) - base.set_userinfo(rel.userinfo) if rel.userinfo - base.set_host(rel.host) if rel.host - base.set_port(rel.port) if rel.port base.query = rel.query if rel.query base.fragment=(rel.fragment) if rel.fragment @@ -1392,10 +1391,12 @@ module Bundler::URI end end + # Returns the hash value. def hash self.component_ary.hash end + # Compares with _oth_ for Hash. def eql?(oth) self.class == oth.class && parser == oth.parser && @@ -1438,7 +1439,7 @@ module Bundler::URI end end - def inspect + def inspect # :nodoc: "#<#{self.class} #{self}>" end diff --git a/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb b/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb index c199f911c4..229971f73c 100644 --- a/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +++ b/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb @@ -321,14 +321,14 @@ module Bundler::URI str.gsub(escaped) { [$&[1, 2]].pack('H2').force_encoding(enc) } end - @@to_s = Kernel.instance_method(:to_s) - if @@to_s.respond_to?(:bind_call) - def inspect - @@to_s.bind_call(self) + TO_S = Kernel.instance_method(:to_s) # :nodoc: + if TO_S.respond_to?(:bind_call) + def inspect # :nodoc: + TO_S.bind_call(self) end else - def inspect - @@to_s.bind(self).call + def inspect # :nodoc: + TO_S.bind(self).call end end diff --git a/lib/bundler/vendor/uri/lib/uri/version.rb b/lib/bundler/vendor/uri/lib/uri/version.rb index 4f4207f3d0..d4996a12e2 100644 --- a/lib/bundler/vendor/uri/lib/uri/version.rb +++ b/lib/bundler/vendor/uri/lib/uri/version.rb @@ -1,6 +1,6 @@ module Bundler::URI # :stopdoc: - VERSION_CODE = '010002'.freeze + VERSION_CODE = '010003'.freeze VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze # :startdoc: end diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index 64219c4886..96dd8374bb 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.6.5".freeze + VERSION = "2.6.6".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 005d240d8f..383d0cdc78 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -9,7 +9,7 @@ require "rbconfig" module Gem - VERSION = "3.6.5" + VERSION = "3.6.6" end # Must be first since it unloads the prelude from 1.9.2 diff --git a/lib/rubygems/local_remote_options.rb b/lib/rubygems/local_remote_options.rb index 51a61213a5..3b88c43149 100644 --- a/lib/rubygems/local_remote_options.rb +++ b/lib/rubygems/local_remote_options.rb @@ -134,13 +134,13 @@ module Gem::LocalRemoteOptions # Is local fetching enabled? def local? - options[:domain] == :local || options[:domain] == :both + [:local, :both].include?(options[:domain]) end ## # Is remote fetching enabled? def remote? - options[:domain] == :remote || options[:domain] == :both + [:remote, :both].include?(options[:domain]) end end diff --git a/lib/rubygems/rdoc.rb b/lib/rubygems/rdoc.rb index 977a51da01..3524b161b2 100644 --- a/lib/rubygems/rdoc.rb +++ b/lib/rubygems/rdoc.rb @@ -5,8 +5,6 @@ require_relative "../rubygems" begin require "rdoc/rubygems_hook" module Gem - RDoc = ::RDoc::RubygemsHook - ## # Returns whether RDoc defines its own install hooks through a RubyGems # plugin. This and whatever is guarded by it can be removed once no @@ -15,8 +13,14 @@ begin def self.rdoc_hooks_defined_via_plugin? Gem::Version.new(::RDoc::VERSION) >= Gem::Version.new("6.9.0") end - end - Gem.done_installing(&Gem::RDoc.method(:generation_hook)) unless Gem.rdoc_hooks_defined_via_plugin? + if rdoc_hooks_defined_via_plugin? + RDoc = ::RDoc::RubyGemsHook + else + RDoc = ::RDoc::RubygemsHook + + Gem.done_installing(&Gem::RDoc.method(:generation_hook)) + end + end rescue LoadError end diff --git a/lib/rubygems/vendor/uri/lib/uri/common.rb b/lib/rubygems/vendor/uri/lib/uri/common.rb index 4d2f78db84..f0755f5fdc 100644 --- a/lib/rubygems/vendor/uri/lib/uri/common.rb +++ b/lib/rubygems/vendor/uri/lib/uri/common.rb @@ -13,15 +13,19 @@ require_relative "rfc2396_parser" require_relative "rfc3986_parser" module Gem::URI + # The default parser instance for RFC 2396. RFC2396_PARSER = RFC2396_Parser.new Ractor.make_shareable(RFC2396_PARSER) if defined?(Ractor) + # The default parser instance for RFC 3986. RFC3986_PARSER = RFC3986_Parser.new Ractor.make_shareable(RFC3986_PARSER) if defined?(Ractor) + # The default parser instance. DEFAULT_PARSER = RFC3986_PARSER Ractor.make_shareable(DEFAULT_PARSER) if defined?(Ractor) + # Set the default parser instance. def self.parser=(parser = RFC3986_PARSER) remove_const(:Parser) if defined?(::Gem::URI::Parser) const_set("Parser", parser.class) @@ -40,7 +44,7 @@ module Gem::URI end self.parser = RFC3986_PARSER - def self.const_missing(const) + def self.const_missing(const) # :nodoc: if const == :REGEXP warn "Gem::URI::REGEXP is obsolete. Use Gem::URI::RFC2396_REGEXP explicitly.", uplevel: 1 if $VERBOSE Gem::URI::RFC2396_REGEXP @@ -87,7 +91,7 @@ module Gem::URI module_function :make_components_hash end - module Schemes + module Schemes # :nodoc: end private_constant :Schemes @@ -305,7 +309,7 @@ module Gem::URI 256.times do |i| TBLENCWWWCOMP_[-i.chr] = -('%%%02X' % i) end - TBLENCURICOMP_ = TBLENCWWWCOMP_.dup.freeze + TBLENCURICOMP_ = TBLENCWWWCOMP_.dup.freeze # :nodoc: TBLENCWWWCOMP_[' '] = '+' TBLENCWWWCOMP_.freeze TBLDECWWWCOMP_ = {} # :nodoc: @@ -424,7 +428,7 @@ module Gem::URI private_class_method :_decode_uri_component # Returns a URL-encoded string derived from the given - # {Enumerable}[https://docs.ruby-lang.org/en/master/Enumerable.html#module-Enumerable-label-Enumerable+in+Ruby+Classes] + # {Enumerable}[rdoc-ref:Enumerable@Enumerable+in+Ruby+Classes] # +enum+. # # The result is suitable for use as form data @@ -493,7 +497,7 @@ module Gem::URI # each +key+/+value+ pair is converted to one or more fields: # # - If +value+ is - # {Array-convertible}[https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html#label-Array-Convertible+Objects], + # {Array-convertible}[rdoc-ref:implicit_conversion.rdoc@Array-Convertible+Objects], # each element +ele+ in +value+ is paired with +key+ to form a field: # # name = Gem::URI.encode_www_form_component(key, enc) @@ -551,7 +555,7 @@ module Gem::URI # each subarray is a name/value pair (both are strings). # Each returned string has encoding +enc+, # and has had invalid characters removed via - # {String#scrub}[https://docs.ruby-lang.org/en/master/String.html#method-i-scrub]. + # {String#scrub}[rdoc-ref:String#scrub]. # # A simple example: # diff --git a/lib/rubygems/vendor/uri/lib/uri/generic.rb b/lib/rubygems/vendor/uri/lib/uri/generic.rb index 06da4a3b4e..2eabe2b4e3 100644 --- a/lib/rubygems/vendor/uri/lib/uri/generic.rb +++ b/lib/rubygems/vendor/uri/lib/uri/generic.rb @@ -737,12 +737,12 @@ module Gem::URI end private :check_registry - def set_registry(v) #:nodoc: + def set_registry(v) # :nodoc: raise InvalidURIError, "cannot set registry" end protected :set_registry - def registry=(v) + def registry=(v) # :nodoc: raise InvalidURIError, "cannot set registry" end @@ -1133,17 +1133,16 @@ module Gem::URI base.fragment=(nil) # RFC2396, Section 5.2, 4) - if !authority - base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path - else - # RFC2396, Section 5.2, 4) - base.set_path(rel.path) if rel.path + if authority + base.set_userinfo(rel.userinfo) + base.set_host(rel.host) + base.set_port(rel.port || base.default_port) + base.set_path(rel.path) + elsif base.path && rel.path + base.set_path(merge_path(base.path, rel.path)) end # RFC2396, Section 5.2, 7) - base.set_userinfo(rel.userinfo) if rel.userinfo - base.set_host(rel.host) if rel.host - base.set_port(rel.port) if rel.port base.query = rel.query if rel.query base.fragment=(rel.fragment) if rel.fragment @@ -1392,10 +1391,12 @@ module Gem::URI end end + # Returns the hash value. def hash self.component_ary.hash end + # Compares with _oth_ for Hash. def eql?(oth) self.class == oth.class && parser == oth.parser && @@ -1438,7 +1439,7 @@ module Gem::URI end end - def inspect + def inspect # :nodoc: "#<#{self.class} #{self}>" end diff --git a/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb b/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb index a9b326e6b0..04a1d0c869 100644 --- a/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb +++ b/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb @@ -321,14 +321,14 @@ module Gem::URI str.gsub(escaped) { [$&[1, 2]].pack('H2').force_encoding(enc) } end - @@to_s = Kernel.instance_method(:to_s) - if @@to_s.respond_to?(:bind_call) - def inspect - @@to_s.bind_call(self) + TO_S = Kernel.instance_method(:to_s) # :nodoc: + if TO_S.respond_to?(:bind_call) + def inspect # :nodoc: + TO_S.bind_call(self) end else - def inspect - @@to_s.bind(self).call + def inspect # :nodoc: + TO_S.bind(self).call end end diff --git a/lib/rubygems/vendor/uri/lib/uri/version.rb b/lib/rubygems/vendor/uri/lib/uri/version.rb index 72268badfd..c2f617ce25 100644 --- a/lib/rubygems/vendor/uri/lib/uri/version.rb +++ b/lib/rubygems/vendor/uri/lib/uri/version.rb @@ -1,6 +1,6 @@ module Gem::URI # :stopdoc: - VERSION_CODE = '010002'.freeze + VERSION_CODE = '010003'.freeze VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze # :startdoc: end diff --git a/spec/bundler/bundler/compact_index_client/updater_spec.rb b/spec/bundler/bundler/compact_index_client/updater_spec.rb index 87a73d993f..fd63a652a4 100644 --- a/spec/bundler/bundler/compact_index_client/updater_spec.rb +++ b/spec/bundler/bundler/compact_index_client/updater_spec.rb @@ -115,6 +115,23 @@ RSpec.describe Bundler::CompactIndexClient::Updater do expect(local_path.read).to eq(full_body) expect(etag_path.read).to eq("NewEtag") end + + it "tries the request again if the partial response is blank" do + allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" } + allow(response).to receive(:body) { "" } + allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true } + expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response) + + full_response = double(:full_response, body: full_body, is_a?: false) + allow(full_response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" } + allow(full_response).to receive(:[]).with("ETag") { '"NewEtag"' } + expect(fetcher).to receive(:call).once.with(remote_path, { "If-None-Match" => '"LocalEtag"' }).and_return(full_response) + + updater.update(remote_path, local_path, etag_path) + + expect(local_path.read).to eq(full_body) + expect(etag_path.read).to eq("NewEtag") + end end context "without an etag file" do diff --git a/spec/bundler/bundler/shared_helpers_spec.rb b/spec/bundler/bundler/shared_helpers_spec.rb index 6db8cd6783..604141bfc5 100644 --- a/spec/bundler/bundler/shared_helpers_spec.rb +++ b/spec/bundler/bundler/shared_helpers_spec.rb @@ -354,7 +354,7 @@ RSpec.describe Bundler::SharedHelpers do it "ENV['PATH'] should only contain one instance of bundle bin path" do subject.set_bundle_environment - paths = (ENV["PATH"]).split(File::PATH_SEPARATOR) + paths = ENV["PATH"].split(File::PATH_SEPARATOR) expect(paths.count(bundle_path)).to eq(1) end end diff --git a/spec/bundler/bundler/source/git/git_proxy_spec.rb b/spec/bundler/bundler/source/git/git_proxy_spec.rb index f7c883eed4..c350904994 100644 --- a/spec/bundler/bundler/source/git/git_proxy_spec.rb +++ b/spec/bundler/bundler/source/git/git_proxy_spec.rb @@ -211,4 +211,45 @@ RSpec.describe Bundler::Source::Git::GitProxy do subject.checkout end end + + describe "#installed_to?" do + let(:destination) { "install/dir" } + let(:destination_dir_exists) { true } + let(:children) { ["gem.gemspec", "README.me", ".git", "Rakefile"] } + + before do + allow(Dir).to receive(:exist?).with(destination).and_return(destination_dir_exists) + allow(Dir).to receive(:children).with(destination).and_return(children) + end + + context "when destination dir exists with children other than just .git" do + it "returns true" do + expect(git_proxy.installed_to?(destination)).to be true + end + end + + context "when destination dir does not exist" do + let(:destination_dir_exists) { false } + + it "returns false" do + expect(git_proxy.installed_to?(destination)).to be false + end + end + + context "when destination dir is empty" do + let(:children) { [] } + + it "returns false" do + expect(git_proxy.installed_to?(destination)).to be false + end + end + + context "when destination dir has only .git directory" do + let(:children) { [".git"] } + + it "returns false" do + expect(git_proxy.installed_to?(destination)).to be false + end + end + end end diff --git a/spec/bundler/bundler/source/git_spec.rb b/spec/bundler/bundler/source/git_spec.rb index feef54bbf4..14e91c6bdc 100644 --- a/spec/bundler/bundler/source/git_spec.rb +++ b/spec/bundler/bundler/source/git_spec.rb @@ -70,4 +70,54 @@ RSpec.describe Bundler::Source::Git do end end end + + describe "#locked_revision_checked_out?" do + let(:revision) { "abc" } + let(:git_proxy_revision) { revision } + let(:git_proxy_installed) { true } + let(:git_proxy) { subject.send(:git_proxy) } + let(:options) do + { + "uri" => uri, + "revision" => revision, + } + end + + before do + allow(git_proxy).to receive(:revision).and_return(git_proxy_revision) + allow(git_proxy).to receive(:installed_to?).with(subject.install_path).and_return(git_proxy_installed) + end + + context "when the locked revision is checked out" do + it "returns true" do + expect(subject.send(:locked_revision_checked_out?)).to be true + end + end + + context "when no revision is provided" do + let(:options) do + { "uri" => uri } + end + + it "returns falsey value" do + expect(subject.send(:locked_revision_checked_out?)).to be_falsey + end + end + + context "when the git proxy revision is different than the git revision" do + let(:git_proxy_revision) { revision.next } + + it "returns falsey value" do + expect(subject.send(:locked_revision_checked_out?)).to be_falsey + end + end + + context "when the gem hasn't been installed" do + let(:git_proxy_installed) { false } + + it "returns falsey value" do + expect(subject.send(:locked_revision_checked_out?)).to be_falsey + end + end + end end diff --git a/spec/bundler/cache/gems_spec.rb b/spec/bundler/cache/gems_spec.rb index c68b20225a..780972b9af 100644 --- a/spec/bundler/cache/gems_spec.rb +++ b/spec/bundler/cache/gems_spec.rb @@ -291,7 +291,7 @@ RSpec.describe "bundle cache" do expect(cached_gem("platform_specific-1.0-java")).to exist end - simulate_new_machine + pristine_system_gems :bundler simulate_platform "x86-darwin-100" do install_gemfile <<-G @@ -312,7 +312,8 @@ RSpec.describe "bundle cache" do path: cached_myrack.parent, rubygems_version: "1.3.2" - simulate_new_machine + FileUtils.rm_r default_bundle_path + system_gems :bundler FileUtils.rm bundled_app_lock bundle :install, raise_on_error: false @@ -344,7 +345,8 @@ RSpec.describe "bundle cache" do c.checksum gem_repo1, "myrack", "1.0.0" end - simulate_new_machine + FileUtils.rm_r default_bundle_path + system_gems :bundler lockfile <<-L GEM @@ -369,7 +371,7 @@ RSpec.describe "bundle cache" do setup_main_repo cached_gem("myrack-1.0.0").rmtree build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache") - simulate_new_machine + pristine_system_gems :bundler lockfile <<-L GEM diff --git a/spec/bundler/cache/git_spec.rb b/spec/bundler/cache/git_spec.rb index 38333c0219..b337882a6e 100644 --- a/spec/bundler/cache/git_spec.rb +++ b/spec/bundler/cache/git_spec.rb @@ -28,7 +28,7 @@ RSpec.describe "bundle cache with git" do expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.bundlecache")).to be_file - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") expect(the_bundle).to include_gems "foo 1.0" end @@ -49,7 +49,7 @@ RSpec.describe "bundle cache with git" do expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") expect(the_bundle).to include_gems "foo 1.0" end @@ -66,7 +66,7 @@ RSpec.describe "bundle cache with git" do bundle :cache expect(out).to include "Updating files in vendor/cache" - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") expect(the_bundle).to include_gems "foo 1.0" end @@ -95,7 +95,7 @@ RSpec.describe "bundle cache with git" do expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist expect(bundled_app("vendor/cache/foo-1.0-#{old_ref}")).not_to exist - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") run "require 'foo'" expect(out).to eq("CACHE") end @@ -124,7 +124,7 @@ RSpec.describe "bundle cache with git" do expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist expect(bundled_app("vendor/cache/foo-1.0-#{old_ref}")).not_to exist - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") run "require 'foo'" expect(out).to eq("CACHE") end @@ -164,7 +164,7 @@ RSpec.describe "bundle cache with git" do bundle "config set path vendor/bundle" bundle :install - simulate_new_machine + pristine_system_gems :bundler with_path_as "" do bundle "config set deployment true" bundle "install --local" @@ -181,10 +181,8 @@ RSpec.describe "bundle cache with git" do G bundle "config set cache_all true" bundle :cache, "all-platforms" => true - FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s - FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/foo-1.0-*")).first.to_s - simulate_new_machine + pristine_system_gems :bundler bundle "config set frozen true" bundle "install --local --verbose" expect(out).to_not include("Fetching") @@ -200,12 +198,9 @@ RSpec.describe "bundle cache with git" do G bundle "config set cache_all true" bundle :cache, "all-platforms" => true - FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s - FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/foo-1.0-*")).first.to_s - simulate_new_machine + pristine_system_gems :bundler bundle "config set frozen true" - FileUtils.rm_rf "#{default_bundle_path}/cache/bundler/git/foo-1.0-*" bundle "install --local --verbose" expect(out).to_not include("Fetching") expect(the_bundle).to include_gem "foo 1.0" @@ -220,12 +215,9 @@ RSpec.describe "bundle cache with git" do G bundle "config set cache_all true" bundle :cache, "all-platforms" => true - FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s - FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/foo-1.0-*")).first.to_s - simulate_new_machine + pristine_system_gems :bundler bundle "config set frozen true" - FileUtils.rm_rf "#{default_bundle_path}/cache/bundler/git/foo-1.0-*" # Remove untracked files (including the empty refs dir in the cache) Dir.chdir(bundled_app) do @@ -257,7 +249,7 @@ RSpec.describe "bundle cache with git" do # Simulate old cache by copying the real cache folder to vendor/cache FileUtils.mkdir_p bundled_app("vendor/cache") FileUtils.cp_r "#{Dir.glob(vendored_gems("cache/bundler/git/foo-1.0-*")).first}/.", cache_dir - FileUtils.rm_rf bundled_app("vendor/bundle") + FileUtils.rm_r bundled_app("vendor/bundle") bundle "install --local --verbose" expect(err).to include("Installing from cache in old \"bare repository\" format for compatibility") @@ -289,7 +281,7 @@ RSpec.describe "bundle cache with git" do # Simulate old cache by copying the real cache folder to vendor/cache FileUtils.mkdir_p bundled_app("vendor/cache") FileUtils.cp_r "#{Dir.glob(vendored_gems("cache/bundler/git/foo-1.0-*")).first}/.", cache_dir - FileUtils.rm_rf bundled_app("vendor/bundle") + FileUtils.rm_r bundled_app("vendor/bundle") bundle "install --verbose" expect(out).to include("Fetching") @@ -388,7 +380,7 @@ RSpec.describe "bundle cache with git" do bundle "config set cache_all true" bundle :cache, "all-platforms" => true, :install => false - simulate_new_machine + pristine_system_gems :bundler with_path_as "" do bundle "config set deployment true" bundle :install, local: true @@ -431,7 +423,7 @@ RSpec.describe "bundle cache with git" do # Simulate an old incorrect situation where vendor/cache would be the install location of git gems FileUtils.mkdir_p bundled_app("vendor/cache") FileUtils.cp_r git_path, bundled_app("vendor/cache/foo-1.0-#{path_revision}") - FileUtils.rm_rf bundled_app("vendor/cache/foo-1.0-#{path_revision}/.git") + FileUtils.rm_r bundled_app("vendor/cache/foo-1.0-#{path_revision}/.git") bundle :install, env: { "BUNDLE_DEPLOYMENT" => "true", "BUNDLE_CACHE_ALL" => "true" } end diff --git a/spec/bundler/commands/add_spec.rb b/spec/bundler/commands/add_spec.rb index e63b0b9658..2676b06c78 100644 --- a/spec/bundler/commands/add_spec.rb +++ b/spec/bundler/commands/add_spec.rb @@ -88,25 +88,25 @@ RSpec.describe "bundle add" do describe "with --require" do it "adds the require param for the gem" do bundle "add 'foo' --require=foo/engine" - expect(bundled_app_gemfile.read).to match(%r{gem "foo",(?: .*,) :require => "foo\/engine"}) + expect(bundled_app_gemfile.read).to match(%r{gem "foo",(?: .*,) require: "foo\/engine"}) end it "converts false to a boolean" do bundle "add 'foo' --require=false" - expect(bundled_app_gemfile.read).to match(/gem "foo",(?: .*,) :require => false/) + expect(bundled_app_gemfile.read).to match(/gem "foo",(?: .*,) require: false/) end end describe "with --group" do it "adds dependency for the specified group" do bundle "add 'foo' --group='development'" - expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", :group => :development/) + expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", group: :development/) expect(the_bundle).to include_gems "foo 2.0" end it "adds dependency to more than one group" do bundle "add 'foo' --group='development, test'" - expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", :groups => \[:development, :test\]/) + expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", groups: \[:development, :test\]/) expect(the_bundle).to include_gems "foo 2.0" end end @@ -115,7 +115,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified source" do bundle "add 'foo' --source='https://gem.repo2'" - expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :source => "https://gem.repo2"}) + expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", source: "https://gem.repo2"}) expect(the_bundle).to include_gems "foo 2.0" end end @@ -124,7 +124,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified path" do bundle "add 'foo' --path='#{lib_path("foo-2.0")}'" - expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", :path => "#{lib_path("foo-2.0")}"/) + expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", path: "#{lib_path("foo-2.0")}"/) expect(the_bundle).to include_gems "foo 2.0" end end @@ -133,7 +133,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified git source" do bundle "add foo --git=#{lib_path("foo-2.0")}" - expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}"/) + expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}"/) expect(the_bundle).to include_gems "foo 2.0" end end @@ -146,7 +146,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified git source and branch" do bundle "add foo --git=#{lib_path("foo-2.0")} --branch=test" - expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}", :branch => "test"/) + expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}", branch: "test"/) expect(the_bundle).to include_gems "foo 2.0" end end @@ -155,7 +155,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified git source and branch" do bundle "add foo --git=#{lib_path("foo-2.0")} --ref=#{revision_for(lib_path("foo-2.0"))}" - expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2\.0", :git => "#{lib_path("foo-2.0")}", :ref => "#{revision_for(lib_path("foo-2.0"))}"/) + expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2\.0", git: "#{lib_path("foo-2.0")}", ref: "#{revision_for(lib_path("foo-2.0"))}"/) expect(the_bundle).to include_gems "foo 2.0" end end @@ -164,7 +164,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified github source" do bundle "add rake --github=ruby/rake" - expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake"}) + expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake"}) end end @@ -172,7 +172,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified github source and branch" do bundle "add rake --github=ruby/rake --branch=master" - expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :branch => "master"}) + expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", branch: "master"}) end end @@ -180,7 +180,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified github source and ref" do bundle "add rake --github=ruby/rake --ref=5c60da8" - expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :ref => "5c60da8"}) + expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", ref: "5c60da8"}) end end @@ -188,7 +188,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified git source" do bundle "add foo --git=#{lib_path("foo-2.0")} --glob='./*.gemspec'" - expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}", :glob => "\./\*\.gemspec"}) + expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}", glob: "\./\*\.gemspec"}) expect(the_bundle).to include_gems "foo 2.0" end end @@ -201,7 +201,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified git source and branch" do bundle "add foo --git=#{lib_path("foo-2.0")} --branch=test --glob='./*.gemspec'" - expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}", :branch => "test", :glob => "\./\*\.gemspec"}) + expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", git: "#{lib_path("foo-2.0")}", branch: "test", glob: "\./\*\.gemspec"}) expect(the_bundle).to include_gems "foo 2.0" end end @@ -210,7 +210,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified git source and branch" do bundle "add foo --git=#{lib_path("foo-2.0")} --ref=#{revision_for(lib_path("foo-2.0"))} --glob='./*.gemspec'" - expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2\.0", :git => "#{lib_path("foo-2.0")}", :ref => "#{revision_for(lib_path("foo-2.0"))}", :glob => "\./\*\.gemspec"}) + expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2\.0", git: "#{lib_path("foo-2.0")}", ref: "#{revision_for(lib_path("foo-2.0"))}", glob: "\./\*\.gemspec"}) expect(the_bundle).to include_gems "foo 2.0" end end @@ -219,7 +219,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified github source" do bundle "add rake --github=ruby/rake --glob='./*.gemspec'" - expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :glob => "\.\/\*\.gemspec"}) + expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", glob: "\.\/\*\.gemspec"}) end end @@ -227,7 +227,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified github source and branch" do bundle "add rake --github=ruby/rake --branch=master --glob='./*.gemspec'" - expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :branch => "master", :glob => "\.\/\*\.gemspec"}) + expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", branch: "master", glob: "\.\/\*\.gemspec"}) end end @@ -235,7 +235,7 @@ RSpec.describe "bundle add" do it "adds dependency with specified github source and ref" do bundle "add rake --github=ruby/rake --ref=5c60da8 --glob='./*.gemspec'" - expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :ref => "5c60da8", :glob => "\.\/\*\.gemspec"}) + expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", github: "ruby\/rake", ref: "5c60da8", glob: "\.\/\*\.gemspec"}) end end @@ -250,7 +250,7 @@ RSpec.describe "bundle add" do it "using combination of short form options works like long form" do bundle "add 'foo' -s='https://gem.repo2' -g='development' -v='~>1.0'" - expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 1.0", :group => :development, :source => "https://gem.repo2") + expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 1.0", group: :development, source: "https://gem.repo2") expect(the_bundle).to include_gems "foo 1.1" end diff --git a/spec/bundler/commands/cache_spec.rb b/spec/bundler/commands/cache_spec.rb index ee05bf2e49..7dbaae766c 100644 --- a/spec/bundler/commands/cache_spec.rb +++ b/spec/bundler/commands/cache_spec.rb @@ -344,8 +344,8 @@ RSpec.describe "bundle install with gem sources" do G bundle :cache - simulate_new_machine - FileUtils.rm_rf gem_repo2 + pristine_system_gems :bundler + FileUtils.rm_r gem_repo2 bundle "install --local" expect(the_bundle).to include_gems "myrack 1.0.0" @@ -359,8 +359,8 @@ RSpec.describe "bundle install with gem sources" do G bundle :cache - simulate_new_machine - FileUtils.rm_rf gem_repo2 + pristine_system_gems :bundler + FileUtils.rm_r gem_repo2 bundle "config set --local deployment true" bundle "config set --local path vendor/bundle" @@ -376,8 +376,8 @@ RSpec.describe "bundle install with gem sources" do G bundle :cache - simulate_new_machine - FileUtils.rm_rf gem_repo2 + pristine_system_gems :bundler + FileUtils.rm_r gem_repo2 bundle "config set --local cache_all_platforms true" bundle "config set --local path vendor/bundle" @@ -433,12 +433,11 @@ RSpec.describe "bundle install with gem sources" do bundle "config set path vendor/bundle" bundle :cache, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } - build_repo4 do - # simulate removal of all remote gems - end + # simulate removal of all remote gems + empty_repo4 # delete compact index cache - FileUtils.rm_rf home(".bundle/cache/compact_index") + FileUtils.rm_r home(".bundle/cache/compact_index") bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } @@ -471,7 +470,7 @@ RSpec.describe "bundle install with gem sources" do bundle :cache end - simulate_new_machine + pristine_system_gems :bundler bundle "config set --local force_ruby_platform true" diff --git a/spec/bundler/commands/check_spec.rb b/spec/bundler/commands/check_spec.rb index 78c2aef58b..71bc4e39d7 100644 --- a/spec/bundler/commands/check_spec.rb +++ b/spec/bundler/commands/check_spec.rb @@ -95,7 +95,7 @@ RSpec.describe "bundle check" do gem "foo", git: "#{lib_path("foo")}" G - FileUtils.rm_rf bundled_app("vendor/bundle") + FileUtils.rm_r bundled_app("vendor/bundle") bundle :check, raise_on_error: false expect(exitstatus).to eq 1 expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.") @@ -281,7 +281,7 @@ RSpec.describe "bundle check" do G bundle "install --path vendor/bundle" - FileUtils.rm_rf(bundled_app(".bundle")) + FileUtils.rm_r(bundled_app(".bundle")) end it "returns success" do @@ -328,7 +328,8 @@ RSpec.describe "bundle check" do end it "shows what is missing with the current Gemfile if it is not satisfied" do - simulate_new_machine + FileUtils.rm_r default_bundle_path + system_gems :bundler bundle :check, raise_on_error: false expect(err).to match(/The following gems are missing/) expect(err).to include("* myrack (1.0") diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb index c27766835e..2559be0205 100644 --- a/spec/bundler/commands/clean_spec.rb +++ b/spec/bundler/commands/clean_spec.rb @@ -352,8 +352,8 @@ RSpec.describe "bundle clean" do bundle "install" FileUtils.rm(vendored_gems("bin/myrackup")) - FileUtils.rm_rf(vendored_gems("gems/thin-1.0")) - FileUtils.rm_rf(vendored_gems("gems/myrack-1.0.0")) + FileUtils.rm_r(vendored_gems("gems/thin-1.0")) + FileUtils.rm_r(vendored_gems("gems/myrack-1.0.0")) bundle :clean diff --git a/spec/bundler/commands/console_spec.rb b/spec/bundler/commands/console_spec.rb index dd7461ced4..dbfbec874f 100644 --- a/spec/bundler/commands/console_spec.rb +++ b/spec/bundler/commands/console_spec.rb @@ -35,6 +35,8 @@ RSpec.describe "bundle console", readline: true do end RUBY end + + build_dummy_irb end end @@ -46,7 +48,8 @@ RSpec.describe "bundle console", readline: true do end install_gemfile <<-G - source "https://gem.repo1" + source "https://gem.repo2" + gem "irb" path "#{lib_path}" do gem "loadfuuu", require: true end @@ -66,6 +69,7 @@ RSpec.describe "bundle console", readline: true do before do install_gemfile <<-G source "https://gem.repo2" + gem "irb" gem "myrack" gem "activesupport", :group => :test gem "myrack_middleware", :group => :development @@ -81,16 +85,19 @@ RSpec.describe "bundle console", readline: true do end it "uses IRB as default console" do + skip "Does not work in a ruby-core context if irb is in the default $LOAD_PATH because it enables the real IRB, not our dummy one" if ruby_core? && Gem.ruby_version < Gem::Version.new("3.5.0.a") + bundle "console" do |input, _, _| - input.puts("__FILE__") + input.puts("__method__") input.puts("exit") end - expect(out).to include("(irb)") + expect(out).to include("__irb__") end it "starts another REPL if configured as such" do install_gemfile <<-G source "https://gem.repo2" + gem "irb" gem "pry" G bundle "config set console pry" @@ -103,14 +110,16 @@ RSpec.describe "bundle console", readline: true do end it "falls back to IRB if the other REPL isn't available" do + skip "Does not work in a ruby-core context if irb is in the default $LOAD_PATH because it enables the real IRB, not our dummy one" if ruby_core? && Gem.ruby_version < Gem::Version.new("3.5.0.a") + bundle "config set console pry" # make sure pry isn't there bundle "console" do |input, _, _| - input.puts("__FILE__") + input.puts("__method__") input.puts("exit") end - expect(out).to include("(irb)") + expect(out).to include("__irb__") end it "does not try IRB twice if no console is configured and IRB is not available" do @@ -161,6 +170,7 @@ RSpec.describe "bundle console", readline: true do it "performs an automatic bundle install" do gemfile <<-G source "https://gem.repo2" + gem "irb" gem "myrack" gem "activesupport", :group => :test gem "myrack_middleware", :group => :development diff --git a/spec/bundler/commands/doctor_spec.rb b/spec/bundler/commands/doctor_spec.rb index c040602bde..7c30d0e91b 100644 --- a/spec/bundler/commands/doctor_spec.rb +++ b/spec/bundler/commands/doctor_spec.rb @@ -14,7 +14,7 @@ RSpec.describe "bundle doctor" do @stdout = StringIO.new - [:error, :warn].each do |method| + [:error, :warn, :info].each do |method| allow(Bundler.ui).to receive(method).and_wrap_original do |m, message| m.call message @stdout.puts message @@ -45,20 +45,20 @@ RSpec.describe "bundle doctor" do allow(File).to receive(:writable?).with(File.expand_path("..", Gem.default_dir)) end - it "exits with no message if the installed gem has no C extensions" do + it "exits with a success message if the installed gem has no C extensions" do doctor = Bundler::CLI::Doctor.new({}) allow(doctor).to receive(:lookup_with_fiddle).and_return(false) expect { doctor.run }.not_to raise_error - expect(@stdout.string).to be_empty + expect(@stdout.string).to include("No issues") end - it "exits with no message if the installed gem's C extension dylib breakage is fine" do + it "exits with a success message if the installed gem's C extension dylib breakage is fine" do doctor = Bundler::CLI::Doctor.new({}) expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/myrack/myrack.bundle"] expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/lib/libSystem.dylib"] allow(doctor).to receive(:lookup_with_fiddle).with("/usr/lib/libSystem.dylib").and_return(false) expect { doctor.run }.not_to raise_error - expect(@stdout.string).to be_empty + expect(@stdout.string).to include("No issues") end it "exits with a message if one of the linked libraries is missing" do @@ -105,7 +105,7 @@ RSpec.describe "bundle doctor" do allow(File).to receive(:stat).with(@unwritable_file) { @stat } end - it "exits with an error if home contains files that are not readable/writable" do + it "exits with an error if home contains files that are not readable" do doctor = Bundler::CLI::Doctor.new({}) allow(doctor).to receive(:lookup_with_fiddle).and_return(false) allow(@stat).to receive(:uid) { Process.uid } @@ -113,11 +113,24 @@ RSpec.describe "bundle doctor" do allow(File).to receive(:readable?).with(@unwritable_file) { false } expect { doctor.run }.not_to raise_error expect(@stdout.string).to include( - "Files exist in the Bundler home that are not readable/writable by the current user. These files are:\n - #{@unwritable_file}" + "Files exist in the Bundler home that are not readable by the current user. These files are:\n - #{@unwritable_file}" ) expect(@stdout.string).not_to include("No issues") end + it "exits without an error if home contains files that are not writable" do + doctor = Bundler::CLI::Doctor.new({}) + allow(doctor).to receive(:lookup_with_fiddle).and_return(false) + allow(@stat).to receive(:uid) { Process.uid } + allow(File).to receive(:writable?).with(@unwritable_file) { false } + allow(File).to receive(:readable?).with(@unwritable_file) { true } + expect { doctor.run }.not_to raise_error + expect(@stdout.string).not_to include( + "Files exist in the Bundler home that are not readable by the current user. These files are:\n - #{@unwritable_file}" + ) + expect(@stdout.string).to include("No issues") + end + context "when home contains files that are not owned by the current process", :permissions do before(:each) do allow(@stat).to receive(:uid) { 0o0000 } @@ -130,7 +143,7 @@ RSpec.describe "bundle doctor" do allow(File).to receive(:readable?).with(@unwritable_file) { false } expect { doctor.run }.not_to raise_error expect(@stdout.string).to include( - "Files exist in the Bundler home that are owned by another user, and are not readable/writable. These files are:\n - #{@unwritable_file}" + "Files exist in the Bundler home that are owned by another user, and are not readable. These files are:\n - #{@unwritable_file}" ) expect(@stdout.string).not_to include("No issues") end @@ -142,7 +155,7 @@ RSpec.describe "bundle doctor" do allow(File).to receive(:readable?).with(@unwritable_file) { true } expect { doctor.run }.not_to raise_error expect(@stdout.string).to include( - "Files exist in the Bundler home that are owned by another user, but are still readable/writable. These files are:\n - #{@unwritable_file}" + "Files exist in the Bundler home that are owned by another user, but are still readable. These files are:\n - #{@unwritable_file}" ) expect(@stdout.string).not_to include("No issues") end diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb index e2b965c34c..62421410ed 100644 --- a/spec/bundler/commands/exec_spec.rb +++ b/spec/bundler/commands/exec_spec.rb @@ -193,74 +193,68 @@ RSpec.describe "bundle exec" do end context "with default gems" do - let(:default_irb_version) { ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", raise_on_error: false } + let(:default_erb_version) { ruby "gem 'erb', '< 999999'; require 'erb/version'; puts Erb::VERSION", raise_on_error: false } context "when not specified in Gemfile" do before do - skip "irb isn't a default gem" if default_irb_version.empty? - install_gemfile "source \"https://gem.repo1\"" end it "uses version provided by ruby" do - bundle "exec irb --version" + bundle "exec erb --version" - expect(out).to include(default_irb_version) + expect(out).to include(default_erb_version) end end context "when specified in Gemfile directly" do - let(:specified_irb_version) { "0.9.6" } + let(:specified_erb_version) { "2.0.0" } before do - skip "irb isn't a default gem" if default_irb_version.empty? - build_repo2 do - build_gem "irb", specified_irb_version do |s| - s.executables = "irb" + build_gem "erb", specified_erb_version do |s| + s.executables = "erb" end end install_gemfile <<-G source "https://gem.repo2" - gem "irb", "#{specified_irb_version}" + gem "erb", "#{specified_erb_version}" G end it "uses version specified" do - bundle "exec irb --version" + bundle "exec erb --version", artifice: nil - expect(out).to eq(specified_irb_version) + expect(out).to eq(specified_erb_version) expect(err).to be_empty end end context "when specified in Gemfile indirectly" do - let(:indirect_irb_version) { "0.9.6" } + let(:indirect_erb_version) { "2.0.0" } before do - skip "irb isn't a default gem" if default_irb_version.empty? - build_repo2 do - build_gem "irb", indirect_irb_version do |s| - s.executables = "irb" + build_gem "erb", indirect_erb_version do |s| + s.executables = "erb" end - build_gem "gem_depending_on_old_irb" do |s| - s.add_dependency "irb", indirect_irb_version + build_gem "gem_depending_on_old_erb" do |s| + s.add_dependency "erb", indirect_erb_version end end install_gemfile <<-G source "https://gem.repo2" - gem "gem_depending_on_old_irb" + gem "gem_depending_on_old_erb" G - bundle "exec irb --version" + bundle "exec erb --version", artifice: nil end it "uses resolved version" do - expect(out).to eq(indirect_irb_version) + expect(out).to eq(indirect_erb_version) expect(err).to be_empty end end @@ -657,7 +651,7 @@ RSpec.describe "bundle exec" do gem "foo", :path => "#{lib_path("foo-1.0")}" G - bundle "exec irb", raise_on_error: false + bundle "exec erb", raise_on_error: false expect(err).to match("The gemspec at #{lib_path("foo-1.0").join("foo.gemspec")} is not valid") expect(err).to match(/missing value for attribute rubygems_version|rubygems_version must not be nil/) @@ -1262,7 +1256,7 @@ RSpec.describe "bundle exec" do end it "allows calling bundle install after removing gem.build_complete" do - FileUtils.rm_rf Dir[bundled_app(".bundle/**/gem.build_complete")] + FileUtils.rm_r Dir[bundled_app(".bundle/**/gem.build_complete")] bundle "exec #{Gem.ruby} -S bundle install" end end diff --git a/spec/bundler/commands/info_spec.rb b/spec/bundler/commands/info_spec.rb index 4016cc5291..478cf06405 100644 --- a/spec/bundler/commands/info_spec.rb +++ b/spec/bundler/commands/info_spec.rb @@ -70,7 +70,7 @@ RSpec.describe "bundle info" do end it "warns if path does not exist on disk, but specification is there" do - FileUtils.rm_rf(default_bundle_path("gems", "rails-2.3.2")) + FileUtils.rm_r(default_bundle_path("gems", "rails-2.3.2")) bundle "info rails --path" diff --git a/spec/bundler/commands/inject_spec.rb b/spec/bundler/commands/inject_spec.rb index 193806a02a..4998b6e89d 100644 --- a/spec/bundler/commands/inject_spec.rb +++ b/spec/bundler/commands/inject_spec.rb @@ -55,7 +55,7 @@ Usage: "bundle inject GEM VERSION" it "add gem with source option in gemfile" do bundle "inject 'foo' '>0' --source https://gem.repo1" gemfile = bundled_app_gemfile.read - str = "gem \"foo\", \"> 0\", :source => \"https://gem.repo1\"" + str = "gem \"foo\", \"> 0\", source: \"https://gem.repo1\"" expect(gemfile).to include str end end @@ -64,14 +64,14 @@ Usage: "bundle inject GEM VERSION" it "add gem with group option in gemfile" do bundle "inject 'myrack-obama' '>0' --group=development" gemfile = bundled_app_gemfile.read - str = "gem \"myrack-obama\", \"> 0\", :group => :development" + str = "gem \"myrack-obama\", \"> 0\", group: :development" expect(gemfile).to include str end it "add gem with multiple groups in gemfile" do bundle "inject 'myrack-obama' '>0' --group=development,test" gemfile = bundled_app_gemfile.read - str = "gem \"myrack-obama\", \"> 0\", :groups => [:development, :test]" + str = "gem \"myrack-obama\", \"> 0\", groups: [:development, :test]" expect(gemfile).to include str end end diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb index 0eafee3b12..c4861e9dbc 100644 --- a/spec/bundler/commands/install_spec.rb +++ b/spec/bundler/commands/install_spec.rb @@ -100,7 +100,7 @@ RSpec.describe "bundle install with gem sources" do gem 'myrack' G - FileUtils.rm_rf(default_bundle_path("gems/myrack-1.0.0")) + FileUtils.rm_r(default_bundle_path("gems/myrack-1.0.0")) bundle "install --verbose" @@ -337,13 +337,13 @@ RSpec.describe "bundle install with gem sources" do it "allows running bundle install --system without deleting foo", bundler: "< 3" do bundle "install --path vendor" bundle "install --system" - FileUtils.rm_rf(bundled_app("vendor")) + FileUtils.rm_r(bundled_app("vendor")) expect(the_bundle).to include_gems "myrack 1.0" end it "allows running bundle install --system after deleting foo", bundler: "< 3" do bundle "install --path vendor" - FileUtils.rm_rf(bundled_app("vendor")) + FileUtils.rm_r(bundled_app("vendor")) bundle "install --system" expect(the_bundle).to include_gems "myrack 1.0" end @@ -1369,6 +1369,7 @@ RSpec.describe "bundle install with gem sources" do bundle "install --verbose" expect(out).to include("re-resolving dependencies because your lockfile does not include the current platform") + expect(out).not_to include("you are adding a new platform to your lockfile") expect(lockfile).to eq <<~L GEM @@ -1549,88 +1550,94 @@ RSpec.describe "bundle install with gem sources" do end context "with --prefer-local flag" do - before do - build_repo4 do - build_gem "foo", "1.0.1" - build_gem "foo", "1.0.0" - build_gem "bar", "1.0.0" + context "and gems available locally" do + before do + build_repo4 do + build_gem "foo", "1.0.1" + build_gem "foo", "1.0.0" + build_gem "bar", "1.0.0" - build_gem "a", "1.0.0" do |s| - s.add_dependency "foo", "~> 1.0.0" + build_gem "a", "1.0.0" do |s| + s.add_dependency "foo", "~> 1.0.0" + end + + build_gem "b", "1.0.0" do |s| + s.add_dependency "foo", "~> 1.0.1" + end end - build_gem "b", "1.0.0" do |s| - s.add_dependency "foo", "~> 1.0.1" + system_gems "foo-1.0.0", path: default_bundle_path, gem_repo: gem_repo4 + end + + it "fetches remote sources when not available locally" do + install_gemfile <<-G, "prefer-local": true, verbose: true + source "https://gem.repo4" + + gem "foo" + gem "bar" + G + + expect(out).to include("Using foo 1.0.0").and include("Fetching bar 1.0.0").and include("Installing bar 1.0.0") + expect(last_command).to be_success + end + + it "fetches remote sources when local version does not match requirements" do + install_gemfile <<-G, "prefer-local": true, verbose: true + source "https://gem.repo4" + + gem "foo", "1.0.1" + gem "bar" + G + + expect(out).to include("Fetching foo 1.0.1").and include("Installing foo 1.0.1").and include("Fetching bar 1.0.0").and include("Installing bar 1.0.0") + expect(last_command).to be_success + end + + it "uses the locally available version for sub-dependencies when possible" do + install_gemfile <<-G, "prefer-local": true, verbose: true + source "https://gem.repo4" + + gem "a" + G + + expect(out).to include("Using foo 1.0.0").and include("Fetching a 1.0.0").and include("Installing a 1.0.0") + expect(last_command).to be_success + end + + it "fetches remote sources for sub-dependencies when the locally available version does not satisfy the requirement" do + install_gemfile <<-G, "prefer-local": true, verbose: true + source "https://gem.repo4" + + gem "b" + G + + expect(out).to include("Fetching foo 1.0.1").and include("Installing foo 1.0.1").and include("Fetching b 1.0.0").and include("Installing b 1.0.0") + expect(last_command).to be_success + end + end + + context "and no gems available locally" do + before do + build_repo4 do + build_gem "myreline", "0.3.8" + build_gem "debug", "0.2.1" + + build_gem "debug", "1.10.0" do |s| + s.add_dependency "myreline" + end end end - system_gems "foo-1.0.0", path: default_bundle_path, gem_repo: gem_repo4 - end + it "resolves to the latest version if no gems are available locally" do + install_gemfile <<~G, "prefer-local": true, verbose: true + source "https://gem.repo4" - it "fetches remote sources when not available locally" do - install_gemfile <<-G, "prefer-local": true, verbose: true - source "https://gem.repo4" + gem "debug" + G - gem "foo" - gem "bar" - G - - expect(out).to include("Using foo 1.0.0").and include("Fetching bar 1.0.0").and include("Installing bar 1.0.0") - expect(last_command).to be_success - end - - it "fetches remote sources when local version does not match requirements" do - install_gemfile <<-G, "prefer-local": true, verbose: true - source "https://gem.repo4" - - gem "foo", "1.0.1" - gem "bar" - G - - expect(out).to include("Fetching foo 1.0.1").and include("Installing foo 1.0.1").and include("Fetching bar 1.0.0").and include("Installing bar 1.0.0") - expect(last_command).to be_success - end - - it "uses the locally available version for sub-dependencies when possible" do - install_gemfile <<-G, "prefer-local": true, verbose: true - source "https://gem.repo4" - - gem "a" - G - - expect(out).to include("Using foo 1.0.0").and include("Fetching a 1.0.0").and include("Installing a 1.0.0") - expect(last_command).to be_success - end - - it "fetches remote sources for sub-dependencies when the locally available version does not satisfy the requirement" do - install_gemfile <<-G, "prefer-local": true, verbose: true - source "https://gem.repo4" - - gem "b" - G - - expect(out).to include("Fetching foo 1.0.1").and include("Installing foo 1.0.1").and include("Fetching b 1.0.0").and include("Installing b 1.0.0") - expect(last_command).to be_success - end - - it "resolves to the latest version if no gems are available locally" do - build_repo4 do - build_gem "myreline", "0.3.8" - build_gem "debug", "0.2.1" - - build_gem "debug", "1.10.0" do |s| - s.add_dependency "myreline" - end + expect(out).to include("Fetching debug 1.10.0").and include("Installing debug 1.10.0").and include("Fetching myreline 0.3.8").and include("Installing myreline 0.3.8") + expect(last_command).to be_success end - - install_gemfile <<~G, "prefer-local": true, verbose: true - source "https://gem.repo4" - - gem "debug" - G - - expect(out).to include("Fetching debug 1.10.0").and include("Installing debug 1.10.0").and include("Fetching myreline 0.3.8").and include("Installing myreline 0.3.8") - expect(last_command).to be_success end end diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index cd20faa9a2..11b8164cbd 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -99,7 +99,7 @@ RSpec.describe "bundle lock" do L end - before :each do + let(:gemfile_with_rails_weakling_and_foo_from_repo4) do build_repo4 do FileUtils.cp rake_path, "#{gem_repo4}/gems/" @@ -143,12 +143,16 @@ RSpec.describe "bundle lock" do end it "prints a lockfile when there is no existing lockfile with --print" do + gemfile_with_rails_weakling_and_foo_from_repo4 + bundle "lock --print" expect(out).to eq(expected_lockfile.chomp) end it "prints a lockfile when there is an existing lockfile with --print" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile expected_lockfile bundle "lock --print" @@ -157,6 +161,8 @@ RSpec.describe "bundle lock" do end it "prints a lockfile when there is an existing checksums lockfile with --print" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile expected_lockfile bundle "lock --print" @@ -165,12 +171,16 @@ RSpec.describe "bundle lock" do end it "writes a lockfile when there is no existing lockfile" do + gemfile_with_rails_weakling_and_foo_from_repo4 + bundle "lock" expect(read_lockfile).to eq(expected_lockfile) end it "prints a lockfile without fetching new checksums if the existing lockfile had no checksums" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile expected_lockfile bundle "lock --print" @@ -179,6 +189,8 @@ RSpec.describe "bundle lock" do end it "touches the lockfile when there is an existing lockfile that does not need changes" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile expected_lockfile expect do @@ -187,6 +199,8 @@ RSpec.describe "bundle lock" do end it "does not touch lockfile with --print" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile expected_lockfile expect do @@ -195,6 +209,8 @@ RSpec.describe "bundle lock" do end it "writes a lockfile when there is an outdated lockfile using --update" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile outdated_lockfile bundle "lock --update" @@ -203,6 +219,8 @@ RSpec.describe "bundle lock" do end it "prints an updated lockfile when there is an outdated lockfile using --print --update" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile outdated_lockfile bundle "lock --print --update" @@ -211,6 +229,8 @@ RSpec.describe "bundle lock" do end it "emits info messages to stderr when updating an outdated lockfile using --print --update" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile outdated_lockfile bundle "lock --print --update" @@ -222,6 +242,8 @@ RSpec.describe "bundle lock" do end it "writes a lockfile when there is an outdated lockfile and bundle is frozen" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile outdated_lockfile bundle "lock --update", env: { "BUNDLE_FROZEN" => "true" } @@ -230,12 +252,16 @@ RSpec.describe "bundle lock" do end it "does not fetch remote specs when using the --local option" do + gemfile_with_rails_weakling_and_foo_from_repo4 + bundle "lock --update --local", raise_on_error: false expect(err).to match(/locally installed gems/) end it "does not fetch remote checksums with --local" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile expected_lockfile bundle "lock --print --local" @@ -244,6 +270,8 @@ RSpec.describe "bundle lock" do end it "works with --gemfile flag" do + gemfile_with_rails_weakling_and_foo_from_repo4 + gemfile "CustomGemfile", <<-G source "https://gem.repo4" gem "foo" @@ -275,6 +303,8 @@ RSpec.describe "bundle lock" do end it "writes to a custom location using --lockfile" do + gemfile_with_rails_weakling_and_foo_from_repo4 + bundle "lock --lockfile=lock" expect(out).to match(/Writing lockfile to.+lock/) @@ -283,6 +313,8 @@ RSpec.describe "bundle lock" do end it "writes to custom location using --lockfile when a default lockfile is present" do + gemfile_with_rails_weakling_and_foo_from_repo4 + bundle "install" bundle "lock --lockfile=lock" @@ -338,6 +370,8 @@ RSpec.describe "bundle lock" do end it "update specific gems using --update" do + gemfile_with_rails_weakling_and_foo_from_repo4 + checksums = checksums_section_when_enabled do |c| c.checksum gem_repo4, "actionmailer", "2.3.1" c.checksum gem_repo4, "actionpack", "2.3.1" @@ -515,6 +549,8 @@ RSpec.describe "bundle lock" do end it "preserves unknown checksum algorithms" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile expected_lockfile.gsub(/(sha256=[a-f0-9]+)$/, "constant=true,\\1,xyz=123") previous_lockfile = read_lockfile @@ -525,6 +561,8 @@ RSpec.describe "bundle lock" do end it "does not unlock git sources when only uri shape changes" do + gemfile_with_rails_weakling_and_foo_from_repo4 + build_git("foo") install_gemfile <<-G @@ -543,6 +581,8 @@ RSpec.describe "bundle lock" do end it "updates specific gems using --update using the locked revision of unrelated git gems for resolving" do + gemfile_with_rails_weakling_and_foo_from_repo4 + ref = build_git("foo").ref_for("HEAD") gemfile <<-G @@ -581,6 +621,8 @@ RSpec.describe "bundle lock" do end it "errors when updating a missing specific gems using --update" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile expected_lockfile bundle "lock --update blahblah", raise_on_error: false @@ -590,6 +632,8 @@ RSpec.describe "bundle lock" do end it "can lock without downloading gems" do + gemfile_with_rails_weakling_and_foo_from_repo4 + gemfile <<-G source "https://gem.repo1" @@ -761,8 +805,22 @@ RSpec.describe "bundle lock" do expect(lockfile).to end_with("BUNDLED WITH\n 99\n") end - it "supports adding new platforms" do - bundle "lock --add-platform java x86-mingw32" + it "supports adding new platforms when there's no previous lockfile" do + gemfile_with_rails_weakling_and_foo_from_repo4 + + bundle "lock --add-platform java x86-mingw32 --verbose" + expect(out).to include("Resolving dependencies because there's no lockfile") + + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + expect(the_bundle.locked_platforms).to match_array(default_platform_list("java", "x86-mingw32")) + end + + it "supports adding new platforms when a previous lockfile exists" do + gemfile_with_rails_weakling_and_foo_from_repo4 + + bundle "lock" + bundle "lock --add-platform java x86-mingw32 --verbose" + expect(out).to include("Found changes from the lockfile, re-resolving dependencies because you are adding a new platform to your lockfile") allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) expect(the_bundle.locked_platforms).to match_array(default_platform_list("java", "x86-mingw32")) @@ -825,6 +883,8 @@ RSpec.describe "bundle lock" do end it "supports adding new platforms with force_ruby_platform = true" do + gemfile_with_rails_weakling_and_foo_from_repo4 + lockfile <<-L GEM remote: https://gem.repo1/ @@ -848,6 +908,8 @@ RSpec.describe "bundle lock" do end it "supports adding the `ruby` platform" do + gemfile_with_rails_weakling_and_foo_from_repo4 + bundle "lock --add-platform ruby" allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) @@ -855,12 +917,16 @@ RSpec.describe "bundle lock" do end it "fails when adding an unknown platform" do + gemfile_with_rails_weakling_and_foo_from_repo4 + bundle "lock --add-platform foobarbaz", raise_on_error: false expect(err).to include("The platform `foobarbaz` is unknown to RubyGems and can't be added to the lockfile") expect(last_command).to be_failure end it "allows removing platforms" do + gemfile_with_rails_weakling_and_foo_from_repo4 + bundle "lock --add-platform java x86-mingw32" allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) @@ -934,6 +1000,8 @@ RSpec.describe "bundle lock" do end it "errors when removing all platforms" do + gemfile_with_rails_weakling_and_foo_from_repo4 + bundle "lock --remove-platform #{local_platform}", raise_on_error: false expect(err).to include("Removing all platforms from the bundle is not allowed") end @@ -1368,6 +1436,8 @@ RSpec.describe "bundle lock" do context "when an update is available" do before do + gemfile_with_rails_weakling_and_foo_from_repo4 + update_repo4 do build_gem "foo", "2.0" end diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb index 2389eda521..a7fe31143d 100644 --- a/spec/bundler/commands/newgem_spec.rb +++ b/spec/bundler/commands/newgem_spec.rb @@ -478,9 +478,12 @@ RSpec.describe "bundle gem" do prepare_gemspec(bundled_app("newgem", "newgem.gemspec")) - gems = ["rake-#{rake_version}"] + build_repo2 do + build_dummy_irb "9.9.9" + end + gems = ["rake-#{rake_version}", "irb-9.9.9"] path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(base: bundled_app("newgem")) : system_gem_path - system_gems gems, path: path + system_gems gems, path: path, gem_repo: gem_repo2 bundle "exec rake build", dir: bundled_app("newgem") expect(last_command.stdboth).not_to include("ERROR") diff --git a/spec/bundler/commands/outdated_spec.rb b/spec/bundler/commands/outdated_spec.rb index 38121ce50e..09b0e6f32f 100644 --- a/spec/bundler/commands/outdated_spec.rb +++ b/spec/bundler/commands/outdated_spec.rb @@ -417,7 +417,7 @@ RSpec.describe "bundle outdated" do end it "doesn't hit repo2" do - FileUtils.rm_rf(gem_repo2) + FileUtils.rm_r(gem_repo2) bundle "outdated --local" expect(out).not_to match(/Fetching (gem|version|dependency) metadata from/) @@ -974,7 +974,7 @@ RSpec.describe "bundle outdated" do gem "terranova", '8' G - simulate_new_machine + pristine_system_gems :bundler update_git "foo", path: lib_path("foo") update_repo2 do diff --git a/spec/bundler/commands/platform_spec.rb b/spec/bundler/commands/platform_spec.rb index 6e0a02bcf0..17183e7546 100644 --- a/spec/bundler/commands/platform_spec.rb +++ b/spec/bundler/commands/platform_spec.rb @@ -939,10 +939,15 @@ G end end - context "bundle console", bundler: "< 3" do + context "bundle console" do before do + build_repo2 do + build_dummy_irb + end + install_gemfile <<-G - source "https://gem.repo1" + source "https://gem.repo2" + gem "irb" gem "myrack" gem "activesupport", :group => :test gem "myrack_middleware", :group => :development @@ -950,14 +955,7 @@ G end it "starts IRB with the default group loaded when ruby version matches", :readline do - gemfile <<-G - source "https://gem.repo1" - gem "myrack" - gem "activesupport", :group => :test - gem "myrack_middleware", :group => :development - - #{ruby_version_correct} - G + gemfile gemfile + "\n\n#{ruby_version_correct}\n" bundle "console" do |input, _, _| input.puts("puts MYRACK") @@ -967,14 +965,7 @@ G end it "starts IRB with the default group loaded when ruby version matches", :readline, :jruby_only do - gemfile <<-G - source "https://gem.repo1" - gem "myrack" - gem "activesupport", :group => :test - gem "myrack_middleware", :group => :development - - #{ruby_version_correct_engineless} - G + gemfile gemfile + "\n\n#{ruby_version_correct_engineless}\n" bundle "console" do |input, _, _| input.puts("puts MYRACK") @@ -984,56 +975,28 @@ G end it "fails when ruby version doesn't match" do - gemfile <<-G - source "https://gem.repo1" - gem "myrack" - gem "activesupport", :group => :test - gem "myrack_middleware", :group => :development - - #{ruby_version_incorrect} - G + gemfile gemfile + "\n\n#{ruby_version_incorrect}\n" bundle "console", raise_on_error: false should_be_ruby_version_incorrect end it "fails when engine doesn't match" do - gemfile <<-G - source "https://gem.repo1" - gem "myrack" - gem "activesupport", :group => :test - gem "myrack_middleware", :group => :development - - #{engine_incorrect} - G + gemfile gemfile + "\n\n#{engine_incorrect}\n" bundle "console", raise_on_error: false should_be_engine_incorrect end it "fails when engine version doesn't match", :jruby_only do - gemfile <<-G - source "https://gem.repo1" - gem "myrack" - gem "activesupport", :group => :test - gem "myrack_middleware", :group => :development - - #{engine_version_incorrect} - G + gemfile gemfile + "\n\n#{engine_version_incorrect}\n" bundle "console", raise_on_error: false should_be_engine_version_incorrect end it "fails when patchlevel doesn't match" do - gemfile <<-G - source "https://gem.repo1" - gem "myrack" - gem "activesupport", :group => :test - gem "myrack_middleware", :group => :development - - #{patchlevel_incorrect} - G + gemfile gemfile + "\n\n#{patchlevel_incorrect}\n" bundle "console", raise_on_error: false should_be_patchlevel_incorrect diff --git a/spec/bundler/commands/show_spec.rb b/spec/bundler/commands/show_spec.rb index 8ccda50c9c..0ff9416757 100644 --- a/spec/bundler/commands/show_spec.rb +++ b/spec/bundler/commands/show_spec.rb @@ -36,7 +36,7 @@ RSpec.describe "bundle show", bundler: "< 3" do end it "warns if specification is installed, but path does not exist on disk" do - FileUtils.rm_rf(default_bundle_path("gems", "rails-2.3.2")) + FileUtils.rm_r(default_bundle_path("gems", "rails-2.3.2")) bundle "show rails" diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index f6d0188794..6cbd167bb0 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -653,7 +653,7 @@ RSpec.describe "bundle update" do bundle "install" - FileUtils.rm_rf(gem_repo2) + FileUtils.rm_r(gem_repo2) bundle "update --local --all" expect(out).not_to include("Fetching source index") diff --git a/spec/bundler/install/deploy_spec.rb b/spec/bundler/install/deploy_spec.rb index bd39ac5cc1..f44e24b790 100644 --- a/spec/bundler/install/deploy_spec.rb +++ b/spec/bundler/install/deploy_spec.rb @@ -88,7 +88,7 @@ RSpec.describe "install in deployment or frozen mode" do it "still works if you are not in the app directory and specify --gemfile" do bundle "install" - simulate_new_machine + pristine_system_gems :bundler bundle "config set --local deployment true" bundle "config set --local path vendor/bundle" bundle "install --gemfile #{tmp}/bundled_app/Gemfile", dir: tmp @@ -547,7 +547,7 @@ RSpec.describe "install in deployment or frozen mode" do bundle "install --local" expect(out).to include("Updating files in vendor/cache") - simulate_new_machine + pristine_system_gems :bundler bundle "config set --local deployment true" bundle "install --verbose" expect(out).not_to include("but the lockfile can't be updated because frozen mode is set") diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb index ada74c311c..c763da4c00 100644 --- a/spec/bundler/install/gemfile/git_spec.rb +++ b/spec/bundler/install/gemfile/git_spec.rb @@ -31,14 +31,13 @@ RSpec.describe "bundle install with git sources" do end it "does not write to cache on bundler/setup" do - cache_path = default_bundle_path("cache") - FileUtils.rm_rf(cache_path) + FileUtils.rm_r(default_cache_path) ruby "require 'bundler/setup'" - expect(cache_path).not_to exist + expect(default_cache_path).not_to exist end it "caches the git repo globally and properly uses the cached repo on the next invocation" do - simulate_new_machine + pristine_system_gems :bundler bundle "config set global_gem_cache true" bundle :install expect(Dir["#{home}/.bundle/cache/git/foo-1.0-*"]).to have_attributes size: 1 @@ -1039,7 +1038,7 @@ RSpec.describe "bundle install with git sources" do gem "foo", :git => "#{lib_path("foo-1.0")}" G - FileUtils.rm_rf(lib_path("foo-1.0")) + FileUtils.rm_r(lib_path("foo-1.0")) bundle "install" expect(out).not_to match(/updating/i) @@ -1218,7 +1217,7 @@ RSpec.describe "bundle install with git sources" do gem "valim", "= 1.0", :git => "#{lib_path("valim")}" G - simulate_new_machine + pristine_system_gems :bundler bundle "config set --local deployment true" bundle :install @@ -1605,7 +1604,7 @@ In Gemfile: G bundle "config set --global path vendor/bundle" bundle :install - simulate_new_machine + pristine_system_gems :bundler bundle "install", env: { "PATH" => "" } expect(out).to_not include("You need to install git to be able to use gems from git repositories.") diff --git a/spec/bundler/install/gemfile/groups_spec.rb b/spec/bundler/install/gemfile/groups_spec.rb index 71871899a2..c5f50a8c5d 100644 --- a/spec/bundler/install/gemfile/groups_spec.rb +++ b/spec/bundler/install/gemfile/groups_spec.rb @@ -394,7 +394,7 @@ RSpec.describe "bundle install with groups" do end it "does not hit the remote a second time" do - FileUtils.rm_rf gem_repo2 + FileUtils.rm_r gem_repo2 bundle "config set --local without myrack" bundle :install, verbose: true expect(last_command.stdboth).not_to match(/fetching/i) diff --git a/spec/bundler/install/gemfile/lockfile_spec.rb b/spec/bundler/install/gemfile/lockfile_spec.rb index f80b21e562..ee747c05de 100644 --- a/spec/bundler/install/gemfile/lockfile_spec.rb +++ b/spec/bundler/install/gemfile/lockfile_spec.rb @@ -7,12 +7,8 @@ RSpec.describe "bundle install with a lockfile present" do gem "myrack", "1.0.0" G - subject do - install_gemfile(gf) - end - it "touches the lockfile on install even when nothing has changed" do - subject + install_gemfile(gf) expect { bundle :install }.to change { bundled_app_lock.mtime } end @@ -22,31 +18,24 @@ RSpec.describe "bundle install with a lockfile present" do context "with plugins disabled" do before do bundle "config set plugins false" - subject end - it "does not evaluate the gemfile twice" do + it "does not evaluate the gemfile twice when the gem is already installed" do + install_gemfile(gf) bundle :install with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "myrack 1.0.0" } - # The first eval is from the initial install, we're testing that the - # second install doesn't double-eval expect(bundled_app("evals").read.lines.to_a.size).to eq(2) end - context "when the gem is not installed" do - before { FileUtils.rm_rf bundled_app(".bundle") } + it "does not evaluate the gemfile twice when the gem is not installed" do + gemfile(gf) + bundle :install - it "does not evaluate the gemfile twice" do - bundle :install + with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "myrack 1.0.0" } - with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "myrack 1.0.0" } - - # The first eval is from the initial install, we're testing that the - # second install doesn't double-eval - expect(bundled_app("evals").read.lines.to_a.size).to eq(2) - end + expect(bundled_app("evals").read.lines.to_a.size).to eq(1) end end end diff --git a/spec/bundler/install/gemfile/platform_spec.rb b/spec/bundler/install/gemfile/platform_spec.rb index 64a544a54f..a81ea5d367 100644 --- a/spec/bundler/install/gemfile/platform_spec.rb +++ b/spec/bundler/install/gemfile/platform_spec.rb @@ -161,7 +161,7 @@ RSpec.describe "bundle install across platforms" do expect(the_bundle).to include_gems "nokogiri 1.4.2 java", "weakling 0.0.3" - simulate_new_machine + pristine_system_gems :bundler bundle "config set --local force_ruby_platform true" bundle "install" diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb index cf661ee284..e7322ab5ad 100644 --- a/spec/bundler/install/gems/compact_index_spec.rb +++ b/spec/bundler/install/gems/compact_index_spec.rb @@ -183,8 +183,7 @@ RSpec.describe "compact index api" do gem "myrack" G - versions = Pathname.new(Bundler.rubygems.user_home).join( - ".bundle", "cache", "compact_index", + versions = compact_index_cache_path.join( "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions" ) versions.dirname.mkpath @@ -323,7 +322,7 @@ RSpec.describe "compact index api" do build_gem "back_deps" do |s| s.add_dependency "foo" end - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end gemfile <<-G @@ -341,7 +340,7 @@ RSpec.describe "compact index api" do build_gem "back_deps" do |s| s.add_dependency "foo" end - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end install_gemfile <<-G, artifice: "compact_index_extra", verbose: true @@ -406,7 +405,7 @@ RSpec.describe "compact index api" do build_gem "back_deps" do |s| s.add_dependency "foo" end - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end gemfile <<-G @@ -429,7 +428,7 @@ RSpec.describe "compact index api" do end build_gem "missing" - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end install_gemfile <<-G, artifice: "compact_index_extra_missing" @@ -449,7 +448,7 @@ RSpec.describe "compact index api" do end build_gem "missing" - FileUtils.rm_rf Dir[gem_repo4("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo4("gems/foo-*.gem")] end install_gemfile <<-G, artifice: "compact_index_extra_api_missing" @@ -478,7 +477,7 @@ RSpec.describe "compact index api" do build_gem "back_deps" do |s| s.add_dependency "foo" end - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end gemfile <<-G @@ -498,7 +497,7 @@ RSpec.describe "compact index api" do build_gem "back_deps" do |s| s.add_dependency "foo" end - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end gemfile <<-G @@ -789,8 +788,7 @@ RSpec.describe "compact index api" do end it "performs update with etag not-modified" do - versions_etag = Pathname.new(Bundler.rubygems.user_home).join( - ".bundle", "cache", "compact_index", + versions_etag = compact_index_cache_path.join( "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions.etag" ) expect(versions_etag.file?).to eq(false) @@ -833,8 +831,7 @@ RSpec.describe "compact index api" do gem 'myrack', '1.0.0' G - versions = Pathname.new(Bundler.rubygems.user_home).join( - ".bundle", "cache", "compact_index", + versions = compact_index_cache_path.join( "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions" ) # Modify the cached file. The ranged request will be based on this but, @@ -876,8 +873,7 @@ RSpec.describe "compact index api" do G # Create a partial cache versions file - versions = Pathname.new(Bundler.rubygems.user_home).join( - ".bundle", "cache", "compact_index", + versions = compact_index_cache_path.join( "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions" ) versions.dirname.mkpath @@ -941,7 +937,7 @@ RSpec.describe "compact index api" do bundle :install, artifice: "compact_index" - cache_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5") + cache_path = compact_index_cache_path.join("localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5") # We must remove the etag so that we don't ignore the range and get a 304 Not Modified. myrack_info_etag_path = File.join(cache_path, "info-etags", "myrack-92f3313ce5721296f14445c3a6b9c073") diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb index 01331d1c4b..4e06e3e711 100644 --- a/spec/bundler/install/gems/dependency_api_spec.rb +++ b/spec/bundler/install/gems/dependency_api_spec.rb @@ -260,7 +260,7 @@ RSpec.describe "gemcutter's dependency API" do build_gem "back_deps" do |s| s.add_dependency "foo" end - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end gemfile <<-G @@ -278,7 +278,7 @@ RSpec.describe "gemcutter's dependency API" do build_gem "back_deps" do |s| s.add_dependency "foo" end - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end gemfile <<-G @@ -343,7 +343,7 @@ RSpec.describe "gemcutter's dependency API" do build_gem "back_deps" do |s| s.add_dependency "foo" end - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end gemfile <<-G @@ -366,7 +366,7 @@ RSpec.describe "gemcutter's dependency API" do end build_gem "missing" - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end install_gemfile <<-G, artifice: "endpoint_extra_missing" @@ -385,7 +385,7 @@ RSpec.describe "gemcutter's dependency API" do end build_gem "missing" - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end install_gemfile <<-G, artifice: "endpoint_extra_missing" @@ -403,7 +403,7 @@ RSpec.describe "gemcutter's dependency API" do build_gem "back_deps" do |s| s.add_dependency "foo" end - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end gemfile <<-G @@ -423,7 +423,7 @@ RSpec.describe "gemcutter's dependency API" do build_gem "back_deps" do |s| s.add_dependency "foo" end - FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")] + FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end gemfile <<-G diff --git a/spec/bundler/install/git_spec.rb b/spec/bundler/install/git_spec.rb index d1f6b7a7ca..670bd1fb72 100644 --- a/spec/bundler/install/git_spec.rb +++ b/spec/bundler/install/git_spec.rb @@ -214,5 +214,80 @@ RSpec.describe "bundle install" do expect(out).to include("Using foo 1.0 from #{lib_path("foo")} (at main@#{rev[0..6]})") expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}" end + + context "when install directory exists" do + let(:checkout_confirmation_log_message) { "Checking out revision" } + let(:using_foo_confirmation_log_message) { "Using foo 1.0 from #{lib_path("foo")} (at main@#{revision_for(lib_path("foo"))[0..6]})" } + + context "and no contents besides .git directory are present" do + it "reinstalls gem" do + build_git "foo", "1.0", path: lib_path("foo") + + gemfile = <<-G + source "https://gem.repo1" + gem "foo", :git => "#{lib_path("foo")}" + G + + install_gemfile gemfile, verbose: true + + expect(out).to include(checkout_confirmation_log_message) + expect(out).to include(using_foo_confirmation_log_message) + expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}" + + # validate that the installed directory exists and has some expected contents + install_directory = default_bundle_path("bundler/gems/foo-#{revision_for(lib_path("foo"))[0..11]}") + dot_git_directory = install_directory.join(".git") + lib_directory = install_directory.join("lib") + gemspec = install_directory.join("foo.gemspec") + expect([install_directory, dot_git_directory, lib_directory, gemspec]).to all exist + + # remove all elements in the install directory except .git directory + FileUtils.rm_r(lib_directory) + gemspec.delete + + expect(dot_git_directory).to exist + expect(lib_directory).not_to exist + expect(gemspec).not_to exist + + # rerun bundle install + install_gemfile gemfile, verbose: true + + expect(out).to include(checkout_confirmation_log_message) + expect(out).to include(using_foo_confirmation_log_message) + expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}" + + # validate that it reinstalls all components + expect([install_directory, dot_git_directory, lib_directory, gemspec]).to all exist + end + end + + context "and contents besides .git directory are present" do + # we want to confirm that the change to try to detect partial installs and reinstall does not + # result in repeatedly reinstalling the gem when it is fully installed + it "does not reinstall gem" do + build_git "foo", "1.0", path: lib_path("foo") + + gemfile = <<-G + source "https://gem.repo1" + gem "foo", :git => "#{lib_path("foo")}" + G + + install_gemfile gemfile, verbose: true + + expect(out).to include(checkout_confirmation_log_message) + expect(out).to include(using_foo_confirmation_log_message) + expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}" + + # rerun bundle install + install_gemfile gemfile, verbose: true + + # it isn't altogether straight-forward to validate that bundle didn't do soething on the second run, however, + # the presence of the 2nd log message confirms install got past the point that it would have logged the above if + # it was going to + expect(out).not_to include(checkout_confirmation_log_message) + expect(out).to include(using_foo_confirmation_log_message) + end + end + end end end diff --git a/spec/bundler/install/global_cache_spec.rb b/spec/bundler/install/global_cache_spec.rb index df4559c42e..130c841ce9 100644 --- a/spec/bundler/install/global_cache_spec.rb +++ b/spec/bundler/install/global_cache_spec.rb @@ -7,12 +7,16 @@ RSpec.describe "global gem caching" do let(:source) { "http://localgemserver.test" } let(:source2) { "http://gemserver.example.org" } + def cache_base + home(".bundle", "cache", "gems") + end + def source_global_cache(*segments) - home(".bundle", "cache", "gems", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", *segments) + cache_base.join("localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", *segments) end def source2_global_cache(*segments) - home(".bundle", "cache", "gems", "gemserver.example.org.80.1ae1663619ffe0a3c9d97712f44c705b", *segments) + cache_base.join("gemserver.example.org.80.1ae1663619ffe0a3c9d97712f44c705b", *segments) end it "caches gems into the global cache on download" do @@ -49,14 +53,49 @@ RSpec.describe "global gem caching" do expect(err).to include("Gem::Package::FormatError: package metadata is missing in #{source_global_cache("myrack-1.0.0.gem")}") end + it "uses a shorter path for the cache to not hit filesystem limits" do + install_gemfile <<-G, artifice: "compact_index", verbose: true + source "http://#{"a" * 255}.test" + gem "myrack" + G + + expect(the_bundle).to include_gems "myrack 1.0.0" + source_segment = "a" * 222 + ".a3cb26de2edfce9f509a65c611d99c4b" + source_cache = cache_base.join(source_segment) + cached_gem = source_cache.join("myrack-1.0.0.gem") + expect(cached_gem).to exist + ensure + # We cleanup dummy files created by this spec manually because due to a + # Ruby on Windows bug, `FileUtils.rm_rf` (run in our global after hook) + # cannot traverse directories with such long names. So we delete + # everything explicitly to workaround the bug. An alternative workaround + # would be to shell out to `rm -rf`. That also works fine, but I went with + # the more verbose and explicit approach. This whole ensure block can be + # removed once/if https://bugs.ruby-lang.org/issues/21177 is fixed, and + # once the fix propagates to all supported rubies. + File.delete cached_gem + Dir.rmdir source_cache + + File.delete compact_index_cache_path.join(source_segment, "info", "myrack") + Dir.rmdir compact_index_cache_path.join(source_segment, "info") + File.delete compact_index_cache_path.join(source_segment, "info-etags", "myrack-92f3313ce5721296f14445c3a6b9c073") + Dir.rmdir compact_index_cache_path.join(source_segment, "info-etags") + Dir.rmdir compact_index_cache_path.join(source_segment, "info-special-characters") + File.delete compact_index_cache_path.join(source_segment, "versions") + File.delete compact_index_cache_path.join(source_segment, "versions.etag") + Dir.rmdir compact_index_cache_path.join(source_segment) + end + describe "when the same gem from different sources is installed" do it "should use the appropriate one from the global cache" do + bundle "config path.system true" + install_gemfile <<-G, artifice: "compact_index" source "#{source}" gem "myrack" G - simulate_new_machine + pristine_system_gems :bundler expect(the_bundle).not_to include_gems "myrack 1.0.0" expect(source_global_cache("myrack-1.0.0.gem")).to exist # myrack 1.0.0 is not installed and it is in the global cache @@ -66,7 +105,7 @@ RSpec.describe "global gem caching" do gem "myrack", "0.9.1" G - simulate_new_machine + pristine_system_gems :bundler expect(the_bundle).not_to include_gems "myrack 0.9.1" expect(source2_global_cache("myrack-0.9.1.gem")).to exist # myrack 0.9.1 is not installed and it is in the global cache @@ -80,7 +119,7 @@ RSpec.describe "global gem caching" do # myrack 1.0.0 is installed and myrack 0.9.1 is not expect(the_bundle).to include_gems "myrack 1.0.0" expect(the_bundle).not_to include_gems "myrack 0.9.1" - simulate_new_machine + pristine_system_gems :bundler gemfile <<-G source "#{source2}" @@ -94,13 +133,15 @@ RSpec.describe "global gem caching" do end it "should not install if the wrong source is provided" do + bundle "config path.system true" + gemfile <<-G source "#{source}" gem "myrack" G bundle :install, artifice: "compact_index" - simulate_new_machine + pristine_system_gems :bundler expect(the_bundle).not_to include_gems "myrack 1.0.0" expect(source_global_cache("myrack-1.0.0.gem")).to exist # myrack 1.0.0 is not installed and it is in the global cache @@ -111,7 +152,7 @@ RSpec.describe "global gem caching" do G bundle :install, artifice: "compact_index" - simulate_new_machine + pristine_system_gems :bundler expect(the_bundle).not_to include_gems "myrack 0.9.1" expect(source2_global_cache("myrack-0.9.1.gem")).to exist # myrack 0.9.1 is not installed and it is in the global cache @@ -150,6 +191,8 @@ RSpec.describe "global gem caching" do describe "when installing gems from a different directory" do it "uses the global cache as a source" do + bundle "config path.system true" + install_gemfile <<-G, artifice: "compact_index" source "#{source}" gem "myrack" @@ -161,7 +204,7 @@ RSpec.describe "global gem caching" do expect(the_bundle).to include_gems "activesupport 2.3.5" expect(source_global_cache("myrack-1.0.0.gem")).to exist expect(source_global_cache("activesupport-2.3.5.gem")).to exist - simulate_new_machine + pristine_system_gems :bundler # Both gems are now only in the global cache expect(the_bundle).not_to include_gems "myrack 1.0.0" expect(the_bundle).not_to include_gems "activesupport 2.3.5" @@ -232,7 +275,7 @@ RSpec.describe "global gem caching" do R expect(out).to eq "VERY_SIMPLE_BINARY_IN_C\nVERY_SIMPLE_GIT_BINARY_IN_C" - FileUtils.rm_rf Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")] + FileUtils.rm_r Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")] gem_binary_cache.join("very_simple_binary_c.rb").open("w") {|f| f << "puts File.basename(__FILE__)" } git_binary_cache.join("very_simple_git_binary_c.rb").open("w") {|f| f << "puts File.basename(__FILE__)" } diff --git a/spec/bundler/install/path_spec.rb b/spec/bundler/install/path_spec.rb index 8d32e033d6..1412e8dd24 100644 --- a/spec/bundler/install/path_spec.rb +++ b/spec/bundler/install/path_spec.rb @@ -52,7 +52,7 @@ RSpec.describe "bundle install" do it "remembers to disable system gems after the first time with bundle --path vendor/bundle", bundler: "< 3" do bundle "install --path vendor/bundle" - FileUtils.rm_rf bundled_app("vendor") + FileUtils.rm_r bundled_app("vendor") bundle "install" expect(vendored_gems("gems/myrack-1.0.0")).to be_directory diff --git a/spec/bundler/install/prereleases_spec.rb b/spec/bundler/install/prereleases_spec.rb index 57764ce722..9f764d127c 100644 --- a/spec/bundler/install/prereleases_spec.rb +++ b/spec/bundler/install/prereleases_spec.rb @@ -41,7 +41,7 @@ RSpec.describe "bundle install" do build_repo3 do build_gem "myrack" end - FileUtils.rm_rf Dir[gem_repo3("prerelease*")] + FileUtils.rm_r Dir[gem_repo3("prerelease*")] install_gemfile <<-G source "https://gem.repo3" diff --git a/spec/bundler/install/process_lock_spec.rb b/spec/bundler/install/process_lock_spec.rb index 707d2fde5e..8082ec40fa 100644 --- a/spec/bundler/install/process_lock_spec.rb +++ b/spec/bundler/install/process_lock_spec.rb @@ -21,19 +21,36 @@ RSpec.describe "process lock spec" do expect(the_bundle).to include_gems "myrack 1.0" end + context "when creating a lock raises Errno::ENOTSUP" do + before { allow(File).to receive(:open).and_raise(Errno::ENOTSUP) } + + it "skips creating the lock file and yields" do + processed = false + Bundler::ProcessLock.lock(default_bundle_path) { processed = true } + + expect(processed).to eq true + end + end + context "when creating a lock raises Errno::EPERM" do before { allow(File).to receive(:open).and_raise(Errno::EPERM) } - it "raises a friendly error" do - expect { Bundler::ProcessLock.lock(default_bundle_path) }.to raise_error(Bundler::GenericSystemCallError) + it "skips creating the lock file and yields" do + processed = false + Bundler::ProcessLock.lock(default_bundle_path) { processed = true } + + expect(processed).to eq true end end context "when creating a lock raises Errno::EROFS" do before { allow(File).to receive(:open).and_raise(Errno::EROFS) } - it "raises a friendly error" do - expect { Bundler::ProcessLock.lock(default_bundle_path) }.to raise_error(Bundler::GenericSystemCallError) + it "skips creating the lock file and yields" do + processed = false + Bundler::ProcessLock.lock(default_bundle_path) { processed = true } + + expect(processed).to eq true end end end diff --git a/spec/bundler/install/yanked_spec.rb b/spec/bundler/install/yanked_spec.rb index 6919662671..ffe962d9f3 100644 --- a/spec/bundler/install/yanked_spec.rb +++ b/spec/bundler/install/yanked_spec.rb @@ -1,13 +1,11 @@ # frozen_string_literal: true RSpec.context "when installing a bundle that includes yanked gems" do - before(:each) do + it "throws an error when the original gem version is yanked" do build_repo4 do build_gem "foo", "9.0.0" end - end - it "throws an error when the original gem version is yanked" do lockfile <<-L GEM remote: https://gem.repo4 @@ -116,6 +114,10 @@ RSpec.context "when installing a bundle that includes yanked gems" do end it "throws the original error when only the Gemfile specifies a gem version that doesn't exist" do + build_repo4 do + build_gem "foo", "9.0.0" + end + bundle "config set force_ruby_platform true" install_gemfile <<-G, raise_on_error: false diff --git a/spec/bundler/lock/git_spec.rb b/spec/bundler/lock/git_spec.rb index 0e08b7ee30..49c0a2af1c 100644 --- a/spec/bundler/lock/git_spec.rb +++ b/spec/bundler/lock/git_spec.rb @@ -19,7 +19,7 @@ RSpec.describe "bundle lock with git gems" do it "doesn't print errors even if running lock after removing the cache" do install_gemfile_with_foo_as_a_git_dependency - FileUtils.rm_rf(Dir[default_cache_path("git/foo-1.0-*")].first) + FileUtils.rm_r(Dir[default_cache_path("git/foo-1.0-*")].first) bundle "lock --verbose" diff --git a/spec/bundler/plugins/source/example_spec.rb b/spec/bundler/plugins/source/example_spec.rb index 32940bf849..115a44cc69 100644 --- a/spec/bundler/plugins/source/example_spec.rb +++ b/spec/bundler/plugins/source/example_spec.rb @@ -131,7 +131,7 @@ RSpec.describe "real source plugins" do expect(bundled_app("vendor/cache/a-path-gem-1.0-#{uri_hash}/.git")).not_to exist expect(bundled_app("vendor/cache/a-path-gem-1.0-#{uri_hash}/.bundlecache")).to be_file - FileUtils.rm_rf lib_path("a-path-gem-1.0") + FileUtils.rm_r lib_path("a-path-gem-1.0") expect(the_bundle).to include_gems("a-path-gem 1.0") end @@ -143,7 +143,7 @@ RSpec.describe "real source plugins" do expect(bundled_app("vendor/cache/a-path-gem-1.0-#{uri_hash}")).to exist - FileUtils.rm_rf lib_path("a-path-gem-1.0") + FileUtils.rm_r lib_path("a-path-gem-1.0") expect(the_bundle).to include_gems("a-path-gem 1.0") end @@ -155,7 +155,7 @@ RSpec.describe "real source plugins" do expect(bundled_app("vendor/cache/a-path-gem-1.0-#{uri_hash}")).to exist - FileUtils.rm_rf lib_path("a-path-gem-1.0") + FileUtils.rm_r lib_path("a-path-gem-1.0") expect(the_bundle).to include_gems("a-path-gem 1.0") end end @@ -452,7 +452,7 @@ RSpec.describe "real source plugins" do expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.bundlecache")).to be_file - FileUtils.rm_rf lib_path("foo-1.0") + FileUtils.rm_r lib_path("foo-1.0") expect(the_bundle).to include_gems "foo 1.0" end end diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb index 106f1edc57..09dad71dbf 100644 --- a/spec/bundler/runtime/setup_spec.rb +++ b/spec/bundler/runtime/setup_spec.rb @@ -458,9 +458,8 @@ RSpec.describe "Bundler.setup" do end it "works even when the cache directory has been deleted" do - bundle "config set --local path vendor/bundle" bundle :install - FileUtils.rm_rf vendored_gems("cache") + FileUtils.rm_r default_cache_path expect(the_bundle).to include_gems "myrack 1.0.0" end @@ -497,7 +496,7 @@ RSpec.describe "Bundler.setup" do bundle %(config set local.myrack #{lib_path("local-myrack")}) bundle :install - FileUtils.rm_rf(lib_path("local-myrack")) + FileUtils.rm_r(lib_path("local-myrack")) run "require 'myrack'", raise_on_error: false expect(err).to match(/Cannot use local override for myrack-0.8 because #{Regexp.escape(lib_path("local-myrack").to_s)} does not exist/) end @@ -612,7 +611,7 @@ RSpec.describe "Bundler.setup" do gem 'foo', :path => 'vendor/foo', :group => :development G - FileUtils.rm_rf(path) + FileUtils.rm_r(path) ruby "require 'bundler'; Bundler.setup", env: { "DEBUG" => "1" } expect(out).to include("Assuming that source at `vendor/foo` has not changed since fetching its specs errored") @@ -1656,4 +1655,35 @@ end expect(err).to be_empty expect(out).to include("Installing myrack 1.0.0") end + + context "in a read-only filesystem" do + before do + gemfile <<-G + source "https://gem.repo4" + G + + lockfile <<-L + GEM + remote: https://gem.repo4/ + + PLATFORMS + x86_64-darwin-19 + + DEPENDENCIES + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "should fail loudly if the lockfile platforms don't include the current platform" do + simulate_platform "x86_64-linux" do + ruby <<-RUBY, raise_on_error: false, env: { "BUNDLER_SPEC_READ_ONLY" => "true", "BUNDLER_FORCE_TTY" => "true" } + require "bundler/setup" + RUBY + end + + expect(err).to include("Your lockfile does not include the current platform, but the lockfile can't be updated because file system is read-only") + end + end end diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index bf7604659c..470bf3e414 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -121,6 +121,6 @@ RSpec.configure do |config| end config.after :suite do - FileUtils.rm_rf Spec::Path.pristine_system_gem_path + FileUtils.rm_r Spec::Path.pristine_system_gem_path end end diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb index e375aeee33..13c21bf5cc 100644 --- a/spec/bundler/support/builders.rb +++ b/spec/bundler/support/builders.rb @@ -187,32 +187,37 @@ module Spec end def build_repo2(**kwargs, &blk) - FileUtils.rm_rf gem_repo2 - FileUtils.cp_r gem_repo1, gem_repo2 + FileUtils.cp_r gem_repo1, gem_repo2, remove_destination: true update_repo2(**kwargs, &blk) if block_given? end # A repo that has no pre-installed gems included. (The caller completely # determines the contents with the block.) def build_repo3(**kwargs, &blk) - build_empty_repo gem_repo3, **kwargs, &blk + raise "gem_repo3 already exists -- use update_repo3 instead" if File.exist?(gem_repo3) + build_repo gem_repo3, **kwargs, &blk end # Like build_repo3, this is a repo that has no pre-installed gems included. # We have two different methods for situations where two different empty # sources are needed. def build_repo4(**kwargs, &blk) - build_empty_repo gem_repo4, **kwargs, &blk - end - - def update_repo4(&blk) - update_repo(gem_repo4, &blk) + raise "gem_repo4 already exists -- use update_repo4 instead" if File.exist?(gem_repo4) + build_repo gem_repo4, **kwargs, &blk end def update_repo2(**kwargs, &blk) update_repo(gem_repo2, **kwargs, &blk) end + def update_repo3(&blk) + update_repo(gem_repo3, &blk) + end + + def update_repo4(&blk) + update_repo(gem_repo4, &blk) + end + def build_security_repo build_repo security_repo do build_gem "myrack" @@ -228,6 +233,41 @@ module Spec end end + # A minimal fake irb console + def build_dummy_irb(version = "9.9.9") + build_gem "irb", version do |s| + s.write "lib/irb.rb", <<-RUBY + class IRB + class << self + def toplevel_binding + unless defined?(@toplevel_binding) && @toplevel_binding + TOPLEVEL_BINDING.eval %{ + def self.__irb__; binding; end + IRB.instance_variable_set(:@toplevel_binding, __irb__) + class << self; undef __irb__; end + } + end + @toplevel_binding.eval('private') + @toplevel_binding + end + + def __irb__ + while line = gets + begin + puts eval(line, toplevel_binding).inspect.sub(/^"(.*)"$/, '=> \\1') + rescue Exception => e + puts "\#{e.class}: \#{e.message}" + puts e.backtrace.first + end + end + end + alias start __irb__ + end + end + RUBY + end + end + def build_repo(path, **kwargs, &blk) return if File.directory?(path) @@ -238,7 +278,6 @@ module Spec def check_test_gems! if rake_path.nil? - FileUtils.rm_rf(base_system_gems) Spec::Rubygems.install_test_deps end @@ -317,11 +356,6 @@ module Spec private - def build_empty_repo(gem_repo, **kwargs, &blk) - FileUtils.rm_rf gem_repo - build_repo(gem_repo, **kwargs, &blk) - end - def build_with(builder, name, args, &blk) @_build_path ||= nil @_build_repo ||= nil @@ -632,7 +666,7 @@ module Spec destination = opts[:path] || _default_path FileUtils.mkdir_p(lib_path.join(destination)) - if opts[:gemspec] == :yaml || opts[:gemspec] == false + if [:yaml, false].include?(opts[:gemspec]) Dir.chdir(lib_path) do Bundler.rubygems.build(@spec, opts[:skip_validation]) end diff --git a/spec/bundler/support/hax.rb b/spec/bundler/support/hax.rb index 715af6cab6..01bad64ce7 100644 --- a/spec/bundler/support/hax.rb +++ b/spec/bundler/support/hax.rb @@ -37,4 +37,18 @@ module Gem if ENV["BUNDLER_SPEC_GEM_SOURCES"] self.sources = [ENV["BUNDLER_SPEC_GEM_SOURCES"]] end + + if ENV["BUNDLER_SPEC_READ_ONLY"] + module ReadOnly + def open(file, mode) + if file != IO::NULL && mode == "wb" + raise Errno::EROFS + else + super + end + end + end + + File.singleton_class.prepend ReadOnly + end end diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb index 721926b24b..951c370064 100644 --- a/spec/bundler/support/helpers.rb +++ b/spec/bundler/support/helpers.rb @@ -20,7 +20,7 @@ module Spec def reset! Dir.glob("#{tmp}/{gems/*,*}", File::FNM_DOTMATCH).each do |dir| next if %w[base base_system remote1 rubocop standard gems rubygems . ..].include?(File.basename(dir)) - FileUtils.rm_rf(dir) + FileUtils.rm_r(dir) end FileUtils.mkdir_p(home) FileUtils.mkdir_p(tmpdir) @@ -396,7 +396,7 @@ module Spec end def pristine_system_gems(*gems) - FileUtils.rm_rf(system_gem_path) + FileUtils.rm_r(system_gem_path) system_gems(*gems) end @@ -414,7 +414,6 @@ module Spec def cache_gems(*gems, gem_repo: gem_repo1) gems = gems.flatten - FileUtils.rm_rf("#{bundled_app}/vendor/cache") FileUtils.mkdir_p("#{bundled_app}/vendor/cache") gems.each do |g| @@ -425,7 +424,7 @@ module Spec end def simulate_new_machine - FileUtils.rm_rf bundled_app(".bundle") + FileUtils.rm_r bundled_app(".bundle") pristine_system_gems :bundler end @@ -549,6 +548,12 @@ module Spec 128 + signal_number end + def empty_repo4 + FileUtils.rm_r gem_repo4 + + build_repo4 {} + end + private def allowed_rubygems_warning?(text, extra_allowed_warning) diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb index 6c63666519..9b67ab0229 100644 --- a/spec/bundler/support/path.rb +++ b/spec/bundler/support/path.rb @@ -143,6 +143,10 @@ module Spec end end + def compact_index_cache_path + home(".bundle/cache/compact_index") + end + def bundled_app(*path) root = tmp("bundled_app") FileUtils.mkdir_p(root) diff --git a/spec/bundler/support/rubygems_ext.rb b/spec/bundler/support/rubygems_ext.rb index 82b2819858..67d49ac363 100644 --- a/spec/bundler/support/rubygems_ext.rb +++ b/spec/bundler/support/rubygems_ext.rb @@ -62,8 +62,7 @@ module Spec source = Path.tmp_root("1") destination = Path.tmp_root(n.to_s) - FileUtils.rm_rf destination - FileUtils.cp_r source, destination + FileUtils.cp_r source, destination, remove_destination: true end end diff --git a/spec/bundler/update/git_spec.rb b/spec/bundler/update/git_spec.rb index 64124e0920..2cb0abe02f 100644 --- a/spec/bundler/update/git_spec.rb +++ b/spec/bundler/update/git_spec.rb @@ -87,7 +87,7 @@ RSpec.describe "bundle update" do gem "foo", "1.0", :git => "#{lib_path("foo_one")}" G - FileUtils.rm_rf lib_path("foo_one") + FileUtils.rm_r lib_path("foo_one") install_gemfile <<-G source "https://gem.repo1" diff --git a/test/rubygems/test_gem_ext_cargo_builder.rb b/test/rubygems/test_gem_ext_cargo_builder.rb index 5faf3e2480..5035937544 100644 --- a/test/rubygems/test_gem_ext_cargo_builder.rb +++ b/test/rubygems/test_gem_ext_cargo_builder.rb @@ -3,6 +3,10 @@ require_relative "helper" require "rubygems/ext" require "open3" +begin + require "fiddle" +rescue LoadError +end class TestGemExtCargoBuilder < Gem::TestCase def setup @@ -149,7 +153,8 @@ class TestGemExtCargoBuilder < Gem::TestCase end def assert_ffi_handle(bundle, name) - require "fiddle" + return unless defined?(Fiddle) + dylib_handle = Fiddle.dlopen bundle assert_nothing_raised { dylib_handle[name] } ensure @@ -157,7 +162,8 @@ class TestGemExtCargoBuilder < Gem::TestCase end def refute_ffi_handle(bundle, name) - require "fiddle" + return unless defined?(Fiddle) + dylib_handle = Fiddle.dlopen bundle assert_raise { dylib_handle[name] } ensure diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock index f4e80a801f..f16c0eb140 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock +++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -152,18 +152,18 @@ dependencies = [ [[package]] name = "rb-sys" -version = "0.9.110" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56cf964f8e44115e50009921ea3d3791b6f74d1ae6d6ed37114fbe03a1cd7308" +checksum = "becea799ce051c16fb140be80f5e7cf781070f99ca099332383c2b17861249af" dependencies = [ "rb-sys-build", ] [[package]] name = "rb-sys-build" -version = "0.9.110" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161480347f56473107d4135643b6b1909331eec61445e113b256708a28b691c5" +checksum = "64691175abc704862f60a9ca8ef06174080cc50615f2bf1d4759f46db18b4d29" dependencies = [ "bindgen", "lazy_static", diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml index 292a6d984d..a66404aa41 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml +++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -rb-sys = "0.9.110" +rb-sys = "0.9.111" diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock index 5ab990b894..1230f8ae96 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock +++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -145,18 +145,18 @@ dependencies = [ [[package]] name = "rb-sys" -version = "0.9.110" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56cf964f8e44115e50009921ea3d3791b6f74d1ae6d6ed37114fbe03a1cd7308" +checksum = "becea799ce051c16fb140be80f5e7cf781070f99ca099332383c2b17861249af" dependencies = [ "rb-sys-build", ] [[package]] name = "rb-sys-build" -version = "0.9.110" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161480347f56473107d4135643b6b1909331eec61445e113b256708a28b691c5" +checksum = "64691175abc704862f60a9ca8ef06174080cc50615f2bf1d4759f46db18b4d29" dependencies = [ "bindgen", "lazy_static", diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml index 445bd3a641..03853fea08 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml +++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -rb-sys = "0.9.110" +rb-sys = "0.9.111" diff --git a/test/rubygems/test_gem_ext_cmake_builder.rb b/test/rubygems/test_gem_ext_cmake_builder.rb index b4cf8a8443..5f886af05f 100644 --- a/test/rubygems/test_gem_ext_cmake_builder.rb +++ b/test/rubygems/test_gem_ext_cmake_builder.rb @@ -29,7 +29,7 @@ class TestGemExtCmakeBuilder < Gem::TestCase def test_self_build File.open File.join(@ext, "CMakeLists.txt"), "w" do |cmakelists| cmakelists.write <<-EO_CMAKE -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 2.6) project(self_build NONE) install (FILES test.txt DESTINATION bin) EO_CMAKE diff --git a/test/rubygems/test_gem_rdoc.rb b/test/rubygems/test_gem_rdoc.rb index c4282b309c..9ecbb7d8c3 100644 --- a/test/rubygems/test_gem_rdoc.rb +++ b/test/rubygems/test_gem_rdoc.rb @@ -18,19 +18,7 @@ class TestGemRDoc < Gem::TestCase install_gem @a - hook_class = if defined?(RDoc::RubyGemsHook) - RDoc::RubyGemsHook - else - Gem::RDoc - end - - @hook = hook_class.new @a - - begin - hook_class.load_rdoc - rescue Gem::DocumentError => e - pend e.message - end + @hook = Gem::RDoc.new @a Gem.configuration[:rdoc] = nil end diff --git a/tool/bundler/dev_gems.rb b/tool/bundler/dev_gems.rb index 53e460f5b7..0d4dbd7f2e 100644 --- a/tool/bundler/dev_gems.rb +++ b/tool/bundler/dev_gems.rb @@ -7,7 +7,7 @@ gem "rake", "~> 13.1" gem "rb_sys" gem "turbo_tests", "~> 2.2.3" -gem "parallel_tests", "~> 4.7" +gem "parallel_tests", "~> 4.10.1" gem "parallel", "~> 1.19" gem "rspec-core", "~> 3.12" gem "rspec-expectations", "~> 3.12" diff --git a/tool/bundler/rubocop_gems.rb b/tool/bundler/rubocop_gems.rb index 4d0b21060a..ab13b1b2c3 100644 --- a/tool/bundler/rubocop_gems.rb +++ b/tool/bundler/rubocop_gems.rb @@ -5,6 +5,7 @@ source "https://rubygems.org" gem "rubocop", ">= 1.52.1", "< 2" gem "minitest" +gem "irb" gem "rake" gem "rake-compiler" gem "rspec" diff --git a/tool/bundler/standard_gems.rb b/tool/bundler/standard_gems.rb index 20c1ecd827..fab93e6d6d 100644 --- a/tool/bundler/standard_gems.rb +++ b/tool/bundler/standard_gems.rb @@ -5,6 +5,7 @@ source "https://rubygems.org" gem "standard", "~> 1.0" gem "minitest" +gem "irb" gem "rake" gem "rake-compiler" gem "rspec" diff --git a/tool/bundler/test_gems.rb b/tool/bundler/test_gems.rb index 5b211391b1..e60d187485 100644 --- a/tool/bundler/test_gems.rb +++ b/tool/bundler/test_gems.rb @@ -11,4 +11,5 @@ gem "sinatra", "~> 4.1" gem "rake", "~> 13.1" gem "builder", "~> 3.2" gem "rb_sys" +gem "fiddle" gem "rubygems-generate_index", "~> 1.1"