pdk 1.17.0 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +71 -2
- data/lib/pdk/cli/convert.rb +7 -9
- data/lib/pdk/cli/new/class.rb +2 -1
- data/lib/pdk/cli/new/defined_type.rb +2 -1
- data/lib/pdk/cli/new/provider.rb +2 -1
- data/lib/pdk/cli/new/task.rb +2 -1
- data/lib/pdk/cli/new/test.rb +2 -1
- data/lib/pdk/cli/new/transport.rb +2 -1
- data/lib/pdk/cli/remove/config.rb +80 -0
- data/lib/pdk/cli/remove.rb +20 -0
- data/lib/pdk/cli/set/config.rb +119 -0
- data/lib/pdk/cli/set.rb +20 -0
- data/lib/pdk/cli/update.rb +6 -8
- data/lib/pdk/cli/util/update_manager_printer.rb +82 -0
- data/lib/pdk/cli/util.rb +1 -0
- data/lib/pdk/cli.rb +2 -0
- data/lib/pdk/config.rb +96 -13
- data/lib/pdk/context.rb +8 -5
- data/lib/pdk/generate/defined_type.rb +25 -32
- data/lib/pdk/generate/module.rb +11 -10
- data/lib/pdk/generate/provider.rb +16 -65
- data/lib/pdk/generate/puppet_class.rb +25 -31
- data/lib/pdk/generate/puppet_object.rb +83 -187
- data/lib/pdk/generate/resource_api_object.rb +55 -0
- data/lib/pdk/generate/task.rb +28 -46
- data/lib/pdk/generate/transport.rb +21 -75
- data/lib/pdk/generate.rb +1 -0
- data/lib/pdk/module/convert.rb +41 -23
- data/lib/pdk/module/release.rb +1 -1
- data/lib/pdk/module/update.rb +6 -10
- data/lib/pdk/module/update_manager.rb +7 -0
- data/lib/pdk/module.rb +0 -1
- data/lib/pdk/template/fetcher/git.rb +85 -0
- data/lib/pdk/template/fetcher/local.rb +28 -0
- data/lib/pdk/template/fetcher.rb +98 -0
- data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +116 -0
- data/lib/pdk/template/renderer/v1/renderer.rb +132 -0
- data/lib/pdk/template/renderer/v1/template_file.rb +102 -0
- data/lib/pdk/template/renderer/v1.rb +25 -0
- data/lib/pdk/template/renderer.rb +96 -0
- data/lib/pdk/template/template_dir.rb +67 -0
- data/lib/pdk/template.rb +59 -0
- data/lib/pdk/tests/unit.rb +5 -0
- data/lib/pdk/util/json_finder.rb +84 -0
- data/lib/pdk/util/puppet_strings.rb +3 -3
- data/lib/pdk/util/template_uri.rb +4 -6
- data/lib/pdk/util.rb +4 -35
- data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -0
- data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -0
- data/lib/pdk/validate/invokable_validator.rb +2 -3
- data/lib/pdk/validate/validator.rb +7 -0
- data/lib/pdk/validate/validator_group.rb +1 -0
- data/lib/pdk/validate.rb +17 -10
- data/lib/pdk/version.rb +1 -1
- data/lib/pdk.rb +1 -1
- data/locales/pdk.pot +356 -228
- metadata +33 -12
- data/lib/pdk/module/template_dir/base.rb +0 -268
- data/lib/pdk/module/template_dir/git.rb +0 -91
- data/lib/pdk/module/template_dir/local.rb +0 -21
- data/lib/pdk/module/template_dir.rb +0 -115
- data/lib/pdk/template_file.rb +0 -96
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'pdk'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module Template
|
5
|
+
module Renderer
|
6
|
+
module V1
|
7
|
+
# The old templating code in the PDK passed through a TemplateDir object. This class mimics the methods
|
8
|
+
# of that old class so that existing custom templates will still function with the newer refactor templating code.
|
9
|
+
# Methods which have no use in custom templates exist but do no nothing, for example `def render; end`
|
10
|
+
#
|
11
|
+
# @see https://raw.githubusercontent.com/puppetlabs/pdk/4ffd58062c77ad1e54d2fe16b16015f7207bcee8/lib/pdk/module/template_dir/base.rb
|
12
|
+
# :nocov: This class is tested in the packaging and acceptance testing suites
|
13
|
+
class LegacyTemplateDir
|
14
|
+
attr_accessor :module_metadata
|
15
|
+
attr_reader :uri
|
16
|
+
|
17
|
+
def initialize(context, uri, path, module_metadata = {})
|
18
|
+
@uri = uri
|
19
|
+
@module_metadata = module_metadata
|
20
|
+
@context = context
|
21
|
+
@path = path
|
22
|
+
end
|
23
|
+
|
24
|
+
def metadata; end
|
25
|
+
|
26
|
+
def render; end
|
27
|
+
|
28
|
+
def object_template_for; end
|
29
|
+
|
30
|
+
def object_config
|
31
|
+
config_for(nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Generate a hash of data to be used when rendering the specified
|
35
|
+
# template.
|
36
|
+
#
|
37
|
+
# @param dest_path [String] The destination path of the file that the
|
38
|
+
# data is for, relative to the root of the module.
|
39
|
+
#
|
40
|
+
# @return [Hash] The data that will be available to the template via the
|
41
|
+
# `@configs` instance variable.
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
def config_for(dest_path, sync_config_path = nil)
|
45
|
+
require 'pdk/util'
|
46
|
+
require 'pdk/analytics'
|
47
|
+
|
48
|
+
module_root = PDK::Util.module_root
|
49
|
+
sync_config_path ||= File.join(module_root, '.sync.yml') unless module_root.nil?
|
50
|
+
config_path = File.join(@path, 'config_defaults.yml')
|
51
|
+
|
52
|
+
if @config.nil?
|
53
|
+
require 'deep_merge'
|
54
|
+
conf_defaults = read_config(config_path)
|
55
|
+
@sync_config = read_config(sync_config_path) unless sync_config_path.nil?
|
56
|
+
@config = conf_defaults
|
57
|
+
@config.deep_merge!(@sync_config, knockout_prefix: '---') unless @sync_config.nil?
|
58
|
+
end
|
59
|
+
file_config = @config.fetch(:global, {})
|
60
|
+
file_config['module_metadata'] = @module_metadata
|
61
|
+
file_config.merge!(@config.fetch(dest_path, {})) unless dest_path.nil?
|
62
|
+
file_config.merge!(@config).tap do |c|
|
63
|
+
if uri.default?
|
64
|
+
file_value = if c['unmanaged']
|
65
|
+
'unmanaged'
|
66
|
+
elsif c['delete']
|
67
|
+
'deleted'
|
68
|
+
elsif @sync_config && @sync_config.key?(dest_path)
|
69
|
+
'customized'
|
70
|
+
else
|
71
|
+
'default'
|
72
|
+
end
|
73
|
+
|
74
|
+
PDK.analytics.event('TemplateDir', 'file', label: dest_path, value: file_value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Generates a hash of data from a given yaml file location.
|
80
|
+
#
|
81
|
+
# @param loc [String] The path of the yaml config file.
|
82
|
+
#
|
83
|
+
# @warn If the specified path is not a valid yaml file. Returns an empty Hash
|
84
|
+
# if so.
|
85
|
+
#
|
86
|
+
# @return [Hash] The data that has been read in from the given yaml file.
|
87
|
+
#
|
88
|
+
# @api private
|
89
|
+
def read_config(loc)
|
90
|
+
if PDK::Util::Filesystem.file?(loc) && PDK::Util::Filesystem.readable?(loc)
|
91
|
+
require 'yaml'
|
92
|
+
|
93
|
+
begin
|
94
|
+
YAML.safe_load(PDK::Util::Filesystem.read_file(loc), [], [], true)
|
95
|
+
rescue Psych::SyntaxError => e
|
96
|
+
PDK.logger.warn _("'%{file}' is not a valid YAML file: %{problem} %{context} at line %{line} column %{column}") % {
|
97
|
+
file: loc,
|
98
|
+
problem: e.problem,
|
99
|
+
context: e.context,
|
100
|
+
line: e.line,
|
101
|
+
column: e.column,
|
102
|
+
}
|
103
|
+
{}
|
104
|
+
end
|
105
|
+
else
|
106
|
+
{}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def template_path(_uri); end
|
111
|
+
end
|
112
|
+
# :nocov:
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'pdk'
|
2
|
+
require 'pdk/template/renderer'
|
3
|
+
|
4
|
+
module PDK
|
5
|
+
module Template
|
6
|
+
module Renderer
|
7
|
+
module V1
|
8
|
+
class Renderer < PDK::Template::Renderer::AbstractRenderer
|
9
|
+
# @see PDK::Template::Renderer::AbstractRenderer.render
|
10
|
+
def render(template_type, _name, options = {})
|
11
|
+
render_module(options) { |*args| yield(*args) } if template_type == PDK::Template::MODULE_TEMPLATE_TYPE
|
12
|
+
end
|
13
|
+
|
14
|
+
# @see PDK::Template::Renderer::AbstractRenderer.has_single_item?
|
15
|
+
def has_single_item?(item_path) # rubocop:disable Naming/PredicateName
|
16
|
+
PDK::Util::Filesystem.exist?(single_item_path(item_path))
|
17
|
+
end
|
18
|
+
|
19
|
+
# @see PDK::Template::Renderer::AbstractRenderer.render_single_item
|
20
|
+
def render_single_item(relative_file_path, template_data_hash)
|
21
|
+
template_file = single_item_path(relative_file_path)
|
22
|
+
return nil unless PDK::Util::Filesystem.file?(template_file) && PDK::Util::Filesystem.readable?(template_file)
|
23
|
+
|
24
|
+
PDK.logger.debug(_("Rendering '%{template}'...") % { template: template_file })
|
25
|
+
new_template_file(template_file, template_data_hash).render
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the full path for a single item
|
29
|
+
#
|
30
|
+
# @param item_path [String] The path of the single item to render
|
31
|
+
# @return [String]
|
32
|
+
# @api private
|
33
|
+
#:nocov:
|
34
|
+
def single_item_path(item_path)
|
35
|
+
File.join(template_root, 'object_templates', item_path)
|
36
|
+
end
|
37
|
+
#:nocov:
|
38
|
+
|
39
|
+
# Helper method used during testing
|
40
|
+
#:nocov:
|
41
|
+
# @api private
|
42
|
+
def new_template_file(template_file, template_data_hash)
|
43
|
+
TemplateFile.new(template_file, template_data_hash)
|
44
|
+
end
|
45
|
+
#:nocov:
|
46
|
+
|
47
|
+
# Helper method used during testing
|
48
|
+
#:nocov:
|
49
|
+
# @api private
|
50
|
+
def new_legacy_template_dir(context, uri, path, module_metadata = {})
|
51
|
+
LegacyTemplateDir.new(context, uri, path, module_metadata)
|
52
|
+
end
|
53
|
+
#:nocov:
|
54
|
+
|
55
|
+
# Renders a new module
|
56
|
+
#
|
57
|
+
# @param options [Hash{Object => Object}] A list of options to pass through to the renderer. See PDK::Template::TemplateDir helper methods for other options
|
58
|
+
# @see #render
|
59
|
+
# @api private
|
60
|
+
#:nocov: This is tested in acceptance and packaging tests
|
61
|
+
def render_module(options = {})
|
62
|
+
require 'pdk/template/renderer/v1/template_file'
|
63
|
+
|
64
|
+
moduleroot_dir = File.join(template_root, 'moduleroot')
|
65
|
+
moduleroot_init = File.join(template_root, 'moduleroot_init')
|
66
|
+
|
67
|
+
dirs = [moduleroot_dir]
|
68
|
+
dirs << moduleroot_init if options[:include_first_time]
|
69
|
+
|
70
|
+
legacy_template_dir = new_legacy_template_dir(context, template_uri, template_root, options[:module_metadata] || {})
|
71
|
+
|
72
|
+
files_in_template(dirs).each do |template_file, template_loc|
|
73
|
+
template_file = template_file.to_s
|
74
|
+
PDK.logger.debug(_("Rendering '%{template}'...") % { template: template_file })
|
75
|
+
dest_path = template_file.sub(%r{\.erb\Z}, '')
|
76
|
+
config = legacy_template_dir.config_for(dest_path)
|
77
|
+
|
78
|
+
dest_status = if template_loc.start_with?(moduleroot_init)
|
79
|
+
:init
|
80
|
+
else
|
81
|
+
:manage
|
82
|
+
end
|
83
|
+
|
84
|
+
if config['unmanaged']
|
85
|
+
dest_status = :unmanage
|
86
|
+
elsif config['delete']
|
87
|
+
dest_status = :delete
|
88
|
+
else
|
89
|
+
begin
|
90
|
+
dest_content = new_template_file(File.join(template_loc, template_file), configs: config, template_dir: legacy_template_dir).render
|
91
|
+
rescue => error
|
92
|
+
error_msg = _(
|
93
|
+
"Failed to render template '%{template}'\n" \
|
94
|
+
'%{exception}: %{message}',
|
95
|
+
) % { template: template_file, exception: error.class, message: error.message }
|
96
|
+
raise PDK::CLI::FatalError, error_msg
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
yield dest_path, dest_content, dest_status
|
101
|
+
end
|
102
|
+
end
|
103
|
+
#:nocov:
|
104
|
+
|
105
|
+
# Returns all files in the given template directories
|
106
|
+
#
|
107
|
+
# @param dirs [Array[String]] Directories to search in
|
108
|
+
# @param glob_suffix [Array[String]] File glob to use when searching for files. Defaults to ['**', '*']
|
109
|
+
#
|
110
|
+
# @return [Hash{String => String}] Key is the template file relative path and the value is the absolute path to the template directory
|
111
|
+
# @api private
|
112
|
+
def files_in_template(dirs, glob_suffix = ['**', '*'])
|
113
|
+
temp_paths = []
|
114
|
+
dirlocs = []
|
115
|
+
dirs.each do |dir|
|
116
|
+
raise ArgumentError, _("The directory '%{dir}' doesn't exist") % { dir: dir } unless PDK::Util::Filesystem.directory?(dir)
|
117
|
+
temp_paths += PDK::Util::Filesystem.glob(File.join(dir, *glob_suffix), File::FNM_DOTMATCH).select do |template_path|
|
118
|
+
if PDK::Util::Filesystem.file?(template_path) && !PDK::Util::Filesystem.symlink?(template_path)
|
119
|
+
dirlocs << dir
|
120
|
+
end
|
121
|
+
end
|
122
|
+
temp_paths.map do |template_path|
|
123
|
+
template_path.sub!(%r{\A#{Regexp.escape(dir)}#{Regexp.escape(File::SEPARATOR)}}, '')
|
124
|
+
end
|
125
|
+
end
|
126
|
+
Hash[temp_paths.zip dirlocs]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'pdk'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module PDK
|
5
|
+
module Template
|
6
|
+
module Renderer
|
7
|
+
module V1
|
8
|
+
class TemplateFile < OpenStruct
|
9
|
+
# Initialises the TemplateFile object with the path to the template file
|
10
|
+
# and the data to be used when rendering the template.
|
11
|
+
#
|
12
|
+
# @param template_file [String] The path on disk to the template file.
|
13
|
+
# @param data [Hash{Symbol => Object}] The data that should be provided to
|
14
|
+
# the template when rendering.
|
15
|
+
# @option data [Object] :configs The value of this key will be provided to
|
16
|
+
# the template as an instance variable `@configs` in order to maintain
|
17
|
+
# compatibility with modulesync.
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
def initialize(template_file, data = {})
|
21
|
+
@template_file = template_file
|
22
|
+
|
23
|
+
if data.key?(:configs)
|
24
|
+
@configs = data[:configs]
|
25
|
+
end
|
26
|
+
|
27
|
+
super(data)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Renders the template by calling the appropriate engine based on the file
|
31
|
+
# extension.
|
32
|
+
#
|
33
|
+
# If the template has an `.erb` extension, the content of the template
|
34
|
+
# file will be treated as an ERB template. All other extensions are treated
|
35
|
+
# as plain text.
|
36
|
+
#
|
37
|
+
# @return [String] The rendered template
|
38
|
+
#
|
39
|
+
# @raise (see #template_content)
|
40
|
+
#
|
41
|
+
# @api public
|
42
|
+
def render
|
43
|
+
case File.extname(@template_file)
|
44
|
+
when '.erb'
|
45
|
+
render_erb
|
46
|
+
else
|
47
|
+
render_plain
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def config_for(path)
|
52
|
+
return unless respond_to?(:template_dir)
|
53
|
+
|
54
|
+
template_dir.config_for(path)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Reads the content of the template file into memory.
|
60
|
+
#
|
61
|
+
# @return [String] The content of the template file.
|
62
|
+
#
|
63
|
+
# @raise [ArgumentError] If the template file does not exist or can not be
|
64
|
+
# read.
|
65
|
+
#
|
66
|
+
# @api private
|
67
|
+
def template_content
|
68
|
+
if PDK::Util::Filesystem.file?(@template_file) && PDK::Util::Filesystem.readable?(@template_file)
|
69
|
+
return PDK::Util::Filesystem.read_file(@template_file)
|
70
|
+
end
|
71
|
+
|
72
|
+
raise ArgumentError, _("'%{template}' is not a readable file") % { template: @template_file }
|
73
|
+
end
|
74
|
+
|
75
|
+
# Renders the content of the template file as an ERB template.
|
76
|
+
#
|
77
|
+
# @return [String] The rendered template.
|
78
|
+
#
|
79
|
+
# @raise (see #template_content)
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
def render_erb
|
83
|
+
renderer = ERB.new(template_content, nil, '-')
|
84
|
+
renderer.filename = @template_file
|
85
|
+
renderer.result(binding)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Renders the content of the template file as plain text.
|
89
|
+
#
|
90
|
+
# @return [String] The rendered template.
|
91
|
+
#
|
92
|
+
# @raise (see #template_content)
|
93
|
+
#
|
94
|
+
# @api private
|
95
|
+
def render_plain
|
96
|
+
template_content
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'pdk'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module Template
|
5
|
+
module Renderer
|
6
|
+
module V1
|
7
|
+
autoload :LegacyTemplateDir, 'pdk/template/renderer/v1/legacy_template_dir'
|
8
|
+
autoload :Renderer, 'pdk/template/renderer/v1/renderer'
|
9
|
+
autoload :TemplateFile, 'pdk/template/renderer/v1/template_file'
|
10
|
+
|
11
|
+
# Whether the template directory and context are valid for the V1 renderer
|
12
|
+
# @see PDK::Template::Renderer.instance
|
13
|
+
def self.compatible?(template_root, _context)
|
14
|
+
%w[moduleroot moduleroot_init].all? { |dir| PDK::Util::Filesystem.directory?(File.join(template_root, dir)) }
|
15
|
+
end
|
16
|
+
|
17
|
+
# Creates an instance of the V1 Renderer
|
18
|
+
# @see PDK::Template::Renderer.instance
|
19
|
+
def self.instance(template_root, template_uri, context)
|
20
|
+
PDK::Template::Renderer::V1::Renderer.new(template_root, template_uri, context)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'pdk'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module Template
|
5
|
+
module Renderer
|
6
|
+
autoload :V1, 'pdk/template/renderer/v1'
|
7
|
+
|
8
|
+
# Returns the most appropriate renderer for the given Template Directory and Context
|
9
|
+
#
|
10
|
+
# @param template_root [String] The path to where the template exists on disk
|
11
|
+
# @param template_uri [PDK::Util::TemplateUri] A URI which points to the source location of the Template
|
12
|
+
# @param context [PDK::Context] The context in which the redering will occur in
|
13
|
+
#
|
14
|
+
# @return [AbstractRenderer, nil] An instance of an AbstractRenderer subclass. Returns nil if no renderer could be found
|
15
|
+
def self.instance(template_uri, template_root, context)
|
16
|
+
return V1.instance(template_root, template_uri, context) if V1.compatible?(template_root, context)
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# An abstract class which all Template Renderers should subclass and implement. This class is responsible for
|
21
|
+
# rendering a template or a single item within a template directory
|
22
|
+
#
|
23
|
+
# To implement a new renderer:
|
24
|
+
# 1. Create a new class which subclasses AbstractRenderer and implements the public methods (has_single_item?, render and render_single_item)
|
25
|
+
# 2. Add class methods .compatible? and .instance which are used to detect if a template is compatible with the new renderer
|
26
|
+
# and create an instance of the new renderer respectively
|
27
|
+
# 3. Update the PDK::Template::Renderer.instance method to detect and create an instance of the new renderer (using the .compatible? and .instance methods
|
28
|
+
# created in step 2).
|
29
|
+
#
|
30
|
+
# See the PDK::Template::Renderer::V1 module and classes for an example on how to to this.
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
# @abstract
|
34
|
+
class AbstractRenderer
|
35
|
+
# @return [String] The path to where the template exists on disk
|
36
|
+
attr_reader :template_root
|
37
|
+
|
38
|
+
# @return [PDK::Util::TemplateURI] The URI which points to the source location of the Template
|
39
|
+
attr_reader :template_uri
|
40
|
+
|
41
|
+
# @return context [PDK::Context] The context in which the redering will occur in
|
42
|
+
attr_reader :context
|
43
|
+
|
44
|
+
# @param template_root [String] The path to where the template exists on disk
|
45
|
+
# @param template_uri [PDK::Util::TemplateUri] A URI which points to the source location of the Template
|
46
|
+
# @param context [PDK::Context] The context in which the redering will occur in
|
47
|
+
def initialize(template_root, template_uri, context)
|
48
|
+
@template_root = template_root
|
49
|
+
@template_uri = template_uri
|
50
|
+
@context = context
|
51
|
+
end
|
52
|
+
|
53
|
+
# Whether the renderer supports rendering the a single item called 'item_path'. This is used when rendering things like a new Task or a new Puppet Classes.
|
54
|
+
# Rendering a single item is different than redering an entire project, like a entire Puppet Module or Control Repo.
|
55
|
+
#
|
56
|
+
# @param item_path [String] The path to the item to check
|
57
|
+
#
|
58
|
+
# @return [Boolean] Whether the renderer can render the item
|
59
|
+
# @abstract
|
60
|
+
def has_single_item?(_item_path) # rubocop:disable Naming/PredicateName Changing the method name to `single_item?` will convey the wrong intent
|
61
|
+
false
|
62
|
+
end
|
63
|
+
|
64
|
+
# Loop through the files in the template type, yielding each rendered file to the supplied block.
|
65
|
+
#
|
66
|
+
# @param template_type [PDK::Template::*_TEMPLATE_TYPE] The type of template to render
|
67
|
+
# @param name [String] The name to use in the rendering process
|
68
|
+
# @param options [Hash{Object => Object}] A list of options to pass through to the renderer. See PDK::Template::TemplateDir helper methods for other options
|
69
|
+
# @option options [Boolean] :include_first_time Whether to include "first time" items when rendering the project. While it is up to the renderer to implement this
|
70
|
+
# the expected behavior is that if the item already exists, it will not be rendererd again. Unlike normal items which
|
71
|
+
# are always rendered to keep them in-sync
|
72
|
+
#
|
73
|
+
# @yieldparam dest_path [String] The path of the destination file, relative to the root of the context.
|
74
|
+
# @yieldparam dest_content [String] The rendered content of the destination file.
|
75
|
+
# @yieldparam dest_status [Symbol] :unmanage, :delete, :init, :manage
|
76
|
+
#
|
77
|
+
# @see PDK::Template::TemplateDir.render
|
78
|
+
#
|
79
|
+
# @return [void]
|
80
|
+
# @abstract
|
81
|
+
def render(template_type, name, options = {}); end
|
82
|
+
|
83
|
+
# Render a single item and return the resulting string. This is used when rendering things like a new Task or a new Puppet Classes.
|
84
|
+
# Rendering a single item is different than redering an entire project, like a entire Puppet Module or Control Repo. This method is
|
85
|
+
# used in conjunction with .has_single_item?
|
86
|
+
#
|
87
|
+
# @param item_path [String] The path of the single item to render
|
88
|
+
# @param template_data_hash [Hash{Object => Object}] A hash of information which will be used in the rendering process
|
89
|
+
#
|
90
|
+
# @return [String, Nil] The rendered content, or nil of the file could not be rendered
|
91
|
+
# @abstract
|
92
|
+
def render_single_item(item_path, template_data_hash = {}); end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'pdk'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module PDK
|
5
|
+
module Template
|
6
|
+
# A helper class representing an already fetched template on disk, with an appropriate renderer instance.
|
7
|
+
# @see PDK::Template.with
|
8
|
+
class TemplateDir
|
9
|
+
# Creates an instance of TemplateDir object
|
10
|
+
# @see TemplateDir.new
|
11
|
+
def self.instance(uri, path, context, renderer = nil)
|
12
|
+
new(uri, path, context, renderer)
|
13
|
+
end
|
14
|
+
|
15
|
+
extend Forwardable
|
16
|
+
|
17
|
+
# Helper methods for rendering
|
18
|
+
def_delegators :@renderer, :render, :render_single_item, :has_single_item?
|
19
|
+
|
20
|
+
# @return [PDK::Util::TemplateURI] The URI which points to the source location of the Template
|
21
|
+
attr_accessor :uri
|
22
|
+
|
23
|
+
# @return [String] The path to where the template exists on disk
|
24
|
+
attr_accessor :path
|
25
|
+
|
26
|
+
# @return [Hash{String => String}] A hash of information about the template
|
27
|
+
attr_accessor :metadata
|
28
|
+
|
29
|
+
# @param template_uri [PDK::Util::TemplateUri] A URI which points to the source location of the Template
|
30
|
+
# @param path [String] The path to where the template exists on disk
|
31
|
+
# @param context [PDK::Context] The context in which the redering will occur in
|
32
|
+
# @param renderer [PDK::Template::Renderer::AbstractRenderer] The an instance of a rendering class. If nil, a renderer will be created that's appropriate for the template and context
|
33
|
+
def initialize(uri, path, context, renderer = nil)
|
34
|
+
@uri = uri
|
35
|
+
@path = path
|
36
|
+
@metadata = {}
|
37
|
+
|
38
|
+
@renderer = renderer.nil? ? Renderer.instance(uri, path, context) : renderer
|
39
|
+
raise _('Could not find a compatible template renderer for %{path}') % { path: path } if @renderer.nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
# Later additions may include Control Repo rendering, for example
|
43
|
+
#
|
44
|
+
# def render_control_repo(name, options = {})
|
45
|
+
# render(CONTROL_REPO_TEMPLATE_TYPE, name, options.merge(include_first_time: false)) { |*args| yield(*args) }
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# def render_new_control_repo(name, repo_metadata = {}, options = {})
|
49
|
+
# render(CONTROL_REPO_TEMPLATE_TYPE, name, options.merge(include_first_time: true, control_repo_metadata: repo_metadata)) { |*args| yield(*args) }
|
50
|
+
# end
|
51
|
+
#:nocov: These are just helper methods and are tested elsewhere.
|
52
|
+
|
53
|
+
# Render an existing module
|
54
|
+
# @see PDK::Template::Renderer::AbstractRenderer.render
|
55
|
+
def render_module(module_name, options = {})
|
56
|
+
@renderer.render(MODULE_TEMPLATE_TYPE, module_name, options.merge(include_first_time: false)) { |*args| yield(*args) }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Render a new module
|
60
|
+
# @see PDK::Template::Renderer::AbstractRenderer.render
|
61
|
+
def render_new_module(module_name, module_metadata = {}, options = {})
|
62
|
+
@renderer.render(MODULE_TEMPLATE_TYPE, module_name, options.merge(include_first_time: true, module_metadata: module_metadata)) { |*args| yield(*args) }
|
63
|
+
end
|
64
|
+
#:nocov:
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/pdk/template.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'pdk'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module Template
|
5
|
+
autoload :Fetcher, 'pdk/template/fetcher'
|
6
|
+
autoload :Renderer, 'pdk/template/renderer'
|
7
|
+
autoload :TemplateDir, 'pdk/template/template_dir'
|
8
|
+
|
9
|
+
MODULE_TEMPLATE_TYPE = :module_template
|
10
|
+
|
11
|
+
# Creates a TemplateDir object with the path or URL to the template
|
12
|
+
# and the block of code to run to be run while the template is available.
|
13
|
+
#
|
14
|
+
# The template directory is only guaranteed to be available on disk
|
15
|
+
# within the scope of the block passed to this method.
|
16
|
+
#
|
17
|
+
# @param uri [PDK::Util::TemplateURI] The path to a directory to use as the
|
18
|
+
# template or a URI to a git repository.
|
19
|
+
#
|
20
|
+
# @param context [PDK::Context::AbstractContext] The context in which the template will render to
|
21
|
+
#
|
22
|
+
# @yieldparam self [PDK::Template::TemplateDir] The initialised object with
|
23
|
+
# the template available on disk.
|
24
|
+
#
|
25
|
+
# @example Using a git repository as a template
|
26
|
+
# PDK::Template.with('https://github.com/puppetlabs/pdk-templates') do |t|
|
27
|
+
# t.render_module('module, PDK.context) do |filename, content, status|
|
28
|
+
# File.open(filename, 'w') do |file|
|
29
|
+
# ...
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# @raise [ArgumentError] If no block is given to this method.
|
35
|
+
# @raise [PDK::CLI::FatalError]
|
36
|
+
# @raise [ArgumentError]
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
def self.with(uri, context)
|
40
|
+
unless block_given?
|
41
|
+
raise ArgumentError, _('%{class_name}.with must be passed a block.') % { class_name: name }
|
42
|
+
end
|
43
|
+
unless uri.is_a? PDK::Util::TemplateURI
|
44
|
+
raise ArgumentError, _('%{class_name}.with must be passed a PDK::Util::TemplateURI, got a %{uri_type}') % { uri_type: uri.class, class_name: name }
|
45
|
+
end
|
46
|
+
|
47
|
+
Fetcher.with(uri) do |fetcher|
|
48
|
+
template_dir = TemplateDir.instance(uri, fetcher.path, context)
|
49
|
+
template_dir.metadata = fetcher.metadata
|
50
|
+
|
51
|
+
template_type = uri.default? ? 'default' : 'custom'
|
52
|
+
PDK.analytics.event('TemplateDir', 'initialize', label: template_type)
|
53
|
+
|
54
|
+
yield template_dir
|
55
|
+
end
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/pdk/tests/unit.rb
CHANGED
@@ -89,6 +89,11 @@ module PDK
|
|
89
89
|
setup
|
90
90
|
|
91
91
|
tests = options[:tests]
|
92
|
+
# Due to how rake handles paths in the command line options, any backslashed path (Windows platforms) needs to be converted
|
93
|
+
# to forward slash. We can't use File.expand_path as the files aren't guaranteed to be on-disk
|
94
|
+
#
|
95
|
+
# Ref - https://github.com/puppetlabs/pdk/issues/828
|
96
|
+
tests.tr!('\\', '/') unless tests.nil?
|
92
97
|
|
93
98
|
environment = { 'CI_SPEC_OPTIONS' => '--format j' }
|
94
99
|
environment['PUPPET_GEM_VERSION'] = options[:puppet] if options[:puppet]
|