diff options
-rw-r--r-- | Rakefile | 11 | ||||
-rwxr-xr-x | exe/bundle | 7 | ||||
-rw-r--r-- | lib/bundler/cli.rb | 2 | ||||
-rw-r--r-- | lib/bundler/cli/update.rb | 2 | ||||
-rw-r--r-- | lib/bundler/postit_trampoline.rb | 54 | ||||
-rw-r--r-- | lib/bundler/setup.rb | 1 | ||||
-rw-r--r-- | lib/bundler/shared_helpers.rb | 1 | ||||
-rw-r--r-- | lib/bundler/vendor/postit/lib/postit.rb | 15 | ||||
-rw-r--r-- | lib/bundler/vendor/postit/lib/postit/environment.rb | 44 | ||||
-rw-r--r-- | lib/bundler/vendor/postit/lib/postit/installer.rb | 28 | ||||
-rw-r--r-- | lib/bundler/vendor/postit/lib/postit/parser.rb | 21 | ||||
-rw-r--r-- | lib/bundler/vendor/postit/lib/postit/setup.rb | 12 | ||||
-rw-r--r-- | lib/bundler/vendor/postit/lib/postit/version.rb | 3 | ||||
-rw-r--r-- | spec/bundler/shared_helpers_spec.rb | 2 | ||||
-rw-r--r-- | spec/other/trampoline_spec.rb | 137 | ||||
-rw-r--r-- | spec/support/helpers.rb | 1 | ||||
-rw-r--r-- | spec/support/rubygems_ext.rb | 3 |
17 files changed, 341 insertions, 3 deletions
@@ -296,10 +296,21 @@ begin lib.prefix = "Bundler" lib.vendor_lib = "lib/bundler/vendor/thor" end + + Automatiek::RakeTask.new("postit") do |lib| + lib.download = { :github => "https://github.com/bundler/postit" } + lib.namespace = "PostIt" + lib.vendor_lib = "lib/bundler/vendor/postit" + + def lib.namespace_files + process_files(namespace, "BundlerVendoredPostIt") + end + end rescue LoadError namespace :vendor do task(:molinillo) { abort "Install the automatiek gem to be able to vendor gems." } task(:thor) { abort "Install the automatiek gem to be able to vendor gems." } + task(:postit) { abort "Install the automatiek gem to be able to vendor gems." } end end @@ -4,6 +4,13 @@ # Exit cleanly from an early interrupt Signal.trap("INT") { exit 1 } +unless ENV["BUNDLE_DISABLE_POSTIT"] + update = "update".start_with?(ARGV.first || " ") && ARGV.find {|a| a.start_with?("--bundler") } + update &&= update =~ /--bundler(?:=(.+))?/ && $1 || "> 0.a" + ENV["BUNDLER_VERSION"] = update if update + require "bundler/postit_trampoline" +end + require "bundler" # Check if an older version of bundler is installed $LOAD_PATH.each do |path| diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index 85851423..c3a9a01e 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -204,6 +204,8 @@ module Bundler "Force downloading every gem." method_option "ruby", :type => :boolean, :banner => "Update ruby specified in Gemfile.lock" + method_option "bundler", :type => :string, :lazy_default => "> 0.a", :banner => + "Update the locked version of bundler" def update(*gems) require "bundler/cli/update" Update.new(options, gems).run diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb index 037da291..33b0557f 100644 --- a/lib/bundler/cli/update.rb +++ b/lib/bundler/cli/update.rb @@ -13,7 +13,7 @@ module Bundler sources = Array(options[:source]) groups = Array(options[:group]).map(&:to_sym) - if gems.empty? && sources.empty? && groups.empty? && !options[:ruby] + if gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !options[:bundler] # We're doing a full update Bundler.definition(true) else diff --git a/lib/bundler/postit_trampoline.rb b/lib/bundler/postit_trampoline.rb new file mode 100644 index 00000000..7406612e --- /dev/null +++ b/lib/bundler/postit_trampoline.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +postit_lib = File.expand_path("../vendor/postit/lib", __FILE__) +$:.unshift(postit_lib) +require "postit" +require "rubygems" + +environment = BundlerVendoredPostIt::Environment.new([]) +version = Gem::Requirement.new(environment.bundler_version) + +installed_version = + if defined?(Bundler::VERSION) + Bundler::VERSION + else + File.read(File.expand_path("../version.rb", __FILE__)) =~ /VERSION = "(.+)"/ + $1 + end +installed_version &&= Gem::Version.new(installed_version) + +if !version.satisfied_by?(installed_version) + begin + installer = BundlerVendoredPostIt::Installer.new(version) + installer.install! + rescue => e + abort <<-EOS.strip +Installing the inferred bundler version (#{version}) failed. +If you'd like to update to the current bundler version (#{installed_version}) in this project, run `bundle update --bundler`. +The error was: #{e} + EOS + end + + Gem.loaded_specs.delete("bundler") unless defined?(Bundler) + gem "bundler", version + $:.delete(File.expand_path("../..", __FILE__)) +else + begin + gem "bundler", version + rescue LoadError + $:.unshift(File.expand_path("../..", __FILE__)) + end +end + +running_version = begin + require "bundler/version" + Bundler::VERSION +rescue LoadError, NameError + nil +end + +if !Gem::Version.correct?(running_version.to_s) || !version.satisfied_by?(Gem::Version.create(running_version)) + abort "The running bundler (#{running_version}) does not match the required `#{version}`" +end + +$:.delete_at($:.find_index(postit_lib)) diff --git a/lib/bundler/setup.rb b/lib/bundler/setup.rb index 9aae6478..c888dabf 100644 --- a/lib/bundler/setup.rb +++ b/lib/bundler/setup.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true +require "bundler/postit_trampoline" unless ENV["BUNDLE_DISABLE_POSTIT"] require "bundler/shared_helpers" if Bundler::SharedHelpers.in_bundle? diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index e21d616e..01f1118d 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -169,6 +169,7 @@ module Bundler # Set BUNDLE_GEMFILE ENV["BUNDLE_GEMFILE"] = find_gemfile.to_s + ENV["BUNDLER_VERSION"] = Bundler::VERSION end def set_path diff --git a/lib/bundler/vendor/postit/lib/postit.rb b/lib/bundler/vendor/postit/lib/postit.rb new file mode 100644 index 00000000..4b3ff34d --- /dev/null +++ b/lib/bundler/vendor/postit/lib/postit.rb @@ -0,0 +1,15 @@ +require 'postit/environment' +require 'postit/installer' +require 'postit/parser' +require 'postit/version' +require 'rubygems' + +module BundlerVendoredPostIt + def self.setup + load File.expand_path('../postit/setup.rb', __FILE__) + end + + def self.bundler_version + defined?(Bundler::VERSION) && Bundler::VERSION + end +end diff --git a/lib/bundler/vendor/postit/lib/postit/environment.rb b/lib/bundler/vendor/postit/lib/postit/environment.rb new file mode 100644 index 00000000..b758fa0c --- /dev/null +++ b/lib/bundler/vendor/postit/lib/postit/environment.rb @@ -0,0 +1,44 @@ +require 'postit/parser' + +module BundlerVendoredPostIt + class Environment + def initialize(argv) + @argv = argv + end + + def env_var_version + ENV['BUNDLER_VERSION'] + end + + def cli_arg_version + return unless str = @argv.first + str = str.dup.force_encoding('BINARY') if str.respond_to?(:force_encoding) + if Gem::Version.correct?(str) + @argv.shift + str + end + end + + def gemfile + ENV['BUNDLE_GEMFILE'] || 'Gemfile' + end + + def lockfile + File.expand_path case File.basename(gemfile) + when 'gems.rb' then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" + end + end + + def lockfile_version + BundlerVendoredPostIt::Parser.new(lockfile).parse + end + + def bundler_version + @bundler_version ||= begin + env_var_version || cli_arg_version || + lockfile_version || "#{Gem::Requirement.default}.a" + end + end + end +end diff --git a/lib/bundler/vendor/postit/lib/postit/installer.rb b/lib/bundler/vendor/postit/lib/postit/installer.rb new file mode 100644 index 00000000..4139038d --- /dev/null +++ b/lib/bundler/vendor/postit/lib/postit/installer.rb @@ -0,0 +1,28 @@ +module BundlerVendoredPostIt + class Installer + def initialize(bundler_version) + @bundler_version = bundler_version + end + + def installed? + if Gem::Specification.respond_to?(:find_by_name) + !Gem::Specification.find_by_name('bundler', @bundler_version).nil? + else + requirement = Gem::Requirement.new(@bundler_version) + Gem.source_index.gems.values.any? do |s| + s.name == 'bundler' && requirement.satisfied_by?(s.version) + end + end + rescue LoadError + false + end + + def install! + return if installed? + require 'rubygems/dependency_installer' + installer = Gem::DependencyInstaller.new + installer.install('bundler', @bundler_version) + installer.installed_gems + end + end +end diff --git a/lib/bundler/vendor/postit/lib/postit/parser.rb b/lib/bundler/vendor/postit/lib/postit/parser.rb new file mode 100644 index 00000000..98c4a357 --- /dev/null +++ b/lib/bundler/vendor/postit/lib/postit/parser.rb @@ -0,0 +1,21 @@ +require 'rubygems' + +module BundlerVendoredPostIt + class Parser + def initialize(file) + @file = file + end + + BUNDLED_WITH = + /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + + def parse + return unless lockfile = File.file?(@file) && File.read(@file) + if lockfile =~ BUNDLED_WITH + Regexp.last_match(1) + else + '< 1.10' + end + end + end +end diff --git a/lib/bundler/vendor/postit/lib/postit/setup.rb b/lib/bundler/vendor/postit/lib/postit/setup.rb new file mode 100644 index 00000000..260edd55 --- /dev/null +++ b/lib/bundler/vendor/postit/lib/postit/setup.rb @@ -0,0 +1,12 @@ +require 'postit/environment' +require 'postit/installer' + +environment = BundlerVendoredPostIt::Environment.new(ARGV) +version = environment.bundler_version + +installer = BundlerVendoredPostIt::Installer.new(version) +installer.install! + +gem 'bundler', version + +require 'bundler/version' diff --git a/lib/bundler/vendor/postit/lib/postit/version.rb b/lib/bundler/vendor/postit/lib/postit/version.rb new file mode 100644 index 00000000..1a165010 --- /dev/null +++ b/lib/bundler/vendor/postit/lib/postit/version.rb @@ -0,0 +1,3 @@ +module BundlerVendoredPostIt + VERSION = '0.1.2'.freeze +end diff --git a/spec/bundler/shared_helpers_spec.rb b/spec/bundler/shared_helpers_spec.rb index 98f7994f..2ad0c98d 100644 --- a/spec/bundler/shared_helpers_spec.rb +++ b/spec/bundler/shared_helpers_spec.rb @@ -222,7 +222,7 @@ describe Bundler::SharedHelpers do shared_examples_for "ENV['RUBYOPT'] gets set correctly" do it "ensures -rbundler/setup is at the beginning of ENV['RUBYOPT']" do subject.set_bundle_environment - expect(ENV["RUBYOPT"].split(" ").first).to include("-rbundler/setup") + expect(ENV["RUBYOPT"].split(" ")).to start_with("-rbundler/setup") end end diff --git a/spec/other/trampoline_spec.rb b/spec/other/trampoline_spec.rb new file mode 100644 index 00000000..640c6085 --- /dev/null +++ b/spec/other/trampoline_spec.rb @@ -0,0 +1,137 @@ +# frozen_string_literal: true +require "spec_helper" + +describe "bundler version trampolining" do + before do + ENV["BUNDLE_DISABLE_POSTIT"] = nil + FileUtils.rm_rf(system_gem_path) + FileUtils.cp_r(base_system_gems, system_gem_path) + end + + context "version guessing" do + shared_examples_for "guesses" do |version| + it "guesses the correct bundler version" do + bundle! "--version" + expect(out).to eq("Bundler version #{version}") + + if bundled_app("Gemfile").file? + bundle! "exec ruby -e 'puts Bundler::VERSION'" + expect(out).to eq(version) + end + end + end + + context "with a lockfile" do + before do + install_gemfile "" + lockfile lockfile.sub(Bundler::VERSION, "1.12.0") + end + + include_examples "guesses", "1.12.0" + end + + context "with BUNDLER_VERSION" do + before do + ENV["BUNDLER_VERSION"] = "1.12.0" + end + + context "with a lockfile" do + before { install_gemfile "" } + include_examples "guesses", "1.12.0" + end + + context "without a lockfile" do + include_examples "guesses", "1.12.0" + end + end + + context "with no hints" do + include_examples "guesses", Bundler::VERSION + end + + context "with a gemfile and no lockfile" do + before do + gemfile "" + end + + include_examples "guesses", Bundler::VERSION + end + end + + context "installing missing bundler versions", :realworld => true do + before do + ENV["BUNDLER_VERSION"] = "1.12.3" + if Bundler::RubygemsIntegration.provides?("< 2.6.4") + # necessary since we intall with 2.6.4 but the specs can run against + # older versions that match againt the "gem" invocation + %w(bundle bundler).each do |exe| + system_gem_path.join("bin", exe).open("a") do |f| + f << %(\ngem "bundler", ">= 0.a"\n) + end + end + end + end + + it "guesses & installs the correct bundler version" do + expect(system_gem_path.join("gems", "bundler-1.12.3")).not_to exist + bundle! "--version" + expect(out).to eq("Bundler version 1.12.3") + expect(system_gem_path.join("gems", "bundler-1.12.3")).to exist + end + + it "fails gracefully when installing the bundler fails" do + ENV["BUNDLER_VERSION"] = "9999" + bundle "--version", :expect_err => true + expect(err).to start_with(<<-E.strip) +Installing the inferred bundler version (= 9999) failed. +If you'd like to update to the current bundler version (1.12.5) in this project, run `bundle update --bundler`. +The error was: + E + end + end + + context "bundle update --bundler" do + before do + simulate_bundler_version("1.11.1") do + install_gemfile "" + end + end + + it "updates to the specified version" do + # HACK: since no released bundler version actually supports this feature! + bundle "update --bundler=1.12.0", :expect_err => true + expect(out).to include("Unknown switches '--bundler=1.12.0'") + end + + it "updates to the specified (running) version" do + # HACK: since no released bundler version actually supports this feature! + bundle! "update --bundler=#{Bundler::VERSION}" + bundle! "--version" + expect(out).to eq("Bundler version #{Bundler::VERSION}") + end + + it "updates to the running version" do + # HACK: since no released bundler version actually supports this feature! + bundle! "update --bundler" + bundle! "--version" + expect(out).to eq("Bundler version #{Bundler::VERSION}") + end + end + + context "-rbundler/setup" do + before do + simulate_bundler_version("1.12.0") do + install_gemfile "" + end + end + + it "uses the locked version" do + ruby! <<-R + require "bundler/setup" + puts Bundler::VERSION + R + expect(err).to be_empty + expect(out).to eq("1.12.0") + end + end +end diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb index ff41dfbf..704e2140 100644 --- a/spec/support/helpers.rb +++ b/spec/support/helpers.rb @@ -12,6 +12,7 @@ module Spec end FileUtils.mkdir_p(tmp) FileUtils.mkdir_p(home) + ENV["BUNDLE_DISABLE_POSTIT"] = "1" Bundler.send(:remove_instance_variable, :@settings) if Bundler.send(:instance_variable_defined?, :@settings) end diff --git a/spec/support/rubygems_ext.rb b/spec/support/rubygems_ext.rb index 64cc4144..95f596ea 100644 --- a/spec/support/rubygems_ext.rb +++ b/spec/support/rubygems_ext.rb @@ -11,7 +11,8 @@ module Spec # Rake version has to be consistent for tests to pass "rake" => "10.0.2", # 3.0.0 breaks 1.9.2 specs - "builder" => "2.1.2" + "builder" => "2.1.2", + "bundler" => "1.12.0", } # ruby-graphviz is used by the viz tests deps["ruby-graphviz"] = nil if RUBY_VERSION >= "1.9.3" |