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.
Files changed (163) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +744 -711
  3. data/README.md +23 -21
  4. data/lib/pdk/answer_file.rb +3 -112
  5. data/lib/pdk/bolt.rb +20 -0
  6. data/lib/pdk/cli/build.rb +51 -54
  7. data/lib/pdk/cli/bundle.rb +33 -29
  8. data/lib/pdk/cli/console.rb +148 -0
  9. data/lib/pdk/cli/convert.rb +46 -37
  10. data/lib/pdk/cli/env.rb +51 -0
  11. data/lib/pdk/cli/errors.rb +4 -3
  12. data/lib/pdk/cli/exec/command.rb +285 -0
  13. data/lib/pdk/cli/exec/interactive_command.rb +109 -0
  14. data/lib/pdk/cli/exec.rb +32 -201
  15. data/lib/pdk/cli/exec_group.rb +79 -43
  16. data/lib/pdk/cli/get/config.rb +26 -0
  17. data/lib/pdk/cli/get.rb +22 -0
  18. data/lib/pdk/cli/new/class.rb +20 -22
  19. data/lib/pdk/cli/new/defined_type.rb +21 -21
  20. data/lib/pdk/cli/new/fact.rb +27 -0
  21. data/lib/pdk/cli/new/function.rb +27 -0
  22. data/lib/pdk/cli/new/module.rb +40 -29
  23. data/lib/pdk/cli/new/provider.rb +18 -18
  24. data/lib/pdk/cli/new/task.rb +23 -22
  25. data/lib/pdk/cli/new/test.rb +52 -0
  26. data/lib/pdk/cli/new/transport.rb +27 -0
  27. data/lib/pdk/cli/new.rb +15 -9
  28. data/lib/pdk/cli/release/prep.rb +39 -0
  29. data/lib/pdk/cli/release/publish.rb +46 -0
  30. data/lib/pdk/cli/release.rb +185 -0
  31. data/lib/pdk/cli/remove/config.rb +83 -0
  32. data/lib/pdk/cli/remove.rb +22 -0
  33. data/lib/pdk/cli/set/config.rb +121 -0
  34. data/lib/pdk/cli/set.rb +22 -0
  35. data/lib/pdk/cli/test/unit.rb +71 -69
  36. data/lib/pdk/cli/test.rb +9 -8
  37. data/lib/pdk/cli/update.rb +38 -21
  38. data/lib/pdk/cli/util/command_redirector.rb +13 -3
  39. data/lib/pdk/cli/util/interview.rb +25 -9
  40. data/lib/pdk/cli/util/option_normalizer.rb +6 -6
  41. data/lib/pdk/cli/util/option_validator.rb +19 -9
  42. data/lib/pdk/cli/util/spinner.rb +13 -0
  43. data/lib/pdk/cli/util/update_manager_printer.rb +82 -0
  44. data/lib/pdk/cli/util.rb +105 -48
  45. data/lib/pdk/cli/validate.rb +96 -111
  46. data/lib/pdk/cli.rb +134 -87
  47. data/lib/pdk/config/errors.rb +5 -0
  48. data/lib/pdk/config/ini_file.rb +184 -0
  49. data/lib/pdk/config/ini_file_setting.rb +35 -0
  50. data/lib/pdk/config/json.rb +35 -0
  51. data/lib/pdk/config/json_schema_namespace.rb +137 -0
  52. data/lib/pdk/config/json_schema_setting.rb +51 -0
  53. data/lib/pdk/config/json_with_schema.rb +47 -0
  54. data/lib/pdk/config/namespace.rb +362 -0
  55. data/lib/pdk/config/setting.rb +134 -0
  56. data/lib/pdk/config/task_schema.json +116 -0
  57. data/lib/pdk/config/validator.rb +31 -0
  58. data/lib/pdk/config/yaml.rb +41 -0
  59. data/lib/pdk/config/yaml_with_schema.rb +51 -0
  60. data/lib/pdk/config.rb +304 -0
  61. data/lib/pdk/context/control_repo.rb +61 -0
  62. data/lib/pdk/context/module.rb +28 -0
  63. data/lib/pdk/context/none.rb +22 -0
  64. data/lib/pdk/context.rb +98 -0
  65. data/lib/pdk/control_repo.rb +89 -0
  66. data/lib/pdk/generate/defined_type.rb +27 -33
  67. data/lib/pdk/generate/fact.rb +26 -0
  68. data/lib/pdk/generate/function.rb +49 -0
  69. data/lib/pdk/generate/module.rb +160 -153
  70. data/lib/pdk/generate/provider.rb +16 -69
  71. data/lib/pdk/generate/puppet_class.rb +27 -32
  72. data/lib/pdk/generate/puppet_object.rb +100 -159
  73. data/lib/pdk/generate/task.rb +34 -51
  74. data/lib/pdk/generate/transport.rb +34 -0
  75. data/lib/pdk/generate.rb +21 -8
  76. data/lib/pdk/logger.rb +24 -6
  77. data/lib/pdk/module/build.rb +125 -37
  78. data/lib/pdk/module/convert.rb +146 -65
  79. data/lib/pdk/module/metadata.rb +72 -71
  80. data/lib/pdk/module/release.rb +255 -0
  81. data/lib/pdk/module/update.rb +48 -37
  82. data/lib/pdk/module/update_manager.rb +75 -39
  83. data/lib/pdk/module.rb +10 -2
  84. data/lib/pdk/monkey_patches.rb +268 -0
  85. data/lib/pdk/report/event.rb +36 -48
  86. data/lib/pdk/report.rb +35 -22
  87. data/lib/pdk/template/fetcher/git.rb +84 -0
  88. data/lib/pdk/template/fetcher/local.rb +29 -0
  89. data/lib/pdk/template/fetcher.rb +100 -0
  90. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +108 -0
  91. data/lib/pdk/template/renderer/v1/renderer.rb +131 -0
  92. data/lib/pdk/template/renderer/v1/template_file.rb +100 -0
  93. data/lib/pdk/template/renderer/v1.rb +25 -0
  94. data/lib/pdk/template/renderer.rb +97 -0
  95. data/lib/pdk/template/template_dir.rb +67 -0
  96. data/lib/pdk/template.rb +52 -0
  97. data/lib/pdk/tests/unit.rb +101 -51
  98. data/lib/pdk/util/bundler.rb +44 -42
  99. data/lib/pdk/util/changelog_generator.rb +138 -0
  100. data/lib/pdk/util/env.rb +48 -0
  101. data/lib/pdk/util/filesystem.rb +139 -2
  102. data/lib/pdk/util/git.rb +108 -8
  103. data/lib/pdk/util/json_finder.rb +86 -0
  104. data/lib/pdk/util/puppet_strings.rb +125 -0
  105. data/lib/pdk/util/puppet_version.rb +71 -87
  106. data/lib/pdk/util/ruby_version.rb +49 -25
  107. data/lib/pdk/util/template_uri.rb +283 -0
  108. data/lib/pdk/util/vendored_file.rb +34 -42
  109. data/lib/pdk/util/version.rb +11 -10
  110. data/lib/pdk/util/windows/api_types.rb +74 -44
  111. data/lib/pdk/util/windows/file.rb +31 -27
  112. data/lib/pdk/util/windows/process.rb +74 -0
  113. data/lib/pdk/util/windows/string.rb +19 -12
  114. data/lib/pdk/util/windows.rb +2 -0
  115. data/lib/pdk/util.rb +111 -124
  116. data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -0
  117. data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -0
  118. data/lib/pdk/validate/external_command_validator.rb +213 -0
  119. data/lib/pdk/validate/internal_ruby_validator.rb +101 -0
  120. data/lib/pdk/validate/invokable_validator.rb +238 -0
  121. data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +84 -0
  122. data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +76 -0
  123. data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -0
  124. data/lib/pdk/validate/puppet/puppet_epp_validator.rb +131 -0
  125. data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -0
  126. data/lib/pdk/validate/puppet/puppet_plan_syntax_validator.rb +38 -0
  127. data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +135 -0
  128. data/lib/pdk/validate/puppet/puppet_validator_group.rb +22 -0
  129. data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +79 -0
  130. data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -0
  131. data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +83 -0
  132. data/lib/pdk/validate/tasks/tasks_name_validator.rb +45 -0
  133. data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -0
  134. data/lib/pdk/validate/validator.rb +120 -0
  135. data/lib/pdk/validate/validator_group.rb +107 -0
  136. data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +86 -0
  137. data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -0
  138. data/lib/pdk/validate.rb +86 -12
  139. data/lib/pdk/version.rb +2 -2
  140. data/lib/pdk.rb +60 -10
  141. metadata +138 -100
  142. data/lib/pdk/cli/module/build.rb +0 -14
  143. data/lib/pdk/cli/module/generate.rb +0 -45
  144. data/lib/pdk/cli/module.rb +0 -14
  145. data/lib/pdk/i18n.rb +0 -4
  146. data/lib/pdk/module/templatedir.rb +0 -321
  147. data/lib/pdk/template_file.rb +0 -95
  148. data/lib/pdk/validate/base_validator.rb +0 -215
  149. data/lib/pdk/validate/metadata/metadata_json_lint.rb +0 -86
  150. data/lib/pdk/validate/metadata/metadata_syntax.rb +0 -109
  151. data/lib/pdk/validate/metadata_validator.rb +0 -30
  152. data/lib/pdk/validate/puppet/puppet_lint.rb +0 -67
  153. data/lib/pdk/validate/puppet/puppet_syntax.rb +0 -112
  154. data/lib/pdk/validate/puppet_validator.rb +0 -30
  155. data/lib/pdk/validate/ruby/rubocop.rb +0 -77
  156. data/lib/pdk/validate/ruby_validator.rb +0 -29
  157. data/lib/pdk/validate/tasks/metadata_lint.rb +0 -126
  158. data/lib/pdk/validate/tasks/name.rb +0 -88
  159. data/lib/pdk/validate/tasks_validator.rb +0 -33
  160. data/lib/pdk/validate/yaml/syntax.rb +0 -109
  161. data/lib/pdk/validate/yaml_validator.rb +0 -31
  162. data/locales/config.yaml +0 -21
  163. data/locales/pdk.pot +0 -1291
@@ -0,0 +1,51 @@
1
+ module PDK
2
+ module CLI
3
+ @env_cmd = @base_cmd.define_command do
4
+ name 'env'
5
+ usage 'env'
6
+ summary '(Experimental) Output environment variables for specific Puppet context'
7
+ description <<~EOF
8
+ [experimental] Aids in setting a CLI context for a specified version of Puppet by outputting export commands for necessary environment variables.
9
+ EOF
10
+
11
+ PDK::CLI.puppet_version_options(self)
12
+ PDK::CLI.puppet_dev_option(self)
13
+
14
+ run do |opts, _args, _cmd|
15
+ require 'pdk/util'
16
+ require 'pdk/util/ruby_version'
17
+
18
+ PDK::CLI::Util.validate_puppet_version_opts(opts)
19
+
20
+ # Ensure that the correct Ruby is activated before running command.
21
+ puppet_env = PDK::CLI::Util.puppet_from_opts_or_env(opts)
22
+ PDK::Util::RubyVersion.use(puppet_env[:ruby_version])
23
+
24
+ resolved_env = {
25
+ 'PDK_RESOLVED_PUPPET_VERSION' => puppet_env[:gemset][:puppet],
26
+ 'PDK_RESOLVED_RUBY_VERSION' => puppet_env[:ruby_version]
27
+ }
28
+
29
+ resolved_env['GEM_HOME'] = PDK::Util::RubyVersion.gem_home
30
+ gem_path = PDK::Util::RubyVersion.gem_path
31
+ resolved_env['GEM_PATH'] = gem_path.empty? ? resolved_env['GEM_HOME'] : gem_path
32
+
33
+ # Make sure invocation of Ruby prefers our private installation.
34
+ package_binpath = PDK::Util.package_install? ? File.join(PDK::Util.pdk_package_basedir, 'bin') : nil
35
+
36
+ resolved_env['PATH'] = [
37
+ PDK::Util::RubyVersion.bin_path,
38
+ File.join(resolved_env['GEM_HOME'], 'bin'),
39
+ PDK::Util::RubyVersion.gem_paths_raw.map { |gem_path_raw| File.join(gem_path_raw, 'bin') },
40
+ package_binpath,
41
+ PDK::Util::Env['PATH']
42
+ ].compact.flatten.join(File::PATH_SEPARATOR)
43
+
44
+ resolved_env.each do |var, val|
45
+ puts "export #{var}=\"#{val}\""
46
+ end
47
+ exit 0
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,17 +1,18 @@
1
+ require 'pdk'
2
+
1
3
  module PDK
2
4
  module CLI
3
5
  class FatalError < StandardError
4
6
  attr_reader :exit_code
5
7
 
6
- def initialize(msg = _('An unexpected error has occurred. Try running the command again with --debug'), opts = {})
8
+ def initialize(msg = 'An unexpected error has occurred. Try running the command again with --debug', opts = {})
7
9
  @exit_code = opts.fetch(:exit_code, 1)
8
10
  super(msg)
9
11
  end
10
12
  end
11
13
 
12
14
  class ExitWithError < StandardError
13
- attr_reader :exit_code
14
- attr_reader :log_level
15
+ attr_reader :exit_code, :log_level
15
16
 
16
17
  def initialize(msg, opts = {})
17
18
  @exit_code = opts.fetch(:exit_code, 1)
@@ -0,0 +1,285 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module CLI
5
+ module Exec
6
+ class Command
7
+ attr_reader :argv, :context
8
+ attr_accessor :timeout, :environment
9
+ attr_writer :exec_group
10
+
11
+ # The spinner for this command.
12
+ # This should only be used for testing
13
+ #
14
+ # @return [TTY::Spinner, nil]
15
+ #
16
+ # @api private
17
+ attr_reader :spinner
18
+
19
+ TEMPFILE_MODE = File::RDWR | File::BINARY | File::CREAT | File::TRUNC
20
+
21
+ def initialize(*argv)
22
+ require 'childprocess'
23
+
24
+ require 'pdk/monkey_patches'
25
+ require 'tempfile'
26
+
27
+ @argv = argv
28
+
29
+ @process = ChildProcess.build(*@argv)
30
+ # https://github.com/puppetlabs/pdk/issues/1083:
31
+ # When @process.leader is set, childprocess will set the CREATE_BREAKAWAY_FROM_JOB
32
+ # and JOB_OBJECT_LIMIT_BREAKAWAY_OK flags in the Win32 API calls. This will cause
33
+ # issues on systems > Windows 7 / Server 2008, if the JOB_OBJECT_LIMIT_BREAKAWAY_OK
34
+ # flag is set and the Task Scheduler is trying to kick off a job, it can sometimes
35
+ # result in ACCESS_DENIED being returned by the Win32 API, depending on the permission
36
+ # levels / user account this user.
37
+ # The resolution for pdk/issues/1083 is to ensure @process.leader is not set.
38
+ # This will potentially cause issues on older Windows systems, in which case we may
39
+ # need to revisit and conditionally set this param depending on what OS we're on
40
+ # @process.leader = true
41
+
42
+ @stdout = Tempfile.new('stdout', mode: TEMPFILE_MODE).tap { |io| io.sync = true }
43
+ @stderr = Tempfile.new('stderr', mode: TEMPFILE_MODE).tap { |io| io.sync = true }
44
+
45
+ @process.io.stdout = @stdout
46
+ @process.io.stderr = @stderr
47
+
48
+ # Default to running things in the system context.
49
+ @context = :system
50
+
51
+ # Extra environment vars to add to base set.
52
+ @environment = {}
53
+
54
+ # Register the ExecGroup when running in parallel
55
+ @exec_group = nil
56
+ end
57
+
58
+ def context=(new_context)
59
+ raise ArgumentError, format("Expected execution context to be :system or :module but got '%{context}'.", context: new_context) unless [:system, :module, :pwd].include?(new_context)
60
+
61
+ @context = new_context
62
+ end
63
+
64
+ def register_spinner(spinner, opts = {})
65
+ require 'pdk/cli/util'
66
+
67
+ return unless PDK::CLI::Util.interactive?
68
+
69
+ @success_message = opts.delete(:success)
70
+ @failure_message = opts.delete(:failure)
71
+
72
+ @spinner = spinner
73
+ end
74
+
75
+ def add_spinner(message, opts = {})
76
+ require 'pdk/cli/util'
77
+
78
+ return unless PDK::CLI::Util.interactive?
79
+
80
+ @success_message = opts.delete(:success)
81
+ @failure_message = opts.delete(:failure)
82
+
83
+ require 'pdk/cli/util/spinner'
84
+
85
+ @spinner = TTY::Spinner.new("[:spinner] #{message}", opts.merge(PDK::CLI::Util.spinner_opts_for_platform))
86
+ end
87
+
88
+ def update_environment(additional_env)
89
+ @environment.merge!(additional_env)
90
+ end
91
+
92
+ # @return [Hash[Symbol => Object]] The result from executing the command
93
+ # :stdout => String : The result of STDOUT
94
+ # :stderr => String : The result of STDERR
95
+ # :exit_code => Integer : The exit code from the command
96
+ # :duration => Float : Number seconds it took to execute
97
+ def execute!
98
+ # Start spinning if configured.
99
+ @spinner&.auto_spin
100
+
101
+ # Set env for child process
102
+ resolved_env_for_command.each { |k, v| @process.environment[k] = v }
103
+
104
+ if [:module, :pwd].include?(context)
105
+ require 'pdk/util'
106
+ mod_root = PDK::Util.module_root
107
+
108
+ unless mod_root
109
+ @spinner&.error
110
+
111
+ raise PDK::CLI::FatalError, 'Current working directory is not part of a module. (No metadata.json was found.)'
112
+ end
113
+
114
+ if Dir.pwd == mod_root || context == :pwd
115
+ run_process_in_clean_env!
116
+ else
117
+ Dir.chdir(mod_root) do
118
+ run_process_in_clean_env!
119
+ end
120
+ end
121
+ else
122
+ run_process!
123
+ end
124
+
125
+ # Stop spinning when done (if configured).
126
+ stop_spinner
127
+
128
+ @stdout.rewind
129
+ @stderr.rewind
130
+
131
+ process_data = {
132
+ stdout: @stdout.read,
133
+ stderr: @stderr.read,
134
+ exit_code: @process.exit_code,
135
+ duration: @duration
136
+ }
137
+
138
+ PDK.logger.debug format('STDOUT: %{output}', output: process_data[:stdout].empty? ? 'N/A' : "\n#{process_data[:stdout]}")
139
+ PDK.logger.debug format('STDERR: %{output}', output: process_data[:stderr].empty? ? 'N/A' : "\n#{process_data[:stderr]}")
140
+
141
+ process_data
142
+ ensure
143
+ @stdout.close
144
+ @stderr.close
145
+ end
146
+
147
+ protected
148
+
149
+ def warn_on_legacy_env_vars!
150
+ if PDK::Util::Env['PUPPET_GEM_VERSION']
151
+ PDK.logger.warn_once 'PUPPET_GEM_VERSION is not supported by PDK. ' \
152
+ 'Use the --puppet-version option on your PDK command ' \
153
+ 'or set the PDK_PUPPET_VERSION environment variable instead'
154
+ end
155
+
156
+ ['FACTER', 'HIERA'].each do |gem|
157
+ PDK.logger.warn_once format('%{varname} is not supported by PDK.', varname: "#{gem}_GEM_VERSION") if PDK::Util::Env["#{gem}_GEM_VERSION"]
158
+ end
159
+ end
160
+
161
+ def resolved_env_for_command
162
+ warn_on_legacy_env_vars!
163
+
164
+ resolved_env = {}
165
+
166
+ resolved_env['TERM'] = PDK::Util::Env['TERM']
167
+ resolved_env['PUPPET_GEM_VERSION'] = nil
168
+ resolved_env['FACTER_GEM_VERSION'] = nil
169
+ resolved_env['HIERA_GEM_VERSION'] = nil
170
+
171
+ resolved_env.merge!(@environment.dup)
172
+
173
+ resolved_env['BUNDLE_IGNORE_CONFIG'] = '1'
174
+
175
+ if [:module, :pwd].include?(context)
176
+ require 'pdk/util'
177
+ require 'pdk/util/git'
178
+ require 'pdk/util/ruby_version'
179
+
180
+ resolved_env['GEM_HOME'] = PDK::Util::RubyVersion.gem_home
181
+ gem_path = PDK::Util::RubyVersion.gem_path
182
+ resolved_env['GEM_PATH'] = gem_path.empty? ? resolved_env['GEM_HOME'] : gem_path
183
+
184
+ # Make sure invocation of Ruby prefers our private installation.
185
+ package_binpath = PDK::Util.package_install? ? File.join(PDK::Util.pdk_package_basedir, 'bin') : nil
186
+
187
+ resolved_env['PATH'] = [
188
+ PDK::Util::RubyVersion.bin_path,
189
+ File.join(resolved_env['GEM_HOME'], 'bin'),
190
+ PDK::Util::RubyVersion.gem_paths_raw.map { |gem_path_raw| File.join(gem_path_raw, 'bin') },
191
+ package_binpath,
192
+ PDK::Util.package_install? ? PDK::Util::Git.git_paths : nil,
193
+ PDK::Util::Env['PATH']
194
+ ].compact.flatten.join(File::PATH_SEPARATOR)
195
+ end
196
+
197
+ resolved_env
198
+ end
199
+
200
+ def stop_spinner
201
+ return unless @spinner
202
+
203
+ # If it is a single spinner, we need to send it a success/error message
204
+ if @process.exit_code.zero?
205
+ @spinner.success(@success_message || '')
206
+ else
207
+ @spinner.error(@failure_message || '')
208
+ end
209
+ end
210
+
211
+ def run_process_in_clean_env!
212
+ require 'bundler'
213
+
214
+ # Bundler 2.1.0 has deprecated the use of `Bundler.with_clean_env` in favour of
215
+ # `Bundler.with_unbundled_env`. So prefer to use the newer method if it exists
216
+ # otherwise revert back to the old method.
217
+ if ::Bundler.respond_to?(:with_unbundled_env)
218
+ run_process_with_unbundled_env!
219
+ else
220
+ run_process_with_clean_env!
221
+ end
222
+ end
223
+
224
+ def run_process!
225
+ command_string = argv.join(' ')
226
+
227
+ PDK.logger.debug(format("Executing '%{command}'", command: command_string))
228
+
229
+ if context == :module
230
+ PDK.logger.debug('Command environment:')
231
+ @process.environment.each do |var, val|
232
+ PDK.logger.debug(" #{var}: #{val}")
233
+ end
234
+ end
235
+
236
+ start_time = Time.now
237
+
238
+ begin
239
+ @process.start
240
+ rescue ChildProcess::LaunchError => e
241
+ raise PDK::CLI::FatalError, format("Failed to execute '%{command}': %{message}", command: command_string, message: e.message)
242
+ end
243
+
244
+ if timeout
245
+ begin
246
+ @process.poll_for_exit(timeout)
247
+ rescue ChildProcess::TimeoutError
248
+ @process.stop # tries increasingly harsher methods to kill the process.
249
+ end
250
+ else
251
+ # Wait indfinitely if no timeout set.
252
+ @process.wait
253
+ end
254
+
255
+ @duration = Time.now - start_time
256
+
257
+ PDK.logger.debug(format("Execution of '%{command}' complete (duration: %{duration_in_seconds}s; exit code: %{exit_code})", command: command_string, duration_in_seconds: @duration,
258
+ exit_code: @process.exit_code))
259
+ end
260
+
261
+ private
262
+
263
+ # :nocov:
264
+ # These are just bundler helper methods and are tested via the public run_process_in_clean_env! method
265
+ def run_process_with_unbundled_env!
266
+ # Bundler 2.1.0 or greater
267
+ ::Bundler.with_unbundled_env do
268
+ run_process!
269
+ end
270
+ end
271
+ # :nocov:
272
+
273
+ # :nocov:
274
+ # These are just bundler helper methods and are tested via the public run_process_in_clean_env! method
275
+ def run_process_with_clean_env!
276
+ # Bundler 2.0.2 or less
277
+ ::Bundler.with_clean_env do
278
+ run_process!
279
+ end
280
+ end
281
+ # :nocov:
282
+ end
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,109 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module CLI
5
+ module Exec
6
+ class InteractiveCommand < Command
7
+ # rubocop :disable Lint/MissingSuper
8
+ def initialize(*argv)
9
+ @argv = argv
10
+
11
+ # Default to running things in the system context.
12
+ @context = :system
13
+
14
+ # Extra environment vars to add to base set.
15
+ @environment = {}
16
+ end
17
+ # rubocop :enable Lint/MissingSuper
18
+
19
+ def register_spinner(_spinner, _opts = {})
20
+ raise 'This method is not implemented for PDK::CLI::Exec::InteractiveCommand'
21
+ end
22
+
23
+ def add_spinner(_message, _opts = {})
24
+ raise 'This method is not implemented for PDK::CLI::Exec::InteractiveCommand'
25
+ end
26
+
27
+ def timeout
28
+ raise 'This method is not implemented for PDK::CLI::Exec::InteractiveCommand'
29
+ end
30
+
31
+ def timeout=(_val)
32
+ raise 'This method is not implemented for PDK::CLI::Exec::InteractiveCommand'
33
+ end
34
+
35
+ def exec_group=(_val)
36
+ raise 'This method is not implemented for PDK::CLI::Exec::InteractiveCommand'
37
+ end
38
+
39
+ def execute!
40
+ require 'pdk/util'
41
+
42
+ @resolved_env = resolved_env_for_command
43
+
44
+ if [:module, :pwd].include?(context)
45
+ mod_root = PDK::Util.module_root
46
+
47
+ raise PDK::CLI::FatalError, 'Current working directory is not part of a module. (No metadata.json was found.)' unless mod_root
48
+
49
+ unless context == :pwd || Dir.pwd == mod_root
50
+ orig_workdir = Dir.pwd
51
+ Dir.chdir(mod_root)
52
+ end
53
+
54
+ result = run_process_in_clean_env!
55
+ else
56
+ result = run_process!
57
+ end
58
+
59
+ {
60
+ interactive: true,
61
+ stdout: nil,
62
+ stderr: nil,
63
+ exit_code: result[:exit_code],
64
+ duration: result[:duration]
65
+ }
66
+ ensure
67
+ Dir.chdir(orig_workdir) if orig_workdir
68
+ end
69
+
70
+ protected
71
+
72
+ # TODO: debug logging
73
+ def run_process!
74
+ command_string = argv.join(' ')
75
+ PDK.logger.debug(format("Executing '%{command}' interactively", command: command_string))
76
+
77
+ if context == :module
78
+ PDK.logger.debug('Command environment:')
79
+ @resolved_env.each do |var, val|
80
+ PDK.logger.debug(" #{var}: #{val}")
81
+ end
82
+ end
83
+
84
+ start_time = Time.now
85
+
86
+ system(@resolved_env, *argv)
87
+
88
+ exit_code = child_status.exitstatus
89
+ duration = Time.now - start_time
90
+
91
+ PDK.logger.debug(format("Execution of '%{command}' complete (duration: \
92
+ %{duration_in_seconds}s; exit code: %{exit_code})", command: command_string, exit_code: exit_code, duration_in_seconds: duration))
93
+
94
+ { exit_code: exit_code, duration: duration }
95
+ end
96
+
97
+ def child_status
98
+ require 'English'
99
+
100
+ $CHILD_STATUS
101
+ end
102
+
103
+ def stop_spinner
104
+ raise 'This method is not implemented for PDK::CLI::Exec::InteractiveCommand'
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end