Merge pull request #7354 from mitchellh/sethvargo/bundler_leak

Fix file leaking in bundler
This commit is contained in:
Seth Vargo 2016-05-28 17:10:06 -04:00
commit 11ed254708
2 changed files with 28 additions and 7 deletions

View File

@ -2,6 +2,7 @@ require "monitor"
require "pathname" require "pathname"
require "set" require "set"
require "tempfile" require "tempfile"
require "fileutils"
require "bundler" require "bundler"
@ -61,7 +62,7 @@ module Vagrant
end end
# Setup the Bundler configuration # Setup the Bundler configuration
@configfile = File.open(Tempfile.new("vagrant").path + "1", "w+") @configfile = tempfile("vagrant-configfile")
@configfile.close @configfile.close
# Build up the Gemfile for our Bundler context. We make sure to # Build up the Gemfile for our Bundler context. We make sure to
@ -84,9 +85,13 @@ module Vagrant
# Removes any temporary files created by init # Removes any temporary files created by init
def deinit def deinit
File.unlink(ENV["BUNDLE_APP_CONFIG"]) rescue nil # If we weren't enabled, then we don't do anything.
File.unlink(ENV["BUNDLE_CONFIG"]) rescue nil return if !@enabled
File.unlink(ENV["GEMFILE"]) rescue nil
FileUtils.rm_rf(ENV["BUNDLE_APP_CONFIG"]) rescue nil
FileUtils.rm_f(ENV["BUNDLE_CONFIG"]) rescue nil
FileUtils.rm_f(ENV["BUNDLE_GEMFILE"]) rescue nil
FileUtils.rm_f(ENV["BUNDLE_GEMFILE"]+".lock") rescue nil
end end
# Installs the list of plugins. # Installs the list of plugins.
@ -181,7 +186,7 @@ module Vagrant
def build_gemfile(plugins) def build_gemfile(plugins)
sources = plugins.values.map { |p| p["sources"] }.flatten.compact.uniq sources = plugins.values.map { |p| p["sources"] }.flatten.compact.uniq
f = File.open(Tempfile.new("vagrant").path + "2", "w+") f = tempfile("vagrant-gemfile")
f.tap do |gemfile| f.tap do |gemfile|
sources.each do |source| sources.each do |source|
next if source == "" next if source == ""
@ -203,7 +208,6 @@ module Vagrant
gemfile.puts(%Q[gem "#{name}", #{version.inspect}, #{opts.inspect}]) gemfile.puts(%Q[gem "#{name}", #{version.inspect}, #{opts.inspect}])
end end
gemfile.puts("end") gemfile.puts("end")
gemfile.close gemfile.close
end end
end end
@ -250,11 +254,14 @@ module Vagrant
def with_isolated_gem def with_isolated_gem
raise Errors::BundlerDisabled if !@enabled raise Errors::BundlerDisabled if !@enabled
tmp_gemfile = tempfile("vagrant-gemfile")
tmp_gemfile.close
# Remove bundler settings so that Bundler isn't loaded when building # Remove bundler settings so that Bundler isn't loaded when building
# native extensions because it causes all sorts of problems. # native extensions because it causes all sorts of problems.
old_rubyopt = ENV["RUBYOPT"] old_rubyopt = ENV["RUBYOPT"]
old_gemfile = ENV["BUNDLE_GEMFILE"] old_gemfile = ENV["BUNDLE_GEMFILE"]
ENV["BUNDLE_GEMFILE"] = Tempfile.new("vagrant-gemfile").path ENV["BUNDLE_GEMFILE"] = tmp_gemfile.path
ENV["RUBYOPT"] = (ENV["RUBYOPT"] || "").gsub(/-rbundler\/setup\s*/, "") ENV["RUBYOPT"] = (ENV["RUBYOPT"] || "").gsub(/-rbundler\/setup\s*/, "")
# Set the GEM_HOME so gems are installed only to our local gem dir # Set the GEM_HOME so gems are installed only to our local gem dir
@ -284,6 +291,8 @@ module Vagrant
return yield return yield
end end
ensure ensure
tmp_gemfile.unlink rescue nil
ENV["BUNDLE_GEMFILE"] = old_gemfile ENV["BUNDLE_GEMFILE"] = old_gemfile
ENV["GEM_HOME"] = @gem_home ENV["GEM_HOME"] = @gem_home
ENV["RUBYOPT"] = old_rubyopt ENV["RUBYOPT"] = old_rubyopt
@ -293,6 +302,17 @@ module Vagrant
Gem::Specification.all = old_all Gem::Specification.all = old_all
end end
# This method returns a proper "tempfile" on disk. Ruby's Tempfile class
# would work really great for this, except GC can come along and remove
# the file before we are done with it. This is because we "close" the file,
# but we might be shelling out to a subprocess.
#
# @return [File]
def tempfile(name)
path = Dir::Tmpname.create(name) {}
return File.open(path, "w+")
end
# This is pretty hacky but it is a custom implementation of # This is pretty hacky but it is a custom implementation of
# Gem::ConfigFile so that we don't load any gemrc files. # Gem::ConfigFile so that we don't load any gemrc files.
class NilGemConfig < Gem::ConfigFile class NilGemConfig < Gem::ConfigFile

View File

@ -55,6 +55,7 @@ module VagrantPlugins
exit_status = env[:ssh_run_exit_status] || 0 exit_status = env[:ssh_run_exit_status] || 0
return exit_status return exit_status
else else
Vagrant::Bundler.instance.deinit
@logger.debug("Invoking `ssh` action on machine") @logger.debug("Invoking `ssh` action on machine")
vm.action(:ssh, ssh_opts: ssh_opts) vm.action(:ssh, ssh_opts: ssh_opts)