pdk 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +201 -0
- data/README.md +270 -0
- data/exe/pdk +5 -0
- data/lib/pdk.rb +8 -0
- data/lib/pdk/cli.rb +80 -0
- data/lib/pdk/cli/errors.rb +12 -0
- data/lib/pdk/cli/exec.rb +51 -0
- data/lib/pdk/cli/input.rb +28 -0
- data/lib/pdk/cli/new.rb +30 -0
- data/lib/pdk/cli/new/class.rb +45 -0
- data/lib/pdk/cli/new/module.rb +55 -0
- data/lib/pdk/cli/test.rb +23 -0
- data/lib/pdk/cli/tests/unit.rb +52 -0
- data/lib/pdk/cli/util/option_normalizer.rb +44 -0
- data/lib/pdk/cli/util/option_validator.rb +74 -0
- data/lib/pdk/cli/validate.rb +81 -0
- data/lib/pdk/generate.rb +3 -0
- data/lib/pdk/generators/module.rb +139 -0
- data/lib/pdk/generators/puppet_class.rb +51 -0
- data/lib/pdk/generators/puppet_object.rb +213 -0
- data/lib/pdk/i18n.rb +4 -0
- data/lib/pdk/logger.rb +25 -0
- data/lib/pdk/module/metadata.rb +88 -0
- data/lib/pdk/module/templatedir.rb +231 -0
- data/lib/pdk/report.rb +38 -0
- data/lib/pdk/template_file.rb +87 -0
- data/lib/pdk/tests/unit.rb +21 -0
- data/lib/pdk/util.rb +16 -0
- data/lib/pdk/validate.rb +12 -0
- data/lib/pdk/validators/base_validator.rb +14 -0
- data/lib/pdk/validators/metadata.rb +17 -0
- data/lib/pdk/validators/puppet_lint.rb +17 -0
- data/lib/pdk/validators/puppet_parser.rb +17 -0
- data/lib/pdk/validators/ruby_lint.rb +17 -0
- data/lib/pdk/version.rb +3 -0
- data/locales/config.yaml +21 -0
- data/locales/de/pdk.po +250 -0
- data/locales/pdk.pot +215 -0
- metadata +92 -12
@@ -0,0 +1,74 @@
|
|
1
|
+
module PDK
|
2
|
+
module CLI
|
3
|
+
module Util
|
4
|
+
class OptionValidator
|
5
|
+
def self.is_comma_separated_list?(list, options = {})
|
6
|
+
list =~ /^[\w\-]+(?:,[\w\-]+)+$/ ? true : false
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.enum(val, valid_entries, options = {})
|
10
|
+
vals = val.is_a?(Array) ? val : [val]
|
11
|
+
invalid_entries = vals.find_all { |e| !valid_entries.include?(e) }
|
12
|
+
|
13
|
+
unless invalid_entries.empty?
|
14
|
+
raise _("Error: the following values are invalid: %{invalid_entries}") % {invalid_entries: invalid_entries}
|
15
|
+
end
|
16
|
+
|
17
|
+
val
|
18
|
+
end
|
19
|
+
|
20
|
+
# Validate the module name against the regular expression in the
|
21
|
+
# documentation: https://docs.puppet.com/puppet/4.10/modules_fundamentals.html#allowed-module-names
|
22
|
+
def self.is_valid_module_name?(string)
|
23
|
+
!(string =~ /\A[a-z][a-z0-9_]*\Z/).nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
# Validate a Puppet namespace against the regular expression in the
|
27
|
+
# documentation: https://docs.puppet.com/puppet/4.10/lang_reserved.html#classes-and-defined-resource-types
|
28
|
+
def self.is_valid_namespace?(string)
|
29
|
+
return false if (string || '').split('::').last == 'init'
|
30
|
+
|
31
|
+
!(string =~ /\A([a-z][a-z0-9_]*)(::[a-z][a-z0-9_]*)*\Z/).nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
singleton_class.send(:alias_method, :is_valid_class_name?, :is_valid_namespace?)
|
35
|
+
singleton_class.send(:alias_method, :is_valid_defined_type_name?, :is_valid_namespace?)
|
36
|
+
|
37
|
+
# Validate that a class/defined type parameter matches the regular
|
38
|
+
# expression in the documentation: https://docs.puppet.com/puppet/4.10/lang_reserved.html#parameters
|
39
|
+
# The parameter should also not be a reserved word or overload
|
40
|
+
# a metaparameter.
|
41
|
+
def self.is_valid_param_name?(string)
|
42
|
+
reserved_words = %w{trusted facts server_facts title name}.freeze
|
43
|
+
metaparams = %w{alias audit before loglevel noop notify require schedule stage subscribe tag}.freeze
|
44
|
+
return false if reserved_words.include?(string) || metaparams.include?(string)
|
45
|
+
|
46
|
+
!(string =~ /\A[a-z][a-zA-Z0-9_]*\Z/).nil?
|
47
|
+
end
|
48
|
+
|
49
|
+
# Naive validation of a data type declaration. Extracts all the bare
|
50
|
+
# words and compares them against a list of known data types.
|
51
|
+
#
|
52
|
+
# @todo This prevents the use of dynamic data types like TypeReferences
|
53
|
+
# but that shouldn't be a problem for the current feature set. This
|
54
|
+
# should be replaced eventually by something better (or just call
|
55
|
+
# Puppet::Pops::Types::TypesParser)
|
56
|
+
def self.is_valid_data_type?(string)
|
57
|
+
valid_types = %w{
|
58
|
+
String Integer Float Numeric Boolean Array Hash Regexp Undef
|
59
|
+
Default Class Resource Scalar Collection Variant Data Pattern Enum
|
60
|
+
Tuple Struct Optional Catalogentry Type Any Callable NotUndef
|
61
|
+
}.freeze
|
62
|
+
|
63
|
+
string.scan(/\b(([a-zA-Z]+)(,|\[|\]|\Z))/) do |result|
|
64
|
+
type = result[1]
|
65
|
+
|
66
|
+
return false unless valid_types.include?(type)
|
67
|
+
end
|
68
|
+
|
69
|
+
true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'cri'
|
2
|
+
require 'pdk/cli/util/option_validator'
|
3
|
+
require 'pdk/report'
|
4
|
+
|
5
|
+
require 'pdk/validate'
|
6
|
+
|
7
|
+
module PDK
|
8
|
+
module CLI
|
9
|
+
class Validate
|
10
|
+
include PDK::CLI::Util
|
11
|
+
|
12
|
+
def self.command
|
13
|
+
@validate ||= Cri::Command.define do
|
14
|
+
name 'validate'
|
15
|
+
usage _("validate [options]")
|
16
|
+
summary _("Run static analysis tests.")
|
17
|
+
description _("Run metadata-json-lint, puppet parser validate, puppet-lint, or rubocop.")
|
18
|
+
|
19
|
+
flag nil, :list, _("list all available validators")
|
20
|
+
|
21
|
+
run do |opts, args, cmd|
|
22
|
+
validator_names = PDK::Validate.validators.map { |v| v.name }
|
23
|
+
validators = PDK::Validate.validators
|
24
|
+
targets = []
|
25
|
+
reports = nil
|
26
|
+
|
27
|
+
if opts[:list]
|
28
|
+
puts _("Available validators: %{validator_names}") % {validator_names: validator_names.join(', ')}
|
29
|
+
exit 0
|
30
|
+
end
|
31
|
+
|
32
|
+
if args[0]
|
33
|
+
# This may be a single validator, a list of validators, or a target.
|
34
|
+
if OptionValidator.is_comma_separated_list?(args[0])
|
35
|
+
# This is a comma separated list. Treat each item as a validator.
|
36
|
+
|
37
|
+
vals = OptionNormalizer.comma_separated_list_to_array(args[0])
|
38
|
+
validators = PDK::Validate.validators.find_all { |v| vals.include?(v.name) }
|
39
|
+
|
40
|
+
invalid = vals.find_all { |v| !validator_names.include?(v) }
|
41
|
+
invalid.each do |v|
|
42
|
+
PDK.logger.warn(_("Unknown validator '%{v}'. Available validators: %{validators}") % {v: v, validators: validator_names.join(', ')})
|
43
|
+
end
|
44
|
+
else
|
45
|
+
# This is a single item. Check if it's a known validator, or otherwise treat it as a target.
|
46
|
+
val = PDK::Validate.validators.find { |v| args[0] == v.name }
|
47
|
+
if val
|
48
|
+
validators = [val]
|
49
|
+
else
|
50
|
+
targets = [args[0]]
|
51
|
+
# We now know that no validators were passed, so let the user know we're using all of them by default.
|
52
|
+
PDK.logger.info(_("Running all available validators..."))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
else
|
56
|
+
PDK.logger.info(_("Running all available validators..."))
|
57
|
+
end
|
58
|
+
|
59
|
+
# Subsequent arguments are targets.
|
60
|
+
targets.concat(args[1..-1]) if args.length > 1
|
61
|
+
|
62
|
+
# Note: Reporting may be delegated to the validation tool itself.
|
63
|
+
if opts[:format]
|
64
|
+
reports = OptionNormalizer.report_formats(opts.fetch(:format))
|
65
|
+
end
|
66
|
+
|
67
|
+
options = targets.empty? ? {} : { :targets => targets }
|
68
|
+
validators.each do |validator|
|
69
|
+
result = validator.invoke(options)
|
70
|
+
if reports
|
71
|
+
reports.each do |r|
|
72
|
+
r.write(result)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/pdk/generate.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'etc'
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
require 'pdk'
|
6
|
+
require 'pdk/logger'
|
7
|
+
require 'pdk/module/metadata'
|
8
|
+
require 'pdk/module/templatedir'
|
9
|
+
require 'pdk/cli/exec'
|
10
|
+
require 'pdk/cli/input'
|
11
|
+
require 'pdk/util'
|
12
|
+
|
13
|
+
module PDK
|
14
|
+
module Generate
|
15
|
+
class Module
|
16
|
+
DEFAULT_TEMPLATE = 'https://github.com/puppetlabs/pdk-module-template'
|
17
|
+
|
18
|
+
def self.invoke(opts={})
|
19
|
+
defaults = {
|
20
|
+
'version' => '0.1.0',
|
21
|
+
'dependencies' => [
|
22
|
+
{ 'name' => 'puppetlabs-stdlib', 'version_requirement' => '>= 1.0.0' }
|
23
|
+
]
|
24
|
+
}
|
25
|
+
|
26
|
+
defaults['license'] = opts[:license] if opts.has_key? :license
|
27
|
+
target_dir = File.expand_path(opts[:target_dir])
|
28
|
+
|
29
|
+
if File.exists?(target_dir)
|
30
|
+
raise PDK::CLI::FatalError, _("The destination directory '%{dir}' already exists") % {:dir => target_dir}
|
31
|
+
end
|
32
|
+
|
33
|
+
metadata = PDK::Module::Metadata.new(defaults)
|
34
|
+
|
35
|
+
module_interview(metadata, opts) unless opts[:'skip-interview'] # @todo Build way to get info by answers file
|
36
|
+
|
37
|
+
temp_target_dir = PDK::Util.make_tmpdir_name('pdk-module-target')
|
38
|
+
|
39
|
+
prepare_module_directory(temp_target_dir)
|
40
|
+
|
41
|
+
template_url = opts.fetch(:'template-url', DEFAULT_TEMPLATE)
|
42
|
+
|
43
|
+
PDK::Module::TemplateDir.new(template_url) do |templates|
|
44
|
+
templates.render do |file_path, file_content|
|
45
|
+
file = Pathname.new(temp_target_dir) + file_path
|
46
|
+
file.dirname.mkpath
|
47
|
+
file.write(file_content)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Add information about the template used to generate the module to the
|
51
|
+
# metadata (for a future update command).
|
52
|
+
metadata.update!(templates.metadata)
|
53
|
+
|
54
|
+
File.open(File.join(temp_target_dir, 'metadata.json'), 'w') do |metadata_file|
|
55
|
+
metadata_file.puts metadata.to_json
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
FileUtils.mv(temp_target_dir, target_dir)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.prepare_module_directory(target_dir)
|
63
|
+
[
|
64
|
+
File.join(target_dir, 'manifests'),
|
65
|
+
File.join(target_dir, 'templates'),
|
66
|
+
].each do |dir|
|
67
|
+
begin
|
68
|
+
FileUtils.mkdir_p(dir)
|
69
|
+
rescue SystemCallError
|
70
|
+
raise PDK::CLI::FatalError, _("Unable to create directory '%{dir}'") % {:dir => dir}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.module_interview(metadata, opts={})
|
76
|
+
puts _(
|
77
|
+
"We need to create a metadata.json file for this module. Please answer the " +
|
78
|
+
"following questions; if the question is not applicable to this module, feel free " +
|
79
|
+
"to leave it blank."
|
80
|
+
)
|
81
|
+
|
82
|
+
begin
|
83
|
+
puts ""
|
84
|
+
forge_user = PDK::CLI::Input.get(_("What is your Puppet Forge username?"), Etc.getlogin)
|
85
|
+
metadata.update!('name' => "#{forge_user}-#{opts[:name]}")
|
86
|
+
rescue StandardError => e
|
87
|
+
PDK.logger.error(_("We're sorry, we could not parse your module name: %{message}") % {:message => e.message})
|
88
|
+
retry
|
89
|
+
end
|
90
|
+
|
91
|
+
begin
|
92
|
+
puts "\n" + _("Puppet uses Semantic Versioning (semver.org) to version modules.")
|
93
|
+
module_version = PDK::CLI::Input.get(_("What version is this module?"), metadata.data['version'])
|
94
|
+
metadata.update!('version' => module_version)
|
95
|
+
rescue StandardError => e
|
96
|
+
PDK.logger.error(_("We're sorry, we could not parse that as a Semantic Version: %{message}") % {message: e.message})
|
97
|
+
retry
|
98
|
+
end
|
99
|
+
|
100
|
+
puts ""
|
101
|
+
module_author = PDK::CLI::Input.get(_("Who wrote this module?"), metadata.data['author'])
|
102
|
+
metadata.update!('author' => module_author)
|
103
|
+
|
104
|
+
unless opts.has_key?(:license)
|
105
|
+
puts ""
|
106
|
+
module_license = PDK::CLI::Input.get(_("What license does this module code fall under?"), metadata.data['license'])
|
107
|
+
metadata.update!('license' => module_license)
|
108
|
+
end
|
109
|
+
|
110
|
+
puts ""
|
111
|
+
module_summary = PDK::CLI::Input.get(_("How would you describe this module in a single sentence?"))
|
112
|
+
metadata.update!('summary' => module_summary)
|
113
|
+
|
114
|
+
puts ""
|
115
|
+
module_source = PDK::CLI::Input.get(_("Where is this module's source code repository?"))
|
116
|
+
metadata.update!('source' => module_source)
|
117
|
+
|
118
|
+
puts ""
|
119
|
+
module_page = PDK::CLI::Input.get(_("Where can others go to learn more about this module?"), metadata.data['project_page'])
|
120
|
+
metadata.update!('project_page' => module_page)
|
121
|
+
|
122
|
+
puts ""
|
123
|
+
module_issues = PDK::CLI::Input.get(_("Where can others go to file issues about this module?"), metadata.data['issues_url'])
|
124
|
+
metadata.update!('issues_url' => module_issues)
|
125
|
+
|
126
|
+
puts
|
127
|
+
puts '-' * 40
|
128
|
+
puts metadata.to_json
|
129
|
+
puts '-' * 40
|
130
|
+
puts
|
131
|
+
|
132
|
+
if PDK::CLI::Input.get(_("About to generate this module; continue?"), 'Y') !~ /^y(es)?$/i
|
133
|
+
puts _("Aborting...")
|
134
|
+
exit 0
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'pdk/generators/puppet_object'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module Generate
|
5
|
+
class PuppetClass < PuppetObject
|
6
|
+
OBJECT_TYPE = :class
|
7
|
+
|
8
|
+
# Prepares the data needed to render the new Puppet class template.
|
9
|
+
#
|
10
|
+
# @return [Hash{Symbol => Object}] a hash of information that will be
|
11
|
+
# provided to the class and class spec templates during rendering.
|
12
|
+
def template_data
|
13
|
+
data = {name: object_name}
|
14
|
+
if @options.key?(:params)
|
15
|
+
data[:params] = @options[:params]
|
16
|
+
data[:max_type_length] = @options[:params].map { |r| r[:type].length }.max
|
17
|
+
end
|
18
|
+
data
|
19
|
+
end
|
20
|
+
|
21
|
+
# Calculates the path to the .pp file that the new class will be written
|
22
|
+
# to.
|
23
|
+
#
|
24
|
+
# @return [String] the path where the new class will be written.
|
25
|
+
def target_object_path
|
26
|
+
@target_pp_path ||= begin
|
27
|
+
class_name_parts = object_name.split('::')[1..-1]
|
28
|
+
class_name_parts << 'init' if class_name_parts.empty?
|
29
|
+
|
30
|
+
"#{File.join(module_dir, 'manifests', *class_name_parts)}.pp"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Calculates the path to the file that the tests for the new class will
|
35
|
+
# be written to.
|
36
|
+
#
|
37
|
+
# @return [String] the path where the tests for the new class will be
|
38
|
+
# written.
|
39
|
+
def target_spec_path
|
40
|
+
@target_spec_path ||= begin
|
41
|
+
class_name_parts = object_name.split('::')
|
42
|
+
|
43
|
+
# drop the module name if the object name contains multiple parts
|
44
|
+
class_name_parts.delete_at(0) if class_name_parts.length > 1
|
45
|
+
|
46
|
+
"#{File.join(module_dir, 'spec', 'classes', *class_name_parts)}_spec.rb"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require 'pdk'
|
4
|
+
require 'pdk/logger'
|
5
|
+
require 'pdk/module/metadata'
|
6
|
+
require 'pdk/module/templatedir'
|
7
|
+
require 'pdk/template_file'
|
8
|
+
|
9
|
+
module PDK
|
10
|
+
module Generate
|
11
|
+
class PuppetObject
|
12
|
+
attr_reader :module_dir
|
13
|
+
attr_reader :object_name
|
14
|
+
|
15
|
+
# Initialises the PDK::Generate::PuppetObject object.
|
16
|
+
#
|
17
|
+
# In general, this object should never be instantiated directly. Instead,
|
18
|
+
# one of the subclasses should be used e.g. PDK::Generate::Klass.
|
19
|
+
#
|
20
|
+
# New subclasses generally only need to inherit this class, set the
|
21
|
+
# OBJECT_TYPE constant and implement the {#template_data},
|
22
|
+
# {#target_object_path} and {#target_spec_path} methods.
|
23
|
+
#
|
24
|
+
# @param module_dir [String] The path to the module directory that the
|
25
|
+
# will contain the object.
|
26
|
+
# @param object_name [String] The name of the object.
|
27
|
+
# @param options [Hash{Symbol => Object}]
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
def initialize(module_dir, object_name, options = {})
|
31
|
+
@module_dir = module_dir
|
32
|
+
@options = options
|
33
|
+
|
34
|
+
if [:class, :defined_type].include?(object_type)
|
35
|
+
object_name_parts = object_name.split('::')
|
36
|
+
|
37
|
+
if object_name_parts.first == module_name
|
38
|
+
@object_name = object_name
|
39
|
+
else
|
40
|
+
@object_name = [module_name, object_name].join('::')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @abstract Subclass and implement {#template_data} to provide data to
|
46
|
+
# the templates during rendering. Implementations of this method should
|
47
|
+
# return a Hash[{Symbol => Object}].
|
48
|
+
def template_data
|
49
|
+
raise NotImplementedError
|
50
|
+
end
|
51
|
+
|
52
|
+
# @abstract Subclass and implement {#target_object_path}. Implementations
|
53
|
+
# of this method should return a String containing the destination path
|
54
|
+
# of the object being generated.
|
55
|
+
def target_object_path
|
56
|
+
raise NotImplementedError
|
57
|
+
end
|
58
|
+
|
59
|
+
# @abstract Subclass and implement {#target_spec_path}. Implementations
|
60
|
+
# of this method should return a String containing the destination path
|
61
|
+
# of the tests for the object being generated.
|
62
|
+
def target_spec_path
|
63
|
+
raise NotImplementedError
|
64
|
+
end
|
65
|
+
|
66
|
+
# Retrieves the type of the object being generated, e.g. :class,
|
67
|
+
# :defined_type, etc. This is specified in the subclass' OBJECT_TYPE
|
68
|
+
# constant.
|
69
|
+
#
|
70
|
+
# @return [Symbol] the type of the object being generated.
|
71
|
+
#
|
72
|
+
# @api private
|
73
|
+
def object_type
|
74
|
+
self.class::OBJECT_TYPE
|
75
|
+
end
|
76
|
+
|
77
|
+
# Check that the target files do not exist, find an appropriate template
|
78
|
+
# and create the target files from the template. This is the main entry
|
79
|
+
# point for the class.
|
80
|
+
#
|
81
|
+
# @raise [PDK::CLI::FatalError] if the target files already exist.
|
82
|
+
#
|
83
|
+
# @api public
|
84
|
+
def run
|
85
|
+
[target_object_path, target_spec_path].each do |target_file|
|
86
|
+
if File.exist?(target_file)
|
87
|
+
raise PDK::CLI::FatalError, _("Unable to generate class, '%{file}' already exists.") % {file: target_file}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
with_templates do |template_path, config_hash|
|
92
|
+
data = template_data.merge(:configs => config_hash)
|
93
|
+
|
94
|
+
render_file(target_object_path, template_path[:object], data)
|
95
|
+
render_file(target_spec_path, template_path[:spec], data) if template_path[:spec]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Render a file using the provided template and write it to disk.
|
100
|
+
#
|
101
|
+
# @param dest_path [String] The path that the rendered file should be
|
102
|
+
# written to. Any necessary directories will be automatically created.
|
103
|
+
# @param template_path [String] The path on disk to the file containing
|
104
|
+
# the template.
|
105
|
+
# @param data [Hash{Object => Object}] The data to be provided to the
|
106
|
+
# template when rendering.
|
107
|
+
#
|
108
|
+
# @return [void]
|
109
|
+
#
|
110
|
+
# @api private
|
111
|
+
def render_file(dest_path, template_path, data)
|
112
|
+
PDK.logger.info(_("Creating %{file} from template.") % {file: dest_path})
|
113
|
+
file_content = PDK::TemplateFile.new(template_path, data).render
|
114
|
+
FileUtils.mkdir_p(File.dirname(dest_path))
|
115
|
+
File.open(dest_path, 'w') { |f| f.write file_content }
|
116
|
+
end
|
117
|
+
|
118
|
+
# Search the possible template directories in order of preference to find
|
119
|
+
# a template that can be used to render a new object of the specified
|
120
|
+
# type.
|
121
|
+
#
|
122
|
+
# @yieldparam template_paths [Hash{Symbol => String}] :object contains
|
123
|
+
# the path on disk to the template file for the object, :spec contains
|
124
|
+
# the path on disk to the template file for the tests for the object
|
125
|
+
# (if it exists).
|
126
|
+
# @yieldparam config_hash [Hash{Object => Object}] the contents of the
|
127
|
+
# :global key in the config_defaults.yml file.
|
128
|
+
#
|
129
|
+
# @raise [PDK::CLI::FatalError] if no suitable template could be found.
|
130
|
+
#
|
131
|
+
# @api private
|
132
|
+
def with_templates
|
133
|
+
templates.each do |template|
|
134
|
+
if template[:url].nil?
|
135
|
+
PDK.logger.debug(_("No %{dir_type} template specified; trying next template directory.") % {dir_type: template[:type]})
|
136
|
+
next
|
137
|
+
end
|
138
|
+
|
139
|
+
PDK::Module::TemplateDir.new(template[:url]) do |template_dir|
|
140
|
+
template_paths = template_dir.object_template_for(object_type)
|
141
|
+
|
142
|
+
if template_paths
|
143
|
+
config_hash = template_dir.object_config
|
144
|
+
yield template_paths, config_hash
|
145
|
+
return
|
146
|
+
else
|
147
|
+
if template[:allow_fallback]
|
148
|
+
PDK.logger.debug(_("Unable to find a %{type} template in %{url}, trying next template directory") % {type: object_type, url: template[:url]})
|
149
|
+
else
|
150
|
+
raise PDK::CLI::FatalError, _("Unable to find the %{type} template in %{url}.") % {type: object_type, url: template[:url]}
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Provides the possible template directory locations in the order in
|
158
|
+
# which they should be searched for a valid template.
|
159
|
+
#
|
160
|
+
# If a template-url has been specified on in the options hash (e.g. from
|
161
|
+
# a CLI parameter), then this template directory will be checked first
|
162
|
+
# and we do not fall back to the next possible template directory.
|
163
|
+
#
|
164
|
+
# If we have not been provided a specific template directory to use, we
|
165
|
+
# try the template specified in the module metadata (as set during
|
166
|
+
# PDK::Generate::Module) and fall back to the default template if
|
167
|
+
# necessary.
|
168
|
+
#
|
169
|
+
# @return [Array<Hash{Symbol => Object}>] an array of hashes. Each hash
|
170
|
+
# contains 3 keys: :type contains a String that describes the template
|
171
|
+
# directory, :url contains a String with the URL to the template
|
172
|
+
# directory, and :allow_fallback contains a Boolean that specifies if
|
173
|
+
# the lookup process should proceed to the next template directory if
|
174
|
+
# the template file is not in this template directory.
|
175
|
+
#
|
176
|
+
# @api private
|
177
|
+
def templates
|
178
|
+
@templates ||= [
|
179
|
+
{type: 'CLI', url: @options[:'template-url'], allow_fallback: false},
|
180
|
+
{type: 'metadata', url: module_metadata.data['template-url'], allow_fallback: true},
|
181
|
+
{type: 'default', url: PDK::Generate::Module::DEFAULT_TEMPLATE, allow_fallback: false},
|
182
|
+
]
|
183
|
+
end
|
184
|
+
|
185
|
+
# Retrieves the name of the module (without the forge username) from the
|
186
|
+
# module metadata.
|
187
|
+
#
|
188
|
+
# @raise (see #module_metadata)
|
189
|
+
# @return [String] The name of the module.
|
190
|
+
#
|
191
|
+
# @api private
|
192
|
+
def module_name
|
193
|
+
@module_name ||= module_metadata.data['name'].rpartition('-').last
|
194
|
+
end
|
195
|
+
|
196
|
+
# Parses the metadata.json file for the module.
|
197
|
+
#
|
198
|
+
# @raise [PDK::CLI::FatalError] if the metadata.json file does not exist,
|
199
|
+
# can not be read, or contains invalid metadata.
|
200
|
+
#
|
201
|
+
# @return [PDK::Module::Metadata] the parsed module metadata.
|
202
|
+
#
|
203
|
+
# @api private
|
204
|
+
def module_metadata
|
205
|
+
@module_metadata ||= begin
|
206
|
+
PDK::Module::Metadata.from_file(File.join(module_dir, 'metadata.json'))
|
207
|
+
rescue ArgumentError => e
|
208
|
+
raise PDK::CLI::FatalError, _("'%{dir}' does not contain valid Puppet module metadata; %{msg}") % {dir: module_dir, msg: e.message}
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|