pdk 1.17.0 → 2.1.1
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 +4 -4
- data/CHANGELOG.md +148 -11
- data/README.md +1 -1
- data/lib/pdk.rb +1 -1
- data/lib/pdk/cli.rb +7 -1
- data/lib/pdk/cli/convert.rb +7 -9
- data/lib/pdk/cli/env.rb +52 -0
- data/lib/pdk/cli/exec/command.rb +11 -1
- data/lib/pdk/cli/new.rb +2 -0
- data/lib/pdk/cli/new/class.rb +2 -1
- data/lib/pdk/cli/new/defined_type.rb +2 -1
- data/lib/pdk/cli/new/fact.rb +29 -0
- data/lib/pdk/cli/new/function.rb +29 -0
- 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/release.rb +1 -1
- data/lib/pdk/cli/release/publish.rb +11 -1
- data/lib/pdk/cli/remove.rb +20 -0
- data/lib/pdk/cli/remove/config.rb +80 -0
- data/lib/pdk/cli/set.rb +20 -0
- data/lib/pdk/cli/set/config.rb +119 -0
- data/lib/pdk/cli/update.rb +6 -8
- data/lib/pdk/cli/util.rb +1 -0
- data/lib/pdk/cli/util/option_validator.rb +6 -0
- data/lib/pdk/cli/util/update_manager_printer.rb +82 -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/fact.rb +25 -0
- data/lib/pdk/generate/function.rb +48 -0
- data/lib/pdk/generate/module.rb +11 -10
- data/lib/pdk/generate/provider.rb +15 -64
- data/lib/pdk/generate/puppet_class.rb +25 -31
- data/lib/pdk/generate/puppet_object.rb +83 -187
- data/lib/pdk/generate/task.rb +28 -46
- data/lib/pdk/generate/transport.rb +20 -74
- data/lib/pdk/module.rb +1 -1
- data/lib/pdk/module/convert.rb +43 -23
- data/lib/pdk/module/metadata.rb +6 -2
- data/lib/pdk/module/release.rb +8 -2
- data/lib/pdk/module/update.rb +7 -11
- data/lib/pdk/module/update_manager.rb +7 -0
- data/lib/pdk/report.rb +3 -3
- data/lib/pdk/report/event.rb +8 -2
- data/lib/pdk/template.rb +59 -0
- data/lib/pdk/template/fetcher.rb +98 -0
- data/lib/pdk/template/fetcher/git.rb +85 -0
- data/lib/pdk/template/fetcher/local.rb +28 -0
- data/lib/pdk/template/renderer.rb +96 -0
- data/lib/pdk/template/renderer/v1.rb +25 -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/template_dir.rb +67 -0
- data/lib/pdk/tests/unit.rb +8 -1
- data/lib/pdk/util.rb +4 -35
- data/lib/pdk/util/bundler.rb +1 -1
- data/lib/pdk/util/changelog_generator.rb +20 -3
- data/lib/pdk/util/json_finder.rb +85 -0
- data/lib/pdk/util/puppet_strings.rb +3 -3
- data/lib/pdk/util/puppet_version.rb +2 -2
- data/lib/pdk/util/ruby_version.rb +5 -1
- data/lib/pdk/util/template_uri.rb +9 -11
- data/lib/pdk/util/vendored_file.rb +1 -2
- data/lib/pdk/validate.rb +17 -10
- 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 +8 -4
- data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +1 -1
- data/lib/pdk/validate/validator.rb +7 -0
- data/lib/pdk/validate/validator_group.rb +1 -0
- data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +2 -2
- data/lib/pdk/version.rb +1 -1
- data/locales/pdk.pot +356 -228
- metadata +65 -28
- data/lib/pdk/module/template_dir.rb +0 -115
- 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/template_file.rb +0 -96
@@ -0,0 +1,119 @@
|
|
1
|
+
module PDK::CLI
|
2
|
+
module Set
|
3
|
+
module Config
|
4
|
+
ALLOWED_TYPE_NAMES = %w[array boolean number string].freeze
|
5
|
+
|
6
|
+
# :nocov:
|
7
|
+
def self.pretty_allowed_names
|
8
|
+
ALLOWED_TYPE_NAMES.map { |name| "'#{name}'" }.join(', ')
|
9
|
+
end
|
10
|
+
# :nocov:
|
11
|
+
|
12
|
+
def self.transform_value(type_name, value)
|
13
|
+
normalized_name = type_name.downcase.strip
|
14
|
+
unless ALLOWED_TYPE_NAMES.include?(normalized_name)
|
15
|
+
raise PDK::CLI::ExitWithError, _('Unknown type %{type_name}. Expected one of %{allowed}') % { type_name: type_name, allowed: pretty_allowed_names }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Short circuit string conversions as it's trivial
|
19
|
+
if normalized_name == 'string'
|
20
|
+
raise PDK::CLI::ExitWithError, _('An error occured converting \'%{value}\' into a %{type_name}') % { value: value.nil? ? 'nil' : value, type_name: type_name } unless value.is_a?(String)
|
21
|
+
return value
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
case normalized_name
|
26
|
+
when 'array'
|
27
|
+
convert_to_array(value)
|
28
|
+
when 'boolean'
|
29
|
+
convert_to_boolean(value)
|
30
|
+
when 'number'
|
31
|
+
convert_to_number(value)
|
32
|
+
else
|
33
|
+
value
|
34
|
+
end
|
35
|
+
rescue ArgumentError, TypeError
|
36
|
+
raise PDK::CLI::ExitWithError, _('An error occured converting \'%{value}\' into a %{type_name}') % { value: value.nil? ? 'nil' : value, type_name: type_name }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.convert_to_array(value)
|
41
|
+
return [] if value.nil?
|
42
|
+
value.is_a?(Array) ? value : [value]
|
43
|
+
end
|
44
|
+
private_class_method :convert_to_array
|
45
|
+
|
46
|
+
def self.convert_to_boolean(value)
|
47
|
+
string_val = value.to_s.strip.downcase
|
48
|
+
|
49
|
+
return true if %w[yes true -1 1].include?(string_val)
|
50
|
+
return false if %w[no false 0].include?(string_val)
|
51
|
+
|
52
|
+
raise ArgumentError
|
53
|
+
end
|
54
|
+
private_class_method :convert_to_boolean
|
55
|
+
|
56
|
+
def self.convert_to_number(value)
|
57
|
+
float_val = Float(value)
|
58
|
+
# Return an Integer if this is actually and Integer, otherwise return the float
|
59
|
+
(float_val.truncate == float_val) ? float_val.truncate : float_val
|
60
|
+
end
|
61
|
+
private_class_method :convert_to_number
|
62
|
+
|
63
|
+
def self.run(opts, args)
|
64
|
+
item_name = (args.count > 0) ? args[0] : nil
|
65
|
+
item_value = (args.count > 1) ? args[1] : nil
|
66
|
+
|
67
|
+
opts[:type] = opts[:as] if opts[:type].nil? && !opts[:as].nil?
|
68
|
+
force = opts[:force] || false
|
69
|
+
|
70
|
+
# Transform the value if we need to
|
71
|
+
item_value = PDK::CLI::Set::Config.transform_value(opts[:type], item_value) unless opts[:type].nil?
|
72
|
+
|
73
|
+
raise PDK::CLI::ExitWithError, _('Configuration name is required') if item_name.nil?
|
74
|
+
raise PDK::CLI::ExitWithError, _('Configuration value is required. If you wish to remove a value use \'pdk remove config\'') if item_value.nil?
|
75
|
+
|
76
|
+
current_value = PDK.config.get(item_name)
|
77
|
+
raise PDK::CLI::ExitWithError, _("The configuration item '%{name}' can not have a value set.") % { name: item_name } if current_value.is_a?(PDK::Config::Namespace)
|
78
|
+
|
79
|
+
# If we're forcing the value, don't do any munging
|
80
|
+
unless force
|
81
|
+
# Check if the setting already exists
|
82
|
+
if current_value.is_a?(Array) && current_value.include?(item_value)
|
83
|
+
PDK.logger.info(_("No changes made to '%{name}' as it already contains value '%{to}'") % { name: item_name, to: item_value })
|
84
|
+
return 0
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
new_value = PDK.config.set(item_name, item_value, force: opts[:force])
|
89
|
+
if current_value.nil? || force
|
90
|
+
PDK.logger.info(_("Set initial value of '%{name}' to '%{to}'") % { name: item_name, to: new_value })
|
91
|
+
elsif current_value.is_a?(Array)
|
92
|
+
# Arrays have a special output format
|
93
|
+
PDK.logger.info(_("Added new value '%{to}' to '%{name}'") % { name: item_name, to: item_value })
|
94
|
+
else
|
95
|
+
PDK.logger.info(_("Changed existing value of '%{name}' from '%{from}' to '%{to}'") % { name: item_name, from: current_value, to: new_value })
|
96
|
+
end
|
97
|
+
|
98
|
+
# Same output as `get config`
|
99
|
+
$stdout.puts _('%{name}=%{value}') % { name: item_name, value: PDK.config.get(item_name) }
|
100
|
+
0
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@set_config_cmd = @set_cmd.define_command do
|
106
|
+
name 'config'
|
107
|
+
usage _('config [name] [value]')
|
108
|
+
summary _('Set or update the configuration for <name>')
|
109
|
+
|
110
|
+
option :f, :force, _('Force the configuration setting to be overwitten.'), argument: :forbidden
|
111
|
+
|
112
|
+
option :t, :type, _('The type of value to set. Acceptable values: %{values}') % { values: PDK::CLI::Set::Config.pretty_allowed_names }, argument: :required
|
113
|
+
option nil, :as, _('Alias of --type'), argument: :required
|
114
|
+
|
115
|
+
run do |opts, args, _cmd|
|
116
|
+
exit PDK::CLI::Set::Config.run(opts, args)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/pdk/cli/update.rb
CHANGED
@@ -10,14 +10,12 @@ module PDK::CLI
|
|
10
10
|
PDK::CLI.template_ref_option(self)
|
11
11
|
|
12
12
|
run do |opts, _args, _cmd|
|
13
|
-
|
14
|
-
|
15
|
-
require 'pdk/module/update'
|
13
|
+
# Write the context information to the debug log
|
14
|
+
PDK.context.to_debug_log
|
16
15
|
|
17
|
-
PDK::
|
18
|
-
|
19
|
-
|
20
|
-
)
|
16
|
+
unless PDK.context.is_a?(PDK::Context::Module)
|
17
|
+
raise PDK::CLI::ExitWithError, _('`pdk update` can only be run from inside a valid module directory.')
|
18
|
+
end
|
21
19
|
|
22
20
|
raise PDK::CLI::ExitWithError, _('This module does not appear to be PDK compatible. To make the module compatible with PDK, run `pdk convert`.') unless PDK::Util.module_pdk_compatible?
|
23
21
|
|
@@ -46,7 +44,7 @@ module PDK::CLI
|
|
46
44
|
|
47
45
|
PDK::CLI::Util.analytics_screen_view('update', opts)
|
48
46
|
|
49
|
-
updater = PDK::Module::Update.new(PDK
|
47
|
+
updater = PDK::Module::Update.new(PDK.context.root_path, opts)
|
50
48
|
|
51
49
|
if updater.pinned_to_puppetlabs_template_tag?
|
52
50
|
PDK.logger.info _(
|
data/lib/pdk/cli/util.rb
CHANGED
@@ -8,6 +8,7 @@ module PDK
|
|
8
8
|
autoload :OptionValidator, 'pdk/cli/util/option_validator'
|
9
9
|
autoload :Interview, 'pdk/cli/util/interview'
|
10
10
|
autoload :Spinner, 'pdk/cli/util/spinner'
|
11
|
+
autoload :UpdateManagerPrinter, 'pdk/cli/util/update_manager_printer'
|
11
12
|
|
12
13
|
# Ensures the calling code is being run from inside a module directory.
|
13
14
|
#
|
@@ -8,6 +8,11 @@ module PDK
|
|
8
8
|
(list =~ %r{^[\w\-]+(?:,[\w\-]+)+$}) ? true : false
|
9
9
|
end
|
10
10
|
|
11
|
+
# @return [Boolean] true if the fact name is valid
|
12
|
+
def self.valid_fact_name?(name)
|
13
|
+
name.length > 1
|
14
|
+
end
|
15
|
+
|
11
16
|
def self.enum(val, valid_entries, _options = {})
|
12
17
|
vals = val.is_a?(Array) ? val : [val]
|
13
18
|
invalid_entries = vals.reject { |e| valid_entries.include?(e) }
|
@@ -41,6 +46,7 @@ module PDK
|
|
41
46
|
|
42
47
|
!(string =~ %r{\A([a-z][a-z0-9_]*)(::[a-z][a-z0-9_]*)*\Z}).nil?
|
43
48
|
end
|
49
|
+
singleton_class.send(:alias_method, :valid_function_name?, :valid_namespace?)
|
44
50
|
|
45
51
|
singleton_class.send(:alias_method, :valid_class_name?, :valid_namespace?)
|
46
52
|
singleton_class.send(:alias_method, :valid_defined_type_name?, :valid_namespace?)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'pdk'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module CLI
|
5
|
+
module Util
|
6
|
+
module UpdateManagerPrinter
|
7
|
+
# Prints the summary for a PDK::Module::UpdateManager Object
|
8
|
+
# @param update_manager [PDK::Module::UpdateManager] The object to print a summary of
|
9
|
+
# @param options [Hash{Object => Object}] A list of options when printing
|
10
|
+
# @option options [Boolean] :tense Whether to use future (:future) or past (:past) tense when printing the summary ("Files to be added" versus "Files added"). Default is :future
|
11
|
+
#
|
12
|
+
# @return [void]
|
13
|
+
def self.print_summary(update_manager, options = {})
|
14
|
+
require 'pdk/report'
|
15
|
+
|
16
|
+
options = {
|
17
|
+
tense: :future,
|
18
|
+
}.merge(options)
|
19
|
+
|
20
|
+
footer = false
|
21
|
+
|
22
|
+
summary(update_manager).each do |category, files|
|
23
|
+
next if files.empty?
|
24
|
+
|
25
|
+
PDK::Report.default_target.puts('')
|
26
|
+
PDK::Report.default_target.puts(generate_banner("Files #{(options[:tense] == :future) ? 'to be ' : ''}#{category}", 40))
|
27
|
+
PDK::Report.default_target.puts(files.map(&:to_s).join("\n"))
|
28
|
+
footer = true
|
29
|
+
end
|
30
|
+
|
31
|
+
if footer # rubocop:disable Style/GuardClause No.
|
32
|
+
PDK::Report.default_target.puts('')
|
33
|
+
PDK::Report.default_target.puts(generate_banner('', 40))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#:nocov: Tested as part of the public methods
|
38
|
+
# Returns a hash, summarizing the contents of the Update Manager object
|
39
|
+
# @param update_manager [PDK::Module::UpdateManager] The object to create a summary of
|
40
|
+
#
|
41
|
+
# @return [Hash{Symbol => Array[String]}] A hash of each category and the file paths in each category
|
42
|
+
def self.summary(update_manager)
|
43
|
+
summary = {}
|
44
|
+
update_manager.changes.each do |category, update_category|
|
45
|
+
if update_category.respond_to?(:keys)
|
46
|
+
updated_files = update_category.keys
|
47
|
+
else
|
48
|
+
begin
|
49
|
+
updated_files = update_category.map { |file| file[:path] }
|
50
|
+
rescue TypeError
|
51
|
+
updated_files = update_category.to_a
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
summary[category] = updated_files
|
56
|
+
end
|
57
|
+
|
58
|
+
summary
|
59
|
+
end
|
60
|
+
private_class_method :summary
|
61
|
+
|
62
|
+
# Creates a line of text, with `text` centered in the middle
|
63
|
+
# @param text [String] The text to put in the middle of the banner
|
64
|
+
# @param width [Integer] The width of the banner in characters. Default is 80
|
65
|
+
# @return [String] The generated banner
|
66
|
+
def self.generate_banner(text, width = 80)
|
67
|
+
padding = width - text.length
|
68
|
+
banner = ''
|
69
|
+
padding_char = '-'
|
70
|
+
|
71
|
+
(padding / 2.0).ceil.times { banner << padding_char }
|
72
|
+
banner << text
|
73
|
+
(padding / 2.0).floor.times { banner << padding_char }
|
74
|
+
|
75
|
+
banner
|
76
|
+
end
|
77
|
+
private_class_method :generate_banner
|
78
|
+
#:nocov:
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/pdk/config.rb
CHANGED
@@ -33,20 +33,12 @@ module PDK
|
|
33
33
|
}.merge(options)
|
34
34
|
end
|
35
35
|
|
36
|
-
# The user configuration settings.
|
37
|
-
# @deprecated This method is only provided as a courtesy until the `pdk set config` CLI and associated changes in this class, are completed.
|
38
|
-
# Any read-only operations should be using `.get` or `.get_within_scopes`
|
39
|
-
# @return [PDK::Config::Namespace]
|
40
|
-
def user
|
41
|
-
user_config
|
42
|
-
end
|
43
|
-
|
44
36
|
# The system level configuration settings.
|
45
37
|
# @return [PDK::Config::Namespace]
|
46
38
|
# @api private
|
47
39
|
def system_config
|
48
40
|
local_options = @config_options
|
49
|
-
@
|
41
|
+
@system_config ||= PDK::Config::JSON.new('system', file: local_options['system.path']) do
|
50
42
|
mount :module_defaults, PDK::Config::JSON.new(file: local_options['system.module_defaults.path'])
|
51
43
|
end
|
52
44
|
end
|
@@ -56,7 +48,7 @@ module PDK
|
|
56
48
|
# @api private
|
57
49
|
def user_config
|
58
50
|
local_options = @config_options
|
59
|
-
@
|
51
|
+
@user_config ||= PDK::Config::JSON.new('user', file: local_options['user.path']) do
|
60
52
|
mount :module_defaults, PDK::Config::JSON.new(file: local_options['user.module_defaults.path'])
|
61
53
|
|
62
54
|
# Due to the json-schema gem having issues with Windows based paths, and only supporting Draft 05 (or less) do
|
@@ -119,6 +111,8 @@ module PDK
|
|
119
111
|
# - PDK.config.get('user.a.b.c')
|
120
112
|
# - PDK.config.get(['user', 'a', 'b', 'c'])
|
121
113
|
# - PDK.config.get('user', 'a', 'b', 'c')
|
114
|
+
# @param root [Array[String], String] The root setting name or the entire setting name as a single string
|
115
|
+
# @param keys [String] The child names of the setting
|
122
116
|
# @return [PDK::Config::Namespace, Object, nil] The value of the configuration setting. Returns nil if it does no exist
|
123
117
|
def get(root, *keys)
|
124
118
|
return nil if root.nil? || root.empty?
|
@@ -169,6 +163,26 @@ module PDK
|
|
169
163
|
yield value unless value.nil?
|
170
164
|
end
|
171
165
|
|
166
|
+
# Sets a configuration setting by name. This name can either be a String or an Array
|
167
|
+
# - PDK.config.set('user.a.b.c', ...)
|
168
|
+
# - PDK.config.set(['user', 'a', 'b', 'c'], ...)
|
169
|
+
# @param key [String, Array[String]] The name of the configuration key to change
|
170
|
+
# @param value [Object] The value to set the configuration setting to
|
171
|
+
# @param options [Hash] Changes the behaviour of the setting process
|
172
|
+
# @option options [Boolean] :force Disables any munging or array processing, and sets the value as it is. Default is false
|
173
|
+
# @return [Object] The new value of the configuration setting
|
174
|
+
def set(key, value, options = {})
|
175
|
+
options = {
|
176
|
+
force: false,
|
177
|
+
}.merge(options)
|
178
|
+
|
179
|
+
names = key.is_a?(String) ? split_key_string(key) : key
|
180
|
+
raise ArgumentError, _('Invalid configuration names') if names.nil? || !names.is_a?(Array) || names.empty?
|
181
|
+
scope_name = names[0]
|
182
|
+
raise ArgumentError, _("Unknown configuration root '%{name}'") % { name: scope_name } if all_scopes[scope_name].nil?
|
183
|
+
deep_set_object(value, options[:force], send(all_scopes[scope_name]), *names[1..-1])
|
184
|
+
end
|
185
|
+
|
172
186
|
def self.bolt_analytics_config
|
173
187
|
file = PDK::Util::Filesystem.expand_path('~/.puppetlabs/bolt/analytics.yaml')
|
174
188
|
PDK::Config::YAML.new(file: file)
|
@@ -247,9 +261,9 @@ module PDK
|
|
247
261
|
|
248
262
|
if answers.nil?
|
249
263
|
PDK.logger.info _('No answer given, opting out of analytics collection.')
|
250
|
-
PDK.config.user
|
264
|
+
PDK.config.set(%w[user analytics disabled], true)
|
251
265
|
else
|
252
|
-
PDK.config.user
|
266
|
+
PDK.config.set(%w[user analytics disabled], !answers['enabled'])
|
253
267
|
end
|
254
268
|
|
255
269
|
PDK.logger.info(text: post_message, wrap: true)
|
@@ -260,7 +274,12 @@ module PDK
|
|
260
274
|
#:nocov: This is a private method and is tested elsewhere
|
261
275
|
def traverse_object(object, *names)
|
262
276
|
return nil if object.nil? || !object.respond_to?(:[])
|
263
|
-
return nil if names.nil?
|
277
|
+
return nil if names.nil?
|
278
|
+
# It's possible to pass in empty names at the root traversal layer
|
279
|
+
# but this should _only_ happen at the root namespace level
|
280
|
+
if names.empty?
|
281
|
+
return (object.is_a?(PDK::Config::Namespace) ? object : nil)
|
282
|
+
end
|
264
283
|
|
265
284
|
name = names.shift
|
266
285
|
value = object[name]
|
@@ -296,6 +315,70 @@ module PDK
|
|
296
315
|
'system' => :system_config,
|
297
316
|
}.freeze
|
298
317
|
end
|
318
|
+
|
319
|
+
#:nocov: This is a private method and is tested elsewhere
|
320
|
+
# Deeply traverses an object tree via `[]` and sets the last
|
321
|
+
# element to the value specified.
|
322
|
+
#
|
323
|
+
# Creating any missing parent hashes during the traversal
|
324
|
+
def deep_set_object(value, force, namespace, *names)
|
325
|
+
raise ArgumentError, _('Missing or invalid namespace') unless namespace.is_a?(PDK::Config::Namespace)
|
326
|
+
raise ArgumentError, _('Missing a name to set') if names.nil? || names.empty?
|
327
|
+
|
328
|
+
name = names.shift
|
329
|
+
current_value = namespace[name]
|
330
|
+
|
331
|
+
# If the next thing in the traversal chain is another namespace, set the value using that child namespace.
|
332
|
+
if current_value.is_a?(PDK::Config::Namespace)
|
333
|
+
return deep_set_object(value, force, current_value, *names)
|
334
|
+
end
|
335
|
+
|
336
|
+
# We're at the end of the name traversal
|
337
|
+
if names.empty?
|
338
|
+
if force || !current_value.is_a?(Array)
|
339
|
+
namespace[name] = value
|
340
|
+
return value
|
341
|
+
end
|
342
|
+
|
343
|
+
# Arrays are a special case if we're not forcing the value
|
344
|
+
namespace[name] = current_value << value unless current_value.include?(value)
|
345
|
+
return value
|
346
|
+
end
|
347
|
+
|
348
|
+
# Need to generate a deep hash using the current remaining names
|
349
|
+
# So given an origin *names of ['a', 'b', 'c', 'd'] and a value 'foo',
|
350
|
+
# we eventually want a hash of `{"b"=>{"c"=>{"d"=>"foo"}}}`
|
351
|
+
#
|
352
|
+
# The code above has already shifted the first element so we currently have
|
353
|
+
# name : 'a'
|
354
|
+
# names: ['b', 'c', 'd']
|
355
|
+
#
|
356
|
+
#
|
357
|
+
# First we need to pop off the last element ('d') in this case as we need to set that in the `reduce` call below
|
358
|
+
# So now we have:
|
359
|
+
# name : 'a'
|
360
|
+
# names: ['b', 'c']
|
361
|
+
# last_name : 'd'
|
362
|
+
last_name = names.pop
|
363
|
+
# Using reduce and an accumulator, we create the nested hash from the deepest value first. In this case the deepest value
|
364
|
+
# is the last_name, so the starting condition is {"d"=>"foo"}
|
365
|
+
# After the first iteration ('c'), the accumulator has {"c"=>{"d"=>"foo"}}}
|
366
|
+
# After the last iteration ('b'), the accumulator has {"b"=>{"c"=>{"d"=>"foo"}}}
|
367
|
+
hash_value = names.reverse.reduce(last_name => value) { |accumulator, item| { item => accumulator } }
|
368
|
+
|
369
|
+
# If the current value is nil, then it can't be a namespace or an existing value
|
370
|
+
# or
|
371
|
+
# If the current value is not a Hash and are forcing the change.
|
372
|
+
if current_value.nil? || (force && !current_value.is_a?(Hash))
|
373
|
+
namespace[name] = hash_value
|
374
|
+
return value
|
375
|
+
end
|
376
|
+
|
377
|
+
raise ArgumentError, _("Unable to set '%{key}' to '%{value}' as it is not a Hash") % { key: namespace.name + '.' + name, value: hash_value } unless current_value.is_a?(Hash)
|
378
|
+
|
379
|
+
namespace[name] = current_value.merge(hash_value)
|
380
|
+
value
|
381
|
+
end
|
299
382
|
#:nocov:
|
300
383
|
end
|
301
384
|
end
|
data/lib/pdk/context.rb
CHANGED
@@ -33,13 +33,15 @@ module PDK
|
|
33
33
|
# Abstract class which all PDK Contexts will subclass from.
|
34
34
|
# @abstract
|
35
35
|
class AbstractContext
|
36
|
-
# The root of this context, for example the module root when inside a module. This
|
36
|
+
# The root of this context, for example the module root when inside a module. This can be different from context_path
|
37
37
|
# For example a Module context_path could be /path/to/module/manifests/ but the root_path will be /path/to/module as
|
38
|
-
# that is the root of the Module context
|
39
|
-
# @return [String
|
40
|
-
|
38
|
+
# that is the root of the Module context. Defaults to the context_path if not set.
|
39
|
+
# @return [String]
|
40
|
+
def root_path
|
41
|
+
@root_path || @context_path
|
42
|
+
end
|
41
43
|
|
42
|
-
# The path used to create this context, for example the current working directory. This
|
44
|
+
# The path used to create this context, for example the current working directory. This can be different from root_path
|
43
45
|
# For example a Module context_path could be /path/to/module/manifests/ but the root_path will be /path/to/module as
|
44
46
|
# that is the root of the Module context
|
45
47
|
# @return [String]
|
@@ -48,6 +50,7 @@ module PDK
|
|
48
50
|
# @param context_path [String] The path where this context was created from e.g. Dir.pwd
|
49
51
|
def initialize(context_path)
|
50
52
|
@context_path = context_path
|
53
|
+
@root_path = nil
|
51
54
|
end
|
52
55
|
|
53
56
|
# Whether the current context is compatible with the PDK e.g. in a Module context, whether it has the correct metadata.json content
|