class Quilt
Constants
- ARCHIVE_SUFFIX
- COMMON_KEY
- DEBUG_PREFIX_KEY
- DEFAULT_LRU_SIZE
- DEPENDANCIES_KEY
- FOOTER_KEY
- HEADER_KEY
- OPTIONAL_KEY
- POSITION_KEY
- PREFIX_KEY
- VALID_POSITIONS
Public Class Methods
new(config = "quilt", log = Logger.new(STDOUT))
click to toggle source
# File lib/quilt.rb, line 23 def initialize(config = "quilt", log = Logger.new(STDOUT)) @@fetching_versions = {} config_prefix = config ? "#{config}:" : "" @config = { :local_path => Ecology.property("#{config_prefix}local_path", :as => String), :dev_path => Ecology.property("#{config_prefix}dev_path", :as => String), :remote_host => Ecology.property("#{config_prefix}remote_host", :as => String), :remote_path => Ecology.property("#{config_prefix}remote_path", :as => String), :remote_port => Ecology.property("#{config_prefix}remote_port", :as => String), :lru_size => Ecology.property("#{config_prefix}lru_size", :as => Fixnum) }; @versions = LRUCache.new(@config[:lru_size] ? @config[:lru_size] : DEFAULT_LRU_SIZE) @log = log if (@config[:local_path]) Dir.foreach(@config[:local_path]) do |version_dir| next if version_dir == "." || version_dir == ".." @versions[version_dir] = load_version(@config[:local_path], version_dir) end else throw "Quilt: local path not specified"; end end
Public Instance Methods
fetch_remote(file)
click to toggle source
# File lib/quilt.rb, line 373 def fetch_remote(file) host = @config[:remote_host].to_s port = @config[:remote_port] ? @config[:remote_port].to_i : 80 path = File.join(@config[:remote_path].to_s, file) conn = Faraday.new(:url => "http://#{host}:#{port}") do |faraday| faraday.adapter Faraday.default_adapter end conn.get(path) end
get_module(filename, dependancies, position, version_dir)
click to toggle source
# File lib/quilt.rb, line 68 def get_module(filename, dependancies, position, version_dir) tmp_module = {} tmp_module[:position] = position tmp_module[:dependancies] = dependancies.is_a?(Array) ? dependancies : (dependancies.is_a?(String) ? [ dependancies ] : []) begin tmp_module[:module] = File.open(File.join(version_dir, filename), "rb").read rescue Exception => e log_error(" Could not load module: #{filename}", e) return nil end tmp_module end
get_module_name(filename)
click to toggle source
# File lib/quilt.rb, line 61 def get_module_name(filename) return nil unless filename matches = filename.match(/(^.*\/|^)([^\/]+)$/) return nil unless matches && matches.length >= 3 matches[2] end
get_version(name)
click to toggle source
# File lib/quilt.rb, line 242 def get_version(name) return @versions[name] if @versions[name] if (name == 'dev' && @config[:dev_path]) return load_version(@config[:dev_path], '') end # check local path # sleep at most 10 seconds to wait until a version is fetched and untared @@fetching_versions[name] ||= Mutex.new @@fetching_versions[name].synchronize do if version_exists_locally?(@config[:local_path], name) @versions[name] = load_version(@config[:local_path], name) return @versions[name] if @versions[name] end # check remote path if (!@config[:remote_host] || !@config[:remote_path]) log_error("unable to load from host: #{@config[:remote_host]}, path: #{@config[:remote_path]}") return nil end # Fetch the version filename = "#{name}#{ARCHIVE_SUFFIX}" version_dir = File.join(@config[:local_path], name) begin res = fetch_remote(filename) if (res.status.to_i != 200) log_error("no version fetched : #{res.env[:url].to_s} - status #{res.status.to_i}") return nil end FileUtils.mkdir(version_dir) unless File.exists?(version_dir) open(File.join(version_dir, filename), "wb") do |file| file.write(res.body) end rescue Exception => e log_error("could not fetch version", e) return nil end # Untar the version tar_stdout = nil tar_stderr = nil tar_status = POpen4::popen4("cd #{version_dir} && tar -xzf #{filename} && rm #{filename}") do |stdo, stde, stdi, pid| stdi.close tar_stdout = stdo.read.strip tar_stderr = stde.read.strip end if (!tar_status.exitstatus.zero?) log_error("unable to untar package: cd #{version_dir} && tar -xzf #{filename} && rm #{filename}") log_error("stdout: #{tar_stdout}") log_error("stderr: #{tar_stderr}") begin FileUtils.rm_r(version_dir) rescue Exception => e # do nothing end return nil end # Load the version @versions[name] = load_version(@config[:local_path], name) if (!@versions[name]) begin FileUtils.rm_r(version_dir) rescue Exception => e # do nothing end return nil end end @@fetching_versions.reject! do |key, value| key == name end @versions[name] end
health()
click to toggle source
# File lib/quilt.rb, line 383 def health # return true if no remote info return [true, nil, nil] if !@config[:remote_host] || !@config[:remote_path] # fetch health_check.txt from remote URL begin res = fetch_remote('health_check.txt') if (res.status.to_i != 200) return [false, "Could not fetch heath check file: #{res.env[:url].to_s} - status #{res.status.to_i}", nil] end rescue Exception => e return [false, "Could not fetch heath check file - #{e.message}", e] end [true, nil, nil] end
load_version(local_path, version_name)
click to toggle source
# File lib/quilt.rb, line 91 def load_version(local_path, version_name) log_debug("Loading Version: "+version_name) manifest = {} new_version = { :name => version_name, :dir => File.join(local_path, version_name), :default => { :header => '', :common => '', :optional => {}, :footer => '', :base_modules => [] } } begin manifest = JSON.parse(File.read(File.join(new_version[:dir], "manifest.json"))) new_version[:default][:dir] = manifest[PREFIX_KEY] ? File.join(new_version[:dir], manifest[PREFIX_KEY]) : new_version[:dir] if (manifest[DEBUG_PREFIX_KEY]) new_version[:debug] = { :dir => manifest[DEBUG_PREFIX_KEY] ? File.join(new_version[:dir], manifest[DEBUG_PREFIX_KEY]) : new_version[:dir], :header => '', :common => '', :optional => {}, :footer => '', :base_modules => [] } end rescue Exception => e log_error(" Could not read manifest!", e); return nil end # manifest.json: # { # "prefix" : "<prefix directory>" # "debug_prefix : "<debug prefix directory" # "header" : "<header file>", # "footer" : "<footer file>", # "common" : [ # "<module file>", # { <module file> : "<position>" }, # ... # ], # "optional" : { # "<module file>" : [ "<dependancy module name>", ... ], # "<module file>" : { "dependancies" : [ "<dependancy module name>", ... ], "position" : "<position>" } # ... # } # } # # where <position> can be one of: before_header, after_header, before_common, after_common, # before_optional, optional, after_optional, before_footer, after_footer module_loader = Proc.new do |prefix| dir = new_version[prefix][:dir] if manifest[HEADER_KEY] begin new_version[prefix][:header] = File.open(File.join(dir, manifest[HEADER_KEY]), "rb").read rescue Exception => e log_error(" Could not load #{prefix.to_s} header: #{manifest[HEADER_KEY]}", e) end end if manifest[COMMON_KEY] && manifest[COMMON_KEY].is_a?(Array) manifest[COMMON_KEY].each do |filename| if (filename.is_a?(String)) begin new_version[prefix][:common] = "#{new_version[prefix][:common]}#{File.open(File.join(dir, filename), "rb").read}" rescue Exception => e log_error(" Could not load #{prefix.to_s} common module: #{filename}", e) end elsif (filename.is_a?(Hash)) filename.each do |actual_name, position_str| position = position_str && VALID_POSITIONS.include?(position_str) ? position_str.to_sym : :before_common tmp_module_name = get_module_name(actual_name) if (tmp_module_name) tmp_module = get_module(actual_name, [], position, dir) if (tmp_module) new_version[prefix][:optional][tmp_module_name] = tmp_module new_version[prefix][:base_modules].push(tmp_module_name) end else log_error(" Could not extract #{prefix.to_s} module name from: #{filename}") end end end end end if manifest[OPTIONAL_KEY] && manifest[OPTIONAL_KEY].is_a?(Hash) manifest[OPTIONAL_KEY].each do |filename, value| dependancies = [] position = :optional if (value.is_a?(Array)) dependancies = value elsif (value.is_a?(Hash)) dependancies = value[DEPENDANCIES_KEY] || [] position = value[POSITION_KEY] && VALID_POSITIONS.include?(value[POSITION_KEY]) ? value[POSITION_KEY].to_sym : :optional end tmp_module_name = get_module_name(filename) if (tmp_module_name) tmp_module = get_module(filename, dependancies, position, dir) if (tmp_module) new_version[prefix][:optional][tmp_module_name] = tmp_module end else log_error(" Could not extract #{prefix.to_s} module name from: #{filename}") end end end if manifest[FOOTER_KEY] begin new_version[prefix][:footer] = File.open(File.join(dir, manifest[FOOTER_KEY]), "rb").read rescue Exception => e log_error(" Could not load #{prefix.to_s} footer: #{manifest[FOOTER_KEY]}", e) new_version[:footer] = '' end end end module_loader.call(:default) module_loader.call(:debug) if new_version[:debug] new_version end
log_debug(msg)
click to toggle source
# File lib/quilt.rb, line 56 def log_debug(msg) return unless @log && @log.debug? @log.debug(msg) end
log_error(msg, e = nil)
click to toggle source
# File lib/quilt.rb, line 47 def log_error(msg, e = nil) return unless @log && @log.error? @log.error(msg) if msg if (e) @log.error(e.message) @log.error(e.backtrace.join("\n")) end end
resolve_dependancies(position, modules, version, all_modules = {})
click to toggle source
# File lib/quilt.rb, line 219 def resolve_dependancies(position, modules, version, all_modules = {}) out = '' return out if !modules || !(modules.is_a?(Array)) || modules.empty? my_all_modules = all_modules modules.each do |name| next if my_all_modules[name] == 2 if (!version[:optional][name] || !version[:optional][name][:module]) log_error(" invalid module: #{name}"); my_all_modules[name] = 2 next end if (my_all_modules[name] == 1) log_error(" circular module dependancy: #{name}") next end my_all_modules[name] = 1 out = "#{out}#{resolve_dependancies(position, version[:optional][name][:dependancies], version, my_all_modules)}" out = "#{out}#{version[:optional][name][:module]}" if version[:optional][name][:position] == position my_all_modules[name] = 2 end out end
resolve_dynamic(position, modules, dynamics, version)
click to toggle source
# File lib/quilt.rb, line 368 def resolve_dynamic(position, modules, dynamics, version) dynamics[position].is_a?(Array) ? resolve_dependancies(position, dynamics[position] + modules, version, {}) : "#{(dynamics[position] || '')}#{resolve_dependancies(position, modules, version, {})}" end
status()
click to toggle source
# File lib/quilt.rb, line 400 def status remote_url = "Remote URL: none" if (@config[:remote_host] && @config[:remote_path]) host = @config[:remote_host].to_s port = @config[:remote_port] ? @config[:remote_port].to_i : 80 path = File.join(@config[:remote_path].to_s, "[version]#{ARCHIVE_SUFFIX}") remote_url = "Remote URL: http://#{host}:#{port}#{path}" end body = <<EOS -- Quilt Status -- #{remote_url} Locally Available Versions: #{@versions.keys.join("\n ")} EOS body end
stitch(selector, version_name, prefix = :default, dynamic_modules = nil)
click to toggle source
# File lib/quilt.rb, line 314 def stitch(selector, version_name, prefix = :default, dynamic_modules = nil) return nil if !selector version = get_version(version_name) if (!version) log_error("could not fetch version: #{version_name}") return nil end outversion = version[prefix] || version[:default] # get modules we want to use modules = [] if (selector.is_a?(Proc)) modules = outversion[:optional].keys.select do |mod| selector.call(mod) end elsif (selector.is_a?(Array)) modules = selector end base_modules = [] outversion[:base_modules].each do |mod| next if modules.include?(mod) base_modules.push(mod) end modules = base_modules.concat(modules) # resolve dependancies dynamics = dynamic_modules && dynamic_modules.is_a?(Hash) ? dynamic_modules : {} output = "#{ resolve_dynamic(:before_header, modules, dynamics, outversion) }#{ outversion[:header] }#{ resolve_dynamic(:after_header, modules, dynamics, outversion) }#{ resolve_dynamic(:before_common, modules, dynamics, outversion) }#{ outversion[:common] }#{ resolve_dynamic(:after_common, modules, dynamics, outversion) }#{ resolve_dynamic(:before_optional, modules, dynamics, outversion) }#{ resolve_dynamic(:optional, modules, dynamics, outversion) }#{ resolve_dynamic(:after_optional, modules, dynamics, outversion) }#{ resolve_dynamic(:before_footer, modules, dynamics, outversion) }#{ outversion[:footer] }#{ resolve_dynamic(:after_footer, modules, dynamics, outversion) }" end
version_exists_locally?(local_path, version_name)
click to toggle source
# File lib/quilt.rb, line 83 def version_exists_locally?(local_path, version_name) begin manifest = JSON.parse(File.read(File.join(File.join(local_path, version_name), "manifest.json"))) rescue Exception => e return false end end