pdk 1.9.0 → 3.2.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 +744 -711
- data/README.md +23 -21
- data/lib/pdk/answer_file.rb +3 -112
- data/lib/pdk/bolt.rb +20 -0
- data/lib/pdk/cli/build.rb +51 -54
- data/lib/pdk/cli/bundle.rb +33 -29
- data/lib/pdk/cli/console.rb +148 -0
- data/lib/pdk/cli/convert.rb +46 -37
- data/lib/pdk/cli/env.rb +51 -0
- data/lib/pdk/cli/errors.rb +4 -3
- data/lib/pdk/cli/exec/command.rb +285 -0
- data/lib/pdk/cli/exec/interactive_command.rb +109 -0
- data/lib/pdk/cli/exec.rb +32 -201
- data/lib/pdk/cli/exec_group.rb +79 -43
- data/lib/pdk/cli/get/config.rb +26 -0
- data/lib/pdk/cli/get.rb +22 -0
- data/lib/pdk/cli/new/class.rb +20 -22
- data/lib/pdk/cli/new/defined_type.rb +21 -21
- data/lib/pdk/cli/new/fact.rb +27 -0
- data/lib/pdk/cli/new/function.rb +27 -0
- data/lib/pdk/cli/new/module.rb +40 -29
- data/lib/pdk/cli/new/provider.rb +18 -18
- data/lib/pdk/cli/new/task.rb +23 -22
- data/lib/pdk/cli/new/test.rb +52 -0
- data/lib/pdk/cli/new/transport.rb +27 -0
- data/lib/pdk/cli/new.rb +15 -9
- data/lib/pdk/cli/release/prep.rb +39 -0
- data/lib/pdk/cli/release/publish.rb +46 -0
- data/lib/pdk/cli/release.rb +185 -0
- data/lib/pdk/cli/remove/config.rb +83 -0
- data/lib/pdk/cli/remove.rb +22 -0
- data/lib/pdk/cli/set/config.rb +121 -0
- data/lib/pdk/cli/set.rb +22 -0
- data/lib/pdk/cli/test/unit.rb +71 -69
- data/lib/pdk/cli/test.rb +9 -8
- data/lib/pdk/cli/update.rb +38 -21
- data/lib/pdk/cli/util/command_redirector.rb +13 -3
- data/lib/pdk/cli/util/interview.rb +25 -9
- data/lib/pdk/cli/util/option_normalizer.rb +6 -6
- data/lib/pdk/cli/util/option_validator.rb +19 -9
- data/lib/pdk/cli/util/spinner.rb +13 -0
- data/lib/pdk/cli/util/update_manager_printer.rb +82 -0
- data/lib/pdk/cli/util.rb +105 -48
- data/lib/pdk/cli/validate.rb +96 -111
- data/lib/pdk/cli.rb +134 -87
- data/lib/pdk/config/errors.rb +5 -0
- data/lib/pdk/config/ini_file.rb +184 -0
- data/lib/pdk/config/ini_file_setting.rb +35 -0
- data/lib/pdk/config/json.rb +35 -0
- data/lib/pdk/config/json_schema_namespace.rb +137 -0
- data/lib/pdk/config/json_schema_setting.rb +51 -0
- data/lib/pdk/config/json_with_schema.rb +47 -0
- data/lib/pdk/config/namespace.rb +362 -0
- data/lib/pdk/config/setting.rb +134 -0
- data/lib/pdk/config/task_schema.json +116 -0
- data/lib/pdk/config/validator.rb +31 -0
- data/lib/pdk/config/yaml.rb +41 -0
- data/lib/pdk/config/yaml_with_schema.rb +51 -0
- data/lib/pdk/config.rb +304 -0
- data/lib/pdk/context/control_repo.rb +61 -0
- data/lib/pdk/context/module.rb +28 -0
- data/lib/pdk/context/none.rb +22 -0
- data/lib/pdk/context.rb +98 -0
- data/lib/pdk/control_repo.rb +89 -0
- data/lib/pdk/generate/defined_type.rb +27 -33
- data/lib/pdk/generate/fact.rb +26 -0
- data/lib/pdk/generate/function.rb +49 -0
- data/lib/pdk/generate/module.rb +160 -153
- data/lib/pdk/generate/provider.rb +16 -69
- data/lib/pdk/generate/puppet_class.rb +27 -32
- data/lib/pdk/generate/puppet_object.rb +100 -159
- data/lib/pdk/generate/task.rb +34 -51
- data/lib/pdk/generate/transport.rb +34 -0
- data/lib/pdk/generate.rb +21 -8
- data/lib/pdk/logger.rb +24 -6
- data/lib/pdk/module/build.rb +125 -37
- data/lib/pdk/module/convert.rb +146 -65
- data/lib/pdk/module/metadata.rb +72 -71
- data/lib/pdk/module/release.rb +255 -0
- data/lib/pdk/module/update.rb +48 -37
- data/lib/pdk/module/update_manager.rb +75 -39
- data/lib/pdk/module.rb +10 -2
- data/lib/pdk/monkey_patches.rb +268 -0
- data/lib/pdk/report/event.rb +36 -48
- data/lib/pdk/report.rb +35 -22
- data/lib/pdk/template/fetcher/git.rb +84 -0
- data/lib/pdk/template/fetcher/local.rb +29 -0
- data/lib/pdk/template/fetcher.rb +100 -0
- data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +108 -0
- data/lib/pdk/template/renderer/v1/renderer.rb +131 -0
- data/lib/pdk/template/renderer/v1/template_file.rb +100 -0
- data/lib/pdk/template/renderer/v1.rb +25 -0
- data/lib/pdk/template/renderer.rb +97 -0
- data/lib/pdk/template/template_dir.rb +67 -0
- data/lib/pdk/template.rb +52 -0
- data/lib/pdk/tests/unit.rb +101 -51
- data/lib/pdk/util/bundler.rb +44 -42
- data/lib/pdk/util/changelog_generator.rb +138 -0
- data/lib/pdk/util/env.rb +48 -0
- data/lib/pdk/util/filesystem.rb +139 -2
- data/lib/pdk/util/git.rb +108 -8
- data/lib/pdk/util/json_finder.rb +86 -0
- data/lib/pdk/util/puppet_strings.rb +125 -0
- data/lib/pdk/util/puppet_version.rb +71 -87
- data/lib/pdk/util/ruby_version.rb +49 -25
- data/lib/pdk/util/template_uri.rb +283 -0
- data/lib/pdk/util/vendored_file.rb +34 -42
- data/lib/pdk/util/version.rb +11 -10
- data/lib/pdk/util/windows/api_types.rb +74 -44
- data/lib/pdk/util/windows/file.rb +31 -27
- data/lib/pdk/util/windows/process.rb +74 -0
- data/lib/pdk/util/windows/string.rb +19 -12
- data/lib/pdk/util/windows.rb +2 -0
- data/lib/pdk/util.rb +111 -124
- 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/external_command_validator.rb +213 -0
- data/lib/pdk/validate/internal_ruby_validator.rb +101 -0
- data/lib/pdk/validate/invokable_validator.rb +238 -0
- data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +84 -0
- data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +76 -0
- data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -0
- data/lib/pdk/validate/puppet/puppet_epp_validator.rb +131 -0
- data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -0
- data/lib/pdk/validate/puppet/puppet_plan_syntax_validator.rb +38 -0
- data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +135 -0
- data/lib/pdk/validate/puppet/puppet_validator_group.rb +22 -0
- data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +79 -0
- data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -0
- data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +83 -0
- data/lib/pdk/validate/tasks/tasks_name_validator.rb +45 -0
- data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -0
- data/lib/pdk/validate/validator.rb +120 -0
- data/lib/pdk/validate/validator_group.rb +107 -0
- data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +86 -0
- data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -0
- data/lib/pdk/validate.rb +86 -12
- data/lib/pdk/version.rb +2 -2
- data/lib/pdk.rb +60 -10
- metadata +138 -100
- data/lib/pdk/cli/module/build.rb +0 -14
- data/lib/pdk/cli/module/generate.rb +0 -45
- data/lib/pdk/cli/module.rb +0 -14
- data/lib/pdk/i18n.rb +0 -4
- data/lib/pdk/module/templatedir.rb +0 -321
- data/lib/pdk/template_file.rb +0 -95
- data/lib/pdk/validate/base_validator.rb +0 -215
- data/lib/pdk/validate/metadata/metadata_json_lint.rb +0 -86
- data/lib/pdk/validate/metadata/metadata_syntax.rb +0 -109
- data/lib/pdk/validate/metadata_validator.rb +0 -30
- data/lib/pdk/validate/puppet/puppet_lint.rb +0 -67
- data/lib/pdk/validate/puppet/puppet_syntax.rb +0 -112
- data/lib/pdk/validate/puppet_validator.rb +0 -30
- data/lib/pdk/validate/ruby/rubocop.rb +0 -77
- data/lib/pdk/validate/ruby_validator.rb +0 -29
- data/lib/pdk/validate/tasks/metadata_lint.rb +0 -126
- data/lib/pdk/validate/tasks/name.rb +0 -88
- data/lib/pdk/validate/tasks_validator.rb +0 -33
- data/lib/pdk/validate/yaml/syntax.rb +0 -109
- data/lib/pdk/validate/yaml_validator.rb +0 -31
- data/locales/config.yaml +0 -21
- data/locales/pdk.pot +0 -1291
data/lib/pdk/cli.rb
CHANGED
|
@@ -1,113 +1,160 @@
|
|
|
1
1
|
require 'cri'
|
|
2
2
|
|
|
3
|
+
require 'pdk'
|
|
3
4
|
require 'pdk/cli/errors'
|
|
4
|
-
require 'pdk/cli/util'
|
|
5
|
-
require 'pdk/cli/util/command_redirector'
|
|
6
|
-
require 'pdk/cli/util/option_normalizer'
|
|
7
|
-
require 'pdk/cli/util/option_validator'
|
|
8
|
-
require 'pdk/cli/exec_group'
|
|
9
|
-
require 'pdk/generate/module'
|
|
10
|
-
require 'pdk/i18n'
|
|
11
|
-
require 'pdk/logger'
|
|
12
|
-
require 'pdk/report'
|
|
13
|
-
require 'pdk/util/version'
|
|
14
|
-
require 'pdk/util/puppet_version'
|
|
15
|
-
|
|
16
|
-
module PDK::CLI
|
|
17
|
-
def self.run(args)
|
|
18
|
-
@base_cmd.run(args)
|
|
19
|
-
rescue PDK::CLI::ExitWithError => e
|
|
20
|
-
PDK.logger.send(e.log_level, e.message)
|
|
21
|
-
|
|
22
|
-
exit e.exit_code
|
|
23
|
-
rescue PDK::CLI::FatalError => e
|
|
24
|
-
PDK.logger.fatal(e.message) if e.message
|
|
25
|
-
|
|
26
|
-
# If FatalError was raised as the result of another exception, send the
|
|
27
|
-
# details of that exception to the debug log. If there was no cause
|
|
28
|
-
# (FatalError raised on its own outside a rescue block), send the details
|
|
29
|
-
# of the FatalError exception to the debug log.
|
|
30
|
-
cause = e.cause
|
|
31
|
-
if cause.nil?
|
|
32
|
-
e.backtrace.each { |line| PDK.logger.debug(line) }
|
|
33
|
-
else
|
|
34
|
-
PDK.logger.debug("#{cause.class}: #{cause.message}")
|
|
35
|
-
cause.backtrace.each { |line| PDK.logger.debug(line) }
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
exit e.exit_code
|
|
39
|
-
end
|
|
40
5
|
|
|
41
|
-
|
|
42
|
-
|
|
6
|
+
module TTY
|
|
7
|
+
autoload :Prompt, 'tty/prompt'
|
|
43
8
|
|
|
44
|
-
|
|
9
|
+
class Prompt
|
|
10
|
+
autoload :Test, 'tty/prompt/test'
|
|
45
11
|
end
|
|
12
|
+
end
|
|
46
13
|
|
|
47
|
-
|
|
48
|
-
|
|
14
|
+
module Cri
|
|
15
|
+
class Command
|
|
16
|
+
class CriExitException
|
|
17
|
+
def initialize(is_error:)
|
|
18
|
+
@is_error = is_error
|
|
19
|
+
end
|
|
20
|
+
end
|
|
49
21
|
end
|
|
22
|
+
end
|
|
50
23
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
24
|
+
module PDK
|
|
25
|
+
module CLI
|
|
26
|
+
autoload :Util, 'pdk/cli/util'
|
|
27
|
+
|
|
28
|
+
# Attempt to anonymise the raw ARGV array if the command parsing failed.
|
|
29
|
+
#
|
|
30
|
+
# If an item does not start with '-' but is preceeded by an item that does
|
|
31
|
+
# start with '-', assume that these items are an option/value pair and redact
|
|
32
|
+
# the value. Any additional values that do not start with '-' that follow an
|
|
33
|
+
# option/value pair are assumed to be arguments (rather than subcommand
|
|
34
|
+
# names) and are also redacted.
|
|
35
|
+
#
|
|
36
|
+
# @example
|
|
37
|
+
# # Where PDK::CLI.args => ['new', 'plan', '--some', 'value', 'plan_name']
|
|
38
|
+
#
|
|
39
|
+
# PDK::CLI.anonymised_args
|
|
40
|
+
# => ['new', 'plan', '--some', 'redacted', 'redacted']
|
|
41
|
+
#
|
|
42
|
+
# @return Array[String] the command arguments with any identifying values
|
|
43
|
+
# redacted.
|
|
44
|
+
def self.anonymised_args
|
|
45
|
+
in_args = false
|
|
46
|
+
@args.map do |arg|
|
|
47
|
+
if arg.start_with?('-')
|
|
48
|
+
in_args = true
|
|
49
|
+
arg
|
|
50
|
+
else
|
|
51
|
+
in_args ? 'redacted' : arg
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
def self.run(args)
|
|
57
|
+
@args = args
|
|
58
|
+
@base_cmd.run(args)
|
|
59
|
+
rescue PDK::CLI::ExitWithError => e
|
|
60
|
+
PDK.logger.send(e.log_level, e.message)
|
|
61
|
+
|
|
62
|
+
exit e.exit_code
|
|
63
|
+
rescue PDK::CLI::FatalError => e
|
|
64
|
+
PDK.logger.fatal(e.message) if e.message
|
|
65
|
+
|
|
66
|
+
# If FatalError was raised as the result of another exception, send the
|
|
67
|
+
# details of that exception to the debug log. If there was no cause
|
|
68
|
+
# (FatalError raised on its own outside a rescue block), send the details
|
|
69
|
+
# of the FatalError exception to the debug log.
|
|
70
|
+
cause = e.cause
|
|
71
|
+
if cause.nil?
|
|
72
|
+
e.backtrace.each { |line| PDK.logger.debug(line) }
|
|
73
|
+
else
|
|
74
|
+
PDK.logger.debug("#{cause.class}: #{cause.message}")
|
|
75
|
+
cause.backtrace.each { |line| PDK.logger.debug(line) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
exit e.exit_code
|
|
79
|
+
end
|
|
59
80
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
'puppet-dev',
|
|
63
|
-
_('When specified, PDK will validate or test against the current Puppet source from github.com. To use this option, you must have network access to https://github.com.')
|
|
64
|
-
end
|
|
81
|
+
def self.template_url_option(dsl)
|
|
82
|
+
require 'pdk/util/template_uri'
|
|
65
83
|
|
|
66
|
-
|
|
67
|
-
name 'pdk'
|
|
68
|
-
usage _('pdk command [options]')
|
|
69
|
-
summary _('Puppet Development Kit')
|
|
70
|
-
description _('The shortest path to better modules.')
|
|
71
|
-
default_subcommand 'help'
|
|
84
|
+
desc = format('Specifies the URL to the template to use when creating new modules or classes. (default: %{default_url})', default_url: PDK::Util::TemplateURI.default_template_uri)
|
|
72
85
|
|
|
73
|
-
|
|
74
|
-
puts PDK::Util::Version.version_string
|
|
75
|
-
exit 0
|
|
86
|
+
dsl.option nil, 'template-url', desc, argument: :required
|
|
76
87
|
end
|
|
77
88
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
exit 0
|
|
89
|
+
def self.template_ref_option(dsl)
|
|
90
|
+
dsl.option nil, 'template-ref', 'Specifies the template git branch or tag to use when creating new modules or classes.', argument: :required
|
|
81
91
|
end
|
|
82
92
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
"for example: '--format=junit:report.xml'. This option may be specified " \
|
|
87
|
-
'multiple times if each option specifies a distinct target file.',
|
|
88
|
-
) % { available_formats: PDK::Report.formats.join("', '") }
|
|
93
|
+
def self.skip_interview_option(dsl)
|
|
94
|
+
dsl.option nil, 'skip-interview', 'When specified, skips interactive querying of metadata.'
|
|
95
|
+
end
|
|
89
96
|
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
def self.full_interview_option(dsl)
|
|
98
|
+
dsl.option nil, 'full-interview', 'When specified, interactive querying of metadata will include all optional questions.'
|
|
92
99
|
end
|
|
93
100
|
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
def self.puppet_version_options(dsl)
|
|
102
|
+
dsl.option nil, 'puppet-version', 'Puppet version to run tests or validations against.', argument: :required
|
|
103
|
+
dsl.option nil, 'pe-version', '(Deprecated) Puppet Enterprise version to run tests or validations against.', argument: :required
|
|
96
104
|
end
|
|
97
105
|
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
def self.puppet_dev_option(dsl)
|
|
107
|
+
dsl.option nil,
|
|
108
|
+
'puppet-dev',
|
|
109
|
+
'When specified, PDK will validate or test against the current Puppet source from github.com. To use this option, you must have network access to https://github.com.'
|
|
100
110
|
end
|
|
101
|
-
end
|
|
102
111
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
@base_cmd = Cri::Command.define do
|
|
113
|
+
name 'pdk'
|
|
114
|
+
usage 'pdk command [options]'
|
|
115
|
+
summary 'Puppet Development Kit'
|
|
116
|
+
description 'The shortest path to better modules.'
|
|
117
|
+
default_subcommand 'help'
|
|
118
|
+
|
|
119
|
+
flag nil, :version, 'Show version of pdk.' do |_, _|
|
|
120
|
+
puts PDK::Util::Version.version_string
|
|
121
|
+
exit 0
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
flag :h, :help, 'Show help for this command.' do |_, c|
|
|
125
|
+
puts c.help
|
|
126
|
+
exit 0
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
format_desc =
|
|
130
|
+
"Specify desired output format. Valid formats are '#{PDK::Report.formats.join("', '")}'. " \
|
|
131
|
+
'You may also specify a file to which the formatted output is sent, ' \
|
|
132
|
+
"for example: '--format=junit:report.xml'. This option may be specified " \
|
|
133
|
+
'multiple times if each option specifies a distinct target file.'
|
|
134
|
+
|
|
135
|
+
option :f, :format, format_desc, argument: :required, multiple: true do |values|
|
|
136
|
+
PDK::CLI::Util::OptionNormalizer.report_formats(values.compact)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
flag :d, :debug, 'Enable debug output.' do |_, _|
|
|
140
|
+
PDK.logger.enable_debug_output
|
|
141
|
+
end
|
|
142
|
+
end
|
|
111
143
|
|
|
112
|
-
|
|
144
|
+
require 'pdk/cli/bundle'
|
|
145
|
+
require 'pdk/cli/build'
|
|
146
|
+
require 'pdk/cli/convert'
|
|
147
|
+
require 'pdk/cli/env'
|
|
148
|
+
require 'pdk/cli/get'
|
|
149
|
+
require 'pdk/cli/new'
|
|
150
|
+
require 'pdk/cli/set'
|
|
151
|
+
require 'pdk/cli/test'
|
|
152
|
+
require 'pdk/cli/update'
|
|
153
|
+
require 'pdk/cli/validate'
|
|
154
|
+
# require 'pdk/cli/console' Temporarily disabled while we work on the puppet-debugger gem. It will be back soon! (CONT-1154)
|
|
155
|
+
require 'pdk/cli/release'
|
|
156
|
+
require 'pdk/cli/remove'
|
|
157
|
+
|
|
158
|
+
@base_cmd.add_command Cri::Command.new_basic_help
|
|
159
|
+
end
|
|
113
160
|
end
|
|
@@ -0,0 +1,184 @@
|
|
|
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
|
+
|
|
19
|
+
data = load_data(filename)
|
|
20
|
+
return if data.nil? || data.empty?
|
|
21
|
+
|
|
22
|
+
ini_file = IniFileImpl.parse(data)
|
|
23
|
+
ini_file.to_hash.each do |name, value|
|
|
24
|
+
begin
|
|
25
|
+
new_setting = PDK::Config::IniFileSetting.new(name, self, value)
|
|
26
|
+
rescue StandardError
|
|
27
|
+
# We just ignore invalid initial settings
|
|
28
|
+
new_setting = PDK::Config::IniFileSetting.new(name, self, nil)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
yield name, new_setting
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Serializes object data into an INI file string.
|
|
36
|
+
#
|
|
37
|
+
# @see PDK::Config::Namespace.serialize_data
|
|
38
|
+
def serialize_data(data)
|
|
39
|
+
default_lines = ''
|
|
40
|
+
lines = ''
|
|
41
|
+
data.each do |name, value|
|
|
42
|
+
next if value.nil?
|
|
43
|
+
|
|
44
|
+
if value.is_a?(Hash)
|
|
45
|
+
# Hashes are an INI section
|
|
46
|
+
lines += "\n[#{name}]\n"
|
|
47
|
+
value.each do |child_name, child_value|
|
|
48
|
+
next if child_value.nil?
|
|
49
|
+
|
|
50
|
+
lines += "#{child_name} = #{munge_serialized_value(child_value)}\n"
|
|
51
|
+
end
|
|
52
|
+
else
|
|
53
|
+
default_lines += "#{name} = #{munge_serialized_value(value)}\n"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
default_lines + lines
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def munge_serialized_value(value)
|
|
63
|
+
value = value.to_s unless value.is_a?(String)
|
|
64
|
+
# Add enclosing quotes if there's a space in the value
|
|
65
|
+
value = "\"#{value}\"" if value.include?(' ')
|
|
66
|
+
value
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Adapted from https://raw.githubusercontent.com/puppetlabs/puppet/6c257fc7827989c2af2901f974666f0f23611153/lib/puppet/settings/ini_file.rb
|
|
70
|
+
# rubocop:disable Style/PerlBackrefs
|
|
71
|
+
# rubocop:disable Style/RedundantSelf
|
|
72
|
+
# rubocop:disable Style/StringLiterals
|
|
73
|
+
class IniFileImpl
|
|
74
|
+
DEFAULT_SECTION_NAME = 'default_section_name'.freeze
|
|
75
|
+
|
|
76
|
+
def self.parse(config_fh)
|
|
77
|
+
config = new([DefaultSection.new])
|
|
78
|
+
config_fh.each_line do |line|
|
|
79
|
+
case line.chomp
|
|
80
|
+
when /^(\s*)\[([[:word:]]+)\](\s*)$/
|
|
81
|
+
config.append(SectionLine.new($1, $2, $3))
|
|
82
|
+
when /^(\s*)([[:word:]]+)(\s*=\s*)(.*?)(\s*)$/
|
|
83
|
+
config.append(SettingLine.new($1, $2, $3, $4, $5))
|
|
84
|
+
else
|
|
85
|
+
config.append(Line.new(line))
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
config
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def initialize(lines = [])
|
|
93
|
+
@lines = lines
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def to_hash
|
|
97
|
+
result = {}
|
|
98
|
+
|
|
99
|
+
current_section_name = nil
|
|
100
|
+
@lines.each do |line|
|
|
101
|
+
if line.instance_of?(SectionLine)
|
|
102
|
+
current_section_name = line.name
|
|
103
|
+
result[current_section_name] = {}
|
|
104
|
+
elsif line.instance_of?(SettingLine)
|
|
105
|
+
if current_section_name.nil?
|
|
106
|
+
result[line.name] = munge_value(line.value)
|
|
107
|
+
else
|
|
108
|
+
result[current_section_name][line.name] = munge_value(line.value)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
result
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def munge_value(value)
|
|
117
|
+
value = value.to_s unless value.is_a?(String)
|
|
118
|
+
# Strip enclosing quotes
|
|
119
|
+
value = value.slice(1...-1) if value.start_with?('"') && value.end_with?('"')
|
|
120
|
+
value
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def append(line)
|
|
124
|
+
line.previous = @lines.last
|
|
125
|
+
@lines << line
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
module LineNumber
|
|
129
|
+
attr_accessor :previous
|
|
130
|
+
|
|
131
|
+
def line_number
|
|
132
|
+
line = 0
|
|
133
|
+
previous_line = previous
|
|
134
|
+
while previous_line
|
|
135
|
+
line += 1
|
|
136
|
+
previous_line = previous_line.previous
|
|
137
|
+
end
|
|
138
|
+
line
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
Line = Struct.new(:text) do
|
|
143
|
+
include LineNumber
|
|
144
|
+
|
|
145
|
+
def to_s
|
|
146
|
+
text
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
SettingLine = Struct.new(:prefix, :name, :infix, :value, :suffix) do
|
|
151
|
+
include LineNumber
|
|
152
|
+
|
|
153
|
+
def to_s
|
|
154
|
+
"#{prefix}#{name}#{infix}#{value}#{suffix}"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def ==(other)
|
|
158
|
+
super(other) && self.line_number == other.line_number
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
SectionLine = Struct.new(:prefix, :name, :suffix) do
|
|
163
|
+
include LineNumber
|
|
164
|
+
|
|
165
|
+
def to_s
|
|
166
|
+
"#{prefix}[#{name}]#{suffix}"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
class DefaultSection < SectionLine
|
|
171
|
+
attr_accessor :write_sectionline
|
|
172
|
+
|
|
173
|
+
def initialize
|
|
174
|
+
@write_sectionline = false
|
|
175
|
+
super("", DEFAULT_SECTION_NAME, "")
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
# rubocop:enable Style/StringLiterals
|
|
180
|
+
# rubocop:enable Style/RedundantSelf
|
|
181
|
+
# rubocop:enable Style/PerlBackrefs
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'pdk'
|
|
2
|
+
|
|
3
|
+
module PDK
|
|
4
|
+
class Config
|
|
5
|
+
class IniFileSetting < PDK::Config::Setting
|
|
6
|
+
# Initialises the PDK::Config::JSONSchemaSetting object.
|
|
7
|
+
#
|
|
8
|
+
# @see PDK::Config::Setting.initialize
|
|
9
|
+
def initialize(_name, namespace, initial_value = nil)
|
|
10
|
+
raise 'The IniFileSetting object can only be created within the IniFile Namespace' unless namespace.is_a?(PDK::Config::IniFile)
|
|
11
|
+
|
|
12
|
+
super
|
|
13
|
+
validate!(initial_value) unless initial_value.nil?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Verifies that the new setting value is valid in an Ini File
|
|
17
|
+
#
|
|
18
|
+
# @see PDK::Config::Setting.validate!
|
|
19
|
+
def validate!(value)
|
|
20
|
+
# We're very restrictive here. Realistically Ini files only have string types
|
|
21
|
+
return if value.nil? || value.is_a?(String) || value.is_a?(Integer)
|
|
22
|
+
|
|
23
|
+
# The only other valid-ish type is a Hash
|
|
24
|
+
raise ArgumentError, format('The setting %{key} may only be a String or Integer, not %{class}', key: qualified_name, class: value.class) unless value.is_a?(Hash)
|
|
25
|
+
|
|
26
|
+
# Any hashes can only have a single String/Integer value
|
|
27
|
+
value.each do |child_name, child_value|
|
|
28
|
+
next if child_value.nil? || child_value.is_a?(String) || child_value.is_a?(Integer)
|
|
29
|
+
|
|
30
|
+
raise ArgumentError, format('The setting %{key} may only be a String or Integer, not %{class}', key: "#{qualified_name}.#{child_name}", class: child_value.class)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'pdk'
|
|
2
|
+
|
|
3
|
+
module PDK
|
|
4
|
+
class Config
|
|
5
|
+
class JSON < Namespace
|
|
6
|
+
# Parses a JSON document.
|
|
7
|
+
#
|
|
8
|
+
# @see PDK::Config::Namespace.parse_file
|
|
9
|
+
def parse_file(filename)
|
|
10
|
+
raise unless block_given?
|
|
11
|
+
|
|
12
|
+
data = load_data(filename)
|
|
13
|
+
return if data.nil? || data.empty?
|
|
14
|
+
|
|
15
|
+
require 'json'
|
|
16
|
+
|
|
17
|
+
data = ::JSON.parse(data)
|
|
18
|
+
return if data.nil? || data.empty?
|
|
19
|
+
|
|
20
|
+
data.each { |k, v| yield k, PDK::Config::Setting.new(k, self, v) }
|
|
21
|
+
rescue ::JSON::ParserError => e
|
|
22
|
+
raise PDK::Config::LoadError, e.message
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Serializes object data into a JSON string.
|
|
26
|
+
#
|
|
27
|
+
# @see PDK::Config::Namespace.serialize_data
|
|
28
|
+
def serialize_data(data)
|
|
29
|
+
require 'json'
|
|
30
|
+
|
|
31
|
+
::JSON.pretty_generate(data)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
require 'pdk'
|
|
2
|
+
|
|
3
|
+
# Due to https://github.com/ruby-json-schema/json-schema/issues/439
|
|
4
|
+
# Windows file paths "appear" as uri's with no host and a schema of drive letter
|
|
5
|
+
# Also it is not possible to craft a URI with a Windows path due to the URI object
|
|
6
|
+
# always prepending the path with forward slash (`/`) so Windows paths end up looking
|
|
7
|
+
# like '/C:\schema.json', which can not be read.
|
|
8
|
+
# Instead we need to monkey patch the Schema Reader reader to remove the errant forward slash
|
|
9
|
+
require 'json-schema/schema/reader'
|
|
10
|
+
module JSON
|
|
11
|
+
class Schema
|
|
12
|
+
class Reader
|
|
13
|
+
alias original_read_file read_file
|
|
14
|
+
|
|
15
|
+
def read_file(pathname)
|
|
16
|
+
new_pathname = JSON::Util::URI.unescaped_path(pathname.to_s)
|
|
17
|
+
# Munge the path if it looks like a Windows path e.g. /C:/Windows ...
|
|
18
|
+
# Note that UNC style paths do not have the same issue (\\host\path)
|
|
19
|
+
new_pathname.slice!(0) if new_pathname.start_with?('/') && new_pathname[2] == ':'
|
|
20
|
+
original_read_file(Pathname.new(new_pathname))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
require 'json-schema'
|
|
27
|
+
|
|
28
|
+
module PDK
|
|
29
|
+
class Config
|
|
30
|
+
class JSONSchemaNamespace < Namespace
|
|
31
|
+
# Initialises the PDK::Config::JSONSchemaNamespace object.
|
|
32
|
+
#
|
|
33
|
+
# @see PDK::Config::Namespace.initialize
|
|
34
|
+
#
|
|
35
|
+
# @option params [String] :schema_file Path to the JSON Schema document
|
|
36
|
+
def initialize(name = nil, file: nil, parent: nil, persistent_defaults: false, schema_file: nil, &block)
|
|
37
|
+
super(name, file: file, parent: parent, persistent_defaults: persistent_defaults, &block)
|
|
38
|
+
@schema_file = schema_file
|
|
39
|
+
@unmanaged_settings = {}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# The JSON Schema for the namespace
|
|
43
|
+
#
|
|
44
|
+
# @return [Hash]
|
|
45
|
+
def schema
|
|
46
|
+
document_schema.schema
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Whether the schema is valid but empty.
|
|
50
|
+
#
|
|
51
|
+
# @return [Boolean]
|
|
52
|
+
def empty_schema?
|
|
53
|
+
document_schema.schema.empty?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Name of all the top level properties for the schema
|
|
57
|
+
#
|
|
58
|
+
# @return [String[]]
|
|
59
|
+
def schema_property_names
|
|
60
|
+
return [] if schema['properties'].nil?
|
|
61
|
+
|
|
62
|
+
schema['properties'].keys
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Extends the to_h namespace method to include unmanaged settings
|
|
66
|
+
#
|
|
67
|
+
# @see PDK::Config::Namespace.to_h
|
|
68
|
+
def to_h
|
|
69
|
+
# This may seem counter-intuitive but we need to call super first as the settings
|
|
70
|
+
# may not have been loaded yet, which means @unmanaged_settings will be empty.
|
|
71
|
+
# We call super first to force any file loading and then merge the unmanaged settings
|
|
72
|
+
settings_hash = super
|
|
73
|
+
@unmanaged_settings = {} if @unmanaged_settings.nil?
|
|
74
|
+
@unmanaged_settings.merge(settings_hash)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Validates a document (Hash table) against the schema
|
|
78
|
+
#
|
|
79
|
+
# @return [Boolean]
|
|
80
|
+
def validate_document!(document)
|
|
81
|
+
::JSON::Validator.validate!(schema, document)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
protected
|
|
85
|
+
|
|
86
|
+
# @!attribute [w] unmanaged_settings
|
|
87
|
+
# Sets the list of unmanaged settings. For subclass use only
|
|
88
|
+
#
|
|
89
|
+
# @param unmanaged_settings [Hash<String, Object]] A hashtable of all unmanaged settings which will be persisted, but not visible
|
|
90
|
+
# @protected
|
|
91
|
+
attr_writer :unmanaged_settings
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
# Override the create_setting method to always fail. This is called
|
|
96
|
+
# to dyanmically add settings. However as we're using a schema, no
|
|
97
|
+
# new settings can be created
|
|
98
|
+
#
|
|
99
|
+
# @see PDK::Config::Namespace.create_missing_setting
|
|
100
|
+
#
|
|
101
|
+
# @private
|
|
102
|
+
def create_missing_setting(key, _initial_value = nil)
|
|
103
|
+
raise ArgumentError, "Setting '#{key}' does not exist'"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Create a valid, but empty schema
|
|
107
|
+
#
|
|
108
|
+
# @return [JSON::Schema]
|
|
109
|
+
def create_empty_schema
|
|
110
|
+
::JSON::Schema.new({}, 'http://json-schema.org/draft-06/schema#')
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Lazily retrieve the JSON schema from disk for this namespace
|
|
114
|
+
#
|
|
115
|
+
# @return [JSON::Schema]
|
|
116
|
+
def document_schema
|
|
117
|
+
return @document_schema unless @document_schema.nil?
|
|
118
|
+
|
|
119
|
+
# Create an empty schema by default.
|
|
120
|
+
@document_schema = create_empty_schema
|
|
121
|
+
|
|
122
|
+
return @document_schema if @schema_file.nil?
|
|
123
|
+
|
|
124
|
+
raise PDK::Config::LoadError, format('Unable to open %{file} for reading. File does not exist', file: @schema_file) unless PDK::Util::Filesystem.file?(@schema_file)
|
|
125
|
+
|
|
126
|
+
# The schema should not query external URI references, except for the meta-schema. Local files are allowed
|
|
127
|
+
schema_reader = ::JSON::Schema::Reader.new(
|
|
128
|
+
accept_file: true,
|
|
129
|
+
accept_uri: proc { |uri| uri.host.nil? || ['json-schema.org'].include?(uri.host) }
|
|
130
|
+
)
|
|
131
|
+
@document_schema = schema_reader.read(Addressable::URI.convert_path(@schema_file))
|
|
132
|
+
rescue ::JSON::Schema::JsonParseError => e
|
|
133
|
+
raise PDK::Config::LoadError, format('Unable to open %{file} for reading. JSON Error: %{msg}', file: @schema_file, msg: e.message)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|