lib/linecook/cookbook.rb in linecook-1.2.1 vs lib/linecook/cookbook.rb in linecook-2.0.0
- old
+ new
@@ -1,160 +1,178 @@
-require 'linecook/utils'
-require 'lazydoc'
-
module Linecook
class Cookbook
class << self
- def config_file(project_dir='.')
- Dir.glob(File.join(project_dir, '{C,c}ookbook')).first
+ attr_writer :default_path_map
+ def default_path_map
+ @default_path_map ||= {
+ :attributes => ['attributes'],
+ :files => ['files'],
+ :templates => ['templates'],
+ :recipes => ['recipes']
+ }
end
-
- def setup(config={}, project_dir='.')
- unless config.kind_of?(Hash)
- config = Utils.load_config(config)
- end
-
- config[PATHS_KEY] ||= [project_dir]
- config[GEMS_KEY] ||= gems
-
- new(config, project_dir)
+
+ attr_writer :default_file_name
+ def default_file_name
+ @default_file_name ||= 'cookbook.yml'
end
-
- def init(project_dir='.')
- setup config_file(project_dir), project_dir
- end
-
- def gems
+
+ def gemspecs(latest=true)
return [] unless Object.const_defined?(:Gem)
-
- Gem.source_index.latest_specs.select do |spec|
- config_file(spec.full_gem_path) != nil
- end.collect do |spec|
- spec.name
+
+ index = Gem.source_index
+ specs = latest ? index.latest_specs : index.gems.values
+
+ specs.select do |spec|
+ cookbook_file = File.expand_path(default_file_name, spec.full_gem_path)
+ File.exists?(cookbook_file)
end
end
end
-
- MANIFEST_KEY = 'manifest'
- PATHS_KEY = 'paths'
- GEMS_KEY = 'gems'
- REWRITE_KEY = 'rewrite'
-
- PATTERNS = [
- ['attributes', '**/*{.rb,.yaml,.yml,.json}', true],
- ['files', '**/*'],
- ['recipes', '**/*.rb', true],
- ['templates', '**/*']
- ]
-
- attr_reader :project_dir
- attr_reader :config
-
- def initialize(config={}, project_dir='.')
- @project_dir = project_dir
- @config = config
+
+ attr_reader :registry
+
+ def initialize(*project_dirs)
+ @registry = {}
+ project_dirs.each do |dir|
+ case dir
+ when String then add(dir)
+ when Hash then add('.', dir)
+ else add(*dir)
+ end
+ end
end
-
- def paths
- Utils.arrayify config[PATHS_KEY]
+
+ # Returns an array of directories comprising the path for type.
+ def path(type)
+ registry[type] || []
end
-
- def gems
- Utils.arrayify config[GEMS_KEY]
- end
-
- def rewrites
- config[REWRITE_KEY]
- end
-
- def overrides
- config[MANIFEST_KEY]
- end
-
- def full_gem_paths
- return [] if gems.empty?
- specs = latest_specs
-
- gems.collect do |name|
- spec = specs[name] or raise "no such gem: #{name.inspect}"
- spec.full_gem_path
+
+ def add(dir, path_map=nil)
+ resolve_path_map(dir, path_map).each_pair do |type, paths|
+ (registry[type] ||= []).concat(paths)
end
end
-
- def rewrite(manifest)
- replacements = {}
-
- rewrites.each_pair do |pattern, substitution|
- manifest.keys.each do |key|
- replacement = key.sub(pattern, substitution)
- next if key == replacement
- raise "multiple replacements for: #{key}" if replacements.has_key?(key)
-
- replacements[key] = replacement
+
+ def rm(dir, path_map=nil)
+ resolve_path_map(dir, path_map).each_pair do |type, paths|
+ if current = registry[type]
+ current = current - paths
+ if current.empty?
+ registry.delete(type)
+ else
+ registry[type] = current
+ end
end
- end if rewrites
-
- replacements.each do |key, replacement|
- manifest[replacement] = manifest.delete(key)
end
-
- manifest
end
-
- def glob(*paths)
- manifest = Hash.new {|hash, key| hash[key] = {} }
-
- paths.each do |path|
- PATTERNS.each do |(type, glob, chomp_extname)|
- resource_dir = File.expand_path(File.join(path, type), project_dir)
- pattern = File.join(resource_dir, glob)
-
- Dir.glob(pattern).each do |full_path|
- next unless File.file?(full_path)
-
- name = relative_path(resource_dir, full_path)
- name.chomp!(File.extname(full_path)) if chomp_extname
-
- manifest[type][name] = full_path
+
+ # Same as find but returns nil if no file can be found.
+ def _find_(type, filename, extnames=nil)
+ if type.nil? || filename.nil?
+ return nil
+ end
+
+ if absolute?(filename)
+ return File.exists?(filename) ? filename : nil
+ end
+
+ path(type).each do |dir|
+ each_full_path(dir, filename, extnames) do |full_path|
+ if File.exists?(full_path) && subpath?(dir, full_path)
+ return full_path
end
end
end
-
- manifest
+
+ nil
end
-
- def manifest
- manifest = glob(*(full_gem_paths + paths))
-
- if overrides
- manifest = Utils.deep_merge(manifest, overrides)
+
+ # Searches for a file by expanding filename vs each directory in the path
+ # for type. The first existing full path is returned. If an array of
+ # extnames is provided, then each extname is tried for each directory,
+ # much as with Kernal.require. Absolute paths that exists are returned
+ # directly. Raises an error if the file cannot be found.
+ def find(type, source_name, extnames=nil)
+ _find_(type, source_name, extnames) or begin
+ case
+ when type.nil?
+ raise "could not find file: #{source_name.inspect} (nil type specified)"
+ when source_name.nil?
+ raise "could not find file: #{source_name.inspect}"
+ when absolute?(source_name)
+ raise "no such file: #{source_name.inspect}"
+ else
+ try_string = try_extnames?(source_name, extnames) ? " (tried #{extnames.join(', ')})" : nil
+ raise "could not find file: #{source_name.inspect}#{try_string}"
+ end
end
-
- manifest.each_key do |key|
- manifest[key] = rewrite manifest[key]
+ end
+
+ protected
+
+ if Dir.pwd[0] == ?/
+ def absolute?(path)
+ path && path[0] == ?/
end
-
- manifest
+ else
+ def absolute?(path)
+ path && path =~ /^[A-z]:\//
+ end
end
-
- def merge(config={})
- duplicate = dup
- dup.config.merge!(config)
- dup
+
+ def subpath?(dir, full_path)
+ full_path.index(dir) == 0
end
-
- private
-
- def relative_path(dir, path) # :nodoc:
- start = dir.length + 1
- path[start, path.length - start]
+
+ def try_extnames?(path, extnames)
+ extnames && File.extname(path).empty?
end
-
- def latest_specs # :nodoc:
- latest = {}
- Gem.source_index.latest_specs.each do |spec|
- latest[spec.name] = spec
+
+ def each_full_path(dir, path, extnames=nil)
+ full_path = File.expand_path(path, dir)
+ yield full_path
+
+ if try_extnames?(path, extnames)
+ extnames.each do |extname|
+ full_path = File.expand_path("#{path}#{extname}", dir)
+ yield full_path
+ end
end
- latest
+ end
+
+ def resolve_path_map(dir, path_map=nil)
+ path_map ||= self.class.default_file_name
+
+ case path_map
+ when Hash
+ expand_path_map(dir, path_map)
+ when String
+ cookbook_file = File.expand_path(path_map, dir)
+ path_map = File.exists?(cookbook_file) ? YAML.load_file(cookbook_file) : nil
+ path_map ||= self.class.default_path_map
+
+ unless path_map.kind_of?(Hash)
+ raise "could not load path map: #{cookbook_file.inspect} (does not load a Hash)"
+ end
+
+ expand_path_map(dir, path_map)
+ else
+ raise "could not resolve path map: #{path_map.inspect} (must be String, Hash, or nil)"
+ end
+ end
+
+ def expand_path_map(dir, path_map)
+ results = Hash.new {|hash, key| hash[key] = [] }
+
+ path_map.each_pair do |type, paths|
+ unless paths.kind_of?(Array)
+ paths = [paths]
+ end
+ paths.each do |path|
+ results[type.to_sym] << File.expand_path(path, dir)
+ end
+ end
+ results
end
end
end
\ No newline at end of file