diff --git a/Manifest.txt b/Manifest.txt index 048b90ee00d1..9abb1d89395c 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -257,6 +257,8 @@ bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +bundler/lib/bundler/vendor/pathname/LICENSE.txt +bundler/lib/bundler/vendor/pathname/lib/pathname.rb bundler/lib/bundler/vendor/thor/LICENSE.md bundler/lib/bundler/vendor/thor/lib/thor.rb bundler/lib/bundler/vendor/thor/lib/thor/actions.rb @@ -310,6 +312,7 @@ bundler/lib/bundler/vendor/uri/lib/uri/ws.rb bundler/lib/bundler/vendor/uri/lib/uri/wss.rb bundler/lib/bundler/vendored_fileutils.rb bundler/lib/bundler/vendored_molinillo.rb +bundler/lib/bundler/vendored_pathname.rb bundler/lib/bundler/vendored_persistent.rb bundler/lib/bundler/vendored_thor.rb bundler/lib/bundler/vendored_tmpdir.rb diff --git a/bundler/Rakefile b/bundler/Rakefile index 8bb737045ef0..bbdea2238c6e 100644 --- a/bundler/Rakefile +++ b/bundler/Rakefile @@ -209,6 +209,18 @@ Automatiek::RakeTask.new("tmpdir") do |lib| end end +# We currently include the following changes over the official version: +# * Replace the C-extension with a pure ruby implementation. +# * Add back ruby 2.3 support. +Automatiek::RakeTask.new("pathname") do |lib| + lib.version = "v0.2.0" + lib.download = { :github => "https://github.com/ruby/pathname" } + lib.namespace = "Pathname" + lib.prefix = "Bundler" + lib.vendor_lib = "lib/bundler/vendor/pathname" + lib.license_path = "LICENSE.txt" +end + # We currently include the following changes over the official version: # * Avoid requiring the optional `net-http-pipeline` dependency, so that its version can be selected by end users. # * Workaround for incorrect `Process.getrlimit` on JRuby + Windows. diff --git a/bundler/lib/bundler.rb b/bundler/lib/bundler.rb index 81dfd05d26de..24d6ba3a3ebe 100644 --- a/bundler/lib/bundler.rb +++ b/bundler/lib/bundler.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require_relative "bundler/vendored_fileutils" -require "pathname" +require_relative "bundler/vendored_pathname" require "rbconfig" require_relative "bundler/errors" @@ -93,7 +93,7 @@ def ui=(ui) # Returns absolute path of where gems are installed on the filesystem. def bundle_path - @bundle_path ||= Pathname.new(configured_bundle_path.path).expand_path(root) + @bundle_path ||= Bundler::Pathname.new(configured_bundle_path.path).expand_path(root) end def configured_bundle_path @@ -104,7 +104,7 @@ def configured_bundle_path def bin_path @bin_path ||= begin path = settings[:bin] || "bin" - path = Pathname.new(path).expand_path(root).expand_path + path = Bundler::Pathname.new(path).expand_path(root).expand_path SharedHelpers.filesystem_access(path) {|p| FileUtils.mkdir_p(p) } path end @@ -287,7 +287,7 @@ def root rescue GemfileNotFound bundle_dir = default_bundle_dir raise GemfileNotFound, "Could not locate Gemfile or .bundle/ directory" unless bundle_dir - Pathname.new(File.expand_path("..", bundle_dir)) + bundle_dir.parent end end @@ -455,6 +455,10 @@ def default_lockfile SharedHelpers.default_lockfile end + def relative_path_to_lockfile + default_lockfile.relative_path_from(SharedHelpers.pwd) + end + def default_bundle_dir SharedHelpers.default_bundle_dir end @@ -492,11 +496,11 @@ def requires_sudo? 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] + files = [path.to_s, bin_dir.to_s] | 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 ")}" + Bundler.ui.warn "Following files may not be writable, so sudo is needed:\n #{unwritable_files.sort.join("\n ")}" end end diff --git a/bundler/lib/bundler/cli/check.rb b/bundler/lib/bundler/cli/check.rb index 65c51337d2fe..18cd914913a3 100644 --- a/bundler/lib/bundler/cli/check.rb +++ b/bundler/lib/bundler/cli/check.rb @@ -29,7 +29,7 @@ def run Bundler.ui.warn "Install missing gems with `bundle install`" exit 1 elsif !Bundler.default_lockfile.file? && Bundler.frozen_bundle? - Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} present" + Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.relative_path_to_lockfile} present" exit 1 else Bundler.load.lock(:preserve_unknown_sections => true) unless options[:"dry-run"] diff --git a/bundler/lib/bundler/cli/gem.rb b/bundler/lib/bundler/cli/gem.rb index e917ceb7d43c..0510e670b3f9 100644 --- a/bundler/lib/bundler/cli/gem.rb +++ b/bundler/lib/bundler/cli/gem.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "pathname" - module Bundler class CLI Bundler.require_thor_actions @@ -26,7 +24,7 @@ def initialize(options, gem_name, thor) thor.destination_root = nil @name = @gem_name - @target = SharedHelpers.pwd.join(gem_name) + @target = File.expand_path(gem_name) validate_ext_name if options[:ext] end @@ -185,7 +183,7 @@ def run ) end - if target.exist? && !target.directory? + if File.exist?(target) && !File.directory?(target) Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`." exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError] end @@ -193,20 +191,20 @@ def run if use_git Bundler.ui.info "Initializing git repo in #{target}" require "shellwords" - `git init #{target.to_s.shellescape}` + `git init #{target.shellescape}` config[:git_default_branch] = File.read("#{target}/.git/HEAD").split("/").last.chomp end templates.each do |src, dst| - destination = target.join(dst) + destination = File.join(target, dst) thor.template("newgem/#{src}", destination, config) end executables.each do |file| - path = target.join(file) - executable = (path.stat.mode | 0o111) - path.chmod(executable) + path = File.join(target, file) + executable = (File.stat(path).mode | 0o111) + File.chmod(executable, path) end if use_git @@ -216,7 +214,7 @@ def run end # Open gemspec in editor - open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit] + open_editor(options["edit"], File.join(target, "#{name}.gemspec")) if options[:edit] Bundler.ui.info "Gem '#{name}' was successfully created. " \ "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html" @@ -225,7 +223,7 @@ def run private def resolve_name(name) - SharedHelpers.pwd.join(name).basename.to_s + File.basename(File.expand_path(name)) end def ask_and_set(key, header, message) diff --git a/bundler/lib/bundler/cli/install.rb b/bundler/lib/bundler/cli/install.rb index 4c1915fea6e6..887a8c3654be 100644 --- a/bundler/lib/bundler/cli/install.rb +++ b/bundler/lib/bundler/cli/install.rb @@ -26,8 +26,8 @@ def run flag = "--deployment flag" if options[:deployment] flag ||= "--frozen flag" if options[:frozen] flag ||= "deployment setting" - raise ProductionError, "The #{flag} requires a #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}. Please make " \ - "sure you have checked your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} into version control " \ + raise ProductionError, "The #{flag} requires a #{Bundler.relative_path_to_lockfile}. Please make " \ + "sure you have checked your #{Bundler.relative_path_to_lockfile} into version control " \ "before deploying." end diff --git a/bundler/lib/bundler/compact_index_client.rb b/bundler/lib/bundler/compact_index_client.rb index d5dbeb3b1085..f19c3856164a 100644 --- a/bundler/lib/bundler/compact_index_client.rb +++ b/bundler/lib/bundler/compact_index_client.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "pathname" +require_relative "vendored_pathname" require "set" module Bundler diff --git a/bundler/lib/bundler/definition.rb b/bundler/lib/bundler/definition.rb index 59ce07352a24..b991445d2e95 100644 --- a/bundler/lib/bundler/definition.rb +++ b/bundler/lib/bundler/definition.rb @@ -354,7 +354,7 @@ def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) msg = String.new msg << "You are trying to install in deployment mode after changing\n" \ "your Gemfile. Run `bundle install` elsewhere and add the\n" \ - "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control." + "updated #{Bundler.relative_path_to_lockfile} to version control." unless explicit_flag suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any? diff --git a/bundler/lib/bundler/env.rb b/bundler/lib/bundler/env.rb index 00d4ef219647..43005d493f0a 100644 --- a/bundler/lib/bundler/env.rb +++ b/bundler/lib/bundler/env.rb @@ -44,7 +44,7 @@ def self.report(options = {}) out << "```ruby\n" << read_file(gemfile).chomp << "\n```\n" end - out << "\n### #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}\n\n" + out << "\n### #{Bundler.relative_path_to_lockfile}\n\n" out << "```\n" << read_file(Bundler.default_lockfile).chomp << "\n```\n" end diff --git a/bundler/lib/bundler/gem_helper.rb b/bundler/lib/bundler/gem_helper.rb index 034f2e596029..a84a93558771 100644 --- a/bundler/lib/bundler/gem_helper.rb +++ b/bundler/lib/bundler/gem_helper.rb @@ -31,7 +31,7 @@ def gemspec(&block) attr_writer :tag_prefix def initialize(base = nil, name = nil) - @base = File.expand_path(base || SharedHelpers.pwd) + @base = base ? File.expand_path(base) : SharedHelpers.pwd gemspecs = name ? [File.join(@base, "#{name}.gemspec")] : Gem::Util.glob_files_in_dir("{,*}.gemspec", @base) raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1 @spec_path = gemspecs.first diff --git a/bundler/lib/bundler/inline.rb b/bundler/lib/bundler/inline.rb index a718418fceb8..d9ae358313f0 100644 --- a/bundler/lib/bundler/inline.rb +++ b/bundler/lib/bundler/inline.rb @@ -42,7 +42,7 @@ def gemfile(install = false, options = {}, &gemfile) bundler_module = class << Bundler; self; end bundler_module.send(:remove_method, :root) def Bundler.root - Bundler::SharedHelpers.pwd.expand_path + Bundler::Pathname.new(Bundler::SharedHelpers.pwd) end old_gemfile = ENV["BUNDLE_GEMFILE"] Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile" diff --git a/bundler/lib/bundler/installer.rb b/bundler/lib/bundler/installer.rb index 49ff177c0ff3..6cc4d8fff064 100644 --- a/bundler/lib/bundler/installer.rb +++ b/bundler/lib/bundler/installer.rb @@ -178,7 +178,7 @@ def generate_standalone_bundler_executable_stubs(spec, options = {}) spec.executables.each do |executable| next if executable == "bundle" - executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path) + executable_path = Pathname.new(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path) executable_path = executable_path mode = Gem.win_platform? ? "wb:UTF-8" : "w" diff --git a/bundler/lib/bundler/lockfile_parser.rb b/bundler/lib/bundler/lockfile_parser.rb index 6ff4910a36a1..1e44cee02795 100644 --- a/bundler/lib/bundler/lockfile_parser.rb +++ b/bundler/lib/bundler/lockfile_parser.rb @@ -54,8 +54,8 @@ def initialize(lockfile) @specs = {} if lockfile.match(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) - raise LockfileError, "Your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} contains merge conflicts.\n" \ - "Run `git checkout HEAD -- #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` first to get a clean lock." + raise LockfileError, "Your #{Bundler.relative_path_to_lockfile} contains merge conflicts.\n" \ + "Run `git checkout HEAD -- #{Bundler.relative_path_to_lockfile}` first to get a clean lock." end lockfile.split(/(?:\r?\n)+/).each do |line| @@ -80,7 +80,7 @@ def initialize(lockfile) warn_for_outdated_bundler_version rescue ArgumentError => e Bundler.ui.debug(e) - raise LockfileError, "Your lockfile is unreadable. Run `rm #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` " \ + raise LockfileError, "Your lockfile is unreadable. Run `rm #{Bundler.relative_path_to_lockfile}` " \ "and then `bundle install` to generate a new lockfile." end diff --git a/bundler/lib/bundler/rubygems_ext.rb b/bundler/lib/bundler/rubygems_ext.rb index 5d572aa73d6d..0aeb652f2ec8 100644 --- a/bundler/lib/bundler/rubygems_ext.rb +++ b/bundler/lib/bundler/rubygems_ext.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "pathname" +require_relative "vendored_pathname" require "rubygems/specification" @@ -29,7 +29,7 @@ def full_gem_path # gems at that time, this method could be called inside another require, # thus raising with that constant being undefined. Better to check a method if source.respond_to?(:path) || (source.respond_to?(:bundler_plugin_api_source?) && source.bundler_plugin_api_source?) - Pathname.new(loaded_from).dirname.expand_path(source.root).to_s.tap{|x| x.untaint if RUBY_VERSION < "2.7" } + Bundler::Pathname.new(loaded_from).dirname.expand_path(source.root).to_s.tap{|x| x.untaint if RUBY_VERSION < "2.7" } else rg_full_gem_path end diff --git a/bundler/lib/bundler/settings.rb b/bundler/lib/bundler/settings.rb index 1ced590b6f31..e2ca444e3860 100644 --- a/bundler/lib/bundler/settings.rb +++ b/bundler/lib/bundler/settings.rb @@ -252,7 +252,7 @@ def base_path def base_path_relative_to_pwd base_path = Pathname.new(self.base_path) expanded_base_path = base_path.expand_path(Bundler.root) - relative_path = expanded_base_path.relative_path_from(Pathname.pwd) + relative_path = expanded_base_path.relative_path_from(SharedHelpers.pwd) if relative_path.to_s.start_with?("..") relative_path = base_path if base_path.absolute? else diff --git a/bundler/lib/bundler/settings/validator.rb b/bundler/lib/bundler/settings/validator.rb index 0a57ea7f0389..fa959979519f 100644 --- a/bundler/lib/bundler/settings/validator.rb +++ b/bundler/lib/bundler/settings/validator.rb @@ -84,9 +84,9 @@ def self.validate!(key, value, settings) path = path.expand_path root = begin - Bundler.root + Bundler.root.to_s rescue GemfileNotFound - Pathname.pwd.expand_path + SharedHelpers.pwd end path = begin diff --git a/bundler/lib/bundler/shared_helpers.rb b/bundler/lib/bundler/shared_helpers.rb index 405ade95ddfa..7b5b7d793988 100644 --- a/bundler/lib/bundler/shared_helpers.rb +++ b/bundler/lib/bundler/shared_helpers.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "pathname" +require_relative "vendored_pathname" require "rbconfig" require_relative "version" @@ -26,8 +26,8 @@ def default_lockfile gemfile = default_gemfile case gemfile.basename.to_s - when "gems.rb" then Pathname.new(gemfile.sub(/.rb$/, ".locked")) - else Pathname.new("#{gemfile}.lock") + when "gems.rb" then gemfile.sub(/.rb$/, ".locked") + else gemfile.sub(/$/, ".lock") end.tap{|x| x.untaint if RUBY_VERSION < "2.7" } end @@ -55,7 +55,7 @@ def chdir(dir, &blk) def pwd Bundler.rubygems.ext_lock.synchronize do - Pathname.pwd + Dir.pwd end end diff --git a/bundler/lib/bundler/source/git/git_proxy.rb b/bundler/lib/bundler/source/git/git_proxy.rb index e37ff8724a36..7393cbcd8324 100644 --- a/bundler/lib/bundler/source/git/git_proxy.rb +++ b/bundler/lib/bundler/source/git/git_proxy.rb @@ -31,7 +31,7 @@ def initialize(command, path, extra_info = nil) msg = String.new msg << "Git error: command `#{command}` in directory #{path} has failed." msg << "\n#{extra_info}" if extra_info - msg << "\nIf this error persists you could try removing the cache directory '#{path}'" if path.exist? + msg << "\nIf this error persists you could try removing the cache directory '#{path}'" if File.exist?(path) super msg end end @@ -169,7 +169,7 @@ def git(*command, dir: nil) filtered_out = URICredentialsFilter.credential_filtered_string(out, uri) - raise GitCommandError.new(command_with_no_credentials, dir || SharedHelpers.pwd, filtered_out) unless status.success? + raise GitCommandError.new(command_with_no_credentials, dir ? dir.to_s : SharedHelpers.pwd, filtered_out) unless status.success? filtered_out end diff --git a/bundler/lib/bundler/source/rubygems.rb b/bundler/lib/bundler/source/rubygems.rb index b1dd9572c055..e698eae64449 100644 --- a/bundler/lib/bundler/source/rubygems.rb +++ b/bundler/lib/bundler/source/rubygems.rb @@ -503,7 +503,7 @@ def default_cache_path_for(dir) end def cache_path - Bundler.app_cache + Bundler.app_cache.to_s end private diff --git a/bundler/lib/bundler/templates/Executable b/bundler/lib/bundler/templates/Executable index 3e8d5b317ad8..f6487e3c89d0 100644 --- a/bundler/lib/bundler/templates/Executable +++ b/bundler/lib/bundler/templates/Executable @@ -8,11 +8,9 @@ # this file is here to facilitate running it. # -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../<%= relative_gemfile_path %>", - Pathname.new(__FILE__).realpath) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("<%= relative_gemfile_path %>", __dir__) -bundle_binstub = File.expand_path("../bundle", __FILE__) +bundle_binstub = File.expand_path("bundle", __dir__) if File.file?(bundle_binstub) if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ diff --git a/bundler/lib/bundler/templates/Executable.standalone b/bundler/lib/bundler/templates/Executable.standalone index 4bf0753f44d5..d591e3fc0459 100644 --- a/bundler/lib/bundler/templates/Executable.standalone +++ b/bundler/lib/bundler/templates/Executable.standalone @@ -6,9 +6,7 @@ # this file is here to facilitate running it. # -require "pathname" -path = Pathname.new(__FILE__) -$:.unshift File.expand_path "../<%= standalone_path %>", path.realpath +$:.unshift File.expand_path "<%= standalone_path %>", __dir__ require "bundler/setup" -load File.expand_path "../<%= executable_path %>", path.realpath +load File.expand_path "<%= executable_path %>", __dir__ diff --git a/bundler/lib/bundler/vendor/pathname/LICENSE.txt b/bundler/lib/bundler/vendor/pathname/LICENSE.txt new file mode 100644 index 000000000000..a009caefea81 --- /dev/null +++ b/bundler/lib/bundler/vendor/pathname/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/bundler/lib/bundler/vendor/pathname/lib/pathname.rb b/bundler/lib/bundler/vendor/pathname/lib/pathname.rb new file mode 100644 index 000000000000..93bda5d7ff82 --- /dev/null +++ b/bundler/lib/bundler/vendor/pathname/lib/pathname.rb @@ -0,0 +1,606 @@ +# frozen_string_literal: true +# +# = pathname.rb +# +# Object-Oriented Bundler::Pathname Class +# +# Author:: Tanaka Akira +# Documentation:: Author and Gavin Sinclair +# +# For documentation, see class Bundler::Pathname. +# + +class Bundler::Pathname + + # :stopdoc: + + # to_path is implemented so Bundler::Pathname objects are usable with File.open, etc. + TO_PATH = :to_path + + SAME_PATHS = if File::FNM_SYSCASE.nonzero? + # Avoid #zero? here because #casecmp can return nil. + proc {|a, b| a.casecmp(b) == 0} + else + proc {|a, b| a == b} + end + + + if File::ALT_SEPARATOR + SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}" + SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/ + else + SEPARATOR_LIST = "#{Regexp.quote File::SEPARATOR}" + SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/ + end + + if File.dirname('A:') == 'A:.' # DOSish drive letter + ABSOLUTE_PATH = /\A(?:[A-Za-z]:|#{SEPARATOR_PAT})/o + else + ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/o + end + private_constant :ABSOLUTE_PATH + + # :startdoc: + + def matches_path?(regexp, path) # :nodoc: + if regexp.respond_to?(:match?) + regexp.match?(path) + else + regexp =~ path + end + end + private :matches_path? + + # chop_basename(path) -> [pre-basename, basename] or nil + def chop_basename(path) # :nodoc: + base = File.basename(path) + if matches_path?(/\A#{SEPARATOR_PAT}?\z/o, base) + return nil + else + return path[0, path.rindex(base)], base + end + end + private :chop_basename + + # split_names(path) -> prefix, [name, ...] + def split_names(path) # :nodoc: + names = [] + while r = chop_basename(path) + path, basename = r + names.unshift basename + end + return path, names + end + private :split_names + + def prepend_prefix(prefix, relpath) # :nodoc: + if relpath.empty? + File.dirname(prefix) + elsif matches_path?(/#{SEPARATOR_PAT}/o, prefix) + prefix = File.dirname(prefix) + prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a' + prefix + relpath + else + prefix + relpath + end + end + private :prepend_prefix + + # Returns clean pathname of +self+ with consecutive slashes and useless dots + # removed. The filesystem is not accessed. + # + # If +consider_symlink+ is +true+, then a more conservative algorithm is used + # to avoid breaking symbolic linkages. This may retain more +..+ + # entries than absolutely necessary, but without accessing the filesystem, + # this can't be avoided. + # + # See Bundler::Pathname#realpath. + # + def cleanpath(consider_symlink=false) + if consider_symlink + cleanpath_conservative + else + cleanpath_aggressive + end + end + + # + # Clean the path simply by resolving and removing excess +.+ and +..+ entries. + # Nothing more, nothing less. + # + def cleanpath_aggressive # :nodoc: + path = @path + names = [] + pre = path + while r = chop_basename(pre) + pre, base = r + case base + when '.' + when '..' + names.unshift base + else + if names[0] == '..' + names.shift + else + names.unshift base + end + end + end + pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR + if matches_path?(/#{SEPARATOR_PAT}/o, File.basename(pre)) + names.shift while names[0] == '..' + end + self.class.new(prepend_prefix(pre, File.join(*names))) + end + private :cleanpath_aggressive + + # has_trailing_separator?(path) -> bool + def has_trailing_separator?(path) # :nodoc: + if r = chop_basename(path) + pre, basename = r + pre.length + basename.length < path.length + else + false + end + end + private :has_trailing_separator? + + # add_trailing_separator(path) -> path + def add_trailing_separator(path) # :nodoc: + if File.basename(path + 'a') == 'a' + path + else + File.join(path, "") # xxx: Is File.join is appropriate to add separator? + end + end + private :add_trailing_separator + + def del_trailing_separator(path) # :nodoc: + if r = chop_basename(path) + pre, basename = r + pre + basename + elsif matches_path?(/#{SEPARATOR_PAT}+\z/o, path) + $` + File.dirname(path)[/#{SEPARATOR_PAT}*\z/o] + else + path + end + end + private :del_trailing_separator + + def cleanpath_conservative # :nodoc: + path = @path + names = [] + pre = path + while r = chop_basename(pre) + pre, base = r + names.unshift base if base != '.' + end + pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR + if matches_path?(/#{SEPARATOR_PAT}/o, File.basename(pre)) + names.shift while names[0] == '..' + end + if names.empty? + self.class.new(File.dirname(pre)) + else + if names.last != '..' && File.basename(path) == '.' + names << '.' + end + result = prepend_prefix(pre, File.join(*names)) + if /\A(?:\.|\.\.)\z/ !~ names.last && has_trailing_separator?(path) + self.class.new(add_trailing_separator(result)) + else + self.class.new(result) + end + end + end + private :cleanpath_conservative + + # Returns the parent directory. + # + # This is same as self + '..'. + def parent + self + '..' + end + + # Returns +true+ if +self+ points to a mountpoint. + def mountpoint? + begin + stat1 = self.lstat + stat2 = self.parent.lstat + stat1.dev != stat2.dev || stat1.ino == stat2.ino + rescue Errno::ENOENT + false + end + end + + # + # Predicate method for root directories. Returns +true+ if the + # pathname consists of consecutive slashes. + # + # It doesn't access the filesystem. So it may return +false+ for some + # pathnames which points to roots such as /usr/... + # + def root? + chop_basename(@path) == nil && matches_path?(/#{SEPARATOR_PAT}/o, @path) + end + + # Predicate method for testing whether a path is absolute. + # + # It returns +true+ if the pathname begins with a slash. + # + # p = Bundler::Pathname.new('/im/sure') + # p.absolute? + # #=> true + # + # p = Bundler::Pathname.new('not/so/sure') + # p.absolute? + # #=> false + def absolute? + matches_path?(ABSOLUTE_PATH, @path) + end + + # The opposite of Bundler::Pathname#absolute? + # + # It returns +false+ if the pathname begins with a slash. + # + # p = Bundler::Pathname.new('/im/sure') + # p.relative? + # #=> false + # + # p = Bundler::Pathname.new('not/so/sure') + # p.relative? + # #=> true + def relative? + !absolute? + end + + # + # Iterates over each component of the path. + # + # Bundler::Pathname.new("/usr/bin/ruby").each_filename {|filename| ... } + # # yields "usr", "bin", and "ruby". + # + # Returns an Enumerator if no block was given. + # + # enum = Bundler::Pathname.new("/usr/bin/ruby").each_filename + # # ... do stuff ... + # enum.each { |e| ... } + # # yields "usr", "bin", and "ruby". + # + def each_filename # :yield: filename + return to_enum(__method__) unless block_given? + _, names = split_names(@path) + names.each {|filename| yield filename } + nil + end + + # Iterates over and yields a new Bundler::Pathname object + # for each element in the given path in descending order. + # + # Bundler::Pathname.new('/path/to/some/file.rb').descend {|v| p v} + # # + # # + # # + # # + # # + # + # Bundler::Pathname.new('path/to/some/file.rb').descend {|v| p v} + # # + # # + # # + # # + # + # Returns an Enumerator if no block was given. + # + # enum = Bundler::Pathname.new("/usr/bin/ruby").descend + # # ... do stuff ... + # enum.each { |e| ... } + # # yields Pathnames /, /usr, /usr/bin, and /usr/bin/ruby. + # + # It doesn't access the filesystem. + # + def descend + return to_enum(__method__) unless block_given? + vs = [] + ascend {|v| vs << v } + vs.reverse_each {|v| yield v } + nil + end + + # Iterates over and yields a new Bundler::Pathname object + # for each element in the given path in ascending order. + # + # Bundler::Pathname.new('/path/to/some/file.rb').ascend {|v| p v} + # # + # # + # # + # # + # # + # + # Bundler::Pathname.new('path/to/some/file.rb').ascend {|v| p v} + # # + # # + # # + # # + # + # Returns an Enumerator if no block was given. + # + # enum = Bundler::Pathname.new("/usr/bin/ruby").ascend + # # ... do stuff ... + # enum.each { |e| ... } + # # yields Pathnames /usr/bin/ruby, /usr/bin, /usr, and /. + # + # It doesn't access the filesystem. + # + def ascend + return to_enum(__method__) unless block_given? + path = @path + yield self + while r = chop_basename(path) + path, = r + break if path.empty? + yield self.class.new(del_trailing_separator(path)) + end + end + + # + # Appends a pathname fragment to +self+ to produce a new Bundler::Pathname object. + # + # p1 = Bundler::Pathname.new("/usr") # Bundler::Pathname:/usr + # p2 = p1 + "bin/ruby" # Bundler::Pathname:/usr/bin/ruby + # p3 = p1 + "/etc/passwd" # Bundler::Pathname:/etc/passwd + # + # # / is aliased to +. + # p4 = p1 / "bin/ruby" # Bundler::Pathname:/usr/bin/ruby + # p5 = p1 / "/etc/passwd" # Bundler::Pathname:/etc/passwd + # + # This method doesn't access the file system; it is pure string manipulation. + # + def +(other) + other = Bundler::Pathname.new(other) unless Bundler::Pathname === other + Bundler::Pathname.new(plus(@path, other.to_s)) + end + alias / + + + def plus(path1, path2) # -> path # :nodoc: + prefix2 = path2 + index_list2 = [] + basename_list2 = [] + while r2 = chop_basename(prefix2) + prefix2, basename2 = r2 + index_list2.unshift prefix2.length + basename_list2.unshift basename2 + end + return path2 if prefix2 != '' + prefix1 = path1 + while true + while !basename_list2.empty? && basename_list2.first == '.' + index_list2.shift + basename_list2.shift + end + break unless r1 = chop_basename(prefix1) + prefix1, basename1 = r1 + next if basename1 == '.' + if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..' + prefix1 = prefix1 + basename1 + break + end + index_list2.shift + basename_list2.shift + end + r1 = chop_basename(prefix1) + if !r1 && (r1 = matches_path?(/#{SEPARATOR_PAT}/o, File.basename(prefix1))) + while !basename_list2.empty? && basename_list2.first == '..' + index_list2.shift + basename_list2.shift + end + end + if !basename_list2.empty? + suffix2 = path2[index_list2.first..-1] + r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2 + else + r1 ? prefix1 : File.dirname(prefix1) + end + end + private :plus + + # + # Joins the given pathnames onto +self+ to create a new Bundler::Pathname object. + # + # path0 = Bundler::Pathname.new("/usr") # Bundler::Pathname:/usr + # path0 = path0.join("bin/ruby") # Bundler::Pathname:/usr/bin/ruby + # # is the same as + # path1 = Bundler::Pathname.new("/usr") + "bin/ruby" # Bundler::Pathname:/usr/bin/ruby + # path0 == path1 + # #=> true + # + def join(*args) + return self if args.empty? + result = args.pop + result = Bundler::Pathname.new(result) unless Bundler::Pathname === result + return result if result.absolute? + args.reverse_each {|arg| + arg = Bundler::Pathname.new(arg) unless Bundler::Pathname === arg + result = arg + result + return result if result.absolute? + } + self + result + end + + # + # Returns the children of the directory (files and subdirectories, not + # recursive) as an array of Bundler::Pathname objects. + # + # By default, the returned pathnames will have enough information to access + # the files. If you set +with_directory+ to +false+, then the returned + # pathnames will contain the filename only. + # + # For example: + # pn = Bundler::Pathname("/usr/lib/ruby/1.8") + # pn.children + # # -> [ Bundler::Pathname:/usr/lib/ruby/1.8/English.rb, + # Bundler::Pathname:/usr/lib/ruby/1.8/Env.rb, + # Bundler::Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ] + # pn.children(false) + # # -> [ Bundler::Pathname:English.rb, Bundler::Pathname:Env.rb, Bundler::Pathname:abbrev.rb, ... ] + # + # Note that the results never contain the entries +.+ and +..+ in + # the directory because they are not children. + # + def children(with_directory=true) + with_directory = false if @path == '.' + result = [] + Dir.foreach(@path) {|e| + next if e == '.' || e == '..' + if with_directory + result << self.class.new(File.join(@path, e)) + else + result << self.class.new(e) + end + } + result + end + + # Iterates over the children of the directory + # (files and subdirectories, not recursive). + # + # It yields Bundler::Pathname object for each child. + # + # By default, the yielded pathnames will have enough information to access + # the files. + # + # If you set +with_directory+ to +false+, then the returned pathnames will + # contain the filename only. + # + # Bundler::Pathname("/usr/local").each_child {|f| p f } + # #=> # + # # # + # # # + # # # + # # # + # # # + # # # + # # # + # + # Bundler::Pathname("/usr/local").each_child(false) {|f| p f } + # #=> # + # # # + # # # + # # # + # # # + # # # + # # # + # # # + # + # Note that the results never contain the entries +.+ and +..+ in + # the directory because they are not children. + # + # See Bundler::Pathname#children + # + def each_child(with_directory=true, &b) + children(with_directory).each(&b) + end + + # + # Returns a relative path from the given +base_directory+ to the receiver. + # + # If +self+ is absolute, then +base_directory+ must be absolute too. + # + # If +self+ is relative, then +base_directory+ must be relative too. + # + # This method doesn't access the filesystem. It assumes no symlinks. + # + # ArgumentError is raised when it cannot find a relative path. + # + # Note that this method does not handle situations where the case sensitivity + # of the filesystem in use differs from the operating system default. + # + def relative_path_from(base_directory) + base_directory = Bundler::Pathname.new(base_directory) unless base_directory.is_a? Bundler::Pathname + dest_directory = self.cleanpath.to_s + base_directory = base_directory.cleanpath.to_s + dest_prefix = dest_directory + dest_names = [] + while r = chop_basename(dest_prefix) + dest_prefix, basename = r + dest_names.unshift basename if basename != '.' + end + base_prefix = base_directory + base_names = [] + while r = chop_basename(base_prefix) + base_prefix, basename = r + base_names.unshift basename if basename != '.' + end + unless SAME_PATHS[dest_prefix, base_prefix] + raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}" + end + while !dest_names.empty? && + !base_names.empty? && + SAME_PATHS[dest_names.first, base_names.first] + dest_names.shift + base_names.shift + end + if base_names.include? '..' + raise ArgumentError, "base_directory has ..: #{base_directory.inspect}" + end + base_names.fill('..') + relpath_names = base_names + dest_names + if relpath_names.empty? + Bundler::Pathname.new('.') + else + Bundler::Pathname.new(File.join(*relpath_names)) + end + end +end + + +class Bundler::Pathname # * Find * + # + # Iterates over the directory tree in a depth first manner, yielding a + # Bundler::Pathname for each file under "this" directory. + # + # Returns an Enumerator if no block is given. + # + # Since it is implemented by the standard library module Find, Find.prune can + # be used to control the traversal. + # + # If +self+ is +.+, yielded pathnames begin with a filename in the + # current directory, not +./+. + # + # See Find.find + # + def find(ignore_error: true) # :yield: pathname + return to_enum(__method__, ignore_error: ignore_error) unless block_given? + require 'find' + if @path == '.' + Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.sub(%r{\A\./}, '')) } + else + Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f) } + end + end +end + + +class Bundler::Pathname # * FileUtils * + autoload(:FileUtils, 'fileutils') + + # Creates a full path, including any intermediate directories that don't yet + # exist. + # + # See FileUtils.mkpath and FileUtils.mkdir_p + def mkpath(mode: nil) + FileUtils.mkpath(@path, mode: mode) + nil + end + + # Recursively deletes a directory, including all directories beneath it. + # + # See FileUtils.rm_r + def rmtree + # The name "rmtree" is borrowed from File::Path of Perl. + # File::Path provides "mkpath" and "rmtree". + FileUtils.rm_r(@path) + nil + end +end + diff --git a/bundler/lib/bundler/vendored_pathname.rb b/bundler/lib/bundler/vendored_pathname.rb new file mode 100644 index 000000000000..c2fc584b038b --- /dev/null +++ b/bundler/lib/bundler/vendored_pathname.rb @@ -0,0 +1,336 @@ +# frozen_string_literal: true + +# +# Pure ruby implementation of the C-extension of the `pathname` gem. +# +module Bundler + def Pathname(str) # rubocop:disable Naming/MethodName + return str if str.is_a?(Bundler::Pathname) + + Pathname.new(str) + end + module_function :Pathname + + class Pathname + attr_reader :path + + def initialize(path) + path = path.to_path if path.respond_to? :to_path + + @path = String.new(path) + end + + def eql?(other) + self.class == other.class && path == other.path + end + + alias_method :==, :eql? + + def hash + path.hash + end + + def to_s + path + end + + alias_method :to_path, :to_s + + def sub(*args, &block) + self.class.new(path.sub(*args), &block) + end + + def read(*args) + File.read(path, *args) + end + + def open(mode, &block) + File.open(path, mode, &block) + end + + def basename + self.class.new(File.basename(path)) + end + + def dirname + self.class.new(File.dirname(path)) + end + + def expand_path(base = Dir.pwd) + self.class.new(File.expand_path(path, base)) + end + + def exist? + File.exist?(path) + end + + def directory? + File.directory?(path) + end + + def file? + File.file?(path) + end + + def size + File.size(path) + end + + # + # The following methods are not used internally by bundler, but are provided + # for backwards compatibility with the original Pathname class. + # + + def freeze + super + path.freeze + self + end + + alias_method :===, :eql? + + def inspect + "#<#{self.class.name}:#{path}>" + end + + def sub_ext(repl) + self.class.new(extname.empty? ? path + repl : path.sub(extname, repl)) + end + + def realpath + self.class.new(File.realpath(path)) + end + + def realdirpath + self.class.new(File.realdirpath(path)) + end + + def each_line(*args, &block) + File.foreach(path, *args, &block) + end + + def binread(*args) + File.binread(path, *args) + end + + def readlines(*args) + File.readlines(path, *args) + end + + def write(*args) + File.write(path, *args) + end + + def binwrite(*args) + File.write(path, *args) + end + + def sysopen(*args) + IO.sysopen(path, *args) + end + + def atime + File.atime(path) + end + + def birthtime + File.birthtime(path) + end + + def ctime + File.ctime(path) + end + + def mtime + File.mtime(path) + end + + def chmod(mode) + File.chmod(mode, path) + end + + def lchmod(mode) + File.lchmod(mode, path) + end + + def chown(owner, group) + File.chowm(owner, group, path) + end + + def lchown(owner, group) + File.lchowm(owner, group, path) + end + + def fnmatch(pattern, *args) + File.fnmatch(pattern, path, *args) + end + + def fnmatch?(pattern, *args) + File.fnmatch?(pattern, path, *args) + end + + def ftype + File.ftype(path) + end + + def make_link(old) + File.link(old, path) + end + + def readlink + self.class.new(File.readlink(path)) + end + + def rename(to) + File.rename(path, to) + end + + def stat + File.stat(path) + end + + def lstat + File.lstat(path) + end + + def make_symlink(old) + File.symlink(old, path) + end + + def truncate(length) + File.truncate(path, length) + end + + def utime(atime, mtime) + File.utime(atime, mtime, path) + end + + def extname + File.extname(path) + end + + def split + File.split(path).map {|str| self.class.new(str) } + end + + def blockdev? + FileTest.blockdev?(path) + end + + def chardev? + FileTest.chardev?(path) + end + + def executable? + FileTest.executable?(path) + end + + def executable_real? + FileTest.executable_real?(path) + end + + def grpowned? + FileTest.grpowned?(path) + end + + def pipe? + FileTest.pipe?(path) + end + + def socket? + FileTest.socket?(path) + end + + def owned? + FileTest.owned?(path) + end + + def readable? + FileTest.readable?(path) + end + + def world_readable? + FileTest.world_readable?(path) + end + + def readable_real? + FileTest.readable_real?(path) + end + + def setuid? + FileTest.setuid?(path) + end + + def setgid? + FileTest.setgid?(path) + end + + def size? + FileTest.size?(path) + end + + def sticky? + FileTest.sticky?(path) + end + + def symlink? + FileTest.symlink?(path) + end + + def writable? + FileTest.writable?(path) + end + + def world_writable? + FileTest.world_writable?(path) + end + + def writable_real? + FileTest.writable_real?(path) + end + + def zero? + FileTest.zero?(path) + end + + def empty? + FileTest.empty?(path) + end + + def glob(pattern, flags = 0) + Dir.glob(pattern, flags, :base => path).map {|str| self.class.new(str) } + end + + def entries + Dir.entries(path).map {|str| self.class.new(str) } + end + + def mkdir(*args) + Dir.mkdir(path, *args) + end + + def rmdir + Dir.mkdir(path) + end + + def opendir(*args) + Dir.opendir(path, *args) + end + + def each_entry(*args, &block) + Dir.foreach(path, *args, &block) + end + + def unlink + Dir.unlink(path) + rescue Errno::ENOTDIR + File.unlink(path) + end + + alias_method :delete, :unlink + + undef_method :"=~" + end +end + +require_relative "vendor/pathname/lib/pathname" diff --git a/bundler/spec/bundler/bundler_spec.rb b/bundler/spec/bundler/bundler_spec.rb index aeadcf9720b5..4ff2c6eb9602 100644 --- a/bundler/spec/bundler/bundler_spec.rb +++ b/bundler/spec/bundler/bundler_spec.rb @@ -186,15 +186,15 @@ allow(Bundler).to receive(:root).and_return(bundled_app) - Bundler.mkdir_p(bundled_app.join("foo", "bar")) - expect(bundled_app.join("foo", "bar")).to exist + Bundler.mkdir_p(bundled_app("foo", "bar")) + expect(bundled_app("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")) + Bundler.mkdir_p(bundled_app("foo")) end end @@ -202,7 +202,7 @@ 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) + Bundler.mkdir_p(bundled_app("foo"), :no_sudo => true) end end end @@ -214,7 +214,7 @@ allow(Bundler.rubygems).to receive(:user_home).and_return(path) allow(File).to receive(:directory?).with(path).and_return true allow(File).to receive(:writable?).with(path).and_return true - expect(Bundler.user_home).to eq(Pathname(path)) + expect(Bundler.user_home.to_s).to eq(path) end context "is not a directory" do @@ -225,7 +225,7 @@ allow(Bundler).to receive(:tmp).and_return(Pathname.new("/tmp/trulyrandom")) expect(Bundler.ui).to receive(:warn).with("`/home/oggy` is not a directory.\n") expect(Bundler.ui).to receive(:warn).with("Bundler will use `/tmp/trulyrandom' as your home directory temporarily.\n") - expect(Bundler.user_home).to eq(Pathname("/tmp/trulyrandom")) + expect(Bundler.user_home.to_s).to eq("/tmp/trulyrandom") end end @@ -241,7 +241,7 @@ allow(Bundler).to receive(:tmp).and_return(Pathname.new("/tmp/trulyrandom")) expect(Bundler.ui).to receive(:warn).with("`/home/oggy` is not writable.\n") expect(Bundler.ui).to receive(:warn).with("Bundler will use `/tmp/trulyrandom' as your home directory temporarily.\n") - expect(Bundler.user_home).to eq(Pathname("/tmp/trulyrandom")) + expect(Bundler.user_home.to_s).to eq("/tmp/trulyrandom") end context ".bundle exists and have correct permissions" do @@ -251,7 +251,7 @@ allow(File).to receive(:writable?).with(path).and_return false allow(File).to receive(:directory?).with(dotbundle).and_return true allow(File).to receive(:writable?).with(dotbundle).and_return true - expect(Bundler.user_home).to eq(Pathname(path)) + expect(Bundler.user_home.to_s).to eq(path) end end end @@ -263,14 +263,14 @@ allow(Bundler).to receive(:tmp).and_return(Pathname.new("/tmp/trulyrandom")) expect(Bundler.ui).to receive(:warn).with("Your home directory is not set.\n") expect(Bundler.ui).to receive(:warn).with("Bundler will use `/tmp/trulyrandom' as your home directory temporarily.\n") - expect(Bundler.user_home).to eq(Pathname("/tmp/trulyrandom")) + expect(Bundler.user_home.to_s).to eq("/tmp/trulyrandom") end end end describe "#requires_sudo?" do let!(:tmpdir) { Dir.mktmpdir } - let(:bundle_path) { Pathname("#{tmpdir}/bundle") } + let(:bundle_path) { Pathname.new("#{tmpdir}/bundle") } def clear_cached_requires_sudo return unless Bundler.instance_variable_defined?(:@requires_sudo_ran) @@ -343,7 +343,7 @@ def clear_cached_requires_sudo 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")) + allow(Bundler).to receive(:bundle_path).and_return(Pathname.new("tmp/vendor/bundle")) expect(Bundler.ui).to_not receive(:warn) expect(Bundler.requires_sudo?).to eq(false) end @@ -358,15 +358,14 @@ def clear_cached_requires_sudo 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(Bundler).to receive(:bundle_path).and_return(Pathname.new("tmp/vendor/bundle")) # 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/")) + allow(File).to receive(:writable?).with("tmp/vendor/bin_dir/").and_return(false) + allow(Bundler).to receive(:system_bindir).and_return("tmp/vendor/bin_dir/") message = <<-MESSAGE.chomp Following files may not be writable, so sudo is needed: tmp/vendor/bin_dir/ @@ -381,7 +380,7 @@ def clear_cached_requires_sudo end context "user cache dir" do - let(:home_path) { Pathname.new(ENV["HOME"]) } + let(:home_path) { Bundler::Pathname.new(ENV["HOME"]) } let(:xdg_data_home) { home_path.join(".local") } let(:xdg_cache_home) { home_path.join(".cache") } diff --git a/bundler/spec/bundler/env_spec.rb b/bundler/spec/bundler/env_spec.rb index a6f4b2ba8569..308a08b31a26 100644 --- a/bundler/spec/bundler/env_spec.rb +++ b/bundler/spec/bundler/env_spec.rb @@ -154,7 +154,7 @@ def with_clear_paths(env_var, env_value) before do gemfile("source \"#{file_uri_for(gem_repo1)}\"; gemspec") - File.open(bundled_app.join("foo.gemspec"), "wb") do |f| + File.open(bundled_app("foo.gemspec"), "wb") do |f| f.write(gemspec) end diff --git a/bundler/spec/bundler/gem_helper_spec.rb b/bundler/spec/bundler/gem_helper_spec.rb index 2c43719aa172..51ec31ecf724 100644 --- a/bundler/spec/bundler/gem_helper_spec.rb +++ b/bundler/spec/bundler/gem_helper_spec.rb @@ -237,11 +237,11 @@ def mock_checksum_message(name, version) end before do - sys_exec("git init", :dir => app_path) - sys_exec("git config user.email \"you@example.com\"", :dir => app_path) - sys_exec("git config user.name \"name\"", :dir => app_path) - sys_exec("git config commit.gpgsign false", :dir => app_path) - sys_exec("git config push.default simple", :dir => app_path) + git("init", app_path) + git("config user.email \"you@example.com\"", app_path) + git("config user.name \"name\"", app_path) + git("config commit.gpgsign false", app_path) + git("config push.default simple", app_path) # silence messages allow(Bundler.ui).to receive(:confirm) @@ -255,13 +255,13 @@ def mock_checksum_message(name, version) end it "when there are uncommitted files" do - sys_exec("git add .", :dir => app_path) + git("add .", app_path) expect { Rake.application["release"].invoke }. to raise_error("There are files that need to be committed first.") end it "when there is no git remote" do - sys_exec("git commit -a -m \"initial commit\"", :dir => app_path) + git("commit -a -m \"initial commit\"", app_path) expect { Rake.application["release"].invoke }.to raise_error(RuntimeError) end end @@ -270,8 +270,8 @@ def mock_checksum_message(name, version) let(:repo) { build_git("foo", :bare => true) } before do - sys_exec("git remote add origin #{file_uri_for(repo.path)}", :dir => app_path) - sys_exec('git commit -a -m "initial commit"', :dir => app_path) + git("remote add origin #{file_uri_for(repo.path)}", app_path) + git('commit -a -m "initial commit"', app_path) end context "on releasing" do @@ -280,7 +280,7 @@ def mock_checksum_message(name, version) mock_confirm_message "Tagged v#{app_version}." mock_confirm_message "Pushed git commits and release tag." - sys_exec("git push -u origin master", :dir => app_path) + git("push -u origin master", app_path) end it "calls rubygem_push with proper arguments" do @@ -298,8 +298,8 @@ def mock_checksum_message(name, version) it "also works when releasing from an ambiguous reference" do # Create a branch with the same name as the tag - sys_exec("git checkout -b v#{app_version}", :dir => app_path) - sys_exec("git push -u origin v#{app_version}", :dir => app_path) + git("checkout -b v#{app_version}", app_path) + git("push -u origin v#{app_version}", app_path) expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s) @@ -307,7 +307,7 @@ def mock_checksum_message(name, version) end it "also works with releasing from a branch not yet pushed" do - sys_exec("git checkout -b module_function", :dir => app_path) + git("checkout -b module_function", app_path) expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s) @@ -321,7 +321,7 @@ def mock_checksum_message(name, version) mock_build_message app_name, app_version mock_confirm_message "Pushed git commits and release tag." - sys_exec("git push -u origin master", :dir => app_path) + git("push -u origin master", app_path) expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s) end @@ -337,7 +337,7 @@ def mock_checksum_message(name, version) mock_confirm_message "Tag v#{app_version} has already been created." expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s) - sys_exec("git tag -a -m \"Version #{app_version}\" v#{app_version}", :dir => app_path) + git("tag -a -m \"Version #{app_version}\" v#{app_version}", app_path) Rake.application["release"].invoke end @@ -358,10 +358,10 @@ def mock_checksum_message(name, version) end before do - sys_exec("git init", :dir => app_path) - sys_exec("git config user.email \"you@example.com\"", :dir => app_path) - sys_exec("git config user.name \"name\"", :dir => app_path) - sys_exec("git config push.gpgsign simple", :dir => app_path) + git("init", app_path) + git("config user.email \"you@example.com\"", app_path) + git("config user.name \"name\"", app_path) + git("config push.gpgsign simple", app_path) # silence messages allow(Bundler.ui).to receive(:confirm) diff --git a/bundler/spec/bundler/plugin/index_spec.rb b/bundler/spec/bundler/plugin/index_spec.rb index d34b0de34210..b3289d93f00f 100644 --- a/bundler/spec/bundler/plugin/index_spec.rb +++ b/bundler/spec/bundler/plugin/index_spec.rb @@ -19,7 +19,7 @@ describe "#register plugin" do it "is available for retrieval" do - expect(index.plugin_path(plugin_name)).to eq(lib_path(plugin_name)) + expect(index.plugin_path(plugin_name).to_s).to eq(lib_path(plugin_name).to_s) end it "load_paths is available for retrieval" do @@ -28,7 +28,7 @@ it "is persistent" do new_index = Index.new - expect(new_index.plugin_path(plugin_name)).to eq(lib_path(plugin_name)) + expect(new_index.plugin_path(plugin_name).to_s).to eq(lib_path(plugin_name).to_s) end it "load_paths are persistent" do diff --git a/bundler/spec/bundler/plugin_spec.rb b/bundler/spec/bundler/plugin_spec.rb index 8a1a6cd97ab7..4d71cf20e2db 100644 --- a/bundler/spec/bundler/plugin_spec.rb +++ b/bundler/spec/bundler/plugin_spec.rb @@ -78,7 +78,7 @@ allow(index).to receive(:installed?). with("new-plugin") allow(subject). - to receive(:validate_plugin!).with(lib_path("new-plugin")).once + to receive(:validate_plugin!).with(Bundler::Pathname.new(lib_path("new-plugin").to_s)).once subject.install ["new-plugin"], opts end @@ -247,7 +247,7 @@ end it "returns plugin dir in app .bundle path" do - expect(subject.root).to eq(bundled_app.join(".bundle/plugin")) + expect(subject.root.to_s).to eq(bundled_app(".bundle/plugin").to_s) end end @@ -257,7 +257,7 @@ end it "returns plugin dir in global bundle path" do - expect(subject.root).to eq(home.join(".bundle/plugin")) + expect(subject.root.to_s).to eq(home(".bundle/plugin").to_s) end end end diff --git a/bundler/spec/bundler/shared_helpers_spec.rb b/bundler/spec/bundler/shared_helpers_spec.rb index 68a24be31c69..7a0e37d553e4 100644 --- a/bundler/spec/bundler/shared_helpers_spec.rb +++ b/bundler/spec/bundler/shared_helpers_spec.rb @@ -17,7 +17,7 @@ before { ENV["BUNDLE_GEMFILE"] = "/path/Gemfile" } context "Gemfile is present" do - let(:expected_gemfile_path) { Pathname.new("/path/Gemfile").expand_path } + let(:expected_gemfile_path) { Bundler::Pathname.new("/path/Gemfile").expand_path } it "returns the Gemfile path" do expect(subject.default_gemfile).to eq(expected_gemfile_path) @@ -37,7 +37,7 @@ context "Gemfile is not an absolute path" do before { ENV["BUNDLE_GEMFILE"] = "Gemfile" } - let(:expected_gemfile_path) { Pathname.new("Gemfile").expand_path } + let(:expected_gemfile_path) { Bundler::Pathname.new("Gemfile").expand_path } it "returns the Gemfile path" do expect(subject.default_gemfile).to eq(expected_gemfile_path) @@ -47,8 +47,8 @@ describe "#default_lockfile" do context "gemfile is gems.rb" do - let(:gemfile_path) { Pathname.new("/path/gems.rb") } - let(:expected_lockfile_path) { Pathname.new("/path/gems.locked") } + let(:gemfile_path) { Bundler::Pathname.new("/path/gems.rb") } + let(:expected_lockfile_path) { Bundler::Pathname.new("/path/gems.locked") } before { allow(subject).to receive(:default_gemfile).and_return(gemfile_path) } @@ -58,8 +58,8 @@ end context "is a regular Gemfile" do - let(:gemfile_path) { Pathname.new("/path/Gemfile") } - let(:expected_lockfile_path) { Pathname.new("/path/Gemfile.lock") } + let(:gemfile_path) { Bundler::Pathname.new("/path/Gemfile") } + let(:expected_lockfile_path) { Bundler::Pathname.new("/path/Gemfile.lock") } before { allow(subject).to receive(:default_gemfile).and_return(gemfile_path) } @@ -77,7 +77,7 @@ end context ".bundle is global .bundle" do - let(:global_rubygems_dir) { Pathname.new(bundled_app) } + let(:global_rubygems_dir) { Bundler::Pathname.new(bundled_app) } before do Dir.mkdir bundled_app(".bundle") @@ -90,8 +90,8 @@ end context ".bundle is not global .bundle" do - let(:global_rubygems_dir) { Pathname.new("/path/rubygems") } - let(:expected_bundle_dir_path) { Pathname.new("#{bundled_app}/.bundle") } + let(:global_rubygems_dir) { Bundler::Pathname.new("/path/rubygems") } + let(:expected_bundle_dir_path) { Bundler::Pathname.new("#{bundled_app}/.bundle") } before do Dir.mkdir bundled_app(".bundle") @@ -163,7 +163,7 @@ let(:pwd_stub) { nil } it "returns the current absolute path" do - expect(subject.pwd).to eq(source_root) + expect(subject.pwd).to eq(source_root.to_s) end end @@ -283,7 +283,7 @@ else stub_const("File::PATH_SEPARATOR", ":".freeze) end - allow(Bundler).to receive(:bundle_path) { Pathname.new("so:me/dir/bin") } + allow(Bundler).to receive(:bundle_path) { Bundler::Pathname.new("so:me/dir/bin") } expect { subject.send(:validate_bundle_path) }.to raise_error( Bundler::PathError, "Your bundle path contains text matching \":\", which is the " \ @@ -300,14 +300,14 @@ let(:regex) { Regexp.new("(? "u:p") do original = "https://orig:info@github.com/rubygems/rubygems.git" - subject = described_class.new(Pathname("path"), original, "HEAD") + subject = described_class.new(Pathname.new("path"), original, "HEAD") expect(subject).to receive(:git_retry).with("clone", original, any_args) subject.checkout end diff --git a/bundler/spec/bundler/source/rubygems_spec.rb b/bundler/spec/bundler/source/rubygems_spec.rb index 884fa810465f..f2376822b1e1 100644 --- a/bundler/spec/bundler/source/rubygems_spec.rb +++ b/bundler/spec/bundler/source/rubygems_spec.rb @@ -7,7 +7,7 @@ describe "caches" do it "includes Bundler.app_cache" do - expect(subject.caches).to include(Bundler.app_cache) + expect(subject.caches).to include(Bundler.app_cache.to_s) end it "includes GEM_PATH entries" do @@ -16,9 +16,9 @@ end end - it "is an array of strings or pathnames" do + it "is an array of strings" do subject.caches.each do |cache| - expect([String, Pathname]).to include(cache.class) + expect(String).to eq(cache.class) end end end diff --git a/bundler/spec/cache/git_spec.rb b/bundler/spec/cache/git_spec.rb index b88993e9b1b1..e7e236d08916 100644 --- a/bundler/spec/cache/git_spec.rb +++ b/bundler/spec/cache/git_spec.rb @@ -162,8 +162,8 @@ s.add_dependency "submodule" end - sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0") - sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0") + git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0") + git "commit -m \"submodulator\"", lib_path("has_submodule-1.0") install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" diff --git a/bundler/spec/commands/init_spec.rb b/bundler/spec/commands/init_spec.rb index 683a453c7d75..32f469d68914 100644 --- a/bundler/spec/commands/init_spec.rb +++ b/bundler/spec/commands/init_spec.rb @@ -56,7 +56,7 @@ end context "given --gemspec option" do - let(:spec_file) { tmp.join("test.gemspec") } + let(:spec_file) { tmp("test.gemspec") } it "should generate from an existing gemspec" do File.open(spec_file, "w") do |file| @@ -137,7 +137,7 @@ end context "given --gemspec option" do - let(:spec_file) { tmp.join("test.gemspec") } + let(:spec_file) { tmp("test.gemspec") } before do File.open(spec_file, "w") do |file| diff --git a/bundler/spec/commands/install_spec.rb b/bundler/spec/commands/install_spec.rb index e00caa53153e..dfa262de1d62 100644 --- a/bundler/spec/commands/install_spec.rb +++ b/bundler/spec/commands/install_spec.rb @@ -783,7 +783,7 @@ def run it "includes the standalone path" do bundle "binstubs rack", :standalone => true standalone_line = File.read(bundled_app("bin/rackup")).each_line.find {|line| line.include? "$:.unshift" }.strip - expect(standalone_line).to eq %($:.unshift File.expand_path "../../bundle", path.realpath) + expect(standalone_line).to eq %($:.unshift File.expand_path "../bundle", __dir__) end end diff --git a/bundler/spec/commands/list_spec.rb b/bundler/spec/commands/list_spec.rb index 66930ded75a2..fb0d1638db03 100644 --- a/bundler/spec/commands/list_spec.rb +++ b/bundler/spec/commands/list_spec.rb @@ -126,7 +126,7 @@ build_git "git_test", "1.0.0", :path => lib_path("git_test") - build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s| + build_lib("gemspec_test", :path => tmp("gemspec_test")) do |s| s.add_dependency "bar", "=1.0.0" end @@ -135,7 +135,7 @@ gem "rack" gem "rails" gem "git_test", :git => "#{lib_path("git_test")}" - gemspec :path => "#{tmp.join("gemspec_test")}" + gemspec :path => "#{tmp("gemspec_test")}" G end diff --git a/bundler/spec/commands/newgem_spec.rb b/bundler/spec/commands/newgem_spec.rb index 5ba513861c2a..a05782c883ff 100644 --- a/bundler/spec/commands/newgem_spec.rb +++ b/bundler/spec/commands/newgem_spec.rb @@ -29,9 +29,9 @@ def bundle_exec_standardrb let(:require_path) { "mygem" } before do - sys_exec("git config --global user.name 'Bundler User'") - sys_exec("git config --global user.email user@example.com") - sys_exec("git config --global github.user bundleuser") + git("config --global user.name 'Bundler User'") + git("config --global user.email user@example.com") + git("config --global github.user bundleuser") end describe "git repo initialization" do @@ -100,7 +100,7 @@ def bundle_exec_standardrb end it "generates the README with a section for the Code of Conduct, respecting the configured git default branch", :git => ">= 2.28.0" do - sys_exec("git config --global init.defaultBranch main") + git("config --global init.defaultBranch main") bundle "gem #{gem_name} --coc" expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct") @@ -374,7 +374,7 @@ def bundle_exec_standardrb context "git config github.user is absent" do before do - sys_exec("git config --global --unset github.user") + git("config --global --unset github.user") bundle "gem #{gem_name}" end @@ -545,8 +545,8 @@ def create_temporary_dir(dir) context "git config user.{name,email} is not set" do before do - sys_exec("git config --global --unset user.name") - sys_exec("git config --global --unset user.email") + git("config --global --unset user.name") + git("config --global --unset user.email") bundle "gem #{gem_name}" end @@ -1238,7 +1238,7 @@ def create_temporary_dir(dir) context "testing --github-username option against git and bundle config settings", :readline do context "without git config set" do before do - sys_exec("git config --global --unset github.user") + git("config --global --unset github.user") end context "with github-username option in bundle config settings set to some value" do before do @@ -1275,7 +1275,7 @@ def create_temporary_dir(dir) context "testing github_username bundle config against git config settings", :readline do context "without git config set" do before do - sys_exec("git config --global --unset github.user") + git("config --global --unset github.user") end it_behaves_like "github_username configuration" diff --git a/bundler/spec/commands/open_spec.rb b/bundler/spec/commands/open_spec.rb index 53dc35c2c772..76600b9fdc1a 100644 --- a/bundler/spec/commands/open_spec.rb +++ b/bundler/spec/commands/open_spec.rb @@ -44,7 +44,7 @@ G bundle "open foo", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" } - expect(out).to match("editor #{default_bundle_path.join("bundler/gems/foo-1.0-#{ref}")}") + expect(out).to match("editor #{default_bundle_path("bundler/gems/foo-1.0-#{ref}")}") end it "suggests alternatives for similar-sounding gems" do diff --git a/bundler/spec/commands/remove_spec.rb b/bundler/spec/commands/remove_spec.rb index 70dc09c9b671..64fa81e38d40 100644 --- a/bundler/spec/commands/remove_spec.rb +++ b/bundler/spec/commands/remove_spec.rb @@ -602,14 +602,14 @@ context "with gemspec" do it "should not remove the gem" do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.write("foo.gemspec", "") s.add_dependency "rack" end install_gemfile(<<-G) source "#{file_uri_for(gem_repo1)}" - gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + gemspec :path => '#{tmp("foo")}', :name => 'foo' G bundle "remove foo" diff --git a/bundler/spec/install/gemfile/eval_gemfile_spec.rb b/bundler/spec/install/gemfile/eval_gemfile_spec.rb index 02283291b422..a90cef450473 100644 --- a/bundler/spec/install/gemfile/eval_gemfile_spec.rb +++ b/bundler/spec/install/gemfile/eval_gemfile_spec.rb @@ -2,7 +2,7 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do before do - build_lib("gunks", :path => bundled_app.join("gems/gunks")) do |s| + build_lib("gunks", :path => bundled_app("gems/gunks")) do |s| s.name = "gunks" s.version = "0.0.1" end diff --git a/bundler/spec/install/gemfile/gemspec_spec.rb b/bundler/spec/install/gemfile/gemspec_spec.rb index 6d9cd2dafffe..99a9071cb897 100644 --- a/bundler/spec/install/gemfile/gemspec_spec.rb +++ b/bundler/spec/install/gemfile/gemspec_spec.rb @@ -9,14 +9,14 @@ end it "should install runtime and development dependencies" do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.write("Gemfile", "source :rubygems\ngemspec") s.add_dependency "bar", "=1.0.0" s.add_development_dependency "bar-dev", "=1.0.0" end install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" - gemspec :path => '#{tmp.join("foo")}' + gemspec :path => '#{tmp("foo")}' G expect(the_bundle).to include_gems "bar 1.0.0" @@ -24,16 +24,16 @@ end it "that is hidden should install runtime and development dependencies" do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.write("Gemfile", "source :rubygems\ngemspec") s.add_dependency "bar", "=1.0.0" s.add_development_dependency "bar-dev", "=1.0.0" end - FileUtils.mv tmp.join("foo", "foo.gemspec"), tmp.join("foo", ".gemspec") + FileUtils.mv tmp("foo", "foo.gemspec"), tmp("foo", ".gemspec") install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" - gemspec :path => '#{tmp.join("foo")}' + gemspec :path => '#{tmp("foo")}' G expect(the_bundle).to include_gems "bar 1.0.0" @@ -46,42 +46,42 @@ build_gem "baz", "1.1" end - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.write("Gemfile", "source :rubygems\ngemspec") s.add_dependency "baz", ">= 1.0", "< 1.1" end install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" - gemspec :path => '#{tmp.join("foo")}' + gemspec :path => '#{tmp("foo")}' G expect(the_bundle).to include_gems "baz 1.0" end it "should raise if there are no gemspecs available" do - build_lib("foo", :path => tmp.join("foo"), :gemspec => false) + build_lib("foo", :path => tmp("foo"), :gemspec => false) install_gemfile <<-G, :raise_on_error => false source "#{file_uri_for(gem_repo2)}" - gemspec :path => '#{tmp.join("foo")}' + gemspec :path => '#{tmp("foo")}' G - expect(err).to match(/There are no gemspecs at #{tmp.join('foo')}/) + expect(err).to match(/There are no gemspecs at #{tmp('foo')}/) end it "should raise if there are too many gemspecs available" do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.write("foo2.gemspec", build_spec("foo", "4.0").first.to_ruby) end install_gemfile <<-G, :raise_on_error => false source "#{file_uri_for(gem_repo2)}" - gemspec :path => '#{tmp.join("foo")}' + gemspec :path => '#{tmp("foo")}' G - expect(err).to match(/There are multiple gemspecs at #{tmp.join('foo')}/) + expect(err).to match(/There are multiple gemspecs at #{tmp('foo')}/) end it "should pick a specific gemspec" do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.write("foo2.gemspec", "") s.add_dependency "bar", "=1.0.0" s.add_development_dependency "bar-dev", "=1.0.0" @@ -89,7 +89,7 @@ install_gemfile(<<-G) source "#{file_uri_for(gem_repo2)}" - gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + gemspec :path => '#{tmp("foo")}', :name => 'foo' G expect(the_bundle).to include_gems "bar 1.0.0" @@ -97,7 +97,7 @@ end it "should use a specific group for development dependencies" do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.write("foo2.gemspec", "") s.add_dependency "bar", "=1.0.0" s.add_development_dependency "bar-dev", "=1.0.0" @@ -105,7 +105,7 @@ install_gemfile(<<-G) source "#{file_uri_for(gem_repo2)}" - gemspec :path => '#{tmp.join("foo")}', :name => 'foo', :development_group => :dev + gemspec :path => '#{tmp("foo")}', :name => 'foo', :development_group => :dev G expect(the_bundle).to include_gems "bar 1.0.0" @@ -114,33 +114,33 @@ end it "should match a lockfile even if the gemspec defines development dependencies" do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.write("Gemfile", "source '#{file_uri_for(gem_repo1)}'\ngemspec") s.add_dependency "actionpack", "=2.3.2" s.add_development_dependency "rake", "=13.0.1" end - bundle "install", :dir => tmp.join("foo") + bundle "install", :dir => tmp("foo") # This should really be able to rely on $stderr, but, it's not written # right, so we can't. In fact, this is a bug negation test, and so it'll # ghost pass in future, and will only catch a regression if the message # doesn't change. Exit codes should be used correctly (they can be more # than just 0 and 1). bundle "config set --local deployment true" - output = bundle("install", :dir => tmp.join("foo")) + output = bundle("install", :dir => tmp("foo")) expect(output).not_to match(/You have added to the Gemfile/) expect(output).not_to match(/You have deleted from the Gemfile/) expect(output).not_to match(/install in deployment mode after changing/) end it "should match a lockfile without needing to re-resolve" do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.add_dependency "rack" end install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gemspec :path => '#{tmp.join("foo")}' + gemspec :path => '#{tmp("foo")}' G bundle "install", :verbose => true @@ -152,31 +152,31 @@ it "should match a lockfile without needing to re-resolve with development dependencies" do simulate_platform java - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.add_dependency "rack" s.add_development_dependency "thin" end install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gemspec :path => '#{tmp.join("foo")}' + gemspec :path => '#{tmp("foo")}' G bundle "install", :verbose => true message = "Found no changes, using resolution from the lockfile" - expect(out.scan(message).size).to eq(1) + expect(out).to include(message).once end it "should match a lockfile on non-ruby platforms with a transitive platform dependency", :jruby do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.add_dependency "platform_specific" end system_gems "platform_specific-1.0-java", :path => default_bundle_path install_gemfile <<-G - gemspec :path => '#{tmp.join("foo")}' + gemspec :path => '#{tmp("foo")}' G bundle "update --bundler", :verbose => true @@ -184,13 +184,13 @@ end it "should evaluate the gemspec in its directory" do - build_lib("foo", :path => tmp.join("foo")) - File.open(tmp.join("foo/foo.gemspec"), "w") do |s| - s.write "raise 'ahh' unless Dir.pwd == '#{tmp.join("foo")}'" + build_lib("foo", :path => tmp("foo")) + File.open(tmp("foo/foo.gemspec"), "w") do |s| + s.write "raise 'ahh' unless Dir.pwd == '#{tmp("foo")}'" end install_gemfile <<-G, :raise_on_error => false - gemspec :path => '#{tmp.join("foo")}' + gemspec :path => '#{tmp("foo")}' G expect(last_command.stdboth).not_to include("ahh") end @@ -218,7 +218,7 @@ end it "allows conflicts" do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.version = "1.0.0" s.add_dependency "bar", "= 1.0.0" end @@ -230,14 +230,14 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "deps" - gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + gemspec :path => '#{tmp("foo")}', :name => 'foo' G expect(the_bundle).to include_gems "foo 1.0.0" end it "does not break Gem.finish_resolve with conflicts" do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.version = "1.0.0" s.add_dependency "bar", "= 1.0.0" end @@ -251,7 +251,7 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "deps" - gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + gemspec :path => '#{tmp("foo")}', :name => 'foo' G expect(the_bundle).to include_gems "foo 1.0.0" @@ -334,7 +334,7 @@ before do skip "not installing for some reason" if Gem.win_platform? - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.add_dependency "rack", "=1.0.0" end @@ -369,7 +369,7 @@ context "using JRuby with explicit platform", :jruby do before do create_file( - tmp.join("foo", "foo-java.gemspec"), + tmp("foo", "foo-java.gemspec"), build_spec("foo", "1.0", "java") do dep "rack", "=1.0.0" @spec.authors = "authors" @@ -538,7 +538,7 @@ context "with multiple platforms" do before do - build_lib("foo", :path => tmp.join("foo")) do |s| + build_lib("foo", :path => tmp("foo")) do |s| s.version = "1.0.0" s.add_development_dependency "rack" s.write "foo-universal-java.gemspec", build_spec("foo", "1.0.0", "universal-java") {|sj| sj.runtime "rack", "1.0.0" }.first.to_ruby @@ -550,7 +550,7 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + gemspec :path => '#{tmp("foo")}', :name => 'foo' G expect(the_bundle).to include_gems "foo 1.0.0", "rack 1.0.0" @@ -562,7 +562,7 @@ bundle "config set --local without development" install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + gemspec :path => '#{tmp("foo")}', :name => 'foo' G expect(the_bundle).to include_gem "foo 1.0.0" @@ -572,7 +572,7 @@ context "with multiple platforms and resolving for more specific platforms" do before do - build_lib("chef", :path => tmp.join("chef")) do |s| + build_lib("chef", :path => tmp("chef")) do |s| s.version = "17.1.17" s.write "chef-universal-mingw32.gemspec", build_spec("chef", "17.1.17", "universal-mingw32") {|sw| sw.runtime "win32-api", "~> 1.5.3" }.first.to_ruby end diff --git a/bundler/spec/install/gemfile/git_spec.rb b/bundler/spec/install/gemfile/git_spec.rb index 150fcf2c4204..bf5060b88e3b 100644 --- a/bundler/spec/install/gemfile/git_spec.rb +++ b/bundler/spec/install/gemfile/git_spec.rb @@ -52,7 +52,7 @@ bundle "update foo" sha = git.ref_for("master", 11) - spec_file = default_bundle_path.join("bundler/gems/foo-1.0-#{sha}/foo.gemspec").to_s + spec_file = default_bundle_path("bundler/gems/foo-1.0-#{sha}/foo.gemspec").to_s ruby_code = Gem::Specification.load(spec_file).to_ruby file_code = File.read(spec_file) expect(file_code).to eq(ruby_code) @@ -228,7 +228,7 @@ s.write("lib/foo.rb", "raise 'FAIL'") end - sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", :dir => lib_path("foo-1.0")) + git("update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", lib_path("foo-1.0")) # want to ensure we don't fallback to HEAD update_git "foo", :path => lib_path("foo-1.0"), :branch => "rando" do |s| @@ -264,7 +264,7 @@ s.write("lib/foo.rb", "raise 'FAIL'") end - sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", :dir => lib_path("foo-1.0")) + git("update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", lib_path("foo-1.0")) # want to ensure we don't fallback to HEAD update_git "foo", :path => lib_path("foo-1.0"), :branch => "rando" do |s| @@ -288,7 +288,7 @@ end it "does not download random non-head refs" do - sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", :dir => lib_path("foo-1.0")) + git("update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", lib_path("foo-1.0")) bundle "config set global_gem_cache true" @@ -302,7 +302,7 @@ # ensure we also git fetch after cloning bundle :update, :all => true - sys_exec("git ls-remote .", :dir => Dir[home(".bundle/cache/git/foo-*")].first) + git("ls-remote .", Dir[home(".bundle/cache/git/foo-*")].first) expect(out).not_to include("refs/bundler/1") end @@ -865,7 +865,7 @@ bundle "update", :all => true expect(the_bundle).to include_gems "forced 1.1" - sys_exec("git reset --hard HEAD^", :dir => lib_path("forced-1.0")) + git("reset --hard HEAD^", lib_path("forced-1.0")) bundle "update", :all => true expect(the_bundle).to include_gems "forced 1.0" @@ -876,8 +876,8 @@ build_git "has_submodule", "1.0" do |s| s.add_dependency "submodule" end - sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0") - sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0") + git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0") + git "commit -m \"submodulator\"", lib_path("has_submodule-1.0") install_gemfile <<-G, :raise_on_error => false source "#{file_uri_for(gem_repo1)}" @@ -895,8 +895,8 @@ build_git "has_submodule", "1.0" do |s| s.add_dependency "submodule" end - sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0") - sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0") + git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0") + git "commit -m \"submodulator\"", lib_path("has_submodule-1.0") install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -912,8 +912,8 @@ build_git "submodule", "1.0" build_git "has_submodule", "1.0" - sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0") - sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0") + git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0") + git "commit -m \"submodulator\"", lib_path("has_submodule-1.0") install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -1231,7 +1231,7 @@ void Init_foo() { rb_define_global_function("foo", &foo, 0); } C end - sys_exec("git commit -m \"commit for iteration #{i}\" ext/foo.c", :dir => git_reader.path) + git("commit -m \"commit for iteration #{i}\" ext/foo.c", git_reader.path) git_commit_sha = git_reader.ref_for("HEAD") diff --git a/bundler/spec/install/gemfile/sources_spec.rb b/bundler/spec/install/gemfile/sources_spec.rb index 9885145662f0..fc874d8496ef 100644 --- a/bundler/spec/install/gemfile/sources_spec.rb +++ b/bundler/spec/install/gemfile/sources_spec.rb @@ -1239,14 +1239,14 @@ build_gem "bar" end - build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s| + build_lib("gemspec_test", :path => tmp("gemspec_test")) do |s| s.add_dependency "bar", "=1.0.0" end install_gemfile <<-G, :artifice => "compact_index" source "https://gem.repo2" gem "rack" - gemspec :path => "#{tmp.join("gemspec_test")}" + gemspec :path => "#{tmp("gemspec_test")}" G end diff --git a/bundler/spec/install/gems/standalone_spec.rb b/bundler/spec/install/gems/standalone_spec.rb index db16a1b0e13a..d5b87e09e3a2 100644 --- a/bundler/spec/install/gems/standalone_spec.rb +++ b/bundler/spec/install/gems/standalone_spec.rb @@ -413,7 +413,7 @@ it "creates stubs with the correct load path" do extension_line = File.read(bundled_app("bin/rails")).each_line.find {|line| line.include? "$:.unshift" }.strip - expect(extension_line).to eq %($:.unshift File.expand_path "../../bundle", path.realpath) + expect(extension_line).to eq %($:.unshift File.expand_path "../bundle", __dir__) end end end diff --git a/bundler/spec/lock/lockfile_spec.rb b/bundler/spec/lock/lockfile_spec.rb index 8befb0d4004b..b2438325ec77 100644 --- a/bundler/spec/lock/lockfile_spec.rb +++ b/bundler/spec/lock/lockfile_spec.rb @@ -1022,7 +1022,7 @@ end it "stores relative paths when the path is provided for gemspec" do - build_lib("foo", :path => tmp.join("foo")) + build_lib("foo", :path => tmp("foo")) install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" diff --git a/bundler/spec/plugins/source/example_spec.rb b/bundler/spec/plugins/source/example_spec.rb index 7d098997ec04..5e718c0a9583 100644 --- a/bundler/spec/plugins/source/example_spec.rb +++ b/bundler/spec/plugins/source/example_spec.rb @@ -16,7 +16,7 @@ class MPath < Bundler::Plugin::API def initialize(opts) super - @path = Pathname.new options["uri"] + @path = Bundler::Pathname.new options["uri"] end def fetch_gemspec_files diff --git a/bundler/spec/runtime/gem_tasks_spec.rb b/bundler/spec/runtime/gem_tasks_spec.rb index b0ef0cc144c3..93953e662718 100644 --- a/bundler/spec/runtime/gem_tasks_spec.rb +++ b/bundler/spec/runtime/gem_tasks_spec.rb @@ -57,7 +57,7 @@ context "rake build when path has spaces", :ruby_repo do before do - spaced_bundled_app = tmp.join("bundled app") + spaced_bundled_app = tmp("bundled app") FileUtils.cp_r bundled_app, spaced_bundled_app bundle "exec rake build", :dir => spaced_bundled_app end @@ -69,7 +69,7 @@ context "rake build when path has brackets", :ruby_repo do before do - bracketed_bundled_app = tmp.join("bundled[app") + bracketed_bundled_app = tmp("bundled[app") FileUtils.cp_r bundled_app, bracketed_bundled_app bundle "exec rake build", :dir => bracketed_bundled_app end diff --git a/bundler/spec/runtime/setup_spec.rb b/bundler/spec/runtime/setup_spec.rb index 804e29c3c13a..5e2f933d5d53 100644 --- a/bundler/spec/runtime/setup_spec.rb +++ b/bundler/spec/runtime/setup_spec.rb @@ -1323,7 +1323,6 @@ def lock_with(ruby_version = nil) end << "bundler" exempts << "fiddle" if Gem.win_platform? && Gem.rubygems_version >= Gem::Version.new("2.7") exempts << "uri" if Gem.ruby_version >= Gem::Version.new("2.7") - exempts << "pathname" if Gem.ruby_version >= Gem::Version.new("3.0") exempts << "set" unless Gem.rubygems_version >= Gem::Version.new("3.2.6") exempts << "tsort" unless Gem.rubygems_version >= Gem::Version.new("3.2.31") exempts << "error_highlight" # added in Ruby 3.1 as a default gem diff --git a/bundler/spec/support/build_metadata.rb b/bundler/spec/support/build_metadata.rb index 98d8ac23c893..35db705e39dd 100644 --- a/bundler/spec/support/build_metadata.rb +++ b/bundler/spec/support/build_metadata.rb @@ -41,7 +41,7 @@ def replace_build_metadata(build_metadata, dir:) end def git_commit_sha - ruby_core_tarball? ? "unknown" : sys_exec("git rev-parse --short HEAD", :dir => source_root).strip + ruby_core_tarball? ? "unknown" : git("rev-parse --short HEAD", source_root).strip end extend self diff --git a/bundler/spec/support/env.rb b/bundler/spec/support/env.rb new file mode 100644 index 000000000000..4d99c892cd48 --- /dev/null +++ b/bundler/spec/support/env.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Spec + module Env + def ruby_core? + !ENV["GEM_COMMAND"].nil? + end + end +end diff --git a/bundler/spec/support/helpers.rb b/bundler/spec/support/helpers.rb index 13fa36fbc249..6916a9ba0c84 100644 --- a/bundler/spec/support/helpers.rb +++ b/bundler/spec/support/helpers.rb @@ -1,12 +1,15 @@ # frozen_string_literal: true -require_relative "command_execution" require_relative "the_bundle" require_relative "path" +require_relative "options" +require_relative "subprocess" module Spec module Helpers include Spec::Path + include Spec::Options + include Spec::Subprocess def reset! Dir.glob("#{tmp}/{gems/*,*}", File::FNM_DOTMATCH).each do |dir| @@ -27,22 +30,6 @@ def the_bundle(*args) TheBundle.new(*args) end - def command_executions - @command_executions ||= [] - end - - def last_command - command_executions.last || raise("There is no last command") - end - - def out - last_command.stdout - end - - def err - last_command.stderr - end - MAJOR_DEPRECATION = /^\[DEPRECATED\]\s*/.freeze def err_without_deprecations @@ -53,10 +40,6 @@ def deprecations err.split("\n").select {|l| l =~ MAJOR_DEPRECATION }.join("\n").split(MAJOR_DEPRECATION) end - def exitstatus - last_command.exitstatus - end - def run(cmd, *args) opts = args.last.is_a?(Hash) ? args.pop : {} groups = args.map(&:inspect).join(", ") @@ -126,7 +109,7 @@ def bundle(cmd, options = {}, &block) end def bundler(cmd, options = {}) - options[:bundle_bin] = system_gem_path.join("bin/bundler") + options[:bundle_bin] = system_gem_path("bin/bundler") bundle(cmd, options) end @@ -175,54 +158,13 @@ def rake "#{Gem.ruby} -S #{ENV["GEM_PATH"]}/bin/rake" end - def git(cmd, path, options = {}) - sys_exec("git #{cmd}", options.merge(:dir => path)) - end - - def sys_exec(cmd, options = {}) + def sys_exec(cmd, options = {}, &block) env = options[:env] || {} env["RUBYOPT"] = opt_add("-r#{spec_dir}/support/switch_rubygems.rb", env["RUBYOPT"] || ENV["RUBYOPT"]) - dir = options[:dir] || bundled_app - command_execution = CommandExecution.new(cmd.to_s, dir) - - require "open3" - require "shellwords" - Open3.popen3(env, *cmd.shellsplit, :chdir => dir) do |stdin, stdout, stderr, wait_thr| - yield stdin, stdout, wait_thr if block_given? - stdin.close - - stdout_read_thread = Thread.new { stdout.read } - stderr_read_thread = Thread.new { stderr.read } - command_execution.stdout = stdout_read_thread.value.strip - command_execution.stderr = stderr_read_thread.value.strip - - status = wait_thr.value - command_execution.exitstatus = if status.exited? - status.exitstatus - elsif status.signaled? - 128 + status.termsig - end - end - - unless options[:raise_on_error] == false || command_execution.success? - raise <<~ERROR - - Invoking `#{cmd}` failed with output: - ---------------------------------------------------------------------- - #{command_execution.stdboth} - ---------------------------------------------------------------------- - ERROR - end - - command_executions << command_execution - - command_execution.stdout - end - - def all_commands_output - return [] if command_executions.empty? + options[:env] = env + options[:dir] ||= bundled_app - "\n\nCommands:\n#{command_executions.map(&:to_s_verbose).join("\n\n")}" + sh(cmd, options, &block) end def config(config = nil, path = bundled_app(".bundle/config")) @@ -374,16 +316,6 @@ def with_path_added(path) end end - def opt_add(option, options) - [option.strip, options].compact.reject(&:empty?).join(" ") - end - - def opt_remove(option, options) - return unless options - - options.split(" ").reject {|opt| opt.strip == option.strip }.join(" ") - end - def break_git! FileUtils.mkdir_p(tmp("broken_path")) File.open(tmp("broken_path/git"), "w", 0o755) do |f| @@ -489,7 +421,7 @@ def rubygems_version_failing_to_activate_bundler_prereleases end def revision_for(path) - sys_exec("git rev-parse HEAD", :dir => path).strip + git("rev-parse HEAD", path).strip end def with_read_only(pattern) diff --git a/bundler/spec/support/options.rb b/bundler/spec/support/options.rb new file mode 100644 index 000000000000..551fa1acd87a --- /dev/null +++ b/bundler/spec/support/options.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Spec + module Options + def opt_add(option, options) + [option.strip, options].compact.reject(&:empty?).join(" ") + end + + def opt_remove(option, options) + return unless options + + options.split(" ").reject {|opt| opt.strip == option.strip }.join(" ") + end + end +end diff --git a/bundler/spec/support/path.rb b/bundler/spec/support/path.rb index a73b3e699ebd..e859a1c281f6 100644 --- a/bundler/spec/support/path.rb +++ b/bundler/spec/support/path.rb @@ -3,8 +3,12 @@ require "pathname" require "rbconfig" +require_relative "env" + module Spec module Path + include Spec::Env + def source_root @source_root ||= Pathname.new(ruby_core? ? "../../.." : "../..").expand_path(__dir__) end @@ -58,7 +62,7 @@ def gem_cmd end def gem_bin - @gem_bin ||= ruby_core? ? ENV["GEM_COMMAND"] : "gem" + @gem_bin ||= ENV["GEM_COMMAND"] || "gem" end def path @@ -107,7 +111,7 @@ def scope end def home(*path) - tmp.join("home", *path) + tmp("home", *path) end def default_bundle_path(*path) @@ -119,13 +123,13 @@ def default_bundle_path(*path) end def bundled_app(*path) - root = tmp.join("bundled_app") + root = tmp("bundled_app") FileUtils.mkdir_p(root) root.join(*path) end def bundled_app2(*path) - root = tmp.join("bundled_app2") + root = tmp("bundled_app2") FileUtils.mkdir_p(root) root.join(*path) end @@ -147,15 +151,15 @@ def bundled_app_lock end def base_system_gems - tmp.join("gems/base") + tmp("gems/base") end def rubocop_gems - tmp.join("gems/rubocop") + tmp("gems/rubocop") end def standard_gems - tmp.join("gems/standard") + tmp("gems/standard") end def file_uri_for(path) @@ -243,23 +247,12 @@ def replace_version_file(version, dir: source_root) File.open(version_file, "w") {|f| f << contents } end - def ruby_core? - # avoid to warnings - @ruby_core ||= nil - - if @ruby_core.nil? - @ruby_core = true & ENV["GEM_COMMAND"] - else - @ruby_core - end - end - private def git_ls_files(glob) skip "Not running on a git context, since running tests from a tarball" if ruby_core_tarball? - sys_exec("git ls-files -z -- #{glob}", :dir => source_root).split("\x0") + git("ls-files -z -- #{glob}", source_root).split("\x0") end def tracked_files_glob diff --git a/bundler/spec/support/rubygems_ext.rb b/bundler/spec/support/rubygems_ext.rb index 9389543a0f60..51602e485e85 100644 --- a/bundler/spec/support/rubygems_ext.rb +++ b/bundler/spec/support/rubygems_ext.rb @@ -60,7 +60,7 @@ def setup_test_paths ENV["BUNDLE_PATH"] = nil ENV["GEM_HOME"] = ENV["GEM_PATH"] = Path.base_system_gems.to_s - ENV["PATH"] = [Path.system_gem_path.join("bin"), ENV["PATH"]].join(File::PATH_SEPARATOR) + ENV["PATH"] = [Path.system_gem_path("bin"), ENV["PATH"]].join(File::PATH_SEPARATOR) ENV["PATH"] = [Path.bindir, ENV["PATH"]].join(File::PATH_SEPARATOR) if Path.ruby_core? end diff --git a/bundler/spec/support/rubygems_version_manager.rb b/bundler/spec/support/rubygems_version_manager.rb index c2e5a5f484ec..36f013f88dfa 100644 --- a/bundler/spec/support/rubygems_version_manager.rb +++ b/bundler/spec/support/rubygems_version_manager.rb @@ -1,12 +1,13 @@ # frozen_string_literal: true -require "pathname" -require_relative "helpers" -require_relative "path" +require_relative "options" +require_relative "env" +require_relative "subprocess" class RubygemsVersionManager - include Spec::Helpers - include Spec::Path + include Spec::Options + include Spec::Env + include Spec::Subprocess def initialize(source) @source = source @@ -24,12 +25,6 @@ def switch def assert_system_features_not_loaded! at_exit do - errors = if $?.nil? - "" - else - all_commands_output - end - rubylibdir = RbConfig::CONFIG["rubylibdir"] rubygems_path = rubylibdir + "/rubygems" @@ -43,11 +38,11 @@ def assert_system_features_not_loaded! (loaded_feature.start_with?(bundler_path) && !bundler_exemptions.any? {|bundler_exemption| loaded_feature.start_with?(bundler_exemption) }) end - if bad_loaded_features.any? - errors += "the following features were incorrectly loaded:\n#{bad_loaded_features.join("\n")}" + errors = if bad_loaded_features.any? + all_commands_output + "the following features were incorrectly loaded:\n#{bad_loaded_features.join("\n")}" end - raise errors unless errors.empty? + raise errors if errors end end @@ -64,7 +59,7 @@ def reexec_if_needed cmd = [RbConfig.ruby, $0, *ARGV].compact - ENV["RUBYOPT"] = opt_add("-I#{local_copy_path.join("lib")}", opt_remove("--disable-gems", ENV["RUBYOPT"])) + ENV["RUBYOPT"] = opt_add("-I#{File.join(local_copy_path, "lib")}", opt_remove("--disable-gems", ENV["RUBYOPT"])) exec(ENV, *cmd) end @@ -72,14 +67,14 @@ def reexec_if_needed def switch_local_copy_if_needed return unless local_copy_switch_needed? - sys_exec("git checkout #{target_tag}", :dir => local_copy_path) + git("checkout #{target_tag}", local_copy_path) - ENV["RGV"] = local_copy_path.to_s + ENV["RGV"] = local_copy_path end def rubygems_unrequire_needed? require "rubygems" - !$LOADED_FEATURES.include?(local_copy_path.join("lib/rubygems.rb").to_s) + !$LOADED_FEATURES.include?(File.join(local_copy_path, "lib/rubygems.rb")) end def local_copy_switch_needed? @@ -91,7 +86,7 @@ def target_tag end def local_copy_tag - sys_exec("git rev-parse --abbrev-ref HEAD", :dir => local_copy_path) + git("rev-parse --abbrev-ref HEAD", local_copy_path) end def local_copy_path @@ -101,21 +96,25 @@ def local_copy_path def resolve_local_copy_path return expanded_source if source_is_path? - rubygems_path = source_root.join("tmp/rubygems") + rubygems_path = File.join(source_root, "tmp/rubygems") - unless rubygems_path.directory? - sys_exec("git clone .. #{rubygems_path}", :dir => source_root) + unless File.directory?(rubygems_path) + git("clone .. #{rubygems_path}", source_root) end rubygems_path end def source_is_path? - expanded_source.directory? + File.directory?(expanded_source) end def expanded_source - @expanded_source ||= Pathname.new(@source).expand_path(source_root) + @expanded_source ||= File.expand_path(@source, source_root) + end + + def source_root + @source_root ||= File.expand_path(ruby_core? ? "../../.." : "../..", __dir__) end def resolve_target_tag diff --git a/bundler/spec/support/subprocess.rb b/bundler/spec/support/subprocess.rb new file mode 100644 index 000000000000..33c682f6778e --- /dev/null +++ b/bundler/spec/support/subprocess.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require_relative "command_execution" + +module Spec + module Subprocess + def command_executions + @command_executions ||= [] + end + + def last_command + command_executions.last || raise("There is no last command") + end + + def out + last_command.stdout + end + + def err + last_command.stderr + end + + def exitstatus + last_command.exitstatus + end + + def git(cmd, path = Dir.pwd, options = {}) + sh("git #{cmd}", options.merge(:dir => path)) + end + + def sh(cmd, options = {}) + dir = options[:dir] + env = options[:env] || {} + + command_execution = CommandExecution.new(cmd.to_s, dir) + + require "open3" + require "shellwords" + Open3.popen3(env, *cmd.shellsplit, :chdir => dir) do |stdin, stdout, stderr, wait_thr| + yield stdin, stdout, wait_thr if block_given? + stdin.close + + stdout_read_thread = Thread.new { stdout.read } + stderr_read_thread = Thread.new { stderr.read } + command_execution.stdout = stdout_read_thread.value.strip + command_execution.stderr = stderr_read_thread.value.strip + + status = wait_thr.value + command_execution.exitstatus = if status.exited? + status.exitstatus + elsif status.signaled? + 128 + status.termsig + end + end + + unless options[:raise_on_error] == false || command_execution.success? + raise <<~ERROR + + Invoking `#{cmd}` failed with output: + ---------------------------------------------------------------------- + #{command_execution.stdboth} + ---------------------------------------------------------------------- + ERROR + end + + command_executions << command_execution + + command_execution.stdout + end + + def all_commands_output + return "" if command_executions.empty? + + "\n\nCommands:\n#{command_executions.map(&:to_s_verbose).join("\n\n")}" + end + end +end diff --git a/bundler/spec/update/git_spec.rb b/bundler/spec/update/git_spec.rb index 0787ee41a73f..de3ae78f69a9 100644 --- a/bundler/spec/update/git_spec.rb +++ b/bundler/spec/update/git_spec.rb @@ -138,8 +138,8 @@ s.add_dependency "submodule" end - sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0") - sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0") + git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0") + git "commit -m \"submodulator\"", lib_path("has_submodule-1.0") end it "it unlocks the source when submodules are added to a git source" do