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,
:home_path => nil,
:local_data_path => nil,
:lock_path => nil,
:ui_class => nil,
:vagrantfile_name => nil,
}.merge(opts || {})
@ -99,7 +98,6 @@ module Vagrant
# Set instance variables for all the configuration parameters.
@cwd = opts[:cwd]
@home_path = opts[:home_path]
@lock_path = opts[:lock_path]
@vagrantfile_name = opts[:vagrantfile_name]
@ui = opts[:ui_class].new
@ui_class = opts[:ui_class]
@ -108,7 +106,7 @@ module Vagrant
# runs at a time from {#batch}.
@batch_lock = Mutex.new
@lock_acquired = false
@locks = {}
@logger = Log4r::Logger.new("vagrant::environment")
@logger.info("Environment initialized (#{self})")
@ -341,38 +339,46 @@ module Vagrant
end
end
# This returns the path which Vagrant uses to determine the location
# of the file lock. This is specific to each operating system.
def lock_path
@lock_path || tmp_path.join("vagrant.lock")
end
# This locks Vagrant for the duration of the block passed to this
# method. During this time, any other environment which attempts
# to lock which points to the same lock file will fail.
def lock
# This acquires a process-level lock with the given name.
#
# The lock file is held within the data directory of this environment,
# so make sure that all environments that are locking are sharing
# the same data directory.
#
# This will raise Errors::EnvironmentLockedError if the lock can't
# be obtained.
#
# @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
return if !block_given?
# 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|
# The file locking fails only if it returns "false." If it
# succeeds it returns a 0, so we must explicitly check for
# 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
# Mark that we have a lock
@lock_acquired = true
@locks[name] = true
yield
ensure
# 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
# actually don't.
@lock_acquired = false
@locks.delete(name)
end
end
end

View File

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