pdk 2.3.0 → 2.4.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 +1329 -1321
- data/LICENSE +201 -201
- data/README.md +163 -163
- data/exe/pdk +10 -10
- data/lib/pdk/analytics/client/google_analytics.rb +143 -143
- data/lib/pdk/analytics/client/noop.rb +25 -25
- data/lib/pdk/analytics/util.rb +19 -19
- data/lib/pdk/analytics.rb +30 -30
- data/lib/pdk/answer_file.rb +12 -12
- data/lib/pdk/bolt.rb +19 -19
- data/lib/pdk/cli/build.rb +82 -82
- data/lib/pdk/cli/bundle.rb +48 -48
- data/lib/pdk/cli/config/get.rb +26 -26
- data/lib/pdk/cli/config.rb +22 -22
- data/lib/pdk/cli/console.rb +148 -148
- data/lib/pdk/cli/convert.rb +52 -52
- data/lib/pdk/cli/env.rb +52 -52
- data/lib/pdk/cli/errors.rb +25 -25
- data/lib/pdk/cli/exec/command.rb +293 -293
- data/lib/pdk/cli/exec/interactive_command.rb +114 -114
- data/lib/pdk/cli/exec.rb +84 -84
- data/lib/pdk/cli/exec_group.rb +104 -104
- data/lib/pdk/cli/get/config.rb +24 -24
- data/lib/pdk/cli/get.rb +20 -20
- data/lib/pdk/cli/module/build.rb +12 -12
- data/lib/pdk/cli/module/generate.rb +47 -47
- data/lib/pdk/cli/module.rb +14 -14
- data/lib/pdk/cli/new/class.rb +32 -32
- data/lib/pdk/cli/new/defined_type.rb +32 -32
- data/lib/pdk/cli/new/fact.rb +29 -29
- data/lib/pdk/cli/new/function.rb +29 -29
- data/lib/pdk/cli/new/module.rb +53 -53
- data/lib/pdk/cli/new/provider.rb +29 -29
- data/lib/pdk/cli/new/task.rb +34 -34
- data/lib/pdk/cli/new/test.rb +52 -52
- data/lib/pdk/cli/new/transport.rb +27 -27
- data/lib/pdk/cli/new.rb +21 -21
- data/lib/pdk/cli/release/prep.rb +39 -39
- data/lib/pdk/cli/release/publish.rb +50 -50
- data/lib/pdk/cli/release.rb +194 -194
- data/lib/pdk/cli/remove/config.rb +80 -80
- data/lib/pdk/cli/remove.rb +20 -20
- data/lib/pdk/cli/set/config.rb +119 -119
- data/lib/pdk/cli/set.rb +20 -20
- data/lib/pdk/cli/test/unit.rb +90 -90
- data/lib/pdk/cli/test.rb +11 -11
- data/lib/pdk/cli/update.rb +64 -64
- data/lib/pdk/cli/util/command_redirector.rb +27 -27
- data/lib/pdk/cli/util/interview.rb +72 -72
- data/lib/pdk/cli/util/option_normalizer.rb +55 -55
- data/lib/pdk/cli/util/option_validator.rb +68 -68
- data/lib/pdk/cli/util/spinner.rb +13 -13
- data/lib/pdk/cli/util/update_manager_printer.rb +82 -82
- data/lib/pdk/cli/util.rb +305 -305
- data/lib/pdk/cli/validate.rb +116 -116
- data/lib/pdk/cli.rb +175 -175
- data/lib/pdk/config/analytics_schema.json +26 -26
- data/lib/pdk/config/errors.rb +5 -5
- data/lib/pdk/config/ini_file.rb +183 -183
- data/lib/pdk/config/ini_file_setting.rb +39 -39
- data/lib/pdk/config/json.rb +34 -34
- data/lib/pdk/config/json_schema_namespace.rb +142 -142
- data/lib/pdk/config/json_schema_setting.rb +53 -53
- data/lib/pdk/config/json_with_schema.rb +49 -49
- data/lib/pdk/config/namespace.rb +354 -354
- data/lib/pdk/config/setting.rb +135 -135
- data/lib/pdk/config/validator.rb +31 -31
- data/lib/pdk/config/yaml.rb +46 -46
- data/lib/pdk/config/yaml_with_schema.rb +59 -59
- data/lib/pdk/config.rb +390 -390
- data/lib/pdk/context/control_repo.rb +60 -60
- data/lib/pdk/context/module.rb +28 -28
- data/lib/pdk/context/none.rb +22 -22
- data/lib/pdk/context.rb +99 -99
- data/lib/pdk/control_repo.rb +90 -90
- data/lib/pdk/generate/defined_type.rb +43 -43
- data/lib/pdk/generate/fact.rb +25 -25
- data/lib/pdk/generate/function.rb +48 -48
- data/lib/pdk/generate/module.rb +352 -352
- data/lib/pdk/generate/provider.rb +28 -28
- data/lib/pdk/generate/puppet_class.rb +43 -43
- data/lib/pdk/generate/puppet_object.rb +232 -232
- data/lib/pdk/generate/task.rb +68 -68
- data/lib/pdk/generate/transport.rb +33 -33
- data/lib/pdk/generate.rb +24 -24
- data/lib/pdk/i18n.rb +4 -4
- data/lib/pdk/logger.rb +45 -45
- data/lib/pdk/module/build.rb +322 -322
- data/lib/pdk/module/convert.rb +296 -296
- data/lib/pdk/module/metadata.rb +202 -202
- data/lib/pdk/module/release.rb +260 -260
- data/lib/pdk/module/update.rb +131 -131
- data/lib/pdk/module/update_manager.rb +227 -227
- data/lib/pdk/module.rb +30 -30
- data/lib/pdk/report/event.rb +370 -370
- data/lib/pdk/report.rb +121 -121
- data/lib/pdk/template/fetcher/git.rb +85 -85
- data/lib/pdk/template/fetcher/local.rb +28 -28
- data/lib/pdk/template/fetcher.rb +98 -98
- data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +116 -116
- data/lib/pdk/template/renderer/v1/renderer.rb +132 -132
- data/lib/pdk/template/renderer/v1/template_file.rb +102 -102
- data/lib/pdk/template/renderer/v1.rb +25 -25
- data/lib/pdk/template/renderer.rb +96 -96
- data/lib/pdk/template/template_dir.rb +67 -67
- data/lib/pdk/template.rb +59 -59
- data/lib/pdk/tests/unit.rb +252 -252
- data/lib/pdk/util/bundler.rb +259 -259
- data/lib/pdk/util/changelog_generator.rb +137 -137
- data/lib/pdk/util/env.rb +47 -47
- data/lib/pdk/util/filesystem.rb +138 -138
- data/lib/pdk/util/git.rb +179 -179
- data/lib/pdk/util/json_finder.rb +85 -85
- data/lib/pdk/util/puppet_strings.rb +125 -125
- data/lib/pdk/util/puppet_version.rb +266 -266
- data/lib/pdk/util/ruby_version.rb +179 -179
- data/lib/pdk/util/template_uri.rb +295 -295
- data/lib/pdk/util/vendored_file.rb +93 -93
- data/lib/pdk/util/version.rb +43 -43
- data/lib/pdk/util/windows/api_types.rb +82 -82
- data/lib/pdk/util/windows/file.rb +36 -36
- data/lib/pdk/util/windows/process.rb +79 -79
- data/lib/pdk/util/windows/string.rb +16 -16
- data/lib/pdk/util/windows.rb +15 -15
- data/lib/pdk/util.rb +278 -277
- data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -23
- data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -98
- data/lib/pdk/validate/external_command_validator.rb +208 -208
- data/lib/pdk/validate/internal_ruby_validator.rb +100 -100
- data/lib/pdk/validate/invokable_validator.rb +228 -228
- data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +86 -86
- data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +78 -78
- data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -20
- data/lib/pdk/validate/puppet/puppet_epp_validator.rb +133 -133
- data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -66
- data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +137 -137
- data/lib/pdk/validate/puppet/puppet_validator_group.rb +21 -21
- data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +80 -80
- data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -19
- data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +88 -88
- data/lib/pdk/validate/tasks/tasks_name_validator.rb +50 -50
- data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -20
- data/lib/pdk/validate/validator.rb +118 -118
- data/lib/pdk/validate/validator_group.rb +104 -104
- data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +95 -95
- data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -19
- data/lib/pdk/validate.rb +94 -94
- data/lib/pdk/version.rb +4 -4
- data/lib/pdk.rb +76 -76
- data/locales/config.yaml +21 -21
- data/locales/pdk.pot +2094 -2094
- metadata +5 -6
data/lib/pdk/cli/exec/command.rb
CHANGED
|
@@ -1,293 +1,293 @@
|
|
|
1
|
-
require 'pdk'
|
|
2
|
-
|
|
3
|
-
module PDK
|
|
4
|
-
module CLI
|
|
5
|
-
module Exec
|
|
6
|
-
class Command
|
|
7
|
-
attr_reader :argv
|
|
8
|
-
attr_reader :context
|
|
9
|
-
attr_accessor :timeout
|
|
10
|
-
attr_accessor :environment
|
|
11
|
-
attr_writer :exec_group
|
|
12
|
-
|
|
13
|
-
# The spinner for this command.
|
|
14
|
-
# This should only be used for testing
|
|
15
|
-
#
|
|
16
|
-
# @return [TTY::Spinner, nil]
|
|
17
|
-
#
|
|
18
|
-
# @api private
|
|
19
|
-
attr_reader :spinner
|
|
20
|
-
|
|
21
|
-
TEMPFILE_MODE = File::RDWR | File::BINARY | File::CREAT | File::TRUNC
|
|
22
|
-
|
|
23
|
-
def initialize(*argv)
|
|
24
|
-
require 'childprocess'
|
|
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
|
-
unless [:system, :module, :pwd].include?(new_context)
|
|
60
|
-
raise ArgumentError, _("Expected execution context to be :system or :module but got '%{context}'.") % { context: new_context }
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
@context = new_context
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def register_spinner(spinner, opts = {})
|
|
67
|
-
require 'pdk/cli/util'
|
|
68
|
-
|
|
69
|
-
return unless PDK::CLI::Util.interactive?
|
|
70
|
-
@success_message = opts.delete(:success)
|
|
71
|
-
@failure_message = opts.delete(:failure)
|
|
72
|
-
|
|
73
|
-
@spinner = spinner
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def add_spinner(message, opts = {})
|
|
77
|
-
require 'pdk/cli/util'
|
|
78
|
-
|
|
79
|
-
return unless PDK::CLI::Util.interactive?
|
|
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 if @spinner
|
|
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 if @spinner
|
|
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 _('STDOUT: %{output}') % {
|
|
139
|
-
output: process_data[:stdout].empty? ? 'N/A' : "\n#{process_data[:stdout]}",
|
|
140
|
-
}
|
|
141
|
-
PDK.logger.debug _('STDERR: %{output}') % {
|
|
142
|
-
output: process_data[:stderr].empty? ? 'N/A' : "\n#{process_data[:stderr]}",
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
process_data
|
|
146
|
-
ensure
|
|
147
|
-
@stdout.close
|
|
148
|
-
@stderr.close
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
protected
|
|
152
|
-
|
|
153
|
-
def warn_on_legacy_env_vars!
|
|
154
|
-
if PDK::Util::Env['PUPPET_GEM_VERSION']
|
|
155
|
-
PDK.logger.warn_once _(
|
|
156
|
-
'PUPPET_GEM_VERSION is not supported by PDK. ' \
|
|
157
|
-
'Use the --puppet-version option on your PDK command ' \
|
|
158
|
-
'or set the PDK_PUPPET_VERSION environment variable instead',
|
|
159
|
-
)
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
%w[FACTER HIERA].each do |gem|
|
|
163
|
-
if PDK::Util::Env["#{gem}_GEM_VERSION"]
|
|
164
|
-
PDK.logger.warn_once _('%{varname} is not supported by PDK.') % { varname: "#{gem}_GEM_VERSION" }
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def resolved_env_for_command
|
|
170
|
-
warn_on_legacy_env_vars!
|
|
171
|
-
|
|
172
|
-
resolved_env = {}
|
|
173
|
-
|
|
174
|
-
resolved_env['TERM'] = PDK::Util::Env['TERM']
|
|
175
|
-
resolved_env['PUPPET_GEM_VERSION'] = nil
|
|
176
|
-
resolved_env['FACTER_GEM_VERSION'] = nil
|
|
177
|
-
resolved_env['HIERA_GEM_VERSION'] = nil
|
|
178
|
-
|
|
179
|
-
resolved_env.merge!(@environment.dup)
|
|
180
|
-
|
|
181
|
-
resolved_env['BUNDLE_IGNORE_CONFIG'] = '1'
|
|
182
|
-
|
|
183
|
-
if [:module, :pwd].include?(context)
|
|
184
|
-
require 'pdk/util'
|
|
185
|
-
require 'pdk/util/git'
|
|
186
|
-
require 'pdk/util/ruby_version'
|
|
187
|
-
|
|
188
|
-
resolved_env['GEM_HOME'] = PDK::Util::RubyVersion.gem_home
|
|
189
|
-
gem_path = PDK::Util::RubyVersion.gem_path
|
|
190
|
-
resolved_env['GEM_PATH'] = gem_path.empty? ? resolved_env['GEM_HOME'] : gem_path
|
|
191
|
-
|
|
192
|
-
# Make sure invocation of Ruby prefers our private installation.
|
|
193
|
-
package_binpath = PDK::Util.package_install? ? File.join(PDK::Util.pdk_package_basedir, 'bin') : nil
|
|
194
|
-
|
|
195
|
-
resolved_env['PATH'] = [
|
|
196
|
-
PDK::Util::RubyVersion.bin_path,
|
|
197
|
-
File.join(resolved_env['GEM_HOME'], 'bin'),
|
|
198
|
-
PDK::Util::RubyVersion.gem_paths_raw.map { |gem_path_raw| File.join(gem_path_raw, 'bin') },
|
|
199
|
-
package_binpath,
|
|
200
|
-
PDK::Util.package_install? ? PDK::Util::Git.git_paths : nil,
|
|
201
|
-
PDK::Util::Env['PATH'],
|
|
202
|
-
].compact.flatten.join(File::PATH_SEPARATOR)
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
resolved_env
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
def stop_spinner
|
|
209
|
-
return unless @spinner
|
|
210
|
-
|
|
211
|
-
# If it is a single spinner, we need to send it a success/error message
|
|
212
|
-
if @process.exit_code.zero?
|
|
213
|
-
@spinner.success(@success_message || '')
|
|
214
|
-
else
|
|
215
|
-
@spinner.error(@failure_message || '')
|
|
216
|
-
end
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
def run_process_in_clean_env!
|
|
220
|
-
require 'bundler'
|
|
221
|
-
|
|
222
|
-
# Bundler 2.1.0 has deprecated the use of `Bundler.with_clean_env` in favour of
|
|
223
|
-
# `Bundler.with_unbundled_env`. So prefer to use the newer method if it exists
|
|
224
|
-
# otherwise revert back to the old method.
|
|
225
|
-
if ::Bundler.respond_to?(:with_unbundled_env)
|
|
226
|
-
run_process_with_unbundled_env!
|
|
227
|
-
else
|
|
228
|
-
run_process_with_clean_env!
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
def run_process!
|
|
233
|
-
command_string = argv.join(' ')
|
|
234
|
-
|
|
235
|
-
PDK.logger.debug(_("Executing '%{command}'") % { command: command_string })
|
|
236
|
-
|
|
237
|
-
if context == :module
|
|
238
|
-
PDK.logger.debug(_('Command environment:'))
|
|
239
|
-
@process.environment.each do |var, val|
|
|
240
|
-
PDK.logger.debug(" #{var}: #{val}")
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
start_time = Time.now
|
|
245
|
-
|
|
246
|
-
begin
|
|
247
|
-
@process.start
|
|
248
|
-
rescue ChildProcess::LaunchError => e
|
|
249
|
-
raise PDK::CLI::FatalError, _("Failed to execute '%{command}': %{message}") % { command: command_string, message: e.message }
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
if timeout
|
|
253
|
-
begin
|
|
254
|
-
@process.poll_for_exit(timeout)
|
|
255
|
-
rescue ChildProcess::TimeoutError
|
|
256
|
-
@process.stop # tries increasingly harsher methods to kill the process.
|
|
257
|
-
end
|
|
258
|
-
else
|
|
259
|
-
# Wait indfinitely if no timeout set.
|
|
260
|
-
@process.wait
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
@duration = Time.now - start_time
|
|
264
|
-
|
|
265
|
-
PDK.logger.debug(_("Execution of '%{command}' complete (duration: %{duration_in_seconds}s; exit code: %{exit_code})") %
|
|
266
|
-
{ command: command_string, duration_in_seconds: @duration, exit_code: @process.exit_code })
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
private
|
|
270
|
-
|
|
271
|
-
#:nocov:
|
|
272
|
-
# These are just bundler helper methods and are tested via the public run_process_in_clean_env! method
|
|
273
|
-
def run_process_with_unbundled_env!
|
|
274
|
-
# Bundler 2.1.0 or greater
|
|
275
|
-
::Bundler.with_unbundled_env do
|
|
276
|
-
run_process!
|
|
277
|
-
end
|
|
278
|
-
end
|
|
279
|
-
#:nocov:
|
|
280
|
-
|
|
281
|
-
#:nocov:
|
|
282
|
-
# These are just bundler helper methods and are tested via the public run_process_in_clean_env! method
|
|
283
|
-
def run_process_with_clean_env!
|
|
284
|
-
# Bundler 2.0.2 or less
|
|
285
|
-
::Bundler.with_clean_env do
|
|
286
|
-
run_process!
|
|
287
|
-
end
|
|
288
|
-
end
|
|
289
|
-
#:nocov:
|
|
290
|
-
end
|
|
291
|
-
end
|
|
292
|
-
end
|
|
293
|
-
end
|
|
1
|
+
require 'pdk'
|
|
2
|
+
|
|
3
|
+
module PDK
|
|
4
|
+
module CLI
|
|
5
|
+
module Exec
|
|
6
|
+
class Command
|
|
7
|
+
attr_reader :argv
|
|
8
|
+
attr_reader :context
|
|
9
|
+
attr_accessor :timeout
|
|
10
|
+
attr_accessor :environment
|
|
11
|
+
attr_writer :exec_group
|
|
12
|
+
|
|
13
|
+
# The spinner for this command.
|
|
14
|
+
# This should only be used for testing
|
|
15
|
+
#
|
|
16
|
+
# @return [TTY::Spinner, nil]
|
|
17
|
+
#
|
|
18
|
+
# @api private
|
|
19
|
+
attr_reader :spinner
|
|
20
|
+
|
|
21
|
+
TEMPFILE_MODE = File::RDWR | File::BINARY | File::CREAT | File::TRUNC
|
|
22
|
+
|
|
23
|
+
def initialize(*argv)
|
|
24
|
+
require 'childprocess'
|
|
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
|
+
unless [:system, :module, :pwd].include?(new_context)
|
|
60
|
+
raise ArgumentError, _("Expected execution context to be :system or :module but got '%{context}'.") % { context: new_context }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
@context = new_context
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def register_spinner(spinner, opts = {})
|
|
67
|
+
require 'pdk/cli/util'
|
|
68
|
+
|
|
69
|
+
return unless PDK::CLI::Util.interactive?
|
|
70
|
+
@success_message = opts.delete(:success)
|
|
71
|
+
@failure_message = opts.delete(:failure)
|
|
72
|
+
|
|
73
|
+
@spinner = spinner
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def add_spinner(message, opts = {})
|
|
77
|
+
require 'pdk/cli/util'
|
|
78
|
+
|
|
79
|
+
return unless PDK::CLI::Util.interactive?
|
|
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 if @spinner
|
|
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 if @spinner
|
|
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 _('STDOUT: %{output}') % {
|
|
139
|
+
output: process_data[:stdout].empty? ? 'N/A' : "\n#{process_data[:stdout]}",
|
|
140
|
+
}
|
|
141
|
+
PDK.logger.debug _('STDERR: %{output}') % {
|
|
142
|
+
output: process_data[:stderr].empty? ? 'N/A' : "\n#{process_data[:stderr]}",
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
process_data
|
|
146
|
+
ensure
|
|
147
|
+
@stdout.close
|
|
148
|
+
@stderr.close
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
protected
|
|
152
|
+
|
|
153
|
+
def warn_on_legacy_env_vars!
|
|
154
|
+
if PDK::Util::Env['PUPPET_GEM_VERSION']
|
|
155
|
+
PDK.logger.warn_once _(
|
|
156
|
+
'PUPPET_GEM_VERSION is not supported by PDK. ' \
|
|
157
|
+
'Use the --puppet-version option on your PDK command ' \
|
|
158
|
+
'or set the PDK_PUPPET_VERSION environment variable instead',
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
%w[FACTER HIERA].each do |gem|
|
|
163
|
+
if PDK::Util::Env["#{gem}_GEM_VERSION"]
|
|
164
|
+
PDK.logger.warn_once _('%{varname} is not supported by PDK.') % { varname: "#{gem}_GEM_VERSION" }
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def resolved_env_for_command
|
|
170
|
+
warn_on_legacy_env_vars!
|
|
171
|
+
|
|
172
|
+
resolved_env = {}
|
|
173
|
+
|
|
174
|
+
resolved_env['TERM'] = PDK::Util::Env['TERM']
|
|
175
|
+
resolved_env['PUPPET_GEM_VERSION'] = nil
|
|
176
|
+
resolved_env['FACTER_GEM_VERSION'] = nil
|
|
177
|
+
resolved_env['HIERA_GEM_VERSION'] = nil
|
|
178
|
+
|
|
179
|
+
resolved_env.merge!(@environment.dup)
|
|
180
|
+
|
|
181
|
+
resolved_env['BUNDLE_IGNORE_CONFIG'] = '1'
|
|
182
|
+
|
|
183
|
+
if [:module, :pwd].include?(context)
|
|
184
|
+
require 'pdk/util'
|
|
185
|
+
require 'pdk/util/git'
|
|
186
|
+
require 'pdk/util/ruby_version'
|
|
187
|
+
|
|
188
|
+
resolved_env['GEM_HOME'] = PDK::Util::RubyVersion.gem_home
|
|
189
|
+
gem_path = PDK::Util::RubyVersion.gem_path
|
|
190
|
+
resolved_env['GEM_PATH'] = gem_path.empty? ? resolved_env['GEM_HOME'] : gem_path
|
|
191
|
+
|
|
192
|
+
# Make sure invocation of Ruby prefers our private installation.
|
|
193
|
+
package_binpath = PDK::Util.package_install? ? File.join(PDK::Util.pdk_package_basedir, 'bin') : nil
|
|
194
|
+
|
|
195
|
+
resolved_env['PATH'] = [
|
|
196
|
+
PDK::Util::RubyVersion.bin_path,
|
|
197
|
+
File.join(resolved_env['GEM_HOME'], 'bin'),
|
|
198
|
+
PDK::Util::RubyVersion.gem_paths_raw.map { |gem_path_raw| File.join(gem_path_raw, 'bin') },
|
|
199
|
+
package_binpath,
|
|
200
|
+
PDK::Util.package_install? ? PDK::Util::Git.git_paths : nil,
|
|
201
|
+
PDK::Util::Env['PATH'],
|
|
202
|
+
].compact.flatten.join(File::PATH_SEPARATOR)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
resolved_env
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def stop_spinner
|
|
209
|
+
return unless @spinner
|
|
210
|
+
|
|
211
|
+
# If it is a single spinner, we need to send it a success/error message
|
|
212
|
+
if @process.exit_code.zero?
|
|
213
|
+
@spinner.success(@success_message || '')
|
|
214
|
+
else
|
|
215
|
+
@spinner.error(@failure_message || '')
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def run_process_in_clean_env!
|
|
220
|
+
require 'bundler'
|
|
221
|
+
|
|
222
|
+
# Bundler 2.1.0 has deprecated the use of `Bundler.with_clean_env` in favour of
|
|
223
|
+
# `Bundler.with_unbundled_env`. So prefer to use the newer method if it exists
|
|
224
|
+
# otherwise revert back to the old method.
|
|
225
|
+
if ::Bundler.respond_to?(:with_unbundled_env)
|
|
226
|
+
run_process_with_unbundled_env!
|
|
227
|
+
else
|
|
228
|
+
run_process_with_clean_env!
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def run_process!
|
|
233
|
+
command_string = argv.join(' ')
|
|
234
|
+
|
|
235
|
+
PDK.logger.debug(_("Executing '%{command}'") % { command: command_string })
|
|
236
|
+
|
|
237
|
+
if context == :module
|
|
238
|
+
PDK.logger.debug(_('Command environment:'))
|
|
239
|
+
@process.environment.each do |var, val|
|
|
240
|
+
PDK.logger.debug(" #{var}: #{val}")
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
start_time = Time.now
|
|
245
|
+
|
|
246
|
+
begin
|
|
247
|
+
@process.start
|
|
248
|
+
rescue ChildProcess::LaunchError => e
|
|
249
|
+
raise PDK::CLI::FatalError, _("Failed to execute '%{command}': %{message}") % { command: command_string, message: e.message }
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
if timeout
|
|
253
|
+
begin
|
|
254
|
+
@process.poll_for_exit(timeout)
|
|
255
|
+
rescue ChildProcess::TimeoutError
|
|
256
|
+
@process.stop # tries increasingly harsher methods to kill the process.
|
|
257
|
+
end
|
|
258
|
+
else
|
|
259
|
+
# Wait indfinitely if no timeout set.
|
|
260
|
+
@process.wait
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
@duration = Time.now - start_time
|
|
264
|
+
|
|
265
|
+
PDK.logger.debug(_("Execution of '%{command}' complete (duration: %{duration_in_seconds}s; exit code: %{exit_code})") %
|
|
266
|
+
{ command: command_string, duration_in_seconds: @duration, exit_code: @process.exit_code })
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
private
|
|
270
|
+
|
|
271
|
+
#:nocov:
|
|
272
|
+
# These are just bundler helper methods and are tested via the public run_process_in_clean_env! method
|
|
273
|
+
def run_process_with_unbundled_env!
|
|
274
|
+
# Bundler 2.1.0 or greater
|
|
275
|
+
::Bundler.with_unbundled_env do
|
|
276
|
+
run_process!
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
#:nocov:
|
|
280
|
+
|
|
281
|
+
#:nocov:
|
|
282
|
+
# These are just bundler helper methods and are tested via the public run_process_in_clean_env! method
|
|
283
|
+
def run_process_with_clean_env!
|
|
284
|
+
# Bundler 2.0.2 or less
|
|
285
|
+
::Bundler.with_clean_env do
|
|
286
|
+
run_process!
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
#:nocov:
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
end
|