pdk 1.16.0 → 1.17.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 +4 -4
- data/CHANGELOG.md +24 -0
- data/lib/pdk.rb +25 -18
- data/lib/pdk/answer_file.rb +2 -93
- data/lib/pdk/cli.rb +1 -5
- data/lib/pdk/cli/config.rb +3 -1
- data/lib/pdk/cli/config/get.rb +3 -1
- data/lib/pdk/cli/convert.rb +1 -1
- data/lib/pdk/cli/exec/command.rb +13 -0
- data/lib/pdk/cli/exec_group.rb +78 -43
- data/lib/pdk/cli/get.rb +20 -0
- data/lib/pdk/cli/get/config.rb +24 -0
- data/lib/pdk/cli/util.rb +6 -3
- data/lib/pdk/cli/validate.rb +26 -44
- data/lib/pdk/config.rb +178 -4
- data/lib/pdk/config/ini_file.rb +183 -0
- data/lib/pdk/config/ini_file_setting.rb +39 -0
- data/lib/pdk/config/namespace.rb +25 -5
- data/lib/pdk/config/setting.rb +3 -2
- data/lib/pdk/context.rb +96 -0
- data/lib/pdk/context/control_repo.rb +60 -0
- data/lib/pdk/context/module.rb +28 -0
- data/lib/pdk/context/none.rb +22 -0
- data/lib/pdk/control_repo.rb +40 -0
- data/lib/pdk/generate/module.rb +8 -12
- data/lib/pdk/module/release.rb +2 -8
- data/lib/pdk/util.rb +35 -5
- data/lib/pdk/util/bundler.rb +1 -0
- data/lib/pdk/util/changelog_generator.rb +6 -1
- data/lib/pdk/util/template_uri.rb +4 -3
- data/lib/pdk/validate.rb +72 -25
- data/lib/pdk/validate/external_command_validator.rb +208 -0
- data/lib/pdk/validate/internal_ruby_validator.rb +100 -0
- data/lib/pdk/validate/invokable_validator.rb +216 -0
- data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +86 -0
- data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +78 -0
- data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -0
- data/lib/pdk/validate/puppet/puppet_epp_validator.rb +133 -0
- data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -0
- data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +137 -0
- data/lib/pdk/validate/puppet/puppet_validator_group.rb +21 -0
- data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +80 -0
- data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -0
- data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +88 -0
- data/lib/pdk/validate/tasks/tasks_name_validator.rb +50 -0
- data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -0
- data/lib/pdk/validate/validator.rb +111 -0
- data/lib/pdk/validate/validator_group.rb +103 -0
- data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +95 -0
- data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -0
- data/lib/pdk/version.rb +1 -1
- data/locales/pdk.pot +161 -125
- metadata +29 -17
- data/lib/pdk/validate/base_validator.rb +0 -215
- data/lib/pdk/validate/metadata/metadata_json_lint.rb +0 -82
- data/lib/pdk/validate/metadata/metadata_syntax.rb +0 -111
- data/lib/pdk/validate/metadata_validator.rb +0 -26
- data/lib/pdk/validate/puppet/puppet_epp.rb +0 -135
- data/lib/pdk/validate/puppet/puppet_lint.rb +0 -64
- data/lib/pdk/validate/puppet/puppet_syntax.rb +0 -135
- data/lib/pdk/validate/puppet_validator.rb +0 -26
- data/lib/pdk/validate/ruby/rubocop.rb +0 -72
- data/lib/pdk/validate/ruby_validator.rb +0 -26
- data/lib/pdk/validate/tasks/metadata_lint.rb +0 -130
- data/lib/pdk/validate/tasks/name.rb +0 -90
- data/lib/pdk/validate/tasks_validator.rb +0 -29
- data/lib/pdk/validate/yaml/syntax.rb +0 -125
- data/lib/pdk/validate/yaml_validator.rb +0 -28
@@ -0,0 +1,24 @@
|
|
1
|
+
module PDK::CLI
|
2
|
+
@get_config_cmd = @get_cmd.define_command do
|
3
|
+
name 'config'
|
4
|
+
usage _('config [name]')
|
5
|
+
summary _('Retrieve the configuration for <name>. If not specified, retrieve all configuration settings')
|
6
|
+
|
7
|
+
run do |_opts, args, _cmd|
|
8
|
+
item_name = args[0]
|
9
|
+
resolved_config = PDK.config.resolve(item_name)
|
10
|
+
# If the user wanted to know a setting but it doesn't exist, raise an error
|
11
|
+
if resolved_config.empty? && !item_name.nil?
|
12
|
+
PDK.logger.error(_("Configuration item '%{name}' does not exist") % { name: item_name })
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
# If the user requested a setting and it's the only one resolved, then just output the value
|
16
|
+
if resolved_config.count == 1 && resolved_config.keys[0] == item_name
|
17
|
+
puts _('%{value}') % { value: resolved_config.values[0] }
|
18
|
+
exit 0
|
19
|
+
end
|
20
|
+
# Otherwise just output everything
|
21
|
+
resolved_config.keys.sort.each { |key| puts _('%{name}=%{value}') % { name: key, value: resolved_config[key] } }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/pdk/cli/util.rb
CHANGED
@@ -129,13 +129,14 @@ module PDK
|
|
129
129
|
end
|
130
130
|
module_function :check_for_deprecated_puppet
|
131
131
|
|
132
|
-
# @param opts [Hash] - the pdk options
|
132
|
+
# @param opts [Hash] - the pdk options to use, defaults to empty hash
|
133
133
|
# @option opts [String] :'puppet-dev' Use the puppet development version, default to PDK_PUPPET_DEV env
|
134
134
|
# @option opts [String] :'puppet-version' Puppet version to use, default to PDK_PUPPET_VERSION env
|
135
135
|
# @option opts [String] :'pe-version' PE Puppet version to use, default to PDK_PE_VERSION env
|
136
136
|
# @param logging_disabled [Boolean] - disable logging of PDK info
|
137
|
+
# @param context [PDK::Context::AbstractContext] - The context the PDK is running in
|
137
138
|
# @return [Hash] - return hash of { gemset: <>, ruby_version: 2.x.x }
|
138
|
-
def puppet_from_opts_or_env(opts, logging_disabled = false)
|
139
|
+
def puppet_from_opts_or_env(opts, logging_disabled = false, context = PDK.context)
|
139
140
|
opts ||= {}
|
140
141
|
use_puppet_dev = opts.fetch(:'puppet-dev', PDK::Util::Env['PDK_PUPPET_DEV'])
|
141
142
|
desired_puppet_version = opts.fetch(:'puppet-version', PDK::Util::Env['PDK_PUPPET_VERSION'])
|
@@ -150,8 +151,10 @@ module PDK
|
|
150
151
|
PDK::Util::PuppetVersion.find_gem_for(desired_puppet_version)
|
151
152
|
elsif desired_pe_version
|
152
153
|
PDK::Util::PuppetVersion.from_pe_version(desired_pe_version)
|
153
|
-
|
154
|
+
elsif context.is_a?(PDK::Context::Module)
|
154
155
|
PDK::Util::PuppetVersion.from_module_metadata || PDK::Util::PuppetVersion.latest_available
|
156
|
+
else
|
157
|
+
PDK::Util::PuppetVersion.latest_available
|
155
158
|
end
|
156
159
|
rescue ArgumentError => e
|
157
160
|
raise PDK::CLI::ExitWithError, e.message
|
data/lib/pdk/cli/validate.rb
CHANGED
@@ -19,6 +19,9 @@ module PDK::CLI
|
|
19
19
|
flag nil, :parallel, _('Run validations in parallel.')
|
20
20
|
|
21
21
|
run do |opts, args, _cmd|
|
22
|
+
# Write the context information to the debug log
|
23
|
+
PDK.context.to_debug_log
|
24
|
+
|
22
25
|
if args == ['help']
|
23
26
|
PDK::CLI.run(['validate', '--help'])
|
24
27
|
exit 0
|
@@ -26,42 +29,42 @@ module PDK::CLI
|
|
26
29
|
|
27
30
|
require 'pdk/validate'
|
28
31
|
|
29
|
-
validator_names = PDK::Validate.validators.map { |v| v.name }
|
30
|
-
validators = PDK::Validate.validators
|
31
|
-
targets = []
|
32
|
-
|
33
32
|
if opts[:list]
|
34
33
|
PDK::CLI::Util.analytics_screen_view('validate', opts)
|
35
|
-
PDK.logger.info(_('Available validators: %{validator_names}') % { validator_names: validator_names.join(', ') })
|
34
|
+
PDK.logger.info(_('Available validators: %{validator_names}') % { validator_names: PDK::Validate.validator_names.join(', ') })
|
36
35
|
exit 0
|
37
36
|
end
|
38
37
|
|
39
38
|
PDK::CLI::Util.validate_puppet_version_opts(opts)
|
39
|
+
unless PDK.feature_flag?('controlrepo') || PDK.context.is_a?(PDK::Context::Module)
|
40
|
+
raise PDK::CLI::ExitWithError.new(_('Code validation can only be run from inside a valid module directory'), log_level: :error)
|
41
|
+
end
|
40
42
|
|
41
|
-
PDK::CLI::Util.
|
42
|
-
message: _('Code validation can only be run from inside a valid module directory'),
|
43
|
-
log_level: :info,
|
44
|
-
)
|
43
|
+
PDK::CLI::Util.module_version_check if PDK.context.is_a?(PDK::Context::Module)
|
45
44
|
|
46
|
-
|
45
|
+
# Set the ruby version we're going to use early. Must be set before the validators are created.
|
46
|
+
# Note that this is a bit of code-smell and should be fixed
|
47
|
+
puppet_env = PDK::CLI::Util.puppet_from_opts_or_env(opts)
|
48
|
+
PDK::Util::RubyVersion.use(puppet_env[:ruby_version])
|
47
49
|
|
50
|
+
targets = []
|
51
|
+
validators_to_run = nil
|
48
52
|
if args[0]
|
49
53
|
# This may be a single validator, a list of validators, or a target.
|
50
54
|
if Util::OptionValidator.comma_separated_list?(args[0])
|
51
55
|
# This is a comma separated list. Treat each item as a validator.
|
52
|
-
|
53
56
|
vals = Util::OptionNormalizer.comma_separated_list_to_array(args[0])
|
54
|
-
|
57
|
+
validators_to_run = PDK::Validate.validator_names.select { |name| vals.include?(name) }
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
PDK.logger.warn(_("Unknown validator '%{v}'. Available validators: %{validators}.") % { v: v, validators: validator_names.join(', ') })
|
59
|
+
vals.reject { |v| PDK::Validate.validator_names.include?(v) }
|
60
|
+
.each do |v|
|
61
|
+
PDK.logger.warn(_("Unknown validator '%{v}'. Available validators: %{validators}.") % { v: v, validators: PDK::Validate.validator_names.join(', ') })
|
59
62
|
end
|
60
63
|
else
|
61
64
|
# This is a single item. Check if it's a known validator, or otherwise treat it as a target.
|
62
|
-
val = PDK::Validate.
|
65
|
+
val = PDK::Validate.validator_names.find { |name| args[0] == name }
|
63
66
|
if val
|
64
|
-
|
67
|
+
validators_to_run = [val]
|
65
68
|
else
|
66
69
|
targets = [args[0]]
|
67
70
|
# We now know that no validators were passed, so let the user know we're using all of them by default.
|
@@ -71,11 +74,12 @@ module PDK::CLI
|
|
71
74
|
else
|
72
75
|
PDK.logger.info(_('Running all available validators...'))
|
73
76
|
end
|
77
|
+
validators_to_run = PDK::Validate.validator_names if validators_to_run.nil?
|
74
78
|
|
75
|
-
if
|
79
|
+
if validators_to_run.sort == PDK::Validate.validator_names.sort
|
76
80
|
PDK::CLI::Util.analytics_screen_view('validate', opts)
|
77
81
|
else
|
78
|
-
PDK::CLI::Util.analytics_screen_view(['validate',
|
82
|
+
PDK::CLI::Util.analytics_screen_view(['validate', validators_to_run.sort].flatten.join('_'), opts)
|
79
83
|
end
|
80
84
|
|
81
85
|
# Subsequent arguments are targets.
|
@@ -93,36 +97,14 @@ module PDK::CLI
|
|
93
97
|
|
94
98
|
options = targets.empty? ? {} : { targets: targets }
|
95
99
|
options[:auto_correct] = true if opts[:'auto-correct']
|
96
|
-
|
97
|
-
# Ensure that the bundled gems are up to date and correct Ruby is activated before running any validations.
|
98
|
-
puppet_env = PDK::CLI::Util.puppet_from_opts_or_env(opts)
|
99
|
-
PDK::Util::RubyVersion.use(puppet_env[:ruby_version])
|
100
|
-
|
101
100
|
options.merge!(puppet_env[:gemset])
|
102
101
|
|
102
|
+
# Ensure that the bundled gems are up to date and correct Ruby is activated before running any validations.
|
103
|
+
# Note that if no Gemfile exists, then ensure_bundle! will log a debug message and exit gracefully
|
103
104
|
require 'pdk/util/bundler'
|
104
|
-
|
105
105
|
PDK::Util::Bundler.ensure_bundle!(puppet_env[:gemset])
|
106
106
|
|
107
|
-
exit_code =
|
108
|
-
if opts[:parallel]
|
109
|
-
require 'pdk/cli/exec_group'
|
110
|
-
|
111
|
-
exec_group = PDK::CLI::ExecGroup.new(_('Validating module using %{num_of_threads} threads' % { num_of_threads: validators.count }), opts)
|
112
|
-
|
113
|
-
validators.each do |validator|
|
114
|
-
exec_group.register do
|
115
|
-
validator.invoke(report, options.merge(exec_group: exec_group))
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
exit_code = exec_group.exit_code
|
120
|
-
else
|
121
|
-
validators.each do |validator|
|
122
|
-
validator_exit_code = validator.invoke(report, options.dup)
|
123
|
-
exit_code = validator_exit_code if validator_exit_code != 0
|
124
|
-
end
|
125
|
-
end
|
107
|
+
exit_code, report = PDK::Validate.invoke_validators_by_name(PDK.context, validators_to_run, opts.fetch(:parallel, false), options)
|
126
108
|
|
127
109
|
report_formats.each do |format|
|
128
110
|
report.send(format[:method], format[:target])
|
data/lib/pdk/config.rb
CHANGED
@@ -2,6 +2,8 @@ require 'pdk'
|
|
2
2
|
|
3
3
|
module PDK
|
4
4
|
class Config
|
5
|
+
autoload :IniFile, 'pdk/config/ini_file'
|
6
|
+
autoload :IniFileSetting, 'pdk/config/ini_file_setting'
|
5
7
|
autoload :JSON, 'pdk/config/json'
|
6
8
|
autoload :JSONSchemaNamespace, 'pdk/config/json_schema_namespace'
|
7
9
|
autoload :JSONSchemaSetting, 'pdk/config/json_schema_setting'
|
@@ -11,16 +13,58 @@ module PDK
|
|
11
13
|
autoload :Validator, 'pdk/config/validator'
|
12
14
|
autoload :YAML, 'pdk/config/yaml'
|
13
15
|
|
16
|
+
# Create a new instance of the PDK Configuration
|
17
|
+
# @param options [Hash[String => Object]] Optional hash to override configuration options
|
18
|
+
# @option options [String] 'system.path' Path to the system PDK configuration file
|
19
|
+
# @option options [String] 'system.module_defaults.path' Path to the system module answers PDK configuration file
|
20
|
+
# @option options [String] 'user.path' Path to the user PDK configuration file
|
21
|
+
# @option options [String] 'user.module_defaults.path' Path to the user module answers PDK configuration file
|
22
|
+
# @option options [String] 'user.analytics.path' Path to the user analytics PDK configuration file
|
23
|
+
# @option options [PDK::Context::AbstractContext] 'context' The context that the configuration should be created in
|
24
|
+
def initialize(options = nil)
|
25
|
+
options = {} if options.nil?
|
26
|
+
@config_options = {
|
27
|
+
'system.path' => PDK::Config.system_config_path,
|
28
|
+
'system.module_defaults.path' => PDK::Config.system_answers_path,
|
29
|
+
'user.path' => PDK::Config.user_config_path,
|
30
|
+
'user.module_defaults.path' => PDK::AnswerFile.default_answer_file_path,
|
31
|
+
'user.analytics.path' => PDK::Config.analytics_config_path,
|
32
|
+
'context' => PDK.context,
|
33
|
+
}.merge(options)
|
34
|
+
end
|
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]
|
14
40
|
def user
|
15
|
-
|
16
|
-
|
41
|
+
user_config
|
42
|
+
end
|
43
|
+
|
44
|
+
# The system level configuration settings.
|
45
|
+
# @return [PDK::Config::Namespace]
|
46
|
+
# @api private
|
47
|
+
def system_config
|
48
|
+
local_options = @config_options
|
49
|
+
@system ||= PDK::Config::JSON.new('system', file: local_options['system.path']) do
|
50
|
+
mount :module_defaults, PDK::Config::JSON.new(file: local_options['system.module_defaults.path'])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# The user level configuration settings.
|
55
|
+
# @return [PDK::Config::Namespace]
|
56
|
+
# @api private
|
57
|
+
def user_config
|
58
|
+
local_options = @config_options
|
59
|
+
@user ||= PDK::Config::JSON.new('user', file: local_options['user.path']) do
|
60
|
+
mount :module_defaults, PDK::Config::JSON.new(file: local_options['user.module_defaults.path'])
|
17
61
|
|
18
62
|
# Due to the json-schema gem having issues with Windows based paths, and only supporting Draft 05 (or less) do
|
19
63
|
# not use JSON validation yet. Once PDK drops support for EOL rubies, we will be able to use the json_schemer gem
|
20
64
|
# Which has much more modern support
|
21
65
|
# Reference - https://github.com/puppetlabs/pdk/pull/777
|
22
66
|
# Reference - https://tickets.puppetlabs.com/browse/PDK-1526
|
23
|
-
mount :analytics, PDK::Config::YAML.new(file:
|
67
|
+
mount :analytics, PDK::Config::YAML.new(file: local_options['user.analytics.path'], persistent_defaults: true) do
|
24
68
|
setting :disabled do
|
25
69
|
validate PDK::Config::Validator.boolean
|
26
70
|
default_to { PDK::Config.bolt_analytics_config.fetch('disabled', true) }
|
@@ -35,6 +79,29 @@ module PDK
|
|
35
79
|
end
|
36
80
|
end
|
37
81
|
end
|
82
|
+
|
83
|
+
# Display the feature flags
|
84
|
+
mount :pdk_feature_flags, PDK::Config::Namespace.new('pdk_feature_flags') do
|
85
|
+
setting 'available' do
|
86
|
+
default_to { PDK.available_feature_flags }
|
87
|
+
end
|
88
|
+
|
89
|
+
setting 'requested' do
|
90
|
+
default_to { PDK.requested_feature_flags }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# The project level configuration settings.
|
97
|
+
# @return [PDK::Config::Namespace]
|
98
|
+
# @api private
|
99
|
+
def project_config
|
100
|
+
context = @config_options['context']
|
101
|
+
@project ||= PDK::Config::Namespace.new('project') do
|
102
|
+
if context.is_a?(PDK::Context::ControlRepo)
|
103
|
+
mount :environment, PDK::ControlRepo.environment_conf_as_config(File.join(context.root_path, 'environment.conf'))
|
104
|
+
end
|
38
105
|
end
|
39
106
|
end
|
40
107
|
|
@@ -43,7 +110,63 @@ module PDK
|
|
43
110
|
# @param filter [String] Only resolve setting names which match the filter. See PDK::Config::Namespace.be_resolved? for matching rules
|
44
111
|
# @return [Hash{String => Object}] All resolved settings for example {'user.module_defaults.author' => 'johndoe'}
|
45
112
|
def resolve(filter = nil)
|
46
|
-
|
113
|
+
all_scopes.values.reverse.reduce({}) do |result, method_name|
|
114
|
+
result.merge(send(method_name).resolve(filter))
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns a configuration setting by name. This name can either be a String, Array or parameters e.g. These are equivalent
|
119
|
+
# - PDK.config.get('user.a.b.c')
|
120
|
+
# - PDK.config.get(['user', 'a', 'b', 'c'])
|
121
|
+
# - PDK.config.get('user', 'a', 'b', 'c')
|
122
|
+
# @return [PDK::Config::Namespace, Object, nil] The value of the configuration setting. Returns nil if it does no exist
|
123
|
+
def get(root, *keys)
|
124
|
+
return nil if root.nil? || root.empty?
|
125
|
+
|
126
|
+
if keys.empty?
|
127
|
+
if root.is_a?(Array)
|
128
|
+
name = root
|
129
|
+
elsif root.is_a?(String)
|
130
|
+
name = split_key_string(root)
|
131
|
+
else
|
132
|
+
return nil
|
133
|
+
end
|
134
|
+
else
|
135
|
+
name = [root].concat(keys)
|
136
|
+
end
|
137
|
+
|
138
|
+
get_within_scopes(name[1..-1], [name[0]])
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns a configuration setting by name, using scope precedence rules. If no scopes are passed, then all scopes are queried using the default precedence rules
|
142
|
+
# @setting_name [String, Array[String]] The setting name to retrieve without the leading scope name e.g. Use 'setting' instead of 'system.setting'
|
143
|
+
# @scopes [Nil, Array[String]] The list of scopes, in order, to query in turn for the setting_name. Invalid or missing scopes are ignored.
|
144
|
+
# @return [PDK::Config::Namespace, Object, nil] The value of the configuration setting. Returns nil if it does no exist
|
145
|
+
def get_within_scopes(setting_name, scopes = nil)
|
146
|
+
raise ArgumentError, _('Expected an Array but got \'%{klass}\' for scopes') % { klass: scopes.class } unless scopes.nil? || scopes.is_a?(Array)
|
147
|
+
raise ArgumentError, _('Expected an Array or String but got \'%{klass}\' for setting_name') % { klass: setting_name.class } unless setting_name.is_a?(Array) || setting_name.is_a?(String)
|
148
|
+
|
149
|
+
setting_arr = setting_name.is_a?(String) ? split_key_string(setting_name) : setting_name
|
150
|
+
all_scope_names = all_scopes.keys
|
151
|
+
|
152
|
+
# Use only valid scope names
|
153
|
+
scopes = scopes.nil? ? all_scope_names : scopes & all_scope_names
|
154
|
+
|
155
|
+
scopes.each do |scope_name|
|
156
|
+
value = traverse_object(send(all_scopes[scope_name]), *setting_arr)
|
157
|
+
return value unless value.nil?
|
158
|
+
end
|
159
|
+
nil
|
160
|
+
end
|
161
|
+
|
162
|
+
# Yields a configuration setting value by name, using scope precedence rules. If no scopes are passed, then all scopes are queried using the default precedence rules
|
163
|
+
# @setting_name [String, Array[String]] The setting name to retrieve without the leading scope name e.g. Use 'setting' instead of 'system.setting'
|
164
|
+
# @scopes [Nil, Array[String]] The list of scopes, in order, to query in turn for the setting_name. Invalid or missing scopes are ignored.
|
165
|
+
# @yield [PDK::Config::Namespace, Object] The value of the configuration setting. Does not yield if the setting does not exist or is nil
|
166
|
+
def with_scoped_value(setting_name, scopes = nil)
|
167
|
+
raise ArgumentError, _('must be passed a block') unless block_given?
|
168
|
+
value = get_within_scopes(setting_name, scopes)
|
169
|
+
yield value unless value.nil?
|
47
170
|
end
|
48
171
|
|
49
172
|
def self.bolt_analytics_config
|
@@ -65,6 +188,14 @@ module PDK
|
|
65
188
|
File.join(PDK::Util.configdir, 'user_config.json')
|
66
189
|
end
|
67
190
|
|
191
|
+
def self.system_config_path
|
192
|
+
File.join(PDK::Util.system_configdir, 'system_config.json')
|
193
|
+
end
|
194
|
+
|
195
|
+
def self.system_answers_path
|
196
|
+
File.join(PDK::Util.system_configdir, 'answers.json')
|
197
|
+
end
|
198
|
+
|
68
199
|
def self.json_schemas_path
|
69
200
|
File.join(__dir__, 'config')
|
70
201
|
end
|
@@ -123,5 +254,48 @@ module PDK
|
|
123
254
|
|
124
255
|
PDK.logger.info(text: post_message, wrap: true)
|
125
256
|
end
|
257
|
+
|
258
|
+
private
|
259
|
+
|
260
|
+
#:nocov: This is a private method and is tested elsewhere
|
261
|
+
def traverse_object(object, *names)
|
262
|
+
return nil if object.nil? || !object.respond_to?(:[])
|
263
|
+
return nil if names.nil? || names.empty?
|
264
|
+
|
265
|
+
name = names.shift
|
266
|
+
value = object[name]
|
267
|
+
if names.empty?
|
268
|
+
return value if value.is_a?(PDK::Config::Namespace)
|
269
|
+
# Duplicate arrays and hashes so that they are isolated from changes being made
|
270
|
+
(value.is_a?(Hash) || value.is_a?(Array)) ? value.dup : value
|
271
|
+
else
|
272
|
+
traverse_object(value, *names)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
#:nocov:
|
276
|
+
|
277
|
+
#:nocov: This is a private method and is tested elsewhere
|
278
|
+
# Takes a string representation of a setting and splits into its constituent setting parts e.g.
|
279
|
+
# 'user.a.b.c' becomes ['user', 'a', 'b', 'c']
|
280
|
+
# @return [Array[String]] The string split into each setting name as an array
|
281
|
+
def split_key_string(key)
|
282
|
+
raise ArgumentError, _('Expected a String but got \'%{klass}\'') % { klass: key.class } unless key.is_a?(String)
|
283
|
+
key.split('.')
|
284
|
+
end
|
285
|
+
#:nocov:
|
286
|
+
|
287
|
+
#:nocov:
|
288
|
+
# Returns all known scope names and their associated method name to call, to query the scope
|
289
|
+
# Note - Order is important. This dictates the resolution precedence order (topmost is processed first)
|
290
|
+
# @return [Hash[String, Symbol]] A hash of the scope name then method name to call to query the scope (as a Symbol)
|
291
|
+
def all_scopes
|
292
|
+
# Note - Order is important. This dictates the resolution precedence order (topmost is processed first)
|
293
|
+
{
|
294
|
+
'project' => :project_config,
|
295
|
+
'user' => :user_config,
|
296
|
+
'system' => :system_config,
|
297
|
+
}.freeze
|
298
|
+
end
|
299
|
+
#:nocov:
|
126
300
|
end
|
127
301
|
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'pdk'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
class Config
|
5
|
+
# Represents a configuration file using the INI file format
|
6
|
+
class IniFile < Namespace
|
7
|
+
# Ini Files have very strict valdiation rules which are set in the IniFileSetting class
|
8
|
+
# @see PDK::Config::Namespace.default_setting_class
|
9
|
+
def default_setting_class
|
10
|
+
PDK::Config::IniFileSetting
|
11
|
+
end
|
12
|
+
|
13
|
+
# Parses an IniFile document.
|
14
|
+
#
|
15
|
+
# @see PDK::Config::Namespace.parse_file
|
16
|
+
def parse_file(filename)
|
17
|
+
raise unless block_given?
|
18
|
+
data = load_data(filename)
|
19
|
+
return if data.nil? || data.empty?
|
20
|
+
|
21
|
+
ini_file = IniFileImpl.parse(data)
|
22
|
+
ini_file.to_hash.each do |name, value|
|
23
|
+
begin
|
24
|
+
new_setting = PDK::Config::IniFileSetting.new(name, self, value)
|
25
|
+
rescue StandardError
|
26
|
+
# We just ignore invalid initial settings
|
27
|
+
new_setting = PDK::Config::IniFileSetting.new(name, self, nil)
|
28
|
+
end
|
29
|
+
|
30
|
+
yield name, new_setting
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Serializes object data into an INI file string.
|
35
|
+
#
|
36
|
+
# @see PDK::Config::Namespace.serialize_data
|
37
|
+
def serialize_data(data)
|
38
|
+
default_lines = ''
|
39
|
+
lines = ''
|
40
|
+
data.each do |name, value|
|
41
|
+
next if value.nil?
|
42
|
+
if value.is_a?(Hash)
|
43
|
+
# Hashes are an INI section
|
44
|
+
lines += "\n[#{name}]\n"
|
45
|
+
value.each do |child_name, child_value|
|
46
|
+
next if child_value.nil?
|
47
|
+
lines += "#{child_name} = #{munge_serialized_value(child_value)}\n"
|
48
|
+
end
|
49
|
+
else
|
50
|
+
default_lines += "#{name} = #{munge_serialized_value(value)}\n"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
default_lines + lines
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def munge_serialized_value(value)
|
60
|
+
value = value.to_s unless value.is_a?(String)
|
61
|
+
# Add enclosing quotes if there's a space in the value
|
62
|
+
value = '"' + value + '"' if value.include?(' ')
|
63
|
+
value
|
64
|
+
end
|
65
|
+
|
66
|
+
# Adapted from https://raw.githubusercontent.com/puppetlabs/puppet/6c257fc7827989c2af2901f974666f0f23611153/lib/puppet/settings/ini_file.rb
|
67
|
+
# rubocop:disable Style/RegexpLiteral
|
68
|
+
# rubocop:disable Style/PerlBackrefs
|
69
|
+
# rubocop:disable Style/RedundantSelf
|
70
|
+
# rubocop:disable Style/StringLiterals
|
71
|
+
class IniFileImpl
|
72
|
+
DEFAULT_SECTION_NAME = 'default_section_name'.freeze
|
73
|
+
|
74
|
+
def self.parse(config_fh)
|
75
|
+
config = new([DefaultSection.new])
|
76
|
+
config_fh.each_line do |line|
|
77
|
+
case line.chomp
|
78
|
+
when /^(\s*)\[([[:word:]]+)\](\s*)$/
|
79
|
+
config.append(SectionLine.new($1, $2, $3))
|
80
|
+
when /^(\s*)([[:word:]]+)(\s*=\s*)(.*?)(\s*)$/
|
81
|
+
config.append(SettingLine.new($1, $2, $3, $4, $5))
|
82
|
+
else
|
83
|
+
config.append(Line.new(line))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
config
|
88
|
+
end
|
89
|
+
|
90
|
+
def initialize(lines = [])
|
91
|
+
@lines = lines
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_hash
|
95
|
+
result = {}
|
96
|
+
|
97
|
+
current_section_name = nil
|
98
|
+
@lines.each do |line|
|
99
|
+
if line.instance_of?(SectionLine)
|
100
|
+
current_section_name = line.name
|
101
|
+
result[current_section_name] = {}
|
102
|
+
elsif line.instance_of?(SettingLine)
|
103
|
+
if current_section_name.nil?
|
104
|
+
result[line.name] = munge_value(line.value)
|
105
|
+
else
|
106
|
+
result[current_section_name][line.name] = munge_value(line.value)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
result
|
112
|
+
end
|
113
|
+
|
114
|
+
def munge_value(value)
|
115
|
+
value = value.to_s unless value.is_a?(String)
|
116
|
+
# Strip enclosing quotes
|
117
|
+
value = value.slice(1...-1) if value.start_with?('"') && value.end_with?('"')
|
118
|
+
value
|
119
|
+
end
|
120
|
+
|
121
|
+
def append(line)
|
122
|
+
line.previous = @lines.last
|
123
|
+
@lines << line
|
124
|
+
end
|
125
|
+
|
126
|
+
module LineNumber
|
127
|
+
attr_accessor :previous
|
128
|
+
|
129
|
+
def line_number
|
130
|
+
line = 0
|
131
|
+
previous_line = previous
|
132
|
+
while previous_line
|
133
|
+
line += 1
|
134
|
+
previous_line = previous_line.previous
|
135
|
+
end
|
136
|
+
line
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
Line = Struct.new(:text) do
|
141
|
+
include LineNumber
|
142
|
+
|
143
|
+
def to_s
|
144
|
+
text
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
SettingLine = Struct.new(:prefix, :name, :infix, :value, :suffix) do
|
149
|
+
include LineNumber
|
150
|
+
|
151
|
+
def to_s
|
152
|
+
"#{prefix}#{name}#{infix}#{value}#{suffix}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def ==(other)
|
156
|
+
super(other) && self.line_number == other.line_number
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
SectionLine = Struct.new(:prefix, :name, :suffix) do
|
161
|
+
include LineNumber
|
162
|
+
|
163
|
+
def to_s
|
164
|
+
"#{prefix}[#{name}]#{suffix}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class DefaultSection < SectionLine
|
169
|
+
attr_accessor :write_sectionline
|
170
|
+
|
171
|
+
def initialize
|
172
|
+
@write_sectionline = false
|
173
|
+
super("", DEFAULT_SECTION_NAME, "")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
# rubocop:enable Style/StringLiterals
|
178
|
+
# rubocop:enable Style/RedundantSelf
|
179
|
+
# rubocop:enable Style/PerlBackrefs
|
180
|
+
# rubocop:enable Style/RegexpLiteral
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|