Class: Chef::Cookbook::CookbookVersionLoader
- Inherits:
-
Object
- Object
- Chef::Cookbook::CookbookVersionLoader
- Defined in:
- lib/chef/cookbook/cookbook_version_loader.rb
Constant Summary collapse
- FILETYPES_SUBJECT_TO_IGNORE =
[ :attribute_filenames, :definition_filenames, :recipe_filenames, :template_filenames, :file_filenames, :library_filenames, :resource_filenames, :provider_filenames]
- UPLOADED_COOKBOOK_VERSION_FILE =
".uploaded-cookbook-version.json".freeze
Instance Attribute Summary collapse
-
#cookbook_path ⇒ Object
readonly
Returns the value of attribute cookbook_path.
-
#cookbook_paths ⇒ Object
readonly
Returns the value of attribute cookbook_paths.
-
#cookbook_settings ⇒ Object
readonly
Returns the value of attribute cookbook_settings.
-
#frozen ⇒ Object
readonly
Returns the value of attribute frozen.
-
#inferred_cookbook_name ⇒ Object
readonly
The cookbook’s name as inferred from its directory.
-
#metadata_error ⇒ Object
readonly
Returns the value of attribute metadata_error.
-
#metadata_filenames ⇒ Object
readonly
Returns the value of attribute metadata_filenames.
-
#uploaded_cookbook_version_file ⇒ Object
readonly
Returns the value of attribute uploaded_cookbook_version_file.
Instance Method Summary collapse
- #apply_json_cookbook_version_metadata(file) ⇒ Object
- #apply_json_metadata(file) ⇒ Object
- #apply_ruby_metadata(file) ⇒ Object
- #chefignore ⇒ Object
- #cookbook_name ⇒ Object
- #cookbook_version ⇒ Object
- #empty? ⇒ Boolean
-
#initialize(path, chefignore = nil) ⇒ CookbookVersionLoader
constructor
A new instance of CookbookVersionLoader.
-
#load ⇒ Object
(also: #load_cookbooks)
Load the cookbook.
-
#load! ⇒ Object
Load the cookbook.
-
#load_all_files ⇒ Object
Enumerate all the files in a cookbook and assign the resulting list to ‘cookbook_settings`.
- #load_as(category, *path_glob) ⇒ Object
- #load_recursively_as(category, category_dir, glob) ⇒ Object
- #load_root_files ⇒ Object
- #merge!(other_cookbook_loader) ⇒ Object
-
#metadata ⇒ Object
Generates the Cookbook::Metadata object.
- #raise_metadata_error! ⇒ Object
- #remove_ignored_files ⇒ Object
-
#select_files_by_glob(pattern, option = 0) ⇒ Object
Mimic Dir.glob inside a cookbook by running ‘File.fnmatch?` against `cookbook_settings`.
- #set_frozen ⇒ Object
Constructor Details
#initialize(path, chefignore = nil) ⇒ CookbookVersionLoader
Returns a new instance of CookbookVersionLoader.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 35 def initialize(path, chefignore = nil) @cookbook_path = File.( path ) # cookbook_path from which this was loaded # We keep a list of all cookbook paths that have been merged in @cookbook_paths = [ cookbook_path ] @inferred_cookbook_name = File.basename( path ) @chefignore = chefignore @metadata = nil @relative_path = /#{Regexp.escape(@cookbook_path)}\/(.+)$/ @metadata_loaded = false @cookbook_settings = { :all_files => {}, :attribute_filenames => {}, :definition_filenames => {}, :recipe_filenames => {}, :template_filenames => {}, :file_filenames => {}, :library_filenames => {}, :resource_filenames => {}, :provider_filenames => {}, :root_filenames => {}, } @metadata_filenames = [] @metadata_error = nil end |
Instance Attribute Details
#cookbook_path ⇒ Object (readonly)
Returns the value of attribute cookbook_path.
28 29 30 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 28 def cookbook_path @cookbook_path end |
#cookbook_paths ⇒ Object (readonly)
Returns the value of attribute cookbook_paths.
23 24 25 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 23 def cookbook_paths @cookbook_paths end |
#cookbook_settings ⇒ Object (readonly)
Returns the value of attribute cookbook_settings.
22 23 24 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 22 def cookbook_settings @cookbook_settings end |
#frozen ⇒ Object (readonly)
Returns the value of attribute frozen.
25 26 27 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 25 def frozen @frozen end |
#inferred_cookbook_name ⇒ Object (readonly)
The cookbook’s name as inferred from its directory.
31 32 33 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 31 def inferred_cookbook_name @inferred_cookbook_name end |
#metadata_error ⇒ Object (readonly)
Returns the value of attribute metadata_error.
33 34 35 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 33 def @metadata_error end |
#metadata_filenames ⇒ Object (readonly)
Returns the value of attribute metadata_filenames.
24 25 26 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 24 def @metadata_filenames end |
#uploaded_cookbook_version_file ⇒ Object (readonly)
Returns the value of attribute uploaded_cookbook_version_file.
26 27 28 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 26 def uploaded_cookbook_version_file @uploaded_cookbook_version_file end |
Instance Method Details
#apply_json_cookbook_version_metadata(file) ⇒ Object
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 320 def (file) begin data = Chef::JSONCompat.parse(IO.read(file)) @metadata.from_hash(data["metadata"]) # the JSON cookbok metadata file is only used by chef-zero. # The Chef Server API currently does not enforce that the metadata # have a `name` field, but that will cause an error when attempting # to load the cookbook. To keep compatibility, we fake it by setting # the metadata name from the cookbook version object's name. # # This behavior can be removed if/when Chef Server enforces that the # metadata contains a name key. @metadata.name(data["cookbook_name"]) unless data["metadata"].key?("name") rescue Chef::Exceptions::JSON::ParseError Chef::Log.error("Couldn't parse cookbook metadata JSON for #@inferred_cookbook_name in " + file) raise end end |
#apply_json_metadata(file) ⇒ Object
311 312 313 314 315 316 317 318 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 311 def (file) begin @metadata.from_json(IO.read(file)) rescue Chef::Exceptions::JSON::ParseError Chef::Log.error("Couldn't parse cookbook metadata JSON for #@inferred_cookbook_name in " + file) raise end end |
#apply_ruby_metadata(file) ⇒ Object
302 303 304 305 306 307 308 309 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 302 def (file) begin @metadata.from_file(file) rescue Chef::Exceptions::JSON::ParseError Chef::Log.error("Error evaluating metadata.rb for #@inferred_cookbook_name in " + file) raise end end |
#chefignore ⇒ Object
215 216 217 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 215 def chefignore @chefignore ||= Chefignore.new(File.basename(cookbook_path)) end |
#cookbook_name ⇒ Object
144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 144 def cookbook_name # The `name` attribute is now required in metadata, so # inferred_cookbook_name generally should not be used. Per CHEF-2923, # we have to not raise errors in cookbook metadata immediately, so that # users can still `knife cookbook upload some-cookbook` when an # unrelated cookbook has an error in its metadata. This situation # could prevent us from reading the `name` attribute from the metadata # entirely, but the name is used as a hash key in CookbookLoader, so we # fall back to the inferred name here. (.name || @inferred_cookbook_name).to_sym end |
#cookbook_version ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 123 def cookbook_version return nil if empty? Chef::CookbookVersion.new(cookbook_name, *cookbook_paths).tap do |c| c.all_files = cookbook_settings[:all_files].values c.attribute_filenames = cookbook_settings[:attribute_filenames].values c.definition_filenames = cookbook_settings[:definition_filenames].values c.recipe_filenames = cookbook_settings[:recipe_filenames].values c.template_filenames = cookbook_settings[:template_filenames].values c.file_filenames = cookbook_settings[:file_filenames].values c.library_filenames = cookbook_settings[:library_filenames].values c.resource_filenames = cookbook_settings[:resource_filenames].values c.provider_filenames = cookbook_settings[:provider_filenames].values c.root_filenames = cookbook_settings[:root_filenames].values c. = c. = c.freeze_version if @frozen end end |
#empty? ⇒ Boolean
199 200 201 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 199 def empty? cookbook_settings.values.all? { |files_hash| files_hash.empty? } && .size == 0 end |
#load ⇒ Object Also known as: load_cookbooks
Load the cookbook. Does not raise an error if given a non-cookbook directory as the cookbook_path. This behavior is provided for compatibility, it is recommended to use #load! instead.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 76 def load # force lazy evaluation to occur # re-raise any exception that occurred when reading the metadata load_all_files remove_ignored_files load_as(:attribute_filenames, "attributes", "*.rb") load_as(:definition_filenames, "definitions", "*.rb") load_as(:recipe_filenames, "recipes", "*.rb") load_recursively_as(:library_filenames, "libraries", "*") load_recursively_as(:template_filenames, "templates", "*") load_recursively_as(:file_filenames, "files", "*") load_recursively_as(:resource_filenames, "resources", "*.rb") load_recursively_as(:provider_filenames, "providers", "*.rb") load_root_files if empty? Chef::Log.warn "Found a directory #{cookbook_name} in the cookbook path, but it contains no cookbook files. skipping." end @cookbook_settings end |
#load! ⇒ Object
Load the cookbook. Raises an error if the cookbook_path given to the constructor doesn’t point to a valid cookbook.
64 65 66 67 68 69 70 71 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 64 def load! file_paths_map = load if empty? raise Exceptions::CookbookNotFoundInRepo, "The directory #{cookbook_path} does not contain a cookbook" end file_paths_map end |
#load_all_files ⇒ Object
Enumerate all the files in a cookbook and assign the resulting list to ‘cookbook_settings`. In order to behave in a compatible way with previous implementations, directories at the cookbook’s root that begin with a dot are ignored. dotfiles are generally not ignored, however if the file is named “.uploaded-cookbook-version.json” it is assumed to be managed by chef-zero and not part of the cookbook.
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 225 def load_all_files Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path), "*"), File::FNM_DOTMATCH).each do |fs_entry| if File.directory?(fs_entry) dir_relpath = Chef::Util::PathHelper.relative_path_from(@cookbook_path, fs_entry) next if dir_relpath.to_s.start_with?(".") Dir.glob(File.join(fs_entry, "**/*"), File::FNM_DOTMATCH).each do |file| next if File.directory?(file) file = Pathname.new(file).cleanpath.to_s name = Chef::Util::PathHelper.relative_path_from(@cookbook_path, file) cookbook_settings[:all_files][name] = file end elsif File.file?(fs_entry) file = Pathname.new(fs_entry).cleanpath.to_s next if File.basename(file) == UPLOADED_COOKBOOK_VERSION_FILE name = Chef::Util::PathHelper.relative_path_from(@cookbook_path, file) cookbook_settings[:all_files][name] = file else # pipes, devices, other weirdness next end end end |
#load_as(category, *path_glob) ⇒ Object
270 271 272 273 274 275 276 277 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 270 def load_as(category, *path_glob) glob_pattern = File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path), *path_glob) select_files_by_glob(glob_pattern).each do |file| file = Chef::Util::PathHelper.cleanpath(file) name = Chef::Util::PathHelper.relative_path_from(@cookbook_path, file) cookbook_settings[category][name] = file end end |
#load_recursively_as(category, category_dir, glob) ⇒ Object
261 262 263 264 265 266 267 268 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 261 def load_recursively_as(category, category_dir, glob) glob_pattern = File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path, category_dir), "**", glob) select_files_by_glob(glob_pattern, File::FNM_DOTMATCH).each do |file| file = Chef::Util::PathHelper.cleanpath(file) name = Chef::Util::PathHelper.relative_path_from(@cookbook_path, file) cookbook_settings[category][name] = file end end |
#load_root_files ⇒ Object
251 252 253 254 255 256 257 258 259 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 251 def load_root_files select_files_by_glob(File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path), "*"), File::FNM_DOTMATCH).each do |file| file = Chef::Util::PathHelper.cleanpath(file) next if File.directory?(file) next if File.basename(file) == UPLOADED_COOKBOOK_VERSION_FILE name = Chef::Util::PathHelper.relative_path_from(@cookbook_path, file) cookbook_settings[:root_filenames][name] = file end end |
#merge!(other_cookbook_loader) ⇒ Object
203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 203 def merge!(other_cookbook_loader) other_cookbook_settings = other_cookbook_loader.cookbook_settings cookbook_settings.each do |file_type, file_list| file_list.merge!(other_cookbook_settings[file_type]) end .concat(other_cookbook_loader.) @cookbook_paths += other_cookbook_loader.cookbook_paths @frozen = true if other_cookbook_loader.frozen @metadata = nil # reset metadata so it gets reloaded and all metadata files applied. self end |
#metadata ⇒ Object
Generates the Cookbook::Metadata object
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 157 def return @metadata unless @metadata.nil? @metadata = Chef::Cookbook::Metadata.new .each do || case when /\.rb$/ () when @uploaded_cookbook_version_file () when /\.json$/ () else raise RuntimeError, "Invalid metadata file: #{} for cookbook: #{cookbook_version}" end end @metadata # Rescue errors so that users can upload cookbooks via `knife cookbook # upload` even if some cookbooks in their chef-repo have errors in # their metadata. We only rescue StandardError because you have to be # doing something *really* terrible to raise an exception that inherits # directly from Exception in your metadata.rb file. rescue StandardError => e @metadata_error = e @metadata end |
#raise_metadata_error! ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 187 def raise @metadata_error unless @metadata_error.nil? # Metadata won't be valid if the cookbook is empty. If the cookbook is # actually empty, a metadata error here would be misleading, so don't # raise it (if called by #load!, a different error is raised). if !empty? && !.valid? = "Cookbook loaded at path(s) [#{@cookbook_paths.join(', ')}] has invalid metadata: #{.errors.join('; ')}" raise Exceptions::MetadataNotValid, end false end |
#remove_ignored_files ⇒ Object
296 297 298 299 300 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 296 def remove_ignored_files cookbook_settings[:all_files].reject! do |relative_path, full_path| chefignore.ignored?(relative_path) end end |
#select_files_by_glob(pattern, option = 0) ⇒ Object
Mimic Dir.glob inside a cookbook by running ‘File.fnmatch?` against `cookbook_settings`.
289 290 291 292 293 294 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 289 def select_files_by_glob(pattern, option = 0) combined_opts = option | File::FNM_PATHNAME cookbook_settings[:all_files].values.select do |path| File.fnmatch?(pattern, path, combined_opts) end end |
#set_frozen ⇒ Object
339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 339 def set_frozen if uploaded_cookbook_version_file begin data = Chef::JSONCompat.parse(IO.read(uploaded_cookbook_version_file)) @frozen = data["frozen?"] rescue Chef::Exceptions::JSON::ParseError Chef::Log.error("Couldn't parse cookbook metadata JSON for #@inferred_cookbook_name in #{uploaded_cookbook_version_file}") raise end end end |