# 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