class Chef::ChefFS::FileSystem::CookbooksDir

Public Class Methods

new(parent) click to toggle source
Calls superclass method
# File lib/chef/chef_fs/file_system/cookbooks_dir.rb, line 35
def initialize(parent)
  super("cookbooks", parent)
end

Public Instance Methods

can_have_child?(name, is_dir) click to toggle source
# File lib/chef/chef_fs/file_system/cookbooks_dir.rb, line 156
def can_have_child?(name, is_dir)
  return false if !is_dir
  return false if Chef::Config[:versioned_cookbooks] && name !~ Chef::ChefFS::FileSystem::CookbookDir::VALID_VERSIONED_COOKBOOK_NAME
  return true
end
child(name) click to toggle source
# File lib/chef/chef_fs/file_system/cookbooks_dir.rb, line 39
def child(name)
  if @children
    result = self.children.select { |child| child.name == name }.first
    if result
      result
    else
      NonexistentFSObject.new(name, self)
    end
  else
    CookbookDir.new(name, self)
  end
end
children() click to toggle source
# File lib/chef/chef_fs/file_system/cookbooks_dir.rb, line 52
def children
  @children ||= begin
    if Chef::Config[:versioned_cookbooks]
      result = []
      root.get_json("#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks|
        cookbooks['versions'].each do |cookbook_version|
          result << CookbookDir.new("#{cookbook_name}-#{cookbook_version['version']}", self, :exists => true)
        end
      end
    else
      result = root.get_json(api_path).keys.map { |cookbook_name| CookbookDir.new(cookbook_name, self, :exists => true) }
    end
    result.sort_by(&:name)
  end
end
create_child_from(other, options = {}) click to toggle source
# File lib/chef/chef_fs/file_system/cookbooks_dir.rb, line 68
def create_child_from(other, options = {})
  @children = nil
  upload_cookbook_from(other, options)
end
upload_cookbook!(uploader, options = {}) click to toggle source
# File lib/chef/chef_fs/file_system/cookbooks_dir.rb, line 148
def upload_cookbook!(uploader, options = {})
  if uploader.respond_to?(:upload_cookbook)
    uploader.upload_cookbook
  else
    uploader.upload_cookbooks
  end
end
upload_cookbook_from(other, options = {}) click to toggle source
# File lib/chef/chef_fs/file_system/cookbooks_dir.rb, line 73
def upload_cookbook_from(other, options = {})
  Chef::Config[:versioned_cookbooks] ? upload_versioned_cookbook(other, options) : upload_unversioned_cookbook(other, options)
rescue Timeout::Error => e
  raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
rescue Net::HTTPServerException => e
  case e.response.code
  when "409"
    raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e), "Cookbook #{other.name} is frozen"
  else
    raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}"
  end
rescue Chef::Exceptions::CookbookFrozen => e
  raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e), "Cookbook #{other.name} is frozen"
end
upload_unversioned_cookbook(other, options) click to toggle source
# File lib/chef/chef_fs/file_system/cookbooks_dir.rb, line 128
def upload_unversioned_cookbook(other, options)
  cookbook_to_upload = other.chef_object
  cookbook_to_upload.freeze_version if options[:freeze]
  uploader = Chef::CookbookUploader.new(cookbook_to_upload, other.parent.file_path, :force => options[:force], :rest => root.chef_rest)

  with_actual_cookbooks_dir(other.parent.file_path) do
    upload_cookbook!(uploader)
  end
end
upload_versioned_cookbook(other, options) click to toggle source

Knife currently does not understand versioned cookbooks Cookbook Version uploader also requires a lot of refactoring to make this work. So instead, we make a temporary cookbook symlinking back to real cookbook, and upload the proxy.

# File lib/chef/chef_fs/file_system/cookbooks_dir.rb, line 92
def upload_versioned_cookbook(other, options)
  cookbook_name = Chef::ChefFS::FileSystem::ChefRepositoryFileSystemCookbookDir.canonical_cookbook_name(other.name)

  Dir.mktmpdir do |temp_cookbooks_path|
    proxy_cookbook_path = "#{temp_cookbooks_path}/#{cookbook_name}"

    # Make a symlink
    file_class.symlink other.file_path, proxy_cookbook_path

    # Instantiate a proxy loader using the temporary symlink
    proxy_loader = Chef::Cookbook::CookbookVersionLoader.new(proxy_cookbook_path, other.parent.chefignore)
    proxy_loader.load_cookbooks

    cookbook_to_upload = proxy_loader.cookbook_version
    cookbook_to_upload.freeze_version if options[:freeze]

    # Instantiate a new uploader based on the proxy loader
    uploader = Chef::CookbookUploader.new(cookbook_to_upload, proxy_cookbook_path, :force => options[:force], :rest => root.chef_rest)

    with_actual_cookbooks_dir(temp_cookbooks_path) do
      upload_cookbook!(uploader)
    end

    #
    # When the temporary directory is being deleted on
    # windows, the contents of the symlink under that
    # directory is also deleted. So explicitly remove
    # the symlink without removing the original contents if we
    # are running on windows
    #
    if Chef::Platform.windows?
      Dir.rmdir proxy_cookbook_path
    end
  end
end
with_actual_cookbooks_dir(actual_cookbook_path) { || ... } click to toggle source

Work around the fact that CookbookUploader doesn't understand chef_repo_path (yet)

# File lib/chef/chef_fs/file_system/cookbooks_dir.rb, line 139
def with_actual_cookbooks_dir(actual_cookbook_path)
  old_cookbook_path = Chef::Config.cookbook_path
  Chef::Config.cookbook_path = actual_cookbook_path if !Chef::Config.cookbook_path

  yield
ensure
  Chef::Config.cookbook_path = old_cookbook_path
end