Class: Puppet::Generate::Type

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/generate/type.rb

Overview

Reponsible for generating type definitions in Puppet

Defined Under Namespace

Classes: Input

Class Method Summary collapse

Class Method Details

.find_inputs(format = :pcore, environment = Puppet.lookup(:current_environment)) ⇒ Array<Input>

Finds the inputs for the generator.

Parameters:

  • format (Symbol) (defaults to: :pcore)

    The format to use.

  • environment (Puppet::Node::Environment) (defaults to: Puppet.lookup(:current_environment))

    The environment to search for inputs. Defaults to the current environment.

Returns:

  • (Array<Input>)

    Returns the array of inputs.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/puppet/generate/type.rb', line 115

def self.find_inputs(format = :pcore, environment = Puppet.lookup(:current_environment))
  Puppet.debug "Searching environment '#{environment.name}' for custom types."
  inputs = []
  environment.modules.each do |mod|
    directory = File.join(Puppet::Util::Autoload.cleanpath(mod.plugin_directory), 'puppet', 'type')
    unless Puppet::FileSystem.exist?(directory)
      Puppet.debug "Skipping '#{mod.name}' module because it contains no custom types."
      next
    end

    Puppet.debug "Searching '#{mod.name}' module for custom types."
    Dir.glob("#{directory}/*.rb") do |file|
      next unless Puppet::FileSystem.file?(file)
      Puppet.debug "Found custom type source file '#{file}'."
      inputs << Input.new(mod.path, file, format)
    end
  end

  # Sort the inputs by path
  inputs.sort_by! { |input| input.path }
end

.generate(inputs, outputdir = nil, force = false) ⇒ void

This method returns an undefined value.

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.

Parameters:

  • inputs (Array<Input>)

    The inputs to generate files for.

  • outputdir (String, nil) (defaults to: nil)

    the outputdir where all output should be generated, or nil if next to input

  • force (Boolean) (defaults to: false)

    True to force the generation of the output files (skip up-to-date checks) or false if not.



147
148
149
150
151
152
153
154
155
156
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
186
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/puppet/generate/type.rb', line 147

def self.generate(inputs, outputdir = nil, force = false)
  # remove files for non existing inputs
  unless outputdir.nil?
    filenames_to_keep = inputs.map {|i| i.output_name }
    existing_files = Puppet::FileSystem.children(outputdir).map {|f| Puppet::FileSystem.basename(f) }
    files_to_remove = existing_files - filenames_to_keep
    files_to_remove.each do |f|
      Puppet::FileSystem.unlink(File.join(outputdir, f))
    end
    Puppet.notice(_("Removed output '%{files_to_remove}' for non existing inputs") % { files_to_remove: files_to_remove }) unless files_to_remove.empty?
  end

  if inputs.empty?
    Puppet.notice _('No custom types were found.')
    return nil
  end

  templates = {}
  templates.default_proc = lambda { |hash, key|
    raise _("template was not found at '%{key}'.") % { key: key } unless Puppet::FileSystem.file?(key)
    template = ERB.new(File.read(key), nil, '-')
    template.filename = key
    template
  }

  up_to_date = true
  Puppet.notice _('Generating Puppet resource types.')
  inputs.each do |input|
    if !force && input.up_to_date?(outputdir)
      Puppet.debug "Skipping '#{input}' because it is up-to-date."
      next
    end

    up_to_date = false

    type_name = input.type_name
    Puppet.debug "Loading custom type '#{type_name}' in '#{input}'."
    begin
      require input.path
    rescue SystemExit
      raise
    rescue Exception => e
      # Log the exception and move on to the next input
      Puppet.log_exception(e, _("Failed to load custom type '%{type_name}' from '%{input}': %{message}") % { type_name: type_name, input: input, message: e.message })
      next
    end

    # HACK: there's no way to get a type without loading it (sigh); for now, just get the types hash directly
    types ||= Puppet::Type.instance_variable_get('@types')

    # Assume the type follows the naming convention
    unless type = types[type_name]
      Puppet.err _("Custom type '%{type_name}' was not defined in '%{input}'.") % { type_name: type_name, input: input }
      next
    end

    # Create the model
    begin
      model = Models::Type::Type.new(type)
    rescue Exception => e
      # Move on to the next input
      Puppet.log_exception(e, "#{input}: #{e.message}")
      next
    end

    # Render the template
    begin
      result = model.render(templates[input.template_path])
    rescue Exception => e
      Puppet.log_exception(e)
      raise
    end

    # Write the output file
    begin
      effective_output_path = input.effective_output_path(outputdir)
      Puppet.notice _("Generating '%{effective_output_path}' using '%{format}' format.") % { effective_output_path: effective_output_path, format: input.format }
      FileUtils.mkdir_p(File.dirname(effective_output_path))
      Puppet::FileSystem.open(effective_output_path, nil, 'w:UTF-8') do |file|
        file.write(result)
      end
    rescue Exception => e
      Puppet.log_exception(e, _("Failed to generate '%{effective_output_path}': %{message}") % { effective_output_path: effective_output_path, message: e.message })
      # Move on to the next input
      next
    end
  end

  Puppet.notice _('No files were generated because all inputs were up-to-date.') if up_to_date
end