SafeChdir all the things for thread safety
This commit is contained in:
parent
36edc4a0fd
commit
d1eccbf98f
|
@ -1,5 +1,6 @@
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
|
|
||||||
|
require 'vagrant/util/safe_chdir'
|
||||||
require 'vagrant/util/subprocess'
|
require 'vagrant/util/subprocess'
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
|
@ -83,7 +84,7 @@ module Vagrant
|
||||||
output_path = tar_path.to_s
|
output_path = tar_path.to_s
|
||||||
|
|
||||||
# Switch into that directory and package everything up
|
# Switch into that directory and package everything up
|
||||||
Dir.chdir(@env["package.directory"]) do
|
Util::SafeChdir.safe_chdir(@env["package.directory"]) do
|
||||||
# Find all the files in our current directory and tar it up!
|
# Find all the files in our current directory and tar it up!
|
||||||
files = Dir.glob(File.join(".", "**", "*"))
|
files = Dir.glob(File.join(".", "**", "*"))
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ require "json"
|
||||||
require "log4r"
|
require "log4r"
|
||||||
|
|
||||||
require "vagrant/util/platform"
|
require "vagrant/util/platform"
|
||||||
|
require "vagrant/util/safe_chdir"
|
||||||
require "vagrant/util/subprocess"
|
require "vagrant/util/subprocess"
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
|
@ -71,7 +72,7 @@ module Vagrant
|
||||||
def repackage(path)
|
def repackage(path)
|
||||||
@logger.debug("Repackaging box '#{@name}' to: #{path}")
|
@logger.debug("Repackaging box '#{@name}' to: #{path}")
|
||||||
|
|
||||||
Dir.chdir(@directory) do
|
Util::SafeChdir.safe_chdir(@directory) do
|
||||||
# Find all the files in our current directory and tar it up!
|
# Find all the files in our current directory and tar it up!
|
||||||
files = Dir.glob(File.join(".", "**", "*"))
|
files = Dir.glob(File.join(".", "**", "*"))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
require 'thread'
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
module Util
|
||||||
|
class SafeChdir
|
||||||
|
@@chdir_lock = Mutex.new
|
||||||
|
@@lock_holder = nil
|
||||||
|
|
||||||
|
# Safely changes directory of this process by putting a lock around
|
||||||
|
# it so that it is thread safe. This will yield a block and when the
|
||||||
|
# block exits it changes back to the original directory.
|
||||||
|
#
|
||||||
|
# @param [String] dir Dir to change to temporarily
|
||||||
|
def self.safe_chdir(dir)
|
||||||
|
lock = @@chdir_lock
|
||||||
|
|
||||||
|
begin
|
||||||
|
@@chdir_lock.synchronize {}
|
||||||
|
rescue ThreadError
|
||||||
|
# If we already hold the lock, just create a new lock so we
|
||||||
|
# definitely don't block and don't get an error.
|
||||||
|
lock = Mutex.new
|
||||||
|
end
|
||||||
|
|
||||||
|
lock.synchronize do
|
||||||
|
Dir.chdir(dir) do
|
||||||
|
return yield
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ require 'childprocess'
|
||||||
require 'log4r'
|
require 'log4r'
|
||||||
|
|
||||||
require 'vagrant/util/platform'
|
require 'vagrant/util/platform'
|
||||||
|
require 'vagrant/util/safe_chdir'
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module Util
|
module Util
|
||||||
|
@ -14,8 +15,6 @@ module Vagrant
|
||||||
# from the subprocess in real time, by simply passing a block to
|
# from the subprocess in real time, by simply passing a block to
|
||||||
# the execute method.
|
# the execute method.
|
||||||
class Subprocess
|
class Subprocess
|
||||||
@@chdir_lock = Mutex.new
|
|
||||||
|
|
||||||
# The chunk size for reading from subprocess IO.
|
# The chunk size for reading from subprocess IO.
|
||||||
READ_CHUNK_SIZE = 4096
|
READ_CHUNK_SIZE = 4096
|
||||||
|
|
||||||
|
@ -76,11 +75,9 @@ module Vagrant
|
||||||
|
|
||||||
# Start the process
|
# Start the process
|
||||||
begin
|
begin
|
||||||
@@chdir_lock.synchronize do
|
SafeChdir.safe_chdir(workdir) do
|
||||||
Dir.chdir(workdir) do
|
|
||||||
process.start
|
process.start
|
||||||
end
|
end
|
||||||
end
|
|
||||||
rescue ChildProcess::LaunchError => ex
|
rescue ChildProcess::LaunchError => ex
|
||||||
# Raise our own version of the error so that users of the class
|
# Raise our own version of the error so that users of the class
|
||||||
# don't need to be aware of ChildProcess
|
# don't need to be aware of ChildProcess
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
require 'tmpdir'
|
||||||
|
|
||||||
|
require File.expand_path("../../../base", __FILE__)
|
||||||
|
|
||||||
|
require 'vagrant/util/safe_chdir'
|
||||||
|
|
||||||
|
describe Vagrant::Util::SafeChdir do
|
||||||
|
it "should change directories" do
|
||||||
|
expected = nil
|
||||||
|
result = nil
|
||||||
|
temp_dir = Dir.mktmpdir
|
||||||
|
|
||||||
|
Dir.chdir(temp_dir) do
|
||||||
|
expected = Dir.pwd
|
||||||
|
end
|
||||||
|
|
||||||
|
described_class.safe_chdir(temp_dir) do
|
||||||
|
result = Dir.pwd
|
||||||
|
end
|
||||||
|
|
||||||
|
result.should == expected
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow recursive chdir" do
|
||||||
|
expected = nil
|
||||||
|
result = nil
|
||||||
|
temp_path = Dir.mktmpdir
|
||||||
|
|
||||||
|
Dir.chdir(temp_path) do
|
||||||
|
expected = Dir.pwd
|
||||||
|
end
|
||||||
|
|
||||||
|
expect do
|
||||||
|
described_class.safe_chdir(Dir.mktmpdir) do
|
||||||
|
described_class.safe_chdir(temp_path) do
|
||||||
|
result = Dir.pwd
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end.to_not raise_error
|
||||||
|
|
||||||
|
result.should == expected
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue