Class: PDK::Module::TemplateDir

Inherits:
Object
  • Object
show all
Defined in:
lib/pdk/module/templatedir.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path_or_url, module_metadata = {}, init = false) {|self| ... } ⇒ TemplateDir

Initialises the TemplateDir object with the path or URL to the template and the block of code to run to be run while the template is available.

The template directory is only guaranteed to be available on disk within the scope of the block passed to this method.

template or a URL to a git repository. Defaults to an empty Hash. the template available on disk.

the git binary is unavailable. the git clone operation fails.

Examples:

Using a git repository as a template

PDK::Module::TemplateDir.new('https://github.com/puppetlabs/pdk-templates') do |t|
  t.render do |filename, content|
    File.open(filename, 'w') do |file|
      file.write(content)
    end
  end
end

Parameters:

  • path_or_url (String)

    The path to a directory to use as the

  • module_metadata (Hash) (defaults to: {})

    A Hash containing the module metadata.

Yield Parameters:

Raises:



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/pdk/module/templatedir.rb', line 40

def initialize(path_or_url,  = {}, init = false)
  if File.directory?(path_or_url)
    @path = path_or_url
  else
    # If path_or_url isn't a directory on disk, we assume that it is
    # a remote git repository.

    # @todo When switching this over to using rugged, cache the cloned
    # template repo in `%AppData%` or `$XDG_CACHE_DIR` and update before
    # use.
    temp_dir = PDK::Util.make_tmpdir_name('pdk-templates')
    git_ref = (path_or_url == PDK::Util.default_template_url) ? PDK::Util.default_template_ref : 'origin/master'

    clone_result = PDK::Util::Git.git('clone', path_or_url, temp_dir)

    if clone_result[:exit_code].zero?
      reset_result = PDK::Util::Git.git('-C', temp_dir, 'reset', '--hard', git_ref)
      unless reset_result[:exit_code].zero?
        PDK.logger.error reset_result[:stdout]
        PDK.logger.error reset_result[:stderr]
        raise PDK::CLI::FatalError, _("Unable to set git repository '%{repo}' to ref:'%{ref}'.") % { repo: temp_dir, ref: git_ref }
      end
    else
      PDK.logger.error clone_result[:stdout]
      PDK.logger.error clone_result[:stderr]
      raise PDK::CLI::FatalError, _("Unable to clone git repository '%{repo}' to '%{dest}'.") % { repo: path_or_url, dest: temp_dir }
    end

    @path = PDK::Util.canonical_path(temp_dir)
    @repo = path_or_url
  end

  @init = init
  @moduleroot_dir = File.join(@path, 'moduleroot')
  @moduleroot_init = File.join(@path, 'moduleroot_init')
  @dirs = [@moduleroot_dir]
  @dirs << @moduleroot_init if @init
  @object_dir = File.join(@path, 'object_templates')
  validate_module_template!

  @module_metadata = 

  yield self
ensure
  # If we cloned a git repo to get the template, remove the clone once
  # we're done with it.
  if @repo
    FileUtils.remove_dir(@path)
  end
end

Class Method Details

.files_in_template(dirs) ⇒ Hash{String=>String}

Get a list of template files in the template directory.

value locations.

Returns:

  • (Hash{String=>String})

    A hash of key file names and



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/pdk/module/templatedir.rb', line 216

def self.files_in_template(dirs)
  temp_paths = []
  dirlocs = []
  dirs.each do |dir|
    raise ArgumentError, _("The directory '%{dir}' doesn't exist") % { dir: dir } unless Dir.exist?(dir)
    temp_paths += Dir.glob(File.join(dir, '**', '*'), File::FNM_DOTMATCH).select do |template_path|
      File.file?(template_path) && !File.symlink?(template_path)
      dirlocs << dir
    end
    temp_paths.map do |template_path|
      template_path.sub!(%r{\A#{Regexp.escape(dir)}#{Regexp.escape(File::SEPARATOR)}}, '')
    end
  end
  template_paths = Hash[temp_paths.zip dirlocs]
  template_paths.delete('.')
  template_paths.delete('spec')
  template_paths.delete('spec/.')
  template_paths
end

Instance Method Details

#config_for(dest_path, sync_config_path = nil) ⇒ Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Generate a hash of data to be used when rendering the specified template.

data is for, relative to the root of the module.

‘@configs` instance variable.

Parameters:

  • dest_path (String)

    The destination path of the file that the

Returns:

  • (Hash)

    The data that will be available to the template via the



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/pdk/module/templatedir.rb', line 246

def config_for(dest_path, sync_config_path = nil)
  module_root = PDK::Util.module_root
  sync_config_path ||= File.join(module_root, '.sync.yml') unless module_root.nil?
  config_path = File.join(@path, 'config_defaults.yml')

  if @config.nil?
    conf_defaults = read_config(config_path)
    sync_config = read_config(sync_config_path) unless sync_config_path.nil?
    @config = conf_defaults
    @config.deep_merge!(sync_config) unless sync_config.nil?
  end
  file_config = @config.fetch(:global, {})
  file_config['module_metadata'] = @module_metadata
  file_config.merge!(@config.fetch(dest_path, {})) unless dest_path.nil?
  file_config.merge!(@config)
end

#metadataHash{String => String}

Retrieve identifying metadata for the template.

For git repositories, this will return the URL to the repository and a reference to the HEAD.

Returns:

  • (Hash{String => String})

    A hash of identifying metadata.



99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/pdk/module/templatedir.rb', line 99

def 
  result = {
    'pdk-version' => PDK::Util::Version.version_string,
  }

  result['template-url'] = @repo ? @repo : @path

  ref_result = PDK::Util::Git.git('--git-dir', File.join(@path, '.git'), 'describe', '--all', '--long', '--always')
  result['template-ref'] = ref_result[:stdout].strip if ref_result[:exit_code].zero?

  result
end

#object_configHash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Generate a hash of data to be used when rendering object templates.

Read ‘config_defaults.yml` from the root of the template directory (if it exists) build a hash of values from the value of the `:global` key.

‘@configs` instance variable.

Returns:

  • (Hash)

    The data that will be available to the template via the



181
182
183
# File 'lib/pdk/module/templatedir.rb', line 181

def object_config
  config_for(nil)
end

#object_template_for(object_type) ⇒ Hash{Symbol => String}

Searches the template directory for template files that can be used to render files for the specified object type.

‘:defined_type`, `:fact`, etc).

template dir, otherwise ‘nil`. The returned hash can contain two keys, :object contains the path on disk to the template for the object, :spec contains the path on disk to the template for the object’s spec file (if available).

Parameters:

  • object_type (Symbol)

    The object type, e.g. (‘:class`,

Returns:

  • (Hash{Symbol => String})

    if the templates are available in the



156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/pdk/module/templatedir.rb', line 156

def object_template_for(object_type)
  object_path = File.join(@object_dir, "#{object_type}.erb")
  addon_path = File.join(@object_dir, "#{object_type}_addon.erb")
  spec_path = File.join(@object_dir, "#{object_type}_spec.erb")

  if File.file?(object_path) && File.readable?(object_path)
    result = { object: object_path }
    result[:addon] = addon_path if File.file?(addon_path) && File.readable?(addon_path)
    result[:spec] = spec_path if File.file?(spec_path) && File.readable?(spec_path)
    result
  else
    nil
  end
end

#read_config(loc) ⇒ Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Generates a hash of data from a given yaml file location.

if so.

Parameters:

  • loc (String)

    The path of the yaml config file.

Returns:

  • (Hash)

    The data that has been read in from the given yaml file.



273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/pdk/module/templatedir.rb', line 273

def read_config(loc)
  if File.file?(loc) && File.readable?(loc)
    begin
      YAML.safe_load(File.read(loc), [], [], true)
    rescue StandardError => e
      PDK.logger.warn(_("'%{file}' is not a valid YAML file: %{message}") % { file: config_path, message: e.message })
      {}
    end
  else
    {}
  end
end

#render {|dest_path, dest_content| ... } ⇒ void

This method returns an undefined value.

Loop through the files in the template, yielding each rendered file to the supplied block.

relative to the root of the module. destination file.

Yield Parameters:

  • dest_path (String)

    The path of the destination file,

  • dest_content (String)

    The rendered content of the

Raises:



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/pdk/module/templatedir.rb', line 125

def render
  PDK::Module::TemplateDir.files_in_template(@dirs).each do |template_file, template_loc|
    template_file = template_file.to_s
    PDK.logger.debug(_("Rendering '%{template}'...") % { template: template_file })
    dest_path = template_file.sub(%r{\.erb\Z}, '')
    begin
      dest_content = PDK::TemplateFile.new(File.join(template_loc, template_file), configs: config_for(dest_path)).render
    rescue => e
      error_msg = _(
        "Failed to render template '%{template}'\n" \
        '%{exception}: %{message}',
      ) % { template: template_file, exception: e.class, message: e.message }
      raise PDK::CLI::FatalError, error_msg
    end
    yield dest_path, dest_content
  end
end

#validate_module_template!void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Validate the content of the template directory.

a directory called ‘moduleroot’.

Raises:

  • (ArgumentError)

    If the specified path is not a directory.

  • (ArgumentError)

    If the template directory does not contain



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/pdk/module/templatedir.rb', line 194

def validate_module_template!
  unless File.directory?(@path)
    raise ArgumentError, _("The specified template '%{path}' is not a directory.") % { path: @path }
  end

  unless File.directory?(@moduleroot_dir)
    raise ArgumentError, _("The template at '%{path}' does not contain a 'moduleroot/' directory.") % { path: @path }
  end

  unless File.directory?(@moduleroot_init) # rubocop:disable Style/GuardClause
    # rubocop:disable Metrics/LineLength
    raise ArgumentError, _("The template at '%{path}' does not contain a 'moduleroot_init/' directory, which indicates you are using an older style of template. Before continuing please use the --template-url flag when running the pdk new commands to pass a new style template.") % { path: @path }
    # rubocop:enable Metrics/LineLength
  end
end