diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 33e3ea93e7..d17bcb7b80 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1,6 +1,7 @@ require 'download_strategy' require 'dependency_collector' require 'formula_support' +require 'formula_lock' require 'hardware' require 'bottles' require 'patches' @@ -241,19 +242,12 @@ class Formula end def lock - HOMEBREW_CACHE_FORMULA.mkpath - lockpath = HOMEBREW_CACHE_FORMULA/"#{@name}.brewing" - @lockfile = lockpath.open(File::RDWR | File::CREAT) - unless @lockfile.flock(File::LOCK_EX | File::LOCK_NB) - raise OperationInProgressError, @name - end + @lock = FormulaLock.new(name) + @lock.lock end def unlock - unless @lockfile.nil? - @lockfile.flock(File::LOCK_UN) - @lockfile.close - end + @lock.unlock unless @lock.nil? end def == b diff --git a/Library/Homebrew/formula_lock.rb b/Library/Homebrew/formula_lock.rb new file mode 100644 index 0000000000..183c2dd9ce --- /dev/null +++ b/Library/Homebrew/formula_lock.rb @@ -0,0 +1,40 @@ +class FormulaLock + LOCKDIR = HOMEBREW_CACHE_FORMULA + + def initialize(name) + @name = name + @path = LOCKDIR.join("#{@name}.brewing") + end + + def lock + LOCKDIR.mkpath + @lockfile = get_or_create_lockfile + unless @lockfile.flock(File::LOCK_EX | File::LOCK_NB) + raise OperationInProgressError, @name + end + end + + def unlock + unless @lockfile.nil? || @lockfile.closed? + @lockfile.flock(File::LOCK_UN) + @lockfile.close + end + end + + def with_lock + lock + yield + ensure + unlock + end + + private + + def get_or_create_lockfile + if @lockfile.nil? || @lockfile.closed? + @path.open(File::RDWR | File::CREAT) + else + @lockfile + end + end +end diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index ff249ed2e5..0ebb1441d9 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -1,4 +1,5 @@ require 'extend/pathname' +require 'formula_lock' class Keg < Pathname def initialize path @@ -62,18 +63,7 @@ class Keg < Pathname end def lock - HOMEBREW_CACHE_FORMULA.mkpath - path = HOMEBREW_CACHE_FORMULA/"#{fname}.brewing" - file = path.open(File::RDWR | File::CREAT) - unless file.flock(File::LOCK_EX | File::LOCK_NB) - raise OperationInProgressError, fname - end - yield - ensure - unless file.nil? - file.flock(File::LOCK_UN) - file.close - end + FormulaLock.new(fname).with_lock { yield } end def linked_keg_record diff --git a/Library/Homebrew/test/test_formula_lock.rb b/Library/Homebrew/test/test_formula_lock.rb new file mode 100644 index 0000000000..a03d19e922 --- /dev/null +++ b/Library/Homebrew/test/test_formula_lock.rb @@ -0,0 +1,21 @@ +require 'testing_env' +require 'formula_lock' + +class FormulaLockTests < Test::Unit::TestCase + def setup + @lock = FormulaLock.new("foo") + @lock.lock + end + + def teardown + @lock.unlock + end + + def test_locking_file_with_existing_lock_raises_error + assert_raises(OperationInProgressError) { FormulaLock.new("foo").lock } + end + + def test_locking_existing_lock_suceeds + assert_nothing_raised { @lock.lock } + end +end