class Puppet::Generate::Type

Responsible for generating type definitions in Puppet

Public Class Methods

find_inputs(format = :pcore, environment = Puppet.lookup(:current_environment)) click to toggle source

Finds the inputs for the generator. @param format [Symbol] The format to use. @param environment [Puppet::Node::Environment] The environment to search for inputs. Defaults to the current environment. @return [Array<Input>] Returns the array of inputs.

    # File lib/puppet/generate/type.rb
115 def self.find_inputs(format = :pcore, environment = Puppet.lookup(:current_environment))
116   Puppet.debug "Searching environment '#{environment.name}' for custom types."
117   inputs = []
118   environment.modules.each do |mod|
119     directory = File.join(Puppet::Util::Autoload.cleanpath(mod.plugin_directory), 'puppet', 'type')
120     unless Puppet::FileSystem.exist?(directory)
121       Puppet.debug "Skipping '#{mod.name}' module because it contains no custom types."
122       next
123     end
124 
125     Puppet.debug "Searching '#{mod.name}' module for custom types."
126     Dir.glob("#{directory}/*.rb") do |file|
127       next unless Puppet::FileSystem.file?(file)
128       Puppet.debug "Found custom type source file '#{file}'."
129       inputs << Input.new(mod.path, file, format)
130     end
131   end
132 
133   # Sort the inputs by path
134   inputs.sort_by! { |input| input.path }
135 end
generate(inputs, outputdir = nil, force = false) click to toggle source

Generates files for the given inputs. If a file is up to date (newer than input) it is kept. If a file is out of date it is regenerated. If there is a file for a non existing output in a given output directory it is removed. If using input specific output removal must be made by hand if input is removed.

@param inputs [Array<Input>] The inputs to generate files for. @param outputdir [String, nil] the outputdir where all output should be generated, or nil if next to input @param force [Boolean] True to force the generation of the output files (skip up-to-date checks) or false if not. @return [void]

    # File lib/puppet/generate/type.rb
147 def self.generate(inputs, outputdir = nil, force = false)
148   # remove files for non existing inputs
149   unless outputdir.nil?
150     filenames_to_keep = inputs.map {|i| i.output_name }
151     existing_files = Puppet::FileSystem.children(outputdir).map {|f| Puppet::FileSystem.basename(f) }
152     files_to_remove = existing_files - filenames_to_keep
153     files_to_remove.each do |f|
154       Puppet::FileSystem.unlink(File.join(outputdir, f))
155     end
156     Puppet.notice(_("Removed output '%{files_to_remove}' for non existing inputs") % { files_to_remove: files_to_remove }) unless files_to_remove.empty?
157   end
158 
159   if inputs.empty?
160     Puppet.notice _('No custom types were found.')
161     return nil
162   end
163 
164   templates = {}
165   templates.default_proc = lambda { |hash, key|
166     raise _("template was not found at '%{key}'.") % { key: key } unless Puppet::FileSystem.file?(key)
167     template = ERB.new(File.read(key), nil, '-')
168     template.filename = key
169     template
170   }
171 
172   up_to_date = true
173   Puppet.notice _('Generating Puppet resource types.')
174   inputs.each do |input|
175     if !force && input.up_to_date?(outputdir)
176       Puppet.debug "Skipping '#{input}' because it is up-to-date."
177       next
178     end
179 
180     up_to_date = false
181 
182     type_name = input.type_name
183     Puppet.debug "Loading custom type '#{type_name}' in '#{input}'."
184     begin
185       require input.path
186     rescue SystemExit
187       raise
188     rescue Exception => e
189       # Log the exception and move on to the next input
190       Puppet.log_exception(e, _("Failed to load custom type '%{type_name}' from '%{input}': %{message}") % { type_name: type_name, input: input, message: e.message })
191       next
192     end
193 
194     # HACK: there's no way to get a type without loading it (sigh); for now, just get the types hash directly
195     types ||= Puppet::Type.instance_variable_get('@types')
196 
197     # Assume the type follows the naming convention
198     type = types[type_name]
199     unless type
200       Puppet.err _("Custom type '%{type_name}' was not defined in '%{input}'.") % { type_name: type_name, input: input }
201       next
202     end
203 
204     # Create the model
205     begin
206       model = Models::Type::Type.new(type)
207     rescue Exception => e
208       # Move on to the next input
209       Puppet.log_exception(e, "#{input}: #{e.message}")
210       next
211     end
212 
213     # Render the template
214     begin
215       result = model.render(templates[input.template_path])
216     rescue Exception => e
217       Puppet.log_exception(e)
218       raise
219     end
220 
221     # Write the output file
222     begin
223       effective_output_path = input.effective_output_path(outputdir)
224       Puppet.notice _("Generating '%{effective_output_path}' using '%{format}' format.") % { effective_output_path: effective_output_path, format: input.format }
225       FileUtils.mkdir_p(File.dirname(effective_output_path))
226       Puppet::FileSystem.open(effective_output_path, nil, 'w:UTF-8') do |file|
227         file.write(result)
228       end
229     rescue Exception => e
230       Puppet.log_exception(e, _("Failed to generate '%{effective_output_path}': %{message}") % { effective_output_path: effective_output_path, message: e.message })
231       # Move on to the next input
232       next
233     end
234   end
235 
236   Puppet.notice _('No files were generated because all inputs were up-to-date.') if up_to_date
237 end