pdk 1.16.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +167 -11
  3. data/README.md +1 -1
  4. data/lib/pdk.rb +26 -19
  5. data/lib/pdk/answer_file.rb +2 -93
  6. data/lib/pdk/cli.rb +8 -6
  7. data/lib/pdk/cli/config.rb +3 -1
  8. data/lib/pdk/cli/config/get.rb +3 -1
  9. data/lib/pdk/cli/convert.rb +7 -9
  10. data/lib/pdk/cli/env.rb +52 -0
  11. data/lib/pdk/cli/exec/command.rb +13 -0
  12. data/lib/pdk/cli/exec_group.rb +78 -43
  13. data/lib/pdk/cli/get.rb +20 -0
  14. data/lib/pdk/cli/get/config.rb +24 -0
  15. data/lib/pdk/cli/new.rb +2 -0
  16. data/lib/pdk/cli/new/class.rb +2 -1
  17. data/lib/pdk/cli/new/defined_type.rb +2 -1
  18. data/lib/pdk/cli/new/fact.rb +29 -0
  19. data/lib/pdk/cli/new/function.rb +29 -0
  20. data/lib/pdk/cli/new/provider.rb +2 -1
  21. data/lib/pdk/cli/new/task.rb +2 -1
  22. data/lib/pdk/cli/new/test.rb +2 -1
  23. data/lib/pdk/cli/new/transport.rb +2 -1
  24. data/lib/pdk/cli/release/publish.rb +11 -1
  25. data/lib/pdk/cli/remove.rb +20 -0
  26. data/lib/pdk/cli/remove/config.rb +80 -0
  27. data/lib/pdk/cli/set.rb +20 -0
  28. data/lib/pdk/cli/set/config.rb +119 -0
  29. data/lib/pdk/cli/update.rb +6 -8
  30. data/lib/pdk/cli/util.rb +7 -3
  31. data/lib/pdk/cli/util/option_validator.rb +6 -0
  32. data/lib/pdk/cli/util/update_manager_printer.rb +82 -0
  33. data/lib/pdk/cli/validate.rb +26 -44
  34. data/lib/pdk/config.rb +264 -7
  35. data/lib/pdk/config/ini_file.rb +183 -0
  36. data/lib/pdk/config/ini_file_setting.rb +39 -0
  37. data/lib/pdk/config/namespace.rb +25 -5
  38. data/lib/pdk/config/setting.rb +3 -2
  39. data/lib/pdk/context.rb +99 -0
  40. data/lib/pdk/context/control_repo.rb +60 -0
  41. data/lib/pdk/context/module.rb +28 -0
  42. data/lib/pdk/context/none.rb +22 -0
  43. data/lib/pdk/control_repo.rb +40 -0
  44. data/lib/pdk/generate/defined_type.rb +25 -32
  45. data/lib/pdk/generate/fact.rb +25 -0
  46. data/lib/pdk/generate/function.rb +48 -0
  47. data/lib/pdk/generate/module.rb +14 -17
  48. data/lib/pdk/generate/provider.rb +15 -64
  49. data/lib/pdk/generate/puppet_class.rb +25 -31
  50. data/lib/pdk/generate/puppet_object.rb +83 -187
  51. data/lib/pdk/generate/task.rb +28 -46
  52. data/lib/pdk/generate/transport.rb +20 -74
  53. data/lib/pdk/module.rb +1 -1
  54. data/lib/pdk/module/convert.rb +43 -23
  55. data/lib/pdk/module/metadata.rb +6 -2
  56. data/lib/pdk/module/release.rb +3 -9
  57. data/lib/pdk/module/update.rb +7 -11
  58. data/lib/pdk/module/update_manager.rb +7 -0
  59. data/lib/pdk/report.rb +3 -3
  60. data/lib/pdk/report/event.rb +8 -2
  61. data/lib/pdk/template.rb +59 -0
  62. data/lib/pdk/template/fetcher.rb +98 -0
  63. data/lib/pdk/template/fetcher/git.rb +85 -0
  64. data/lib/pdk/template/fetcher/local.rb +28 -0
  65. data/lib/pdk/template/renderer.rb +96 -0
  66. data/lib/pdk/template/renderer/v1.rb +25 -0
  67. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +116 -0
  68. data/lib/pdk/template/renderer/v1/renderer.rb +132 -0
  69. data/lib/pdk/template/renderer/v1/template_file.rb +102 -0
  70. data/lib/pdk/template/template_dir.rb +67 -0
  71. data/lib/pdk/tests/unit.rb +8 -1
  72. data/lib/pdk/util.rb +38 -39
  73. data/lib/pdk/util/bundler.rb +2 -1
  74. data/lib/pdk/util/changelog_generator.rb +11 -2
  75. data/lib/pdk/util/json_finder.rb +84 -0
  76. data/lib/pdk/util/puppet_strings.rb +3 -3
  77. data/lib/pdk/util/puppet_version.rb +2 -2
  78. data/lib/pdk/util/ruby_version.rb +5 -1
  79. data/lib/pdk/util/template_uri.rb +13 -14
  80. data/lib/pdk/util/vendored_file.rb +1 -2
  81. data/lib/pdk/validate.rb +79 -25
  82. data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -0
  83. data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -0
  84. data/lib/pdk/validate/external_command_validator.rb +208 -0
  85. data/lib/pdk/validate/internal_ruby_validator.rb +100 -0
  86. data/lib/pdk/validate/invokable_validator.rb +220 -0
  87. data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +86 -0
  88. data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +78 -0
  89. data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -0
  90. data/lib/pdk/validate/puppet/puppet_epp_validator.rb +133 -0
  91. data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -0
  92. data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +137 -0
  93. data/lib/pdk/validate/puppet/puppet_validator_group.rb +21 -0
  94. data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +80 -0
  95. data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -0
  96. data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +88 -0
  97. data/lib/pdk/validate/tasks/tasks_name_validator.rb +50 -0
  98. data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -0
  99. data/lib/pdk/validate/validator.rb +118 -0
  100. data/lib/pdk/validate/validator_group.rb +104 -0
  101. data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +95 -0
  102. data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -0
  103. data/lib/pdk/version.rb +1 -1
  104. data/locales/pdk.pot +477 -313
  105. metadata +77 -35
  106. data/lib/pdk/module/template_dir.rb +0 -115
  107. data/lib/pdk/module/template_dir/base.rb +0 -268
  108. data/lib/pdk/module/template_dir/git.rb +0 -91
  109. data/lib/pdk/module/template_dir/local.rb +0 -21
  110. data/lib/pdk/template_file.rb +0 -96
  111. data/lib/pdk/validate/base_validator.rb +0 -215
  112. data/lib/pdk/validate/metadata/metadata_json_lint.rb +0 -82
  113. data/lib/pdk/validate/metadata/metadata_syntax.rb +0 -111
  114. data/lib/pdk/validate/metadata_validator.rb +0 -26
  115. data/lib/pdk/validate/puppet/puppet_epp.rb +0 -135
  116. data/lib/pdk/validate/puppet/puppet_lint.rb +0 -64
  117. data/lib/pdk/validate/puppet/puppet_syntax.rb +0 -135
  118. data/lib/pdk/validate/puppet_validator.rb +0 -26
  119. data/lib/pdk/validate/ruby/rubocop.rb +0 -72
  120. data/lib/pdk/validate/ruby_validator.rb +0 -26
  121. data/lib/pdk/validate/tasks/metadata_lint.rb +0 -130
  122. data/lib/pdk/validate/tasks/name.rb +0 -90
  123. data/lib/pdk/validate/tasks_validator.rb +0 -29
  124. data/lib/pdk/validate/yaml/syntax.rb +0 -125
  125. data/lib/pdk/validate/yaml_validator.rb +0 -28
@@ -0,0 +1,132 @@
1
+ require 'pdk'
2
+ require 'pdk/template/renderer'
3
+
4
+ module PDK
5
+ module Template
6
+ module Renderer
7
+ module V1
8
+ class Renderer < PDK::Template::Renderer::AbstractRenderer
9
+ # @see PDK::Template::Renderer::AbstractRenderer.render
10
+ def render(template_type, _name, options = {})
11
+ render_module(options) { |*args| yield(*args) } if template_type == PDK::Template::MODULE_TEMPLATE_TYPE
12
+ end
13
+
14
+ # @see PDK::Template::Renderer::AbstractRenderer.has_single_item?
15
+ def has_single_item?(item_path) # rubocop:disable Naming/PredicateName
16
+ PDK::Util::Filesystem.exist?(single_item_path(item_path))
17
+ end
18
+
19
+ # @see PDK::Template::Renderer::AbstractRenderer.render_single_item
20
+ def render_single_item(relative_file_path, template_data_hash)
21
+ template_file = single_item_path(relative_file_path)
22
+ return nil unless PDK::Util::Filesystem.file?(template_file) && PDK::Util::Filesystem.readable?(template_file)
23
+
24
+ PDK.logger.debug(_("Rendering '%{template}'...") % { template: template_file })
25
+ new_template_file(template_file, template_data_hash).render
26
+ end
27
+
28
+ # Returns the full path for a single item
29
+ #
30
+ # @param item_path [String] The path of the single item to render
31
+ # @return [String]
32
+ # @api private
33
+ #:nocov:
34
+ def single_item_path(item_path)
35
+ File.join(template_root, 'object_templates', item_path)
36
+ end
37
+ #:nocov:
38
+
39
+ # Helper method used during testing
40
+ #:nocov:
41
+ # @api private
42
+ def new_template_file(template_file, template_data_hash)
43
+ TemplateFile.new(template_file, template_data_hash)
44
+ end
45
+ #:nocov:
46
+
47
+ # Helper method used during testing
48
+ #:nocov:
49
+ # @api private
50
+ def new_legacy_template_dir(context, uri, path, module_metadata = {})
51
+ LegacyTemplateDir.new(context, uri, path, module_metadata)
52
+ end
53
+ #:nocov:
54
+
55
+ # Renders a new module
56
+ #
57
+ # @param options [Hash{Object => Object}] A list of options to pass through to the renderer. See PDK::Template::TemplateDir helper methods for other options
58
+ # @see #render
59
+ # @api private
60
+ #:nocov: This is tested in acceptance and packaging tests
61
+ def render_module(options = {})
62
+ require 'pdk/template/renderer/v1/template_file'
63
+
64
+ moduleroot_dir = File.join(template_root, 'moduleroot')
65
+ moduleroot_init = File.join(template_root, 'moduleroot_init')
66
+
67
+ dirs = [moduleroot_dir]
68
+ dirs << moduleroot_init if options[:include_first_time]
69
+
70
+ legacy_template_dir = new_legacy_template_dir(context, template_uri, template_root, options[:module_metadata] || {})
71
+
72
+ files_in_template(dirs).each do |template_file, template_loc|
73
+ template_file = template_file.to_s
74
+ PDK.logger.debug(_("Rendering '%{template}'...") % { template: template_file })
75
+ dest_path = template_file.sub(%r{\.erb\Z}, '')
76
+ config = legacy_template_dir.config_for(dest_path)
77
+
78
+ dest_status = if template_loc.start_with?(moduleroot_init)
79
+ :init
80
+ else
81
+ :manage
82
+ end
83
+
84
+ if config['unmanaged']
85
+ dest_status = :unmanage
86
+ elsif config['delete']
87
+ dest_status = :delete
88
+ else
89
+ begin
90
+ dest_content = new_template_file(File.join(template_loc, template_file), configs: config, template_dir: legacy_template_dir).render
91
+ rescue => error
92
+ error_msg = _(
93
+ "Failed to render template '%{template}'\n" \
94
+ '%{exception}: %{message}',
95
+ ) % { template: template_file, exception: error.class, message: error.message }
96
+ raise PDK::CLI::FatalError, error_msg
97
+ end
98
+ end
99
+
100
+ yield dest_path, dest_content, dest_status
101
+ end
102
+ end
103
+ #:nocov:
104
+
105
+ # Returns all files in the given template directories
106
+ #
107
+ # @param dirs [Array[String]] Directories to search in
108
+ # @param glob_suffix [Array[String]] File glob to use when searching for files. Defaults to ['**', '*']
109
+ #
110
+ # @return [Hash{String => String}] Key is the template file relative path and the value is the absolute path to the template directory
111
+ # @api private
112
+ def files_in_template(dirs, glob_suffix = ['**', '*'])
113
+ temp_paths = []
114
+ dirlocs = []
115
+ dirs.each do |dir|
116
+ raise ArgumentError, _("The directory '%{dir}' doesn't exist") % { dir: dir } unless PDK::Util::Filesystem.directory?(dir)
117
+ temp_paths += PDK::Util::Filesystem.glob(File.join(dir, *glob_suffix), File::FNM_DOTMATCH).select do |template_path|
118
+ if PDK::Util::Filesystem.file?(template_path) && !PDK::Util::Filesystem.symlink?(template_path)
119
+ dirlocs << dir
120
+ end
121
+ end
122
+ temp_paths.map do |template_path|
123
+ template_path.sub!(%r{\A#{Regexp.escape(dir)}#{Regexp.escape(File::SEPARATOR)}}, '')
124
+ end
125
+ end
126
+ Hash[temp_paths.zip dirlocs]
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,102 @@
1
+ require 'pdk'
2
+ require 'ostruct'
3
+
4
+ module PDK
5
+ module Template
6
+ module Renderer
7
+ module V1
8
+ class TemplateFile < OpenStruct
9
+ # Initialises the TemplateFile object with the path to the template file
10
+ # and the data to be used when rendering the template.
11
+ #
12
+ # @param template_file [String] The path on disk to the template file.
13
+ # @param data [Hash{Symbol => Object}] The data that should be provided to
14
+ # the template when rendering.
15
+ # @option data [Object] :configs The value of this key will be provided to
16
+ # the template as an instance variable `@configs` in order to maintain
17
+ # compatibility with modulesync.
18
+ #
19
+ # @api public
20
+ def initialize(template_file, data = {})
21
+ @template_file = template_file
22
+
23
+ if data.key?(:configs)
24
+ @configs = data[:configs]
25
+ end
26
+
27
+ super(data)
28
+ end
29
+
30
+ # Renders the template by calling the appropriate engine based on the file
31
+ # extension.
32
+ #
33
+ # If the template has an `.erb` extension, the content of the template
34
+ # file will be treated as an ERB template. All other extensions are treated
35
+ # as plain text.
36
+ #
37
+ # @return [String] The rendered template
38
+ #
39
+ # @raise (see #template_content)
40
+ #
41
+ # @api public
42
+ def render
43
+ case File.extname(@template_file)
44
+ when '.erb'
45
+ render_erb
46
+ else
47
+ render_plain
48
+ end
49
+ end
50
+
51
+ def config_for(path)
52
+ return unless respond_to?(:template_dir)
53
+
54
+ template_dir.config_for(path)
55
+ end
56
+
57
+ private
58
+
59
+ # Reads the content of the template file into memory.
60
+ #
61
+ # @return [String] The content of the template file.
62
+ #
63
+ # @raise [ArgumentError] If the template file does not exist or can not be
64
+ # read.
65
+ #
66
+ # @api private
67
+ def template_content
68
+ if PDK::Util::Filesystem.file?(@template_file) && PDK::Util::Filesystem.readable?(@template_file)
69
+ return PDK::Util::Filesystem.read_file(@template_file)
70
+ end
71
+
72
+ raise ArgumentError, _("'%{template}' is not a readable file") % { template: @template_file }
73
+ end
74
+
75
+ # Renders the content of the template file as an ERB template.
76
+ #
77
+ # @return [String] The rendered template.
78
+ #
79
+ # @raise (see #template_content)
80
+ #
81
+ # @api private
82
+ def render_erb
83
+ renderer = ERB.new(template_content, nil, '-')
84
+ renderer.filename = @template_file
85
+ renderer.result(binding)
86
+ end
87
+
88
+ # Renders the content of the template file as plain text.
89
+ #
90
+ # @return [String] The rendered template.
91
+ #
92
+ # @raise (see #template_content)
93
+ #
94
+ # @api private
95
+ def render_plain
96
+ template_content
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,67 @@
1
+ require 'pdk'
2
+ require 'forwardable'
3
+
4
+ module PDK
5
+ module Template
6
+ # A helper class representing an already fetched template on disk, with an appropriate renderer instance.
7
+ # @see PDK::Template.with
8
+ class TemplateDir
9
+ # Creates an instance of TemplateDir object
10
+ # @see TemplateDir.new
11
+ def self.instance(uri, path, context, renderer = nil)
12
+ new(uri, path, context, renderer)
13
+ end
14
+
15
+ extend Forwardable
16
+
17
+ # Helper methods for rendering
18
+ def_delegators :@renderer, :render, :render_single_item, :has_single_item?
19
+
20
+ # @return [PDK::Util::TemplateURI] The URI which points to the source location of the Template
21
+ attr_accessor :uri
22
+
23
+ # @return [String] The path to where the template exists on disk
24
+ attr_accessor :path
25
+
26
+ # @return [Hash{String => String}] A hash of information about the template
27
+ attr_accessor :metadata
28
+
29
+ # @param template_uri [PDK::Util::TemplateUri] A URI which points to the source location of the Template
30
+ # @param path [String] The path to where the template exists on disk
31
+ # @param context [PDK::Context] The context in which the redering will occur in
32
+ # @param renderer [PDK::Template::Renderer::AbstractRenderer] The an instance of a rendering class. If nil, a renderer will be created that's appropriate for the template and context
33
+ def initialize(uri, path, context, renderer = nil)
34
+ @uri = uri
35
+ @path = path
36
+ @metadata = {}
37
+
38
+ @renderer = renderer.nil? ? Renderer.instance(uri, path, context) : renderer
39
+ raise _('Could not find a compatible template renderer for %{path}') % { path: path } if @renderer.nil?
40
+ end
41
+
42
+ # Later additions may include Control Repo rendering, for example
43
+ #
44
+ # def render_control_repo(name, options = {})
45
+ # render(CONTROL_REPO_TEMPLATE_TYPE, name, options.merge(include_first_time: false)) { |*args| yield(*args) }
46
+ # end
47
+ #
48
+ # def render_new_control_repo(name, repo_metadata = {}, options = {})
49
+ # render(CONTROL_REPO_TEMPLATE_TYPE, name, options.merge(include_first_time: true, control_repo_metadata: repo_metadata)) { |*args| yield(*args) }
50
+ # end
51
+ #:nocov: These are just helper methods and are tested elsewhere.
52
+
53
+ # Render an existing module
54
+ # @see PDK::Template::Renderer::AbstractRenderer.render
55
+ def render_module(module_name, options = {})
56
+ @renderer.render(MODULE_TEMPLATE_TYPE, module_name, options.merge(include_first_time: false)) { |*args| yield(*args) }
57
+ end
58
+
59
+ # Render a new module
60
+ # @see PDK::Template::Renderer::AbstractRenderer.render
61
+ def render_new_module(module_name, module_metadata = {}, options = {})
62
+ @renderer.render(MODULE_TEMPLATE_TYPE, module_name, options.merge(include_first_time: true, module_metadata: module_metadata)) { |*args| yield(*args) }
63
+ end
64
+ #:nocov:
65
+ end
66
+ end
67
+ end
@@ -89,6 +89,11 @@ module PDK
89
89
  setup
90
90
 
91
91
  tests = options[:tests]
92
+ # Due to how rake handles paths in the command line options, any backslashed path (Windows platforms) needs to be converted
93
+ # to forward slash. We can't use File.expand_path as the files aren't guaranteed to be on-disk
94
+ #
95
+ # Ref - https://github.com/puppetlabs/pdk/issues/828
96
+ tests = tests.tr('\\', '/') unless tests.nil?
92
97
 
93
98
  environment = { 'CI_SPEC_OPTIONS' => '--format j' }
94
99
  environment['PUPPET_GEM_VERSION'] = options[:puppet] if options[:puppet]
@@ -134,7 +139,7 @@ module PDK
134
139
 
135
140
  example_results = {
136
141
  # Only possibilities are passed, failed, pending:
137
- # https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/example.rb#L548
142
+ # https://github.com/rspec/rspec-core/blob/main/lib/rspec/core/example.rb#L548
138
143
  'passed' => [],
139
144
  'failed' => [],
140
145
  'pending' => [],
@@ -178,6 +183,8 @@ module PDK
178
183
  end
179
184
 
180
185
  def self.merge_json_results(json_data)
186
+ require 'set'
187
+
181
188
  merged_json_result = {}
182
189
 
183
190
  # Merge messages
data/lib/pdk/util.rb CHANGED
@@ -14,6 +14,7 @@ module PDK
14
14
  autoload :Env, 'pdk/util/env'
15
15
  autoload :Filesystem, 'pdk/util/filesystem'
16
16
  autoload :Git, 'pdk/util/git'
17
+ autoload :JSONFinder, 'pdk/util/json_finder'
17
18
  autoload :PuppetStrings, 'pdk/util/puppet_strings'
18
19
  autoload :PuppetVersion, 'pdk/util/puppet_version'
19
20
  autoload :RubyVersion, 'pdk/util/ruby_version'
@@ -146,6 +147,15 @@ module PDK
146
147
  end
147
148
  module_function :configdir
148
149
 
150
+ def system_configdir
151
+ return @system_configdir unless @system_configdir.nil?
152
+ return @system_configdir = File.join(File::SEPARATOR, 'opt', 'puppetlabs', 'pdk', 'config') unless Gem.win_platform?
153
+
154
+ return @system_configdir = File.join(PDK::Util::Env['ProgramData'], 'PuppetLabs', 'PDK') unless PDK::Util::Env['ProgramData'].nil?
155
+ @system_configdir = File.join(PDK::Util::Env['AllUsersProfile'], 'PuppetLabs', 'PDK')
156
+ end
157
+ module_function :system_configdir
158
+
149
159
  # Returns path to the root of the module being worked on.
150
160
  #
151
161
  # @return [String, nil] Fully qualified base path to module, or nil if
@@ -187,7 +197,7 @@ module PDK
187
197
  # @return [Hash, nil] subset of text as Hash of first valid JSON found, or nil if no valid
188
198
  # JSON found in the text
189
199
  def find_first_json_in(text)
190
- find_valid_json_in(text)
200
+ find_all_json_in(text).first
191
201
  end
192
202
  module_function :find_first_json_in
193
203
 
@@ -197,42 +207,10 @@ module PDK
197
207
  # @return [Array<Hash>] subset of text as Array of all JSON object found, empty Array if none are found
198
208
  # JSON found in the text
199
209
  def find_all_json_in(text)
200
- find_valid_json_in(text, break_on_first: false)
210
+ PDK::Util::JSONFinder.new(text).objects
201
211
  end
202
212
  module_function :find_all_json_in
203
213
 
204
- # Iterate through possible JSON documents until we find one that is valid.
205
- #
206
- # @param [String] text the text in which to find a JSON document
207
- # @param [Hash] opts options
208
- # @option opts [Boolean] :break_on_first Whether or not to break after valid JSON is found, defaults to true
209
- #
210
- # @return [Hash, Array<Hash>, nil] subset of text as Hash of first valid JSON found, array of all valid JSON found, or nil if no valid
211
- # JSON found in the text
212
- #
213
- # @private
214
- def find_valid_json_in(text, opts = {})
215
- break_on_first = opts.key?(:break_on_first) ? opts[:break_on_first] : true
216
-
217
- json_result = break_on_first ? nil : []
218
-
219
- text.scan(%r{\{(?:[^{}]|(?:\g<0>))*\}}x) do |str|
220
- begin
221
- if break_on_first
222
- json_result = JSON.parse(str)
223
- break
224
- else
225
- json_result.push(JSON.parse(str))
226
- end
227
- rescue JSON::ParserError
228
- next
229
- end
230
- end
231
-
232
- json_result
233
- end
234
- module_function :find_valid_json_in
235
-
236
214
  # Returns the targets' paths relative to the working directory
237
215
  #
238
216
  # @return [Array<String>] The absolute or path to the target
@@ -248,16 +226,18 @@ module PDK
248
226
  module_function :targets_relative_to_pwd
249
227
 
250
228
  # TO-DO: Refactor replacement of lib/pdk/module/build.rb:metadata to use this function instead
251
- def module_metadata
229
+ # @param module_path [String] The path to the root of the module. Default is determine the module root automatically
230
+ def module_metadata(module_path = nil)
252
231
  require 'pdk/module/metadata'
253
-
254
- PDK::Module::Metadata.from_file(File.join(module_root, 'metadata.json')).data
232
+ module_path ||= module_root
233
+ PDK::Module::Metadata.from_file(File.join(module_path, 'metadata.json')).data
255
234
  end
256
235
  module_function :module_metadata
257
236
 
258
237
  # TO-DO: Refactor replacement of lib/pdk/module/build.rb:module_pdk_compatible? to use this function instead
259
- def module_pdk_compatible?
260
- ['pdk-version', 'template-url'].any? { |key| module_metadata.key?(key) }
238
+ # @param module_path [String] The path to the root of the module. Default is determine the module root automatically
239
+ def module_pdk_compatible?(module_path = nil)
240
+ ['pdk-version', 'template-url'].any? { |key| module_metadata(module_path).key?(key) }
261
241
  end
262
242
  module_function :module_pdk_compatible?
263
243
 
@@ -274,5 +254,24 @@ module PDK
274
254
  nil
275
255
  end
276
256
  module_function :module_pdk_version
257
+
258
+ # Does a deep copy instead of a shallow copy of an object.
259
+ #
260
+ # @param object [Object] The object to duplicate
261
+ #
262
+ # @return [Object] duplicate of the original object
263
+ # the current working dir does not appear to be within a module.
264
+ def deep_duplicate(object)
265
+ if object.is_a?(Array)
266
+ object.map { |item| deep_duplicate(item) }
267
+ elsif object.is_a?(Hash)
268
+ hash = object.dup
269
+ hash.each_pair { |key, value| hash[key] = deep_duplicate(value) }
270
+ hash
271
+ else
272
+ object
273
+ end
274
+ end
275
+ module_function :deep_duplicate
277
276
  end
278
277
  end