class Puppet::Generate::Type

Responsible for generating type definitions in Puppet

Public Class Methods

bad_input?() click to toggle source
    # File lib/puppet/generate/type.rb
138 def self.bad_input?
139   @bad_input
140 end
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
116 def self.find_inputs(format = :pcore, environment = Puppet.lookup(:current_environment))
117   Puppet.debug "Searching environment '#{environment.name}' for custom types."
118   inputs = []
119   environment.modules.each do |mod|
120     directory = File.join(Puppet::Util::Autoload.cleanpath(mod.plugin_directory), 'puppet', 'type')
121     unless Puppet::FileSystem.exist?(directory)
122       Puppet.debug "Skipping '#{mod.name}' module because it contains no custom types."
123       next
124     end
125 
126     Puppet.debug "Searching '#{mod.name}' module for custom types."
127     Dir.glob("#{directory}/*.rb") do |file|
128       next unless Puppet::FileSystem.file?(file)
129       Puppet.debug "Found custom type source file '#{file}'."
130       inputs << Input.new(mod.path, file, format)
131     end
132   end
133 
134   # Sort the inputs by path
135   inputs.sort_by! { |input| input.path }
136 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
151 def self.generate(inputs, outputdir = nil, force = false)
152   # remove files for non existing inputs
153   unless outputdir.nil?
154     filenames_to_keep = inputs.map {|i| i.output_name }
155     existing_files = Puppet::FileSystem.children(outputdir).map {|f| Puppet::FileSystem.basename(f) }
156     files_to_remove = existing_files - filenames_to_keep
157     files_to_remove.each do |f|
158       Puppet::FileSystem.unlink(File.join(outputdir, f))
159     end
160     Puppet.notice(_("Removed output '%{files_to_remove}' for non existing inputs") % { files_to_remove: files_to_remove }) unless files_to_remove.empty?
161   end
162 
163   if inputs.empty?
164     Puppet.notice _('No custom types were found.')
165     return nil
166   end
167 
168   templates = {}
169   templates.default_proc = lambda { |hash, key|
170     raise _("template was not found at '%{key}'.") % { key: key } unless Puppet::FileSystem.file?(key)
171     template = Puppet::Util.create_erb(File.read(key))
172     template.filename = key
173     template
174   }
175 
176   up_to_date = true
177   @bad_input = false
178 
179   Puppet.notice _('Generating Puppet resource types.')
180   inputs.each do |input|
181     if !force && input.up_to_date?(outputdir)
182       Puppet.debug "Skipping '#{input}' because it is up-to-date."
183       next
184     end
185 
186     up_to_date = false
187 
188     type_name = input.type_name
189     Puppet.debug "Loading custom type '#{type_name}' in '#{input}'."
190     begin
191       require input.path
192     rescue SystemExit
193       raise
194     rescue Exception => e
195       # Log the exception and move on to the next input
196       @bad_input = true
197       Puppet.log_exception(e, _("Failed to load custom type '%{type_name}' from '%{input}': %{message}") % { type_name: type_name, input: input, message: e.message })
198       next
199     end
200 
201     # HACK: there's no way to get a type without loading it (sigh); for now, just get the types hash directly
202     types ||= Puppet::Type.instance_variable_get('@types')
203 
204     # Assume the type follows the naming convention
205     type = types[type_name]
206     unless type
207       Puppet.err _("Custom type '%{type_name}' was not defined in '%{input}'.") % { type_name: type_name, input: input }
208       next
209     end
210 
211     # Create the model
212     begin
213       model = Models::Type::Type.new(type)
214     rescue Exception => e
215       @bad_input = true
216       # Move on to the next input
217       Puppet.log_exception(e, "#{input}: #{e.message}")
218       next
219     end
220 
221     # Render the template
222     begin
223       result = model.render(templates[input.template_path])
224     rescue Exception => e
225       @bad_input = true
226       Puppet.log_exception(e)
227       raise
228     end
229 
230     # Write the output file
231     begin
232       effective_output_path = input.effective_output_path(outputdir)
233       Puppet.notice _("Generating '%{effective_output_path}' using '%{format}' format.") % { effective_output_path: effective_output_path, format: input.format }
234       FileUtils.mkdir_p(File.dirname(effective_output_path))
235       Puppet::FileSystem.open(effective_output_path, nil, 'w:UTF-8') do |file|
236         file.write(result)
237       end
238     rescue Exception => e
239       @bad_input = true
240       Puppet.log_exception(e, _("Failed to generate '%{effective_output_path}': %{message}") % { effective_output_path: effective_output_path, message: e.message })
241       # Move on to the next input
242       next
243     end
244   end
245 
246   Puppet.notice _('No files were generated because all inputs were up-to-date.') if up_to_date
247 end