diff --git a/lib/batali/command/install.rb b/lib/batali/command/install.rb index 71d399f..9753711 100644 --- a/lib/batali/command/install.rb +++ b/lib/batali/command/install.rb @@ -24,27 +24,30 @@ def execute! units_slice.map do |unit| Thread.new do ui.debug "Starting unit install for: #{unit.name}<#{unit.version}>" - if unit.source.respond_to?(:cache_path) - unit.source.cache_path = cache_directory( - Bogo::Utility.snake(unit.source.class.name.split("::").last) - ) - end - asset_path = unit.source.asset - final_path = Utility.join_path(install_path, unit.name) - if infrastructure? - final_path << "-#{unit.version}" - end - begin - FileUtils.cp_r( - Utility.join_path(asset_path, "."), - final_path - ) - ui.debug "Completed unit install for: #{unit.name}<#{unit.version}>" - rescue => e - ui.debug "Failed unit install for: #{unit.name}<#{unit.version}> - #{e.class}: #{e}" - raise - ensure - unit.source.clean_asset(asset_path) + ui.debug "Unit source: #{unit.source.inspect}" + unit.source.synchronize do + if unit.source.respond_to?(:cache_path) + unit.source.cache_path = cache_directory( + Bogo::Utility.snake(unit.source.class.name.split("::").last) + ) + end + asset_path = unit.source.asset + final_path = Utility.join_path(install_path, unit.name) + if infrastructure? + final_path << "-#{unit.version}" + end + begin + FileUtils.cp_r( + Utility.join_path(asset_path, "."), + final_path + ) + ui.debug "Completed unit install for: #{unit.name}<#{unit.version}>" + rescue => e + ui.debug "Failed unit install for: #{unit.name}<#{unit.version}> - #{e.class}: #{e}" + raise + ensure + unit.source.clean_asset(asset_path) + end end end end.map(&:join) diff --git a/lib/batali/git.rb b/lib/batali/git.rb index 8d0a0cc..376db54 100644 --- a/lib/batali/git.rb +++ b/lib/batali/git.rb @@ -49,6 +49,24 @@ def self.included(klass) klass.class_eval do attribute :url, String, :required => true, :equivalent => true attribute :ref, String, :required => true, :equivalent => true + + @@locks = {} + @@lock_init = Mutex.new + + def self.path_lock(path) + @@lock_init.synchronize do + if !@@locks[path] + @@locks[path] = Mutex.new + end + end + if block_given? + @@locks[path].synchronize do + yield + end + else + @@locks[path] + end + end end end end diff --git a/lib/batali/source.rb b/lib/batali/source.rb index fb4d291..f43b73f 100644 --- a/lib/batali/source.rb +++ b/lib/batali/source.rb @@ -18,6 +18,14 @@ def initialize(args = {}) super end + # Helper to synchronize access to this source. + # + # @yield Block to be executed + # @return [Object] + def synchronize + yield + end + # @return [String] def unit_version raise NotImplementedError.new "Abstract class" diff --git a/lib/batali/source/git.rb b/lib/batali/source/git.rb index 872d662..a6f55ed 100644 --- a/lib/batali/source/git.rb +++ b/lib/batali/source/git.rb @@ -19,6 +19,12 @@ def initialize(*_, &block) self.path = Utility.clean_path(path) end + def synchronize + self.class.path_lock(path) do + yield + end + end + # @return [String] directory containing contents def asset clone_repository diff --git a/lib/batali/utility.rb b/lib/batali/utility.rb index 17d5a6d..4362f75 100644 --- a/lib/batali/utility.rb +++ b/lib/batali/utility.rb @@ -11,11 +11,12 @@ class Utility < Grimoire::Utility # on platform in use def self.clean_path(path) if RUBY_PLATFORM =~ /mswin|mingw|windows/ && - ENV["BATALI_DISABLE_UNC"].nil? - if !path.to_s.match(/^[A-Za-z]:/) && !path.start_with?(UNC_PATH) + ENV["BATALI_DISABLE_UNC"].nil? && + path + if !path.to_s.match(/^[A-Za-z]:/) && !path.to_s.start_with?(UNC_PREFIX) path = File.expand_path(path.to_s) end - path = UNC_PREFIX + path unless path.start_with?(UNC_PATH) + path = UNC_PREFIX + path.to_s unless path.to_s.start_with?(UNC_PREFIX) end path end