Class: Chef::Cookbook::CookbookVersionLoader
- Inherits:
-
Object
- Object
- Chef::Cookbook::CookbookVersionLoader
- Defined in:
- lib/chef/cookbook/cookbook_version_loader.rb
Constant Summary collapse
- 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.
-
#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`.
- #merge!(other_cookbook_loader) ⇒ Object
-
#metadata ⇒ Object
Generates the Cookbook::Metadata object.
- #metadata_filenames ⇒ Object
- #raise_metadata_error! ⇒ Object
- #remove_ignored_files ⇒ Object
- #set_frozen ⇒ Object
Constructor Details
#initialize(path, chefignore = nil) ⇒ CookbookVersionLoader
Returns a new instance of CookbookVersionLoader.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 26 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 = nil @relative_path = /#{Regexp.escape(@cookbook_path)}\/(.+)$/ = false @cookbook_settings = { :all_files => {}, } = [] = nil end |
Instance Attribute Details
#cookbook_path ⇒ Object (readonly)
Returns the value of attribute cookbook_path.
19 20 21 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 19 def cookbook_path @cookbook_path end |
#cookbook_paths ⇒ Object (readonly)
Returns the value of attribute cookbook_paths.
15 16 17 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 15 def cookbook_paths @cookbook_paths end |
#cookbook_settings ⇒ Object (readonly)
Returns the value of attribute cookbook_settings.
14 15 16 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 14 def cookbook_settings @cookbook_settings end |
#frozen ⇒ Object (readonly)
Returns the value of attribute frozen.
16 17 18 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 16 def frozen @frozen end |
#inferred_cookbook_name ⇒ Object (readonly)
The cookbook’s name as inferred from its directory.
22 23 24 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 22 def inferred_cookbook_name @inferred_cookbook_name end |
#metadata_error ⇒ Object (readonly)
Returns the value of attribute metadata_error.
24 25 26 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 24 def end |
#uploaded_cookbook_version_file ⇒ Object (readonly)
Returns the value of attribute uploaded_cookbook_version_file.
17 18 19 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 17 def uploaded_cookbook_version_file @uploaded_cookbook_version_file end |
Instance Method Details
#apply_json_cookbook_version_metadata(file) ⇒ Object
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 237 def (file) data = Chef::JSONCompat.parse(IO.read(file)) .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. .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 |
#apply_json_metadata(file) ⇒ Object
230 231 232 233 234 235 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 230 def (file) .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 |
#apply_ruby_metadata(file) ⇒ Object
223 224 225 226 227 228 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 223 def (file) .from_file(file) rescue Chef::Exceptions::JSON::ParseError Chef::Log.error("Error evaluating metadata.rb for #{@inferred_cookbook_name} in " + file) raise end |
#chefignore ⇒ Object
177 178 179 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 177 def chefignore @chefignore ||= Chefignore.new(File.basename(cookbook_path)) end |
#cookbook_name ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 106 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
95 96 97 98 99 100 101 102 103 104 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 95 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. = c.freeze_version if @frozen end end |
#empty? ⇒ Boolean
161 162 163 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 161 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.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 58 def load # force lazy evaluation to occur # re-raise any exception that occurred when reading the metadata load_all_files remove_ignored_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.
46 47 48 49 50 51 52 53 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 46 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.
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 187 def load_all_files return unless File.exist?(cookbook_path) # If cookbook_path is a symlink, Find on Windows Ruby 2.3 will not traverse it. # Dir.entries will do so on all platforms, so we iterate the top level using # Dir.entries. Since we have different behavior at the top anyway (hidden # directories at the top level are not included for backcompat), this # actually keeps things a bit cleaner. Dir.entries(cookbook_path).each do |top_filename| # Skip top-level directories starting with "." top_path = File.join(cookbook_path, top_filename) next if File.directory?(top_path) && top_filename.start_with?(".") # Use Find.find because it: # (a) returns any children, recursively # (b) includes top_path as well # (c) skips symlinks, which is backcompat (no judgement on whether it was *right*) Find.find(top_path) do |path| # Only add files, not directories next unless File.file?(path) # Don't add .uploaded-cookbook-version.json next if File.basename(path) == UPLOADED_COOKBOOK_VERSION_FILE relative_path = Chef::Util::PathHelper.relative_path_from(cookbook_path, path) path = Pathname.new(path).cleanpath.to_s cookbook_settings[:all_files][relative_path] = path end end end |
#merge!(other_cookbook_loader) ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 165 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 = nil # reset metadata so it gets reloaded and all metadata files applied. self end |
#metadata ⇒ Object
Generates the Cookbook::Metadata object
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 119 def return unless .nil? = Chef::Cookbook::Metadata.new .each do || case when /\.rb$/ () when @uploaded_cookbook_version_file () when /\.json$/ () else raise "Invalid metadata file: #{metadata_file} for cookbook: #{cookbook_version}" end end # 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 = e end |
#metadata_filenames ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 76 def return unless .empty? if File.exists?(File.join(cookbook_path, UPLOADED_COOKBOOK_VERSION_FILE)) @uploaded_cookbook_version_file = File.join(cookbook_path, UPLOADED_COOKBOOK_VERSION_FILE) end if File.exists?(File.join(cookbook_path, "metadata.json")) << File.join(cookbook_path, "metadata.json") elsif File.exists?(File.join(cookbook_path, "metadata.rb")) << File.join(cookbook_path, "metadata.rb") elsif @uploaded_cookbook_version_file << @uploaded_cookbook_version_file end # Set frozen based on .uploaded-cookbook-version.json set_frozen end |
#raise_metadata_error! ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 149 def raise unless .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: #{metadata.errors.join('; ')}" raise Exceptions::MetadataNotValid, end false end |
#remove_ignored_files ⇒ Object
217 218 219 220 221 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 217 def remove_ignored_files cookbook_settings[:all_files].reject! do |relative_path, full_path| chefignore.ignored?(relative_path) end end |
#set_frozen ⇒ Object
254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/chef/cookbook/cookbook_version_loader.rb', line 254 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 |