diff options
69 files changed, 499 insertions, 831 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb index 24785ef5eb..dc88bbdcb9 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -488,41 +488,9 @@ EOF configured_bundle_path.use_system_gems? end - def requires_sudo? - return @requires_sudo if defined?(@requires_sudo_ran) - - sudo_present = which "sudo" if settings.allow_sudo? - - if sudo_present - # the bundle path and subdirectories need to be writable for RubyGems - # to be able to unpack and install gems without exploding - path = bundle_path - path = path.parent until path.exist? - - # bins are written to a different location on OS X - bin_dir = Pathname.new(Bundler.system_bindir) - bin_dir = bin_dir.parent until bin_dir.exist? - - # if any directory is not writable, we need sudo - files = [path, bin_dir] | Dir[bundle_path.join("build_info/*").to_s] | Dir[bundle_path.join("*").to_s] - unwritable_files = files.reject {|f| File.writable?(f) } - sudo_needed = !unwritable_files.empty? - if sudo_needed - Bundler.ui.warn "Following files may not be writable, so sudo is needed:\n #{unwritable_files.map(&:to_s).sort.join("\n ")}" - end - end - - @requires_sudo_ran = true - @requires_sudo = settings.allow_sudo? && sudo_present && sudo_needed - end - def mkdir_p(path, options = {}) - if requires_sudo? && !options[:no_sudo] - sudo "mkdir -p '#{path}'" unless File.exist?(path) - else - SharedHelpers.filesystem_access(path, :write) do |p| - FileUtils.mkdir_p(p) - end + SharedHelpers.filesystem_access(path, :write) do |p| + FileUtils.mkdir_p(p) end end @@ -539,31 +507,6 @@ EOF end end - def sudo(str) - SUDO_MUTEX.synchronize do - prompt = "\n\n" + <<-PROMPT.gsub(/^ {6}/, "").strip + " " - Your user account isn't allowed to install to the system RubyGems. - You can cancel this installation and run: - - bundle config set --local path 'vendor/bundle' - bundle install - - to install the gems into ./vendor/bundle/, or you can enter your password - and install the bundled gems to RubyGems using sudo. - - Password: - PROMPT - - unless @prompted_for_sudo ||= system(%(sudo -k -p "#{prompt}" true)) - raise SudoNotPermittedError, - "Bundler requires sudo access to install at the moment. " \ - "Try installing again, granting Bundler sudo access when prompted, or installing into a different path." - end - - `sudo -p "#{prompt}" #{str}` - end - end - def read_file(file) SharedHelpers.filesystem_access(file, :read) do File.open(file, "r:UTF-8", &:read) diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb index 851ae9b840..1765621cb3 100644 --- a/lib/bundler/cli/install.rb +++ b/lib/bundler/cli/install.rb @@ -94,9 +94,8 @@ module Bundler def warn_if_root return if Bundler.settings[:silence_root_warning] || Gem.win_platform? || !Process.uid.zero? - Bundler.ui.warn "Don't run Bundler as root. Bundler can ask for sudo " \ - "if it is needed, and installing your bundle as root will break this " \ - "application for all non-root users on this machine.", :wrap => true + Bundler.ui.warn "Don't run Bundler as root. Installing your bundle as root " \ + "will break this application for all non-root users on this machine.", :wrap => true end def dependencies_count_for(definition) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 8bd9e11f32..79369ec374 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -485,7 +485,7 @@ module Bundler @resolver ||= begin last_resolve = converge_locked_specs remove_ruby_from_platforms_if_necessary!(dependencies) - Resolver.new(source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) + Resolver.new(source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve(last_resolve), platforms) end end @@ -878,9 +878,9 @@ module Bundler end end - def additional_base_requirements_for_resolve + def additional_base_requirements_for_resolve(last_resolve) return [] unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources) - converge_specs(@originally_locked_specs).map do |locked_spec| + converge_specs(@originally_locked_specs - last_resolve).map do |locked_spec| Dependency.new(locked_spec.name, ">= #{locked_spec.version}") end.uniq end diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb index f10b6cc68f..15069065ff 100644 --- a/lib/bundler/errors.rb +++ b/lib/bundler/errors.rb @@ -55,7 +55,6 @@ module Bundler class CyclicDependencyError < BundlerError; status_code(21); end class GemfileLockNotFound < BundlerError; status_code(22); end class PluginError < BundlerError; status_code(29); end - class SudoNotPermittedError < BundlerError; status_code(30); end class ThreadCreationError < BundlerError; status_code(33); end class APIResponseMismatchError < BundlerError; status_code(34); end class APIResponseInvalidDependenciesError < BundlerError; status_code(35); end diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb index e441b941c2..983de3137c 100644 --- a/lib/bundler/feature_flag.rb +++ b/lib/bundler/feature_flag.rb @@ -39,7 +39,6 @@ module Bundler settings_flag(:setup_makes_kernel_gem_public) { !bundler_3_mode? } settings_flag(:suppress_install_using_messages) { bundler_3_mode? } settings_flag(:update_requires_all_flag) { bundler_4_mode? } - settings_flag(:use_gem_version_promoter_for_major_updates) { bundler_3_mode? } settings_option(:default_cli_command) { bundler_3_mode? ? :cli_help : :install } diff --git a/lib/bundler/gem_version_promoter.rb b/lib/bundler/gem_version_promoter.rb index ddf7446dd2..1ae41e2928 100644 --- a/lib/bundler/gem_version_promoter.rb +++ b/lib/bundler/gem_version_promoter.rb @@ -55,19 +55,17 @@ module Bundler @level = v end - # Given a Dependency and an Array of SpecGroups of available versions for a - # gem, this method will return the Array of SpecGroups sorted (and possibly + # Given a Dependency and an Array of Specifications of available versions for a + # gem, this method will return the Array of Specifications sorted (and possibly # truncated if strict is true) in an order to give preference to the current # level (:major, :minor or :patch) when resolution is deciding what versions # best resolve all dependencies in the bundle. # @param dep [Dependency] The Dependency of the gem. - # @param spec_groups [SpecGroup] An array of SpecGroups for the same gem + # @param spec_groups [Specification] An array of Specifications for the same gem # named in the @dep param. - # @return [SpecGroup] A new instance of the SpecGroup Array sorted and + # @return [Specification] A new instance of the Specification Array sorted and # possibly filtered. def sort_versions(dep, spec_groups) - before_result = "before sort_versions: #{debug_format_result(dep, spec_groups).inspect}" if DEBUG - @sort_versions[dep] ||= begin gem_name = dep.name @@ -79,11 +77,6 @@ module Bundler filter_dep_specs(spec_groups, locked_spec) else sort_dep_specs(spec_groups, locked_spec) - end.tap do |specs| - if DEBUG - puts before_result - puts " after sort_versions: #{debug_format_result(dep, specs).inspect}" - end end end end @@ -183,12 +176,5 @@ module Bundler move, keep = result.partition {|s| s.version.to_s == version.to_s } keep.concat(move) end - - def debug_format_result(dep, spec_groups) - a = [dep.to_s, - spec_groups.map {|sg| [sg.version, sg.dependencies_for_activated_platforms.map {|dp| [dp.name, dp.requirement.to_s] }] }] - last_map = a.last.map {|sg_data| [sg_data.first.version, sg_data.last.map {|aa| aa.join(" ") }] } - [a.first, last_map, level, strict ? :strict : :not_strict] - end end end diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1 index 62177095d0..e5f1e228b5 100644 --- a/lib/bundler/man/bundle-add.1 +++ b/lib/bundler/man/bundle-add.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-ADD" "1" "July 2022" "" "" +.TH "BUNDLE\-ADD" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1 index 9c57c7c9c5..d1204104b1 100644 --- a/lib/bundler/man/bundle-binstubs.1 +++ b/lib/bundler/man/bundle-binstubs.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-BINSTUBS" "1" "July 2022" "" "" +.TH "BUNDLE\-BINSTUBS" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1 index fdaaa3b92a..1393caec65 100644 --- a/lib/bundler/man/bundle-cache.1 +++ b/lib/bundler/man/bundle-cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CACHE" "1" "July 2022" "" "" +.TH "BUNDLE\-CACHE" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1 index 5be7886274..71ddb5cee3 100644 --- a/lib/bundler/man/bundle-check.1 +++ b/lib/bundler/man/bundle-check.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CHECK" "1" "July 2022" "" "" +.TH "BUNDLE\-CHECK" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1 index 2bb95ed2de..e5dc4ccf92 100644 --- a/lib/bundler/man/bundle-clean.1 +++ b/lib/bundler/man/bundle-clean.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CLEAN" "1" "July 2022" "" "" +.TH "BUNDLE\-CLEAN" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 9f7887ca91..ffc91ed492 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -1,13 +1,22 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CONFIG" "1" "July 2022" "" "" +.TH "BUNDLE\-CONFIG" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options . .SH "SYNOPSIS" -\fBbundle config\fR [list|get|set|unset] [\fIname\fR [\fIvalue\fR]] +\fBbundle config\fR list +. +.br +\fBbundle config\fR [get] NAME +. +.br +\fBbundle config\fR [set] NAME VALUE +. +.br +\fBbundle config\fR unset NAME . .SH "DESCRIPTION" This command allows you to interact with Bundler\'s configuration system\. diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index 905c85fcd9..6f9edc9c39 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -3,7 +3,10 @@ bundle-config(1) -- Set bundler configuration options ## SYNOPSIS -`bundle config` [list|get|set|unset] [<name> [<value>]] +`bundle config` list<br> +`bundle config` [get] NAME<br> +`bundle config` [set] NAME VALUE<br> +`bundle config` unset NAME ## DESCRIPTION diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1 index 6aad9858db..3f18aaf569 100644 --- a/lib/bundler/man/bundle-doctor.1 +++ b/lib/bundler/man/bundle-doctor.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-DOCTOR" "1" "July 2022" "" "" +.TH "BUNDLE\-DOCTOR" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1 index 210dd178e8..7f6a892f6c 100644 --- a/lib/bundler/man/bundle-exec.1 +++ b/lib/bundler/man/bundle-exec.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-EXEC" "1" "July 2022" "" "" +.TH "BUNDLE\-EXEC" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index 0fb6f7d0ab..63d611bdd2 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-GEM" "1" "July 2022" "" "" +.TH "BUNDLE\-GEM" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem diff --git a/lib/bundler/man/bundle-help.1 b/lib/bundler/man/bundle-help.1 new file mode 100644 index 0000000000..c089342582 --- /dev/null +++ b/lib/bundler/man/bundle-help.1 @@ -0,0 +1,13 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "BUNDLE\-HELP" "1" "August 2022" "" "" +. +.SH "NAME" +\fBbundle\-help\fR \- Displays detailed help for each subcommand +. +.SH "SYNOPSIS" +\fBbundle help\fR [COMMAND] +. +.SH "DESCRIPTION" +Displays detailed help for the given subcommand\. You can specify a single \fBCOMMAND\fR at the same time\. When \fBCOMMAND\fR is omitted, help for \fBhelp\fR command will be displayed\. diff --git a/lib/bundler/man/bundle-help.1.ronn b/lib/bundler/man/bundle-help.1.ronn new file mode 100644 index 0000000000..0e144aead7 --- /dev/null +++ b/lib/bundler/man/bundle-help.1.ronn @@ -0,0 +1,12 @@ +bundle-help(1) -- Displays detailed help for each subcommand +============================================================ + +## SYNOPSIS + +`bundle help` [COMMAND] + +## DESCRIPTION + +Displays detailed help for the given subcommand. +You can specify a single `COMMAND` at the same time. +When `COMMAND` is omitted, help for `help` command will be displayed. diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1 index d3bad843b8..ae9bc48539 100644 --- a/lib/bundler/man/bundle-info.1 +++ b/lib/bundler/man/bundle-info.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INFO" "1" "July 2022" "" "" +.TH "BUNDLE\-INFO" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1 index 0b3abfeefc..0b06ce8997 100644 --- a/lib/bundler/man/bundle-init.1 +++ b/lib/bundler/man/bundle-init.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INIT" "1" "July 2022" "" "" +.TH "BUNDLE\-INIT" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1 index 53f2eaae0a..4ad37ec3eb 100644 --- a/lib/bundler/man/bundle-inject.1 +++ b/lib/bundler/man/bundle-inject.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INJECT" "1" "July 2022" "" "" +.TH "BUNDLE\-INJECT" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1 index 8e94fe2437..077a58f415 100644 --- a/lib/bundler/man/bundle-install.1 +++ b/lib/bundler/man/bundle-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INSTALL" "1" "July 2022" "" "" +.TH "BUNDLE\-INSTALL" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile @@ -170,35 +170,6 @@ As a result, \fBbundle install \-\-deployment\fR installs gems to the \fBvendor/ . .IP "" 0 . -.SH "SUDO USAGE" -By default, Bundler installs gems to the same location as \fBgem install\fR\. -. -.P -In some cases, that location may not be writable by your Unix user\. In that case, Bundler will stage everything in a temporary directory, then ask you for your \fBsudo\fR password in order to copy the gems into their system location\. -. -.P -From your perspective, this is identical to installing the gems directly into the system\. -. -.P -You should never use \fBsudo bundle install\fR\. This is because several other steps in \fBbundle install\fR must be performed as the current user: -. -.IP "\(bu" 4 -Updating your \fBGemfile\.lock\fR -. -.IP "\(bu" 4 -Updating your \fBvendor/cache\fR, if necessary -. -.IP "\(bu" 4 -Checking out private git repositories using your user\'s SSH keys -. -.IP "" 0 -. -.P -Of these three, the first two could theoretically be performed by \fBchown\fRing the resulting files to \fB$SUDO_USER\fR\. The third, however, can only be performed by invoking the \fBgit\fR command as the current user\. Therefore, git gems are downloaded and installed into \fB~/\.bundle\fR rather than $GEM_HOME or $BUNDLE_PATH\. -. -.P -As a result, you should run \fBbundle install\fR as the current user, and Bundler will ask for your password if it is needed to put the gems into their final location\. -. .SH "INSTALLING GROUPS" By default, \fBbundle install\fR will install all gems in all groups in your Gemfile(5), except those declared for a different platform\. . diff --git a/lib/bundler/man/bundle-install.1.ronn b/lib/bundler/man/bundle-install.1.ronn index 47200ac2d5..be9ed0f974 100644 --- a/lib/bundler/man/bundle-install.1.ronn +++ b/lib/bundler/man/bundle-install.1.ronn @@ -224,35 +224,6 @@ will cause an error when the Gemfile(5) is modified. the `vendor/bundle` directory in the application. This may be overridden using the `--path` option. -## SUDO USAGE - -By default, Bundler installs gems to the same location as `gem install`. - -In some cases, that location may not be writable by your Unix user. In -that case, Bundler will stage everything in a temporary directory, -then ask you for your `sudo` password in order to copy the gems into -their system location. - -From your perspective, this is identical to installing the gems -directly into the system. - -You should never use `sudo bundle install`. This is because several -other steps in `bundle install` must be performed as the current user: - -* Updating your `Gemfile.lock` -* Updating your `vendor/cache`, if necessary -* Checking out private git repositories using your user's SSH keys - -Of these three, the first two could theoretically be performed by -`chown`ing the resulting files to `$SUDO_USER`. The third, however, -can only be performed by invoking the `git` command as -the current user. Therefore, git gems are downloaded and installed -into `~/.bundle` rather than $GEM_HOME or $BUNDLE_PATH. - -As a result, you should run `bundle install` as the current user, -and Bundler will ask for your password if it is needed to put the -gems into their final location. - ## INSTALLING GROUPS By default, `bundle install` will install all gems in all groups diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1 index 3a9cc9a237..6e89f810a1 100644 --- a/lib/bundler/man/bundle-list.1 +++ b/lib/bundler/man/bundle-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LIST" "1" "July 2022" "" "" +.TH "BUNDLE\-LIST" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1 index ac03c5478e..f5f0ce2bdb 100644 --- a/lib/bundler/man/bundle-lock.1 +++ b/lib/bundler/man/bundle-lock.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LOCK" "1" "July 2022" "" "" +.TH "BUNDLE\-LOCK" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1 index be6c5af248..7bda0afd33 100644 --- a/lib/bundler/man/bundle-open.1 +++ b/lib/bundler/man/bundle-open.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OPEN" "1" "July 2022" "" "" +.TH "BUNDLE\-OPEN" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1 index fc3d5e8caf..a2b8e2bf92 100644 --- a/lib/bundler/man/bundle-outdated.1 +++ b/lib/bundler/man/bundle-outdated.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OUTDATED" "1" "July 2022" "" "" +.TH "BUNDLE\-OUTDATED" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1 index f5a90c59e9..7fda4ef046 100644 --- a/lib/bundler/man/bundle-platform.1 +++ b/lib/bundler/man/bundle-platform.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PLATFORM" "1" "July 2022" "" "" +.TH "BUNDLE\-PLATFORM" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information diff --git a/lib/bundler/man/bundle-plugin.1 b/lib/bundler/man/bundle-plugin.1 new file mode 100644 index 0000000000..7210806327 --- /dev/null +++ b/lib/bundler/man/bundle-plugin.1 @@ -0,0 +1,81 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "BUNDLE\-PLUGIN" "1" "August 2022" "" "" +. +.SH "NAME" +\fBbundle\-plugin\fR \- Manage Bundler plugins +. +.SH "SYNOPSIS" +\fBbundle plugin\fR install PLUGINS [\-\-source=\fISOURCE\fR] [\-\-version=\fIversion\fR] [\-\-git|\-\-local_git=\fIgit\-url\fR] [\-\-branch=\fIbranch\fR|\-\-ref=\fIrev\fR] +. +.br +\fBbundle plugin\fR uninstall PLUGINS +. +.br +\fBbundle plugin\fR list +. +.br +\fBbundle plugin\fR help [COMMAND] +. +.SH "DESCRIPTION" +You can install, uninstall, and list plugin(s) with this command to extend functionalities of Bundler\. +. +.SH "SUB\-COMMANDS" +. +.SS "install" +Install the given plugin(s)\. +. +.IP "\(bu" 4 +\fBbundle plugin install bundler\-graph\fR: Install bundler\-graph gem from RubyGems\.org\. The global source, specified in source in Gemfile is ignored\. +. +.IP "\(bu" 4 +\fBbundle plugin install bundler\-graph \-\-source https://example\.com\fR: Install bundler\-graph gem from example\.com\. The global source, specified in source in Gemfile is not considered\. +. +.IP "\(bu" 4 +\fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\fR: You can specify the version of the gem via \fB\-\-version\fR\. +. +.IP "\(bu" 4 +\fBbundle plugin install bundler\-graph \-\-git https://github\.com/rubygems/bundler\-graph\fR: Install bundler\-graph gem from Git repository\. \fB\-\-git\fR can be replaced with \fB\-\-local\-git\fR\. You cannot use both \fB\-\-git\fR and \fB\-\-local\-git\fR\. You can use standard Git URLs like: +. +.IP "\(bu" 4 +\fBssh://[user@]host\.xz[:port]/path/to/repo\.git\fR +. +.IP "\(bu" 4 +\fBhttp[s]://host\.xz[:port]/path/to/repo\.git\fR +. +.IP "\(bu" 4 +\fB/path/to/repo\fR +. +.IP "\(bu" 4 +\fBfile:///path/to/repo\fR +. +.IP "" 0 +. +.IP +When you specify \fB\-\-git\fR/\fB\-\-local\-git\fR, you can use \fB\-\-branch\fR or \fB\-\-ref\fR to specify any branch, tag, or commit hash (revision) to use\. When you specify both, only the latter is used\. +. +.IP "" 0 +. +.SS "uninstall" +Uninstall the plugin(s) specified in PLUGINS\. +. +.SS "list" +List the installed plugins and available commands\. +. +.P +No options\. +. +.SS "help" +Describe subcommands or one specific subcommand\. +. +.P +No options\. +. +.SH "SEE ALSO" +. +.IP "\(bu" 4 +How to write a Bundler plugin \fIhttps://bundler\.io/guides/bundler_plugins\.html\fR +. +.IP "" 0 + diff --git a/lib/bundler/man/bundle-plugin.1.ronn b/lib/bundler/man/bundle-plugin.1.ronn new file mode 100644 index 0000000000..4f234eeba7 --- /dev/null +++ b/lib/bundler/man/bundle-plugin.1.ronn @@ -0,0 +1,59 @@ +bundle-plugin(1) -- Manage Bundler plugins +========================================== + +## SYNOPSIS + +`bundle plugin` install PLUGINS [--source=<SOURCE>] [--version=<version>] + [--git|--local_git=<git-url>] [--branch=<branch>|--ref=<rev>]<br> +`bundle plugin` uninstall PLUGINS<br> +`bundle plugin` list<br> +`bundle plugin` help [COMMAND] + +## DESCRIPTION + +You can install, uninstall, and list plugin(s) with this command to extend functionalities of Bundler. + +## SUB-COMMANDS + +### install + +Install the given plugin(s). + +* `bundle plugin install bundler-graph`: + Install bundler-graph gem from RubyGems.org. The global source, specified in source in Gemfile is ignored. + +* `bundle plugin install bundler-graph --source https://example.com`: + Install bundler-graph gem from example.com. The global source, specified in source in Gemfile is not considered. + +* `bundle plugin install bundler-graph --version 0.2.1`: + You can specify the version of the gem via `--version`. + +* `bundle plugin install bundler-graph --git https://github.com/rubygems/bundler-graph`: + Install bundler-graph gem from Git repository. `--git` can be replaced with `--local-git`. You cannot use both `--git` and `--local-git`. You can use standard Git URLs like: + + * `ssh://[user@]host.xz[:port]/path/to/repo.git` + * `http[s]://host.xz[:port]/path/to/repo.git` + * `/path/to/repo` + * `file:///path/to/repo` + + When you specify `--git`/`--local-git`, you can use `--branch` or `--ref` to specify any branch, tag, or commit hash (revision) to use. When you specify both, only the latter is used. + +### uninstall + +Uninstall the plugin(s) specified in PLUGINS. + +### list + +List the installed plugins and available commands. + +No options. + +### help + +Describe subcommands or one specific subcommand. + +No options. + +## SEE ALSO + +* [How to write a Bundler plugin](https://bundler.io/guides/bundler_plugins.html) diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1 index 44e5a83a01..d635d24e2d 100644 --- a/lib/bundler/man/bundle-pristine.1 +++ b/lib/bundler/man/bundle-pristine.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PRISTINE" "1" "July 2022" "" "" +.TH "BUNDLE\-PRISTINE" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1 index 29ec246018..4952e8094e 100644 --- a/lib/bundler/man/bundle-remove.1 +++ b/lib/bundler/man/bundle-remove.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-REMOVE" "1" "July 2022" "" "" +.TH "BUNDLE\-REMOVE" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1 index 227b1c8a1e..72ef3283cc 100644 --- a/lib/bundler/man/bundle-show.1 +++ b/lib/bundler/man/bundle-show.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-SHOW" "1" "July 2022" "" "" +.TH "BUNDLE\-SHOW" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1 index 7d0988bfa5..06ceef85db 100644 --- a/lib/bundler/man/bundle-update.1 +++ b/lib/bundler/man/bundle-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-UPDATE" "1" "July 2022" "" "" +.TH "BUNDLE\-UPDATE" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1 index f6f51cde0e..cf63dd8f9e 100644 --- a/lib/bundler/man/bundle-viz.1 +++ b/lib/bundler/man/bundle-viz.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-VIZ" "1" "July 2022" "" "" +.TH "BUNDLE\-VIZ" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1 index f683e78cc6..d178b2f5dc 100644 --- a/lib/bundler/man/bundle.1 +++ b/lib/bundler/man/bundle.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE" "1" "July 2022" "" "" +.TH "BUNDLE" "1" "August 2022" "" "" . .SH "NAME" \fBbundle\fR \- Ruby Dependency Management @@ -55,7 +55,7 @@ Execute a script in the current bundle Specify and read configuration options for Bundler . .TP -\fBbundle help(1)\fR +\fBbundle help(1)\fR \fIbundle\-help\.1\.html\fR Display detailed help for each subcommand . .SH "UTILITIES" @@ -120,6 +120,10 @@ Display warnings about common problems \fBbundle remove(1)\fR \fIbundle\-remove\.1\.html\fR Removes gems from the Gemfile . +.TP +\fBbundle plugin(1)\fR \fIbundle\-plugin\.1\.html\fR +Manage Bundler plugins +. .SH "PLUGINS" When running a command that isn\'t listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named \fBbundler\-<command>\fR and execute it, passing down any extra arguments to it\. . diff --git a/lib/bundler/man/bundle.1.ronn b/lib/bundler/man/bundle.1.ronn index 8f0159eee5..35c0a7ef87 100644 --- a/lib/bundler/man/bundle.1.ronn +++ b/lib/bundler/man/bundle.1.ronn @@ -46,7 +46,7 @@ We divide `bundle` subcommands into primary commands and utilities: * [`bundle config(1)`](bundle-config.1.html): Specify and read configuration options for Bundler -* `bundle help(1)`: +* [`bundle help(1)`](bundle-help.1.html): Display detailed help for each subcommand ## UTILITIES @@ -97,6 +97,9 @@ We divide `bundle` subcommands into primary commands and utilities: * [`bundle remove(1)`](bundle-remove.1.html): Removes gems from the Gemfile +* [`bundle plugin(1)`](bundle-plugin.1.html): + Manage Bundler plugins + ## PLUGINS When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES, diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5 index 63a16ca3ff..3d3994153b 100644 --- a/lib/bundler/man/gemfile.5 +++ b/lib/bundler/man/gemfile.5 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GEMFILE" "5" "July 2022" "" "" +.TH "GEMFILE" "5" "August 2022" "" "" . .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs diff --git a/lib/bundler/man/index.txt b/lib/bundler/man/index.txt index ef2956b2f9..6de81ea027 100644 --- a/lib/bundler/man/index.txt +++ b/lib/bundler/man/index.txt @@ -9,6 +9,7 @@ bundle-config(1) bundle-config.1 bundle-doctor(1) bundle-doctor.1 bundle-exec(1) bundle-exec.1 bundle-gem(1) bundle-gem.1 +bundle-help(1) bundle-help.1 bundle-info(1) bundle-info.1 bundle-init(1) bundle-init.1 bundle-inject(1) bundle-inject.1 @@ -18,6 +19,7 @@ bundle-lock(1) bundle-lock.1 bundle-open(1) bundle-open.1 bundle-outdated(1) bundle-outdated.1 bundle-platform(1) bundle-platform.1 +bundle-plugin(1) bundle-plugin.1 bundle-pristine(1) bundle-pristine.1 bundle-remove(1) bundle-remove.1 bundle-show(1) bundle-show.1 diff --git a/lib/bundler/match_remote_metadata.rb b/lib/bundler/match_remote_metadata.rb index e1b2f4d0e2..5e46d52441 100644 --- a/lib/bundler/match_remote_metadata.rb +++ b/lib/bundler/match_remote_metadata.rb @@ -2,8 +2,11 @@ module Bundler module FetchMetadata + # A fallback is included because the original version of the specification + # API didn't include that field, so some marshalled specs in the index have it + # set to +nil+. def matches_current_ruby? - @required_ruby_version ||= _remote_specification.required_ruby_version + @required_ruby_version ||= _remote_specification.required_ruby_version || Gem::Requirement.default super end diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb index 158c69e1a1..26458bd596 100644 --- a/lib/bundler/plugin.rb +++ b/lib/bundler/plugin.rb @@ -36,6 +36,8 @@ module Bundler # @param [Hash] options various parameters as described in description. # Refer to cli/plugin for available options def install(names, options) + raise InvalidOption, "You cannot specify `--branch` and `--ref` at the same time." if options["branch"] && options["ref"] + specs = Installer.new.install(names, options) save_plugins names, specs diff --git a/lib/bundler/plugin/installer/rubygems.rb b/lib/bundler/plugin/installer/rubygems.rb index 7277234d9a..cb5db9c30e 100644 --- a/lib/bundler/plugin/installer/rubygems.rb +++ b/lib/bundler/plugin/installer/rubygems.rb @@ -6,10 +6,6 @@ module Bundler class Rubygems < Bundler::Source::Rubygems private - def requires_sudo? - false # Will change on implementation of project level plugins - end - def rubygems_dir Plugin.root end diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index a74af45027..fcb3812c5a 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -3,6 +3,7 @@ module Bundler class Resolver require_relative "vendored_molinillo" + require_relative "resolver/base" require_relative "resolver/spec_group" include GemHelpers @@ -25,15 +26,13 @@ module Bundler def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) @source_requirements = source_requirements - @base = base + @base = Resolver::Base.new(base, additional_base_requirements) @resolver = Molinillo::Resolver.new(self, self) @results_for = {} @search_for = {} - @additional_base_requirements = additional_base_requirements @platforms = platforms @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY] @gem_version_promoter = gem_version_promoter - @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? end def start(requirements, exclude_specs: []) @@ -43,18 +42,11 @@ module Bundler remove_from_candidates(spec) end - @base_dg = Molinillo::DependencyGraph.new - @base.each do |ls| - dep = Dependency.new(ls.name, ls.version) - @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true) - end - @additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } - @gem_version_promoter.prerelease_specified = @prerelease_specified = {} requirements.each {|dep| @prerelease_specified[dep.name] ||= dep.prerelease? } verify_gemfile_dependencies_are_found!(requirements) - result = @resolver.resolve(requirements, @base_dg). + result = @resolver.resolve(requirements). map(&:payload). reject {|sg| sg.name.end_with?("\0") }. map(&:to_specs). @@ -62,8 +54,20 @@ module Bundler SpecSet.new(SpecSet.new(result).for(regular_requirements, false, @platforms)) rescue Molinillo::VersionConflict => e + conflicts = e.conflicts + + deps_to_unlock = conflicts.values.inject([]) do |deps, conflict| + deps |= conflict.requirement_trees.flatten.map {|req| base_requirements[req.name] }.compact + end + + if deps_to_unlock.any? + @base.unlock_deps(deps_to_unlock) + reset_spec_cache + retry + end + message = version_conflict_message(e) - raise VersionConflict.new(e.conflicts.keys.uniq, message) + raise VersionConflict.new(conflicts.keys.uniq, message) rescue Molinillo::CircularDependencyError => e names = e.dependencies.sort_by(&:name).map {|d| "gem '#{d.name}'" } raise CyclicDependencyError, "Your bundle requires gems that depend" \ @@ -118,31 +122,22 @@ module Bundler dependency = dependency_proxy.dep name = dependency.name @search_for[dependency_proxy] ||= begin - results = results_for(dependency) + @base[name].select {|spec| requirement_satisfied_by?(dependency, nil, spec) } + locked_results = @base[name].select {|spec| requirement_satisfied_by?(dependency, nil, spec) } + locked_requirement = base_requirements[name] + results = results_for(dependency) + locked_results + results = results.select {|spec| requirement_satisfied_by?(locked_requirement, nil, spec) } if locked_requirement - if vertex = @base_dg.vertex_named(name) - locked_requirement = vertex.payload.requirement - end - - if !@prerelease_specified[name] && (!@use_gvp || locked_requirement.nil?) + if !@prerelease_specified[name] && locked_results.empty? # Move prereleases to the beginning of the list, so they're considered # last during resolution. pre, results = results.partition {|spec| spec.version.prerelease? } results = pre + results end - spec_groups = if results.any? - nested = [] - results.each do |spec| - version, specs = nested.last - if version == spec.version - specs << spec - else - nested << [spec.version, [spec]] - end - end - nested.reduce([]) do |groups, (version, specs)| - next groups if locked_requirement && !locked_requirement.satisfied_by?(version) + if results.any? + results = @gem_version_promoter.sort_versions(dependency, results) + + results.group_by(&:version).reduce([]) do |groups, (_, specs)| next groups unless specs.any? {|spec| spec.match_platform(platform) } specs_by_platform = Hash.new do |current_specs, current_platform| @@ -165,13 +160,6 @@ module Bundler else [] end - # GVP handles major itself, but it's still a bit risky to trust it with it - # until we get it settled with new behavior. For 2.x it can take over all cases. - if !@use_gvp - spec_groups - else - @gem_version_promoter.sort_versions(dependency, spec_groups) - end end end @@ -197,12 +185,6 @@ module Bundler "Gemfile" end - def name_for_locking_dependency_source - Bundler.default_lockfile.basename.to_s - rescue StandardError - "Gemfile.lock" - end - def requirement_satisfied_by?(requirement, activated, spec) requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec) end @@ -216,7 +198,7 @@ module Bundler name = name_for(dependency) vertex = activated.vertex_named(name) [ - @base_dg.vertex_named(name) ? 0 : 1, + @base[name].any? ? 0 : 1, vertex.payload ? 0 : 1, vertex.root? ? 0 : 1, amount_constrained(dependency), @@ -235,9 +217,12 @@ module Bundler private + def base_requirements + @base.base_requirements + end + def remove_from_candidates(spec) @base.delete(spec) - @gem_version_promoter.reset @results_for.keys.each do |dep| next unless dep.name == spec.name @@ -245,7 +230,12 @@ module Bundler @results_for[dep].reject {|s| s.name == spec.name && s.version == spec.version } end + reset_spec_cache + end + + def reset_spec_cache @search_for = {} + @gem_version_promoter.reset end # returns an integer \in (-\infty, 0] @@ -337,18 +327,6 @@ module Bundler e.message_with_trees( :full_message_for_conflict => lambda do |name, conflict| - o = if name.end_with?("\0") - String.new("Bundler found conflicting requirements for the #{name} version:") - else - String.new("Bundler could not find compatible versions for gem \"#{name}\":") - end - o << %(\n) - if conflict.locked_requirement - o << %( In snapshot (#{name_for_locking_dependency_source}):\n) - o << %( #{SharedHelpers.pretty_dependency(conflict.locked_requirement)}\n) - o << %(\n) - end - o << %( In #{name_for_explicit_dependency_source}:\n) trees = conflict.requirement_trees # called first, because we want to reduce the amount of work required to find maximal empty sets @@ -367,30 +345,41 @@ module Bundler trees.sort_by! {|t| t.reverse.map(&:name) } end - o << trees.map do |tree| - t = "".dup - depth = 2 + if trees.size > 1 || name == "bundler" + o = if name.end_with?("\0") + String.new("Bundler found conflicting requirements for the #{name} version:") + else + String.new("Bundler could not find compatible versions for gem \"#{name}\":") + end + o << %(\n) + o << %( In #{name_for_explicit_dependency_source}:\n) + o << trees.map do |tree| + t = "".dup + depth = 2 - base_tree = tree.first - base_tree_name = base_tree.name + base_tree = tree.first + base_tree_name = base_tree.name - if base_tree_name.end_with?("\0") - t = nil - else - tree.each do |req| - t << " " * depth << SharedHelpers.pretty_dependency(req) - unless tree.last == req - if spec = conflict.activated_by_name[req.name] - t << %( was resolved to #{spec.version}, which) + if base_tree_name.end_with?("\0") + t = nil + else + tree.each do |req| + t << " " * depth << SharedHelpers.pretty_dependency(req) + unless tree.last == req + if spec = conflict.activated_by_name[req.name] + t << %( was resolved to #{spec.version}, which) + end + t << %( depends on) end - t << %( depends on) + t << %(\n) + depth += 1 end - t << %(\n) - depth += 1 end - end - t - end.compact.join("\n") + t + end.compact.join("\n") + else + o = String.new + end if name == "bundler" o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION})) @@ -414,17 +403,13 @@ module Bundler end elsif name.end_with?("\0") o << %(\n Current #{name} version:\n #{SharedHelpers.pretty_dependency(@metadata_requirements.find {|req| req.name == name })}\n\n) - elsif conflict.locked_requirement - o << "\n" - o << %(Deleting your #{name_for_locking_dependency_source} file and running `bundle install` will rebuild your snapshot from scratch, using only\n) - o << %(the gems in your Gemfile, which may resolve the conflict.\n) elsif !conflict.existing o << "\n" relevant_source = conflict.requirement.source || source_for(name) - extra_message = if conflict.requirement_trees.first.size > 1 - ", which is required by gem '#{SharedHelpers.pretty_dependency(conflict.requirement_trees.first[-2])}'," + extra_message = if trees.first.size > 1 + ", which is required by gem '#{SharedHelpers.pretty_dependency(trees.first[-2])}'," else "" end diff --git a/lib/bundler/resolver/base.rb b/lib/bundler/resolver/base.rb new file mode 100644 index 0000000000..84e087b0ae --- /dev/null +++ b/lib/bundler/resolver/base.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Bundler + class Resolver + class Base + def initialize(base, additional_base_requirements) + @base = base + @additional_base_requirements = additional_base_requirements + end + + def [](name) + @base[name] + end + + def delete(spec) + @base.delete(spec) + end + + def base_requirements + @base_requirements ||= build_base_requirements + end + + def unlock_deps(deps) + exact, lower_bound = deps.partition(&:specific?) + + exact.each do |exact_dep| + @base.delete_by_name_and_version(exact_dep.name, exact_dep.requirement.requirements.first.last) + end + + lower_bound.each do |lower_bound_dep| + @additional_base_requirements.delete(lower_bound_dep) + end + + @base_requirements = nil + end + + private + + def build_base_requirements + base_requirements = {} + @base.each do |ls| + dep = Dependency.new(ls.name, ls.version) + base_requirements[ls.name] = DepProxy.get_proxy(dep, ls.platform) + end + @additional_base_requirements.each {|d| base_requirements[d.name] = d } + base_requirements + end + end + end +end diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb index 08af0610c6..d14075c96b 100644 --- a/lib/bundler/rubygems_integration.rb +++ b/lib/bundler/rubygems_integration.rb @@ -504,10 +504,6 @@ module Bundler Gem::Package.build(spec, skip_validation) end - def repository_subdirectories - Gem::REPOSITORY_SUBDIRECTORIES - end - def path_separator Gem.path_separator end diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index cf5675274e..a76a792743 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -45,7 +45,6 @@ module Bundler silence_root_warning suppress_install_using_messages update_requires_all_flag - use_gem_version_promoter_for_major_updates ].freeze NUMBER_KEYS = %w[ @@ -278,12 +277,6 @@ module Bundler end end - def allow_sudo? - key = key_for(:path) - path_configured = @temporary.key?(key) || @local_config.key?(key) - !path_configured - end - def ignore_config? ENV["BUNDLE_IGNORE_CONFIG"] end diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb index ed66dcdc12..fd34edffb7 100644 --- a/lib/bundler/source/git.rb +++ b/lib/bundler/source/git.rb @@ -102,13 +102,7 @@ module Bundler @install_path ||= begin git_scope = "#{base_name}-#{shortref_for_path(revision)}" - path = Bundler.install_path.join(git_scope) - - if !path.exist? && Bundler.requires_sudo? - Bundler.user_bundle_path.join(Bundler.ruby_scope).join(git_scope) - else - path - end + Bundler.install_path.join(git_scope) end end @@ -219,7 +213,7 @@ module Bundler # across different projects, this cache will be shared. # When using local git repos, this is set to the local repo. def cache_path - @cache_path ||= if Bundler.requires_sudo? || Bundler.feature_flag.global_gem_cache? + @cache_path ||= if Bundler.feature_flag.global_gem_cache? Bundler.user_cache else Bundler.bundle_path.join("cache", "bundler") diff --git a/lib/bundler/source/path/installer.rb b/lib/bundler/source/path/installer.rb index a70973bde7..0af28fe770 100644 --- a/lib/bundler/source/path/installer.rb +++ b/lib/bundler/source/path/installer.rb @@ -18,13 +18,7 @@ module Bundler @build_args = options[:build_args] || Bundler.rubygems.build_args @gem_bin_dir = "#{Bundler.rubygems.gem_dir}/bin" @disable_extensions = options[:disable_extensions] - - if Bundler.requires_sudo? - @tmp_dir = Bundler.tmp(spec.full_name).to_s - @bin_dir = "#{@tmp_dir}/bin" - else - @bin_dir = @gem_bin_dir - end + @bin_dir = @gem_bin_dir end def post_install @@ -38,25 +32,10 @@ module Bundler generate_bin unless spec.executables.empty? run_hooks(:post_install) - ensure - Bundler.rm_rf(@tmp_dir) if Bundler.requires_sudo? end private - def generate_bin - super - - if Bundler.requires_sudo? - SharedHelpers.filesystem_access(@gem_bin_dir) do |p| - Bundler.mkdir_p(p) - end - spec.executables.each do |exe| - Bundler.sudo "cp -R #{@bin_dir}/#{exe} #{@gem_bin_dir}" - end - end - end - def run_hooks(type) hooks_meth = "#{type}_hooks" return unless Gem.respond_to?(hooks_meth) diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index a50934b315..396465f0cb 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -160,15 +160,10 @@ module Bundler return if Bundler.settings[:no_install] - if requires_sudo? - install_path = Bundler.tmp(spec.full_name) - bin_path = install_path.join("bin") - else - install_path = rubygems_dir - bin_path = Bundler.system_bindir - end + install_path = rubygems_dir + bin_path = Bundler.system_bindir - Bundler.mkdir_p bin_path, :no_sudo => true unless spec.executables.empty? || Bundler.rubygems.provides?(">= 2.7.5") + Bundler.mkdir_p bin_path unless spec.executables.empty? || Bundler.rubygems.provides?(">= 2.7.5") require_relative "../rubygems_gem_installer" @@ -209,34 +204,7 @@ module Bundler spec.full_gem_path = installed_spec.full_gem_path spec.loaded_from = installed_spec.loaded_from - # SUDO HAX - if requires_sudo? - Bundler.rubygems.repository_subdirectories.each do |name| - src = File.join(install_path, name, "*") - dst = File.join(rubygems_dir, name) - if name == "extensions" && Dir.glob(src).any? - src = File.join(src, "*/*") - ext_src = Dir.glob(src).first - ext_src.gsub!(src[0..-6], "") - dst = File.dirname(File.join(dst, ext_src)) - end - SharedHelpers.filesystem_access(dst) do |p| - Bundler.mkdir_p(p) - end - Bundler.sudo "cp -R #{src} #{dst}" if Dir[src].any? - end - - spec.executables.each do |exe| - SharedHelpers.filesystem_access(Bundler.system_bindir) do |p| - Bundler.mkdir_p(p) - end - Bundler.sudo "cp -R #{install_path}/bin/#{exe} #{Bundler.system_bindir}/" - end - end - spec.post_install_message - ensure - Bundler.rm_rf(install_path) if requires_sudo? end def cache(spec, custom_path = nil) @@ -475,38 +443,18 @@ module Bundler gem_path = package_path(cache_path, spec) return gem_path if File.exist?(gem_path) - if requires_sudo? - download_path = Bundler.tmp(spec.full_name) - download_cache_path = default_cache_path_for(download_path) - else - download_cache_path = cache_path - end - - SharedHelpers.filesystem_access(download_cache_path) do |p| + SharedHelpers.filesystem_access(cache_path) do |p| FileUtils.mkdir_p(p) end - download_gem(spec, download_cache_path, previous_spec) - - if requires_sudo? - SharedHelpers.filesystem_access(cache_path) do |p| - Bundler.mkdir_p(p) - end - Bundler.sudo "mv #{package_path(download_cache_path, spec)} #{gem_path}" - end + download_gem(spec, cache_path, previous_spec) gem_path - ensure - Bundler.rm_rf(download_path) if requires_sudo? end def installed?(spec) installed_specs[spec].any? && !spec.deleted_gem? end - def requires_sudo? - Bundler.requires_sudo? - end - def rubygems_dir Bundler.bundle_path end diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 4965ca9e60..1d0b7a460d 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -114,10 +114,20 @@ module Bundler SpecSet.new(arr) end + def -(other) + SpecSet.new(to_a - other.to_a) + end + def find_by_name_and_platform(name, platform) @specs.detect {|spec| spec.name == name && spec.match_platform(platform) } end + def delete_by_name_and_version(name, version) + @specs.reject! {|spec| spec.name == name && spec.version == version } + @lookup = nil + @sorted = nil + end + def what_required(spec) unless req = find {|s| s.dependencies.any? {|d| d.type == :runtime && d.name == spec.name } } return [spec] diff --git a/spec/bundler/bundler/bundler_spec.rb b/spec/bundler/bundler/bundler_spec.rb index 9e79bc165f..764c55a91f 100644 --- a/spec/bundler/bundler/bundler_spec.rb +++ b/spec/bundler/bundler/bundler_spec.rb @@ -189,22 +189,6 @@ EOF Bundler.mkdir_p(bundled_app.join("foo", "bar")) expect(bundled_app.join("foo", "bar")).to exist end - - context "when mkdir_p requires sudo" do - it "creates a new folder using sudo" do - expect(Bundler).to receive(:requires_sudo?).and_return(true) - expect(Bundler).to receive(:sudo).and_return true - Bundler.mkdir_p(bundled_app.join("foo")) - end - end - - context "with :no_sudo option" do - it "forces mkdir_p to not use sudo" do - expect(Bundler).to receive(:requires_sudo?).and_return(true) - expect(Bundler).to_not receive(:sudo) - Bundler.mkdir_p(bundled_app.join("foo"), :no_sudo => true) - end - end end describe "#user_home" do @@ -268,118 +252,6 @@ EOF end end - describe "#requires_sudo?" do - let!(:tmpdir) { Dir.mktmpdir } - let(:bundle_path) { Pathname("#{tmpdir}/bundle") } - - def clear_cached_requires_sudo - return unless Bundler.instance_variable_defined?(:@requires_sudo_ran) - Bundler.remove_instance_variable(:@requires_sudo_ran) - Bundler.remove_instance_variable(:@requires_sudo) - end - - before do - clear_cached_requires_sudo - allow(Bundler).to receive(:which).with("sudo").and_return("/usr/bin/sudo") - allow(Bundler).to receive(:bundle_path).and_return(bundle_path) - end - - after do - FileUtils.rm_rf(tmpdir) - clear_cached_requires_sudo - end - - subject { Bundler.requires_sudo? } - - context "bundle_path doesn't exist" do - it { should be false } - - context "and parent dir can't be written" do - before do - FileUtils.chmod(0o500, tmpdir) - end - - it { should be true } - end - - context "with unwritable files in a parent dir" do - # Regression test for https://github.com/rubygems/bundler/pull/6316 - # It doesn't matter if there are other unwritable files so long as - # bundle_path can be created - before do - file = File.join(tmpdir, "unrelated_file") - FileUtils.touch(file) - FileUtils.chmod(0o400, file) - end - - it { should be false } - end - end - - context "bundle_path exists" do - before do - FileUtils.mkdir_p(bundle_path) - end - - it { should be false } - - context "and is unwritable" do - before do - FileUtils.chmod(0o500, bundle_path) - end - - it { should be true } - end - end - - context "path writability" do - before do - FileUtils.mkdir_p("tmp/vendor/bundle") - FileUtils.mkdir_p("tmp/vendor/bin_dir") - end - after do - FileUtils.rm_rf("tmp/vendor/bundle") - FileUtils.rm_rf("tmp/vendor/bin_dir") - end - context "writable paths" do - it "should return false and display nothing" do - allow(Bundler).to receive(:bundle_path).and_return(Pathname("tmp/vendor/bundle")) - expect(Bundler.ui).to_not receive(:warn) - expect(Bundler.requires_sudo?).to eq(false) - end - end - context "unwritable paths" do - before do - FileUtils.touch("tmp/vendor/bundle/unwritable1.txt") - FileUtils.touch("tmp/vendor/bundle/unwritable2.txt") - FileUtils.touch("tmp/vendor/bin_dir/unwritable3.txt") - FileUtils.chmod(0o400, "tmp/vendor/bundle/unwritable1.txt") - FileUtils.chmod(0o400, "tmp/vendor/bundle/unwritable2.txt") - FileUtils.chmod(0o400, "tmp/vendor/bin_dir/unwritable3.txt") - end - it "should return true and display warn message" do - allow(Bundler).to receive(:bundle_path).and_return(Pathname("tmp/vendor/bundle")) - bin_dir = Pathname("tmp/vendor/bin_dir/") - - # allow File#writable? to be called with args other than the stubbed on below - allow(File).to receive(:writable?).and_call_original - - # fake make the directory unwritable - allow(File).to receive(:writable?).with(bin_dir).and_return(false) - allow(Bundler).to receive(:system_bindir).and_return(Pathname("tmp/vendor/bin_dir/")) - message = <<-MESSAGE.chomp -Following files may not be writable, so sudo is needed: - tmp/vendor/bin_dir/ - tmp/vendor/bundle/unwritable1.txt - tmp/vendor/bundle/unwritable2.txt -MESSAGE - expect(Bundler.ui).to receive(:warn).with(message) - expect(Bundler.requires_sudo?).to eq(true) - end - end - end - end - context "user cache dir" do let(:home_path) { Pathname.new(ENV["HOME"]) } diff --git a/spec/bundler/bundler/endpoint_specification_spec.rb b/spec/bundler/bundler/endpoint_specification_spec.rb index 02a90d507a..81fcd76e01 100644 --- a/spec/bundler/bundler/endpoint_specification_spec.rb +++ b/spec/bundler/bundler/endpoint_specification_spec.rb @@ -48,6 +48,33 @@ RSpec.describe Bundler::EndpointSpecification do end end + describe "#required_ruby_version" do + context "required_ruby_version is already set on endpoint specification" do + existing_value = "already set value" + let(:required_ruby_version) { existing_value } + + it "should return the current value when already set on endpoint specification" do + remote_spec = double(:remote_spec, :required_ruby_version => "remote_value", :required_rubygems_version => nil) + + expect(spec.required_ruby_version). eql?(existing_value) + end + end + + it "should return the remote spec value when not set on endpoint specification and remote spec has one" do + remote_value = "remote_value" + remote_spec = double(:remote_spec, :required_ruby_version => remote_value, :required_rubygems_version => nil) + allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec) + + expect(spec.required_ruby_version). eql?(remote_value) + end + + it "should use the default Gem Requirement value when not set on endpoint specification and not set on remote spec" do + remote_spec = double(:remote_spec, :required_ruby_version => nil, :required_rubygems_version => nil) + allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec) + expect(spec.required_ruby_version). eql?(Gem::Requirement.default) + end + end + it "supports equality comparison" do remote_spec = double(:remote_spec, :required_ruby_version => nil, :required_rubygems_version => nil) allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec) diff --git a/spec/bundler/bundler/gem_version_promoter_spec.rb b/spec/bundler/bundler/gem_version_promoter_spec.rb index 43a3630bbb..99e008bfbc 100644 --- a/spec/bundler/bundler/gem_version_promoter_spec.rb +++ b/spec/bundler/bundler/gem_version_promoter_spec.rb @@ -166,14 +166,5 @@ RSpec.describe Bundler::GemVersionPromoter do end end end - - context "debug output" do - it "should not kerblooie on its own debug output" do - gvp = unlocking(:level => :patch) - dep = Bundler::DepProxy.get_proxy(dep("foo", "1.2.0").first, "ruby") - result = gvp.send(:debug_format_result, dep, build_spec_groups("foo", %w[1.2.0 1.3.0])) - expect(result.class).to eq Array - end - end end end diff --git a/spec/bundler/install/binstubs_spec.rb b/spec/bundler/install/binstubs_spec.rb index 6961171f4f..928ba80b15 100644 --- a/spec/bundler/install/binstubs_spec.rb +++ b/spec/bundler/install/binstubs_spec.rb @@ -2,10 +2,8 @@ RSpec.describe "bundle install" do describe "when system_bindir is set" do - # On OS X, Gem.bindir defaults to /usr/bin, so system_bindir is useful if - # you want to avoid sudo installs for system gems with OS X's default ruby it "overrides Gem.bindir" do - expect(Pathname.new("/usr/bin")).not_to be_writable unless Process.euid == 0 + expect(Pathname.new("/usr/bin")).not_to be_writable gemfile <<-G def Gem.bindir; "/usr/bin"; end source "#{file_uri_for(gem_repo1)}" diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index ee0aa2a347..d2733993bb 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -1470,6 +1470,59 @@ RSpec.describe "bundle install with gems on multiple sources" do end end + context "when default source includes old gems with nil required_ruby_version" do + before do + build_repo2 do + build_gem "ruport", "1.7.0.3" do |s| + s.add_dependency "pdf-writer", "1.1.8" + end + end + + build_repo gem_repo4 do + build_gem "pdf-writer", "1.1.8" + end + + path = "#{gem_repo4}/#{Gem::MARSHAL_SPEC_DIR}/pdf-writer-1.1.8.gemspec.rz" + spec = Marshal.load(Bundler.rubygems.inflate(File.binread(path))) + spec.instance_variable_set(:@required_ruby_version, nil) + File.open(path, "wb") do |f| + f.write Gem.deflate(Marshal.dump(spec)) + end + + gemfile <<~G + source "https://localgemserver.test" + + gem "ruport", "= 1.7.0.3", :source => "https://localgemserver.test/extra" + G + end + + it "handles that fine" do + bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + + expect(lockfile).to eq <<~L + GEM + remote: https://localgemserver.test/ + specs: + pdf-writer (1.1.8) + + GEM + remote: https://localgemserver.test/extra/ + specs: + ruport (1.7.0.3) + pdf-writer (= 1.1.8) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + ruport (= 1.7.0.3)! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + context "when default source includes old gems with nil required_rubygems_version" do before do build_repo2 do diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb index 5c25b1092a..b6c361186a 100644 --- a/spec/bundler/install/gems/compact_index_spec.rb +++ b/spec/bundler/install/gems/compact_index_spec.rb @@ -519,18 +519,6 @@ The checksum of /versions does not match the checksum provided by the server! So expect(out).to include("Fetching gem metadata from #{source_uri}") end - it "should install when EndpointSpecification has a bin dir owned by root", :sudo => true do - sudo "mkdir -p #{system_gem_path("bin")}" - sudo "chown -R root #{system_gem_path("bin")}" - - gemfile <<-G - source "#{source_uri}" - gem "rails" - G - bundle :install, :artifice => "compact_index" - expect(the_bundle).to include_gems "rails 2.3.2" - end - it "installs the binstubs", :bundler => "< 3" do gemfile <<-G source "#{source_uri}" diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb index 9a83e5ffad..6cb3d9697d 100644 --- a/spec/bundler/install/gems/dependency_api_spec.rb +++ b/spec/bundler/install/gems/dependency_api_spec.rb @@ -476,18 +476,6 @@ RSpec.describe "gemcutter's dependency API" do expect(out).to include("Fetching gem metadata from #{source_uri}") end - it "should install when EndpointSpecification has a bin dir owned by root", :sudo => true do - sudo "mkdir -p #{system_gem_path("bin")}" - sudo "chown -R root #{system_gem_path("bin")}" - - gemfile <<-G - source "#{source_uri}" - gem "rails" - G - bundle :install, :artifice => "endpoint" - expect(the_bundle).to include_gems "rails 2.3.2" - end - it "installs the binstubs", :bundler => "< 3" do gemfile <<-G source "#{source_uri}" diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb index ed61531574..ed30d2cc35 100644 --- a/spec/bundler/install/gems/flex_spec.rb +++ b/spec/bundler/install/gems/flex_spec.rb @@ -190,28 +190,33 @@ RSpec.describe "bundle flex_install" do expect(err).to match(/could not find gem 'rack-obama/i) end - it "suggests deleting the Gemfile.lock file when the Gemfile requires different versions than the lock" do + it "discards the locked gems when the Gemfile requires different versions than the lock" do bundle "config set force_ruby_platform true" nice_error = <<-E.strip.gsub(/^ {8}/, "") - Bundler could not find compatible versions for gem "rack": - In snapshot (Gemfile.lock): - rack (= 0.9.1) + Could not find gem 'rack (= 1.2)', which is required by gem 'rack-obama (= 2.0)', in rubygems repository #{file_uri_for(gem_repo2)}/ or installed locally. - In Gemfile: - rack-obama (= 2.0) was resolved to 2.0, which depends on - rack (= 1.2) - - rack_middleware was resolved to 1.0, which depends on - rack (= 0.9.1) - - Deleting your Gemfile.lock file and running `bundle install` will rebuild your snapshot from scratch, using only - the gems in your Gemfile, which may resolve the conflict. + The source contains the following gems matching 'rack': + * rack-0.9.1 + * rack-1.0.0 E bundle :install, :retry => 0, :raise_on_error => false expect(err).to end_with(nice_error) end + + it "does not include conflicts with a single requirement tree, because that can't possibly be a conflict" do + bundle "config set force_ruby_platform true" + + bad_error = <<-E.strip.gsub(/^ {8}/, "") + Bundler could not find compatible versions for gem "rack-obama": + In Gemfile: + rack-obama (= 2.0) + E + + bundle "update rack_middleware", :retry => 0, :raise_on_error => false + expect(err).not_to end_with(bad_error) + end end describe "when running bundle update and Gemfile conflicts with lockfile" do @@ -230,22 +235,6 @@ RSpec.describe "bundle flex_install" do gem "jekyll-feed", "~> 0.12" G - lockfile <<-L - GEM - remote: #{file_uri_for(gem_repo4)}/ - specs: - jekyll-feed (0.16.0) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - jekyll-feed - - BUNDLED WITH - #{Bundler::VERSION} - L - gemfile <<-G source "#{file_uri_for(gem_repo4)}" gem "github-pages", "~> 226" @@ -253,24 +242,9 @@ RSpec.describe "bundle flex_install" do G end - it "suggests deleting the Gemfile.lock file when the Gemfile requires different versions than the lock" do - nice_error = <<-E.strip.gsub(/^ {8}/, "") - Bundler could not find compatible versions for gem "jekyll-feed": - In snapshot (Gemfile.lock): - jekyll-feed (>= 0.16.0) - - In Gemfile: - jekyll-feed (~> 0.12) - - github-pages (~> 226) was resolved to 226, which depends on - jekyll-feed (= 0.15.1) - - Deleting your Gemfile.lock file and running `bundle install` will rebuild your snapshot from scratch, using only - the gems in your Gemfile, which may resolve the conflict. - E - - bundle :update, :raise_on_error => false - expect(err).to end_with(nice_error) + it "discards the conflicting lockfile information and resolves properly" do + bundle :update, :raise_on_error => false, :all => true + expect(err).to be_empty end end @@ -374,7 +348,7 @@ RSpec.describe "bundle flex_install" do end end - it "prints the correct error message" do + it "resolves them" do # install Rails 3.0.0.rc install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -383,13 +357,12 @@ RSpec.describe "bundle flex_install" do G # upgrade Rails to 3.0.0 and then install again - install_gemfile <<-G, :raise_on_error => false + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "rails", "3.0.0" gem "capybara", "0.3.9" G - - expect(err).to include("Gemfile.lock") + expect(err).to be_empty end end end diff --git a/spec/bundler/install/gems/sudo_spec.rb b/spec/bundler/install/gems/sudo_spec.rb deleted file mode 100644 index 41b241da25..0000000000 --- a/spec/bundler/install/gems/sudo_spec.rb +++ /dev/null @@ -1,205 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe "when using sudo", :sudo => true do - describe "and BUNDLE_PATH is writable" do - context "but BUNDLE_PATH/build_info is not writable" do - let(:subdir) do - system_gem_path("cache") - end - - before do - bundle "config set path.system true" - subdir.mkpath - sudo "chmod u-w #{subdir}" - end - - after do - sudo "chmod u+w #{subdir}" - end - - it "installs" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" - G - - expect(out).to_not match(/an error occurred/i) - expect(system_gem_path("cache/rack-1.0.0.gem")).to exist - expect(the_bundle).to include_gems "rack 1.0" - end - end - end - - describe "and GEM_HOME is owned by root" do - before :each do - bundle "config set path.system true" - chown_system_gems_to_root - end - - it "installs" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", '1.0' - gem "thin" - G - - expect(system_gem_path("gems/rack-1.0.0")).to exist - expect(system_gem_path("gems/rack-1.0.0").stat.uid).to eq(0) - expect(the_bundle).to include_gems "rack 1.0" - end - - it "installs rake and a gem dependent on rake in the same session" do - build_repo2 do - build_gem "another_implicit_rake_dep" do |s| - s.extensions << "Rakefile" - s.write "Rakefile", <<-RUBY - task :default do - path = File.expand_path("lib", __dir__) - FileUtils.mkdir_p(path) - File.open("\#{path}/another_implicit_rake_dep.rb", "w") do |f| - f.puts "ANOTHER_IMPLICIT_RAKE_DEP = 'YES'" - end - end - RUBY - end - end - - gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "rake" - gem "another_implicit_rake_dep" - G - bundle "install" - expect(system_gem_path("gems/another_implicit_rake_dep-1.0")).to exist - end - - it "installs when BUNDLE_PATH is owned by root" do - bundle_path = tmp("owned_by_root") - FileUtils.mkdir_p bundle_path - sudo "chown -R root #{bundle_path}" - - ENV["BUNDLE_PATH"] = bundle_path.to_s - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", '1.0' - G - - expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0")).to exist - expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0").stat.uid).to eq(0) - expect(the_bundle).to include_gems "rack 1.0" - end - - it "installs when BUNDLE_PATH does not exist" do - root_path = tmp("owned_by_root") - FileUtils.mkdir_p root_path - sudo "chown -R root #{root_path}" - bundle_path = root_path.join("does_not_exist") - - ENV["BUNDLE_PATH"] = bundle_path.to_s - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", '1.0' - G - - expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0")).to exist - expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0").stat.uid).to eq(0) - expect(the_bundle).to include_gems "rack 1.0" - end - - it "installs extensions/" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "very_simple_binary" - G - - expect(system_gem_path("gems/very_simple_binary-1.0")).to exist - binary_glob = system_gem_path("extensions/*/*/very_simple_binary-1.0") - expect(Dir.glob(binary_glob).first).to be - end - end - - describe "and BUNDLE_PATH is not writable" do - before do - bundle "config set --local path .bundle" - sudo "chmod ugo-w .bundle" - end - - after do - sudo "chmod ugo+w .bundle" - end - - it "installs" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", '1.0' - G - - expect(local_gem_path("gems/rack-1.0.0")).to exist - expect(the_bundle).to include_gems "rack 1.0" - end - - it "cleans up the tmpdirs generated" do - require "tmpdir" - Dir.glob("#{Dir.tmpdir}/bundler*").each do |tmpdir| - FileUtils.remove_entry_secure(tmpdir) - end - - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" - G - tmpdirs = Dir.glob("#{Dir.tmpdir}/bundler*") - - expect(tmpdirs).to be_empty - end - end - - describe "and GEM_HOME is not writable" do - it "installs" do - bundle "config set path.system true" - gem_home = tmp("sudo_gem_home") - sudo "mkdir -p #{gem_home}" - sudo "chmod ugo-w #{gem_home}" - - system_gems :bundler, :path => gem_home - - gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", '1.0' - G - - bundle :install, :env => { "GEM_HOME" => gem_home.to_s, "GEM_PATH" => nil } - expect(gem_home.join("bin/rackup")).to exist - expect(the_bundle).to include_gems "rack 1.0", :env => { "GEM_HOME" => gem_home.to_s, "GEM_PATH" => nil } - - sudo "rm -rf #{tmp("sudo_gem_home")}" - end - end - - describe "and root runs install" do - let(:warning) { "Don't run Bundler as root." } - - before do - gemfile %(source "#{file_uri_for(gem_repo1)}") - end - - it "warns against that" do - bundle :install, :sudo => :preserve_env - expect(err).to include(warning) - end - - context "when ENV['BUNDLE_SILENCE_ROOT_WARNING'] is set" do - it "skips the warning" do - bundle :install, :sudo => :preserve_env, :env => { "BUNDLE_SILENCE_ROOT_WARNING" => "true" } - expect(err).to_not include(warning) - end - end - - context "when silence_root_warning = false" do - it "warns against that" do - bundle :install, :sudo => :preserve_env, :env => { "BUNDLE_SILENCE_ROOT_WARNING" => "false" } - expect(err).to include(warning) - end - end - end -end diff --git a/spec/bundler/plugins/install_spec.rb b/spec/bundler/plugins/install_spec.rb index 009516260a..efee5fdd23 100644 --- a/spec/bundler/plugins/install_spec.rb +++ b/spec/bundler/plugins/install_spec.rb @@ -32,7 +32,8 @@ RSpec.describe "bundler plugin install" do it "shows help when --help flag is given" do bundle "plugin install --help" - expect(out).to include("bundle plugin install PLUGINS # Install the plugin from the source") + # The help message defined in ../../lib/bundler/man/bundle-plugin.1.ronn will be output. + expect(out).to include("You can install, uninstall, and list plugin(s)") end context "plugin is already installed" do @@ -84,6 +85,26 @@ RSpec.describe "bundler plugin install" do expect(out).to include("Using foo 1.1") end + it "installs when --branch specified" do + bundle "plugin install foo --branch main --source #{file_uri_for(gem_repo2)}" + + expect(out).to include("Installed plugin foo") + end + + it "installs when --ref specified" do + bundle "plugin install foo --ref v1.2.3 --source #{file_uri_for(gem_repo2)}" + + expect(out).to include("Installed plugin foo") + end + + it "raises error when both --branch and --ref options are specified" do + bundle "plugin install foo --source #{file_uri_for(gem_repo2)} --branch main --ref v1.2.3", :raise_on_error => false + + expect(out).not_to include("Installed plugin foo") + + expect(err).to include("You cannot specify `--branch` and `--ref` at the same time.") + end + it "works with different load paths" do build_repo2 do build_plugin "testing" do |s| diff --git a/spec/bundler/plugins/source/example_spec.rb b/spec/bundler/plugins/source/example_spec.rb index 412de04d44..9d153b6063 100644 --- a/spec/bundler/plugins/source/example_spec.rb +++ b/spec/bundler/plugins/source/example_spec.rb @@ -304,13 +304,7 @@ RSpec.describe "real source plugins" do @install_path ||= begin git_scope = "\#{base_name}-\#{shortref_for_path(revision)}" - path = gem_install_dir.join(git_scope) - - if !path.exist? && requires_sudo? - user_bundle_path.join(ruby_scope).join(git_scope) - else - path - end + gem_install_dir.join(git_scope) end end diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb index ee98bcd4d7..86a927c361 100644 --- a/spec/bundler/quality_spec.rb +++ b/spec/bundler/quality_spec.rb @@ -151,7 +151,6 @@ RSpec.describe "The library itself" do git.allow_insecure inline trust-policy - use_gem_version_promoter_for_major_updates ] all_settings = Hash.new {|h, k| h[k] = [] } diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index 892ad10e98..4f67092bc7 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -23,7 +23,6 @@ require_relative "support/indexes" require_relative "support/matchers" require_relative "support/permissions" require_relative "support/platforms" -require_relative "support/sudo" $debug = false @@ -40,7 +39,6 @@ RSpec.configure do |config| config.include Spec::Matchers config.include Spec::Path config.include Spec::Platforms - config.include Spec::Sudo config.include Spec::Permissions # Enable flags like --only-failures and --next-failure @@ -115,10 +113,6 @@ RSpec.configure do |config| end end - config.before :each, :sudo => true do - Spec::Sudo.write_safe_config - end - config.after :suite do FileUtils.rm_r Spec::Path.pristine_system_gem_path end diff --git a/spec/bundler/support/filters.rb b/spec/bundler/support/filters.rb index c3b7a425ae..523f7c742c 100644 --- a/spec/bundler/support/filters.rb +++ b/spec/bundler/support/filters.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative "sudo" - class RequirementChecker < Proc def self.against(present) provided = Gem::Version.new(present) @@ -21,7 +19,6 @@ class RequirementChecker < Proc end RSpec.configure do |config| - config.filter_run_excluding :sudo => true config.filter_run_excluding :realworld => true git_version = Bundler::Source::Git::GitProxy.new(nil, nil, nil).version diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb index f4ee93ccc0..dfc358796a 100644 --- a/spec/bundler/support/helpers.rb +++ b/spec/bundler/support/helpers.rb @@ -78,9 +78,6 @@ module Spec end def bundle(cmd, options = {}, &block) - with_sudo = options.delete(:sudo) - sudo = with_sudo == :preserve_env ? "sudo -E --preserve-env=RUBYOPT" : "sudo" if with_sudo - bundle_bin = options.delete(:bundle_bin) bundle_bin ||= installed_bindir.join("bundle") @@ -119,7 +116,7 @@ module Spec end end.join - ruby_cmd = build_ruby_cmd({ :sudo => sudo, :load_path => load_path, :requires => requires }) + ruby_cmd = build_ruby_cmd({ :load_path => load_path, :requires => requires }) cmd = "#{ruby_cmd} #{bundle_bin} #{cmd}#{args}" sys_exec(cmd, { :env => env, :dir => dir, :raise_on_error => raise_on_error }, &block) end @@ -146,8 +143,6 @@ module Spec end def build_ruby_cmd(options = {}) - sudo = options.delete(:sudo) - libs = options.delete(:load_path) lib_option = libs ? "-I#{libs.join(File::PATH_SEPARATOR)}" : [] @@ -155,7 +150,7 @@ module Spec requires << "#{Path.spec_dir}/support/hax.rb" require_option = requires.map {|r| "-r#{r}" } - [sudo, Gem.ruby, *lib_option, *require_option].compact.join(" ") + [Gem.ruby, *lib_option, *require_option].compact.join(" ") end def gembin(cmd, options = {}) diff --git a/spec/bundler/support/sudo.rb b/spec/bundler/support/sudo.rb deleted file mode 100644 index 7b9b392754..0000000000 --- a/spec/bundler/support/sudo.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -module Spec - module Sudo - def self.present? - @which_sudo ||= Bundler.which("sudo") - end - - def self.write_safe_config - File.write(Spec::Path.tmp("gitconfig"), "[safe]\n\tdirectory = #{Spec::Path.git_root}") - end - - def sudo(cmd) - raise "sudo not present" unless Sudo.present? - sys_exec("sudo #{cmd}") - end - - def chown_system_gems_to_root - sudo "chown -R root #{system_gem_path}" - end - end -end diff --git a/test/rubygems/helper.rb b/test/rubygems/helper.rb index e569986ef2..258107bf04 100644 --- a/test/rubygems/helper.rb +++ b/test/rubygems/helper.rb @@ -463,14 +463,7 @@ class Gem::TestCase < Test::Unit::TestCase Dir.chdir @current_dir - # Prevent a race condition on removing TMPDIR being written by MJIT - if defined?(RubyVM::MJIT.enabled?) && RubyVM::MJIT.enabled? - RubyVM::MJIT.pause(wait: false) - end FileUtils.rm_rf @tempdir - if defined?(RubyVM::MJIT.enabled?) && RubyVM::MJIT.enabled? - RubyVM::MJIT.resume - end ENV.replace(@orig_env) diff --git a/tool/bundler/rubocop_gems.rb.lock b/tool/bundler/rubocop_gems.rb.lock index 13e541bcfa..9b097ba710 100644 --- a/tool/bundler/rubocop_gems.rb.lock +++ b/tool/bundler/rubocop_gems.rb.lock @@ -44,6 +44,7 @@ GEM unicode-display_width (2.1.0) PLATFORMS + aarch64-linux arm64-darwin-20 arm64-darwin-21 universal-java-11 diff --git a/tool/bundler/standard_gems.rb.lock b/tool/bundler/standard_gems.rb.lock index df346ad7ce..03d8195557 100644 --- a/tool/bundler/standard_gems.rb.lock +++ b/tool/bundler/standard_gems.rb.lock @@ -50,6 +50,7 @@ GEM unicode-display_width (2.1.0) PLATFORMS + aarch64-linux arm64-darwin-20 arm64-darwin-21 universal-java-11 |