core: Environment#lock is more useful now

This commit is contained in:
Mitchell Hashimoto 2014-04-15 13:56:00 -07:00
parent 32c9707aa1
commit dc2f729fd3
2 changed files with 26 additions and 21 deletions

View File

@ -73,7 +73,6 @@ module Vagrant
:cwd => nil, :cwd => nil,
:home_path => nil, :home_path => nil,
:local_data_path => nil, :local_data_path => nil,
:lock_path => nil,
:ui_class => nil, :ui_class => nil,
:vagrantfile_name => nil, :vagrantfile_name => nil,
}.merge(opts || {}) }.merge(opts || {})
@ -99,7 +98,6 @@ module Vagrant
# Set instance variables for all the configuration parameters. # Set instance variables for all the configuration parameters.
@cwd = opts[:cwd] @cwd = opts[:cwd]
@home_path = opts[:home_path] @home_path = opts[:home_path]
@lock_path = opts[:lock_path]
@vagrantfile_name = opts[:vagrantfile_name] @vagrantfile_name = opts[:vagrantfile_name]
@ui = opts[:ui_class].new @ui = opts[:ui_class].new
@ui_class = opts[:ui_class] @ui_class = opts[:ui_class]
@ -108,7 +106,7 @@ module Vagrant
# runs at a time from {#batch}. # runs at a time from {#batch}.
@batch_lock = Mutex.new @batch_lock = Mutex.new
@lock_acquired = false @locks = {}
@logger = Log4r::Logger.new("vagrant::environment") @logger = Log4r::Logger.new("vagrant::environment")
@logger.info("Environment initialized (#{self})") @logger.info("Environment initialized (#{self})")
@ -341,38 +339,46 @@ module Vagrant
end end
end end
# This returns the path which Vagrant uses to determine the location # This acquires a process-level lock with the given name.
# of the file lock. This is specific to each operating system. #
def lock_path # The lock file is held within the data directory of this environment,
@lock_path || tmp_path.join("vagrant.lock") # so make sure that all environments that are locking are sharing
end # the same data directory.
#
# This locks Vagrant for the duration of the block passed to this # This will raise Errors::EnvironmentLockedError if the lock can't
# method. During this time, any other environment which attempts # be obtained.
# to lock which points to the same lock file will fail. #
def lock # @param [String] name Name of the lock, since multiple locks can
# be held at one time.
def lock(name="global", **opts)
# If we don't have a block, then locking is useless, so ignore it # If we don't have a block, then locking is useless, so ignore it
return if !block_given? return if !block_given?
# This allows multiple locks in the same process to be nested # This allows multiple locks in the same process to be nested
return yield if @lock_acquired return yield if @locks[name]
# The path to this lock
lock_path = data_dir.join("lock.#{name}.lock")
File.open(lock_path, "w+") do |f| File.open(lock_path, "w+") do |f|
# The file locking fails only if it returns "false." If it # The file locking fails only if it returns "false." If it
# succeeds it returns a 0, so we must explicitly check for # succeeds it returns a 0, so we must explicitly check for
# the proper error case. # the proper error case.
raise Errors::EnvironmentLockedError if f.flock(File::LOCK_EX | File::LOCK_NB) === false if f.flock(File::LOCK_EX | File::LOCK_NB) === false
raise Errors::EnvironmentLockedError,
name: name
end
begin begin
# Mark that we have a lock # Mark that we have a lock
@lock_acquired = true @locks[name] = true
yield yield
ensure ensure
# We need to make sure that no matter what this is always # We need to make sure that no matter what this is always
# reset to false so we don't think we have a lock when we # reset to false so we don't think we have a lock when we
# actually don't. # actually don't.
@lock_acquired = false @locks.delete(name)
end end
end end
end end

View File

@ -658,10 +658,9 @@ en:
The download was interrupted by an external signal. It did not The download was interrupted by an external signal. It did not
complete. complete.
environment_locked: |- environment_locked: |-
An instance of Vagrant is already running. Only one instance of Vagrant Vagrant attempted to acquire a lock named '%{name}', but this
may run at any given time to avoid problems with VirtualBox inconsistencies lock is being held by another instance of Vagrant already. Please
occurring. Please wait for the other instance of Vagrant to end and then wait and try again.
try again.
environment_non_existent_cwd: |- environment_non_existent_cwd: |-
The working directory for Vagrant doesn't exist! This is the The working directory for Vagrant doesn't exist! This is the
specified working directory: specified working directory: