Class: Chef::ChefFS::FileSystem::CookbooksDir

Inherits:
RestListDir show all
Includes:
Mixin::FileClass
Defined in:
lib/chef/chef_fs/file_system/cookbooks_dir.rb

Instance Attribute Summary

Attributes inherited from RestListDir

#api_path, #data_handler

Attributes inherited from BaseFSObject

#name, #parent, #path

Instance Method Summary collapse

Methods included from Mixin::FileClass

#file_class

Methods inherited from RestListDir

#_make_child_entry, #create_child, #environment, #org, #rest

Methods inherited from BaseFSDir

#dir?

Methods inherited from BaseFSObject

#chef_object, #compare_to, #create_child, #delete, #dir?, #exists?, #path_for_printing, #read, #root, #write

Constructor Details

#initialize(parent) ⇒ CookbooksDir

Returns a new instance of CookbooksDir.



35
36
37
# File 'lib/chef/chef_fs/file_system/cookbooks_dir.rb', line 35

def initialize(parent)
  super("cookbooks", parent)
end

Instance Method Details

#can_have_child?(name, is_dir) ⇒ Boolean

Returns:

  • (Boolean)


156
157
158
159
160
# 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 root.versioned_cookbooks && name !~ Chef::ChefFS::FileSystem::CookbookDir::VALID_VERSIONED_COOKBOOK_NAME
  return true
end

#child(name) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
# 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

#childrenObject



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/chef/chef_fs/file_system/cookbooks_dir.rb', line 52

def children
  @children ||= begin
    if root.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 = {}) ⇒ Object



68
69
70
71
# 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 = {}) ⇒ Object



148
149
150
151
152
153
154
# 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 = {}) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/chef/chef_fs/file_system/cookbooks_dir.rb', line 73

def upload_cookbook_from(other, options = {})
  root.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) ⇒ Object



128
129
130
131
132
133
134
135
136
# 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, :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) ⇒ Object

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.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# 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, :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) ⇒ Object

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



139
140
141
142
143
144
145
146
# 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