Skip to content

Commit 3b2b4de

Browse files
committed
Make FileVendor configuration specific to the two implementations
FileVendor previously was configured by storing a closure/anonymous function as a class instance variable. This had the following downsides: * The API was too general, which caused a lot of code repetition * The block was lazily evaluated, which hid errors and made testing more difficult * The closures captured references to classes with references to large data structures, which complicates GC. Since we've only ever had the same two implementations of FileVendor, we can encapsulate configuration of the FileVendor factory by wrapping each configuration option in a method. As a side benefit, arguments to these methods will be eagerly evaluated, which makes it easier to detect errors.
1 parent 27ffe9c commit 3b2b4de

File tree

17 files changed

+128
-23
lines changed

17 files changed

+128
-23
lines changed

lib/chef/cookbook/file_system_file_vendor.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class Cookbook
3131
# non-sensical.
3232
class FileSystemFileVendor < FileVendor
3333

34+
attr_reader :cookbook_name
35+
attr_reader :repo_paths
36+
3437
def initialize(manifest, *repo_paths)
3538
@cookbook_name = manifest[:cookbook_name]
3639
@repo_paths = repo_paths.flatten

lib/chef/cookbook/file_vendor.rb

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,39 @@ class Cookbook
2424
# This class handles fetching of cookbook files based on specificity.
2525
class FileVendor
2626

27-
def self.on_create(&block)
28-
@instance_creator = block
27+
@vendor_class = nil
28+
@initialization_options = nil
29+
30+
# Configures FileVendor to use the RemoteFileVendor implementation. After
31+
# calling this, subsequent calls to create_from_manifest will return a
32+
# RemoteFileVendor object initialized with the given http_client
33+
def self.fetch_from_remote(http_client)
34+
@vendor_class = RemoteFileVendor
35+
@initialization_options = http_client
36+
end
37+
38+
def self.fetch_from_disk(cookbook_paths)
39+
@vendor_class = FileSystemFileVendor
40+
@initialization_options = cookbook_paths
41+
end
42+
43+
# Returns the implementation class that is currently configured, or `nil`
44+
# if one has not been configured yet.
45+
def self.vendor_class
46+
@vendor_class
47+
end
48+
49+
def self.initialization_options
50+
@initialization_options
2951
end
3052

3153
# Factory method that creates the appropriate kind of
3254
# Cookbook::FileVendor to serve the contents of the manifest
3355
def self.create_from_manifest(manifest)
34-
raise "Must call Chef::Cookbook::FileVendor.on_create before calling create_from_manifest factory" unless defined?(@instance_creator)
35-
@instance_creator.call(manifest)
56+
if @vendor_class.nil?
57+
raise "Must configure FileVendor to use a specific implementation before creating an instance"
58+
end
59+
@vendor_class.new(manifest, @initialization_options)
3660
end
3761

3862
# Gets the on-disk location for the given cookbook file.

lib/chef/cookbook/remote_file_vendor.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ class Cookbook
2525
# if not available, loading them from the remote server.
2626
class RemoteFileVendor < FileVendor
2727

28+
attr_reader :rest
29+
attr_reader :cookbook_name
30+
2831
def initialize(manifest, rest)
2932
@manifest = manifest
3033
@cookbook_name = @manifest[:cookbook_name]

lib/chef/knife/cookbook_upload.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def cookbooks_to_upload
184184

185185
def cookbook_repo
186186
@cookbook_loader ||= begin
187-
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, config[:cookbook_path]) }
187+
Chef::Cookbook::FileVendor.fetch_from_disk(config[:cookbook_path])
188188
Chef::CookbookLoader.new(config[:cookbook_path])
189189
end
190190
end

lib/chef/policy_builder/expand_node_object.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ def initialize(node_name, ohai_data, json_attribs, override_runlist, events)
5656

5757
def setup_run_context(specific_recipes=nil)
5858
if Chef::Config[:solo]
59-
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, Chef::Config[:cookbook_path]) }
59+
Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path])
6060
cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
6161
cl.load_cookbooks
6262
cookbook_collection = Chef::CookbookCollection.new(cl)
6363
run_context = Chef::RunContext.new(node, cookbook_collection, @events)
6464
else
65-
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, api_service) }
65+
Chef::Cookbook::FileVendor.fetch_from_remote(api_service)
6666
cookbook_hash = sync_cookbooks
6767
cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
6868
run_context = Chef::RunContext.new(node, cookbook_collection, @events)

lib/chef/policy_builder/policyfile.rb

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,7 @@ def build_node
154154
end
155155

156156
def setup_run_context(specific_recipes=nil)
157-
# TODO: This file vendor stuff is duplicated and initializing it with a
158-
# block traps a reference to this object in a global context which will
159-
# prevent it from getting GC'd. Simplify it.
160-
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, api_service) }
157+
Chef::Cookbook::FileVendor.fetch_from_remote(http_api)
161158
sync_cookbooks
162159
cookbook_collection = Chef::CookbookCollection.new(cookbooks_to_sync)
163160
run_context = Chef::RunContext.new(node, cookbook_collection, events)

lib/chef/shell/shell_session.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def definitions
169169

170170
def rebuild_context
171171
@run_status = Chef::RunStatus.new(@node, @events)
172-
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, Chef::Config[:cookbook_path]) }
172+
Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path])
173173
cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
174174
cl.load_cookbooks
175175
cookbook_collection = Chef::CookbookCollection.new(cl)
@@ -201,7 +201,7 @@ def save_node
201201

202202
def rebuild_context
203203
@run_status = Chef::RunStatus.new(@node, @events)
204-
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, Chef::REST.new(Chef::Config[:server_url])) }
204+
Chef::Cookbook::FileVendor.fetch_from_remote(Chef::REST.new(Chef::Config[:chef_server_url]))
205205
cookbook_hash = @client.sync_cookbooks
206206
cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
207207
@run_context = Chef::RunContext.new(node, cookbook_collection, @events)

spec/functional/resource/cookbook_file_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def create_resource
4040
# set up cookbook collection for this run to use, based on our
4141
# spec data.
4242
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, 'cookbooks'))
43-
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
43+
Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
4444
loader = Chef::CookbookLoader.new(cookbook_repo)
4545
loader.load_cookbooks
4646
cookbook_collection = Chef::CookbookCollection.new(loader)

spec/functional/resource/package_spec.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,7 @@ def apt_data_dir
135135
cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks")
136136
cl = Chef::CookbookLoader.new(cookbook_path)
137137
cl.load_cookbooks
138-
Chef::Cookbook::FileVendor.on_create do |manifest|
139-
Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_path)
140-
end
138+
Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_path)
141139
Chef::CookbookCollection.new(cl)
142140
end
143141

spec/functional/resource/remote_directory_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
def create_resource
2828
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
29-
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
29+
Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
3030
node = Chef::Node.new
3131
cl = Chef::CookbookLoader.new(cookbook_repo)
3232
cl.load_cookbooks

0 commit comments

Comments
 (0)