class Ridley::Chef::Cookbook

Constants

CHEF_JSON_CLASS
CHEF_TYPE

Attributes

chefignore[R]

@return [Ridley::Chef::Chefignore, nil]

cookbook_name[R]
files[R]

@return [Array]

frozen[RW]

@return [Boolean]

manifest[R]

@return [Hashie::Mash]

a Hashie::Mash containing Cookbook file category names as keys and an Array of Hashes
containing metadata about the files belonging to that category. This is used
to communicate what a Cookbook looks like when uploading to a Chef Server.

example:
  {
    :recipes => [
      {
        name: "default.rb",
        path: "recipes/default.rb",
        checksum: "fb1f925dcd5fc4ebf682c4442a21c619",
        specificity: "default"
      }
    ]
    ...
    ...
  }
metadata[R]
path[R]

Public Class Methods

checksum(filepath) click to toggle source

@param [String] filepath

a path on disk to the location of a file to checksum

@return [String]

a checksum that can be used to uniquely identify the file understood
by a Chef Server.
# File lib/ridley/chef/cookbook.rb, line 15
def checksum(filepath)
  Ridley::Chef::Digester.md5_checksum_for_file(filepath)
end
from_path(path) click to toggle source

Creates a new instance of Ridley::Chef::Cookbook from a path on disk containing a Cookbook.

The name of the Cookbook is determined by the value of the name attribute set in the cookbooks' metadata. If the name attribute is not present the name of the loaded cookbook is determined by directory containing the cookbook.

@param [#to_s] path

a path on disk to the location of a Cookbook

@raise [IOError] if the path does not contain a metadata.rb or metadata.json file

@return [Ridley::Chef::Cookbook]

# File lib/ridley/chef/cookbook.rb, line 32
def from_path(path)
  path = Pathname.new(path)

  if (file = path.join(Metadata::COMPILED_FILE_NAME)).exist?
    metadata = Metadata.from_json(File.read(file))
  elsif (file = path.join(Metadata::RAW_FILE_NAME)).exist?
    metadata = Metadata.from_file(file)
  else
    raise IOError, "no #{Metadata::COMPILED_FILE_NAME} or #{Metadata::RAW_FILE_NAME} found at #{path}"
  end

  unless metadata.name.presence
    raise Ridley::Errors::MissingNameAttribute.new(path)
  end

  new(metadata.name, path, metadata)
end
new(name, path, metadata) click to toggle source
# File lib/ridley/chef/cookbook.rb, line 85
def initialize(name, path, metadata)
  @cookbook_name = name
  @path          = Pathname.new(path)
  @metadata      = metadata
  @frozen        = false
  @chefignore    = Ridley::Chef::Chefignore.new(@path) rescue nil

  clear_files
  load_files
end

Public Instance Methods

<=>(other) click to toggle source
# File lib/ridley/chef/cookbook.rb, line 228
def <=>(other)
  [self.cookbook_name, self.version] <=> [other.cookbook_name, other.version]
end
checksums() click to toggle source

@return [Hash]

an hash containing the checksums and expanded file paths of all of the
files found in the instance of CachedCookbook

example:
  {
    "da97c94bb6acb2b7900cbf951654fea3" => "/Users/reset/.ridley/nginx-0.101.2/README.md"
  }
# File lib/ridley/chef/cookbook.rb, line 104
def checksums
  {}.tap do |checksums|
    files.each do |file|
      checksums[self.class.checksum(file)] = file
    end
  end
end
compile_metadata(out = self.path) click to toggle source

Compiles the raw metadata of the cookbook and writes it to a metadata.json file at the given out path. The default out path is the directory containing the cookbook itself.

@param [String] out

directory to output compiled metadata to

@return [String]

path to the compiled metadata
# File lib/ridley/chef/cookbook.rb, line 120
def compile_metadata(out = self.path)
  filepath = File.join(out, Metadata::COMPILED_FILE_NAME)
  File.open(filepath, "wb+") do |f|
    f.write(metadata.to_json)
  end

  filepath
end
compiled_metadata?() click to toggle source

Returns true if the cookbook instance has a compiled metadata file and false if it does not.

@return [Boolean]

# File lib/ridley/chef/cookbook.rb, line 133
def compiled_metadata?
  manifest[:root_files].any? { |file| file[:name].downcase == Metadata::COMPILED_FILE_NAME }
end
file_metadata(category, target) click to toggle source

@param [Symbol] category

the category of file to generate metadata about

@param [String] target

the filepath to the file to get metadata information about

@return [Hash]

a Hash containing a name, path, checksum, and specificity key representing the
metadata about a file contained in a Cookbook. This metadata is used when
uploading a Cookbook's files to a Chef Server.

@example

file_metadata(:root_files, "somefile.h") => {
  name: "default.rb",
  path: "recipes/default.rb",
  checksum: "fb1f925dcd5fc4ebf682c4442a21c619",
  specificity: "default"
}
# File lib/ridley/chef/cookbook.rb, line 154
def file_metadata(category, target)
  target = Pathname.new(target)

  {
    name: target.basename.to_s,
    path: target.relative_path_from(path).to_s,
    checksum: self.class.checksum(target),
    specificity: file_specificity(category, target)
  }
end
file_specificity(category, target) click to toggle source

@param [Symbol] category @param [Pathname] target

@return [String]

# File lib/ridley/chef/cookbook.rb, line 169
def file_specificity(category, target)
  case category
  when :files, :templates
    relpath = target.relative_path_from(path).to_s
    relpath.slice(/(.+)\/(.+)\/.+/, 2) || 'root_default'
  else
    'default'
  end
end
name() click to toggle source

@return [String]

the name of the cookbook and the version number separated by a dash (-).

example:
  "nginx-0.101.2"
# File lib/ridley/chef/cookbook.rb, line 184
def name
  "#{cookbook_name}-#{version}"
end
reload() click to toggle source

Reload the cookbook from the files located on disk at `#path`.

# File lib/ridley/chef/cookbook.rb, line 189
def reload
  clear_files
  load_files
end
to_hash() click to toggle source
# File lib/ridley/chef/cookbook.rb, line 207
def to_hash
  result                 = manifest.dup
  result[:chef_type]     = CHEF_TYPE
  result[:name]          = name
  result[:cookbook_name] = cookbook_name
  result[:version]       = version
  result[:metadata]      = metadata.to_hash
  result[:frozen?]       = frozen
  result
end
to_json(*args) click to toggle source
# File lib/ridley/chef/cookbook.rb, line 218
def to_json(*args)
  result               = self.to_hash
  result['json_class'] = CHEF_JSON_CLASS
  result.to_json(*args)
end
to_s() click to toggle source
# File lib/ridley/chef/cookbook.rb, line 224
def to_s
  "#{cookbook_name} (#{version}) '#{path}'"
end
validate() click to toggle source
# File lib/ridley/chef/cookbook.rb, line 194
def validate
  raise IOError, "No Cookbook found at: #{path}" unless path.exist?

  unless syntax_checker.validate_ruby_files
    raise Ridley::Errors::CookbookSyntaxError, "Invalid ruby files in cookbook: #{cookbook_name} (#{version})."
  end
  unless syntax_checker.validate_templates
    raise Ridley::Errors::CookbookSyntaxError, "Invalid template files in cookbook: #{cookbook_name} (#{version})."
  end

  true
end

Private Instance Methods

clear_files() click to toggle source
# File lib/ridley/chef/cookbook.rb, line 240
def clear_files
  @files    = Array.new
  @manifest = Hashie::Mash.new(
    recipes: Array.new,
    definitions: Array.new,
    libraries: Array.new,
    attributes: Array.new,
    files: Array.new,
    templates: Array.new,
    resources: Array.new,
    providers: Array.new,
    root_files: Array.new
  )
end
ignored?(file) click to toggle source

Determine if the given file should be ignored by the chefignore

@return [Boolean]

true if it should be ignored, false otherwise
# File lib/ridley/chef/cookbook.rb, line 308
def ignored?(file)
  !!chefignore && chefignore.ignored?(file)
end
load_files() click to toggle source
# File lib/ridley/chef/cookbook.rb, line 255
def load_files
  load_shallow(:recipes, 'recipes', '*.rb')
  load_shallow(:definitions, 'definitions', '*.rb')
  load_shallow(:attributes, 'attributes', '*.rb')
  load_recursively(:libraries, 'libraries', '*.rb')
  load_recursively(:files, "files", "*")
  load_recursively(:templates, "templates", "*")
  load_recursively(:resources, "resources", "*.rb")
  load_recursively(:providers, "providers", "*.rb")
  load_root
end
load_recursively(category, category_dir, glob) click to toggle source
# File lib/ridley/chef/cookbook.rb, line 278
def load_recursively(category, category_dir, glob)
  [].tap do |files|
    file_spec = path.join(category_dir, '**', glob)
    Dir.glob(file_spec, File::FNM_DOTMATCH).each do |file|
      next if File.directory?(file)
      next if ignored?(file)
      @files << file
      @manifest[category] << file_metadata(category, file)
    end
  end
end
load_root() click to toggle source
# File lib/ridley/chef/cookbook.rb, line 267
def load_root
  [].tap do |files|
    Dir.glob(path.join('*'), File::FNM_DOTMATCH).each do |file|
      next if File.directory?(file)
      next if ignored?(file)
      @files << file
      @manifest[:root_files] << file_metadata(:root_files, file)
    end
  end
end
load_shallow(category, *path_glob) click to toggle source
# File lib/ridley/chef/cookbook.rb, line 290
def load_shallow(category, *path_glob)
  [].tap do |files|
    Dir[path.join(*path_glob)].each do |file|
      next if ignored?(file)
      @files << file
      @manifest[category] << file_metadata(category, file)
    end
  end
end
syntax_checker() click to toggle source
# File lib/ridley/chef/cookbook.rb, line 300
def syntax_checker
  @syntax_checker ||= Cookbook::SyntaxCheck.new(path.to_s, chefignore)
end