pdk-akerl 1.8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +826 -0
  3. data/LICENSE +201 -0
  4. data/README.md +133 -0
  5. data/exe/pdk +10 -0
  6. data/lib/pdk.rb +10 -0
  7. data/lib/pdk/answer_file.rb +121 -0
  8. data/lib/pdk/cli.rb +113 -0
  9. data/lib/pdk/cli/build.rb +76 -0
  10. data/lib/pdk/cli/bundle.rb +42 -0
  11. data/lib/pdk/cli/convert.rb +41 -0
  12. data/lib/pdk/cli/errors.rb +23 -0
  13. data/lib/pdk/cli/exec.rb +246 -0
  14. data/lib/pdk/cli/exec_group.rb +67 -0
  15. data/lib/pdk/cli/module.rb +14 -0
  16. data/lib/pdk/cli/module/build.rb +14 -0
  17. data/lib/pdk/cli/module/generate.rb +45 -0
  18. data/lib/pdk/cli/new.rb +17 -0
  19. data/lib/pdk/cli/new/class.rb +32 -0
  20. data/lib/pdk/cli/new/defined_type.rb +30 -0
  21. data/lib/pdk/cli/new/module.rb +41 -0
  22. data/lib/pdk/cli/new/provider.rb +27 -0
  23. data/lib/pdk/cli/new/task.rb +31 -0
  24. data/lib/pdk/cli/test.rb +12 -0
  25. data/lib/pdk/cli/test/unit.rb +88 -0
  26. data/lib/pdk/cli/update.rb +32 -0
  27. data/lib/pdk/cli/util.rb +193 -0
  28. data/lib/pdk/cli/util/command_redirector.rb +26 -0
  29. data/lib/pdk/cli/util/interview.rb +63 -0
  30. data/lib/pdk/cli/util/option_normalizer.rb +53 -0
  31. data/lib/pdk/cli/util/option_validator.rb +56 -0
  32. data/lib/pdk/cli/validate.rb +124 -0
  33. data/lib/pdk/generate.rb +11 -0
  34. data/lib/pdk/generate/defined_type.rb +49 -0
  35. data/lib/pdk/generate/module.rb +318 -0
  36. data/lib/pdk/generate/provider.rb +82 -0
  37. data/lib/pdk/generate/puppet_class.rb +48 -0
  38. data/lib/pdk/generate/puppet_object.rb +288 -0
  39. data/lib/pdk/generate/task.rb +86 -0
  40. data/lib/pdk/i18n.rb +4 -0
  41. data/lib/pdk/logger.rb +28 -0
  42. data/lib/pdk/module.rb +21 -0
  43. data/lib/pdk/module/build.rb +214 -0
  44. data/lib/pdk/module/convert.rb +209 -0
  45. data/lib/pdk/module/metadata.rb +193 -0
  46. data/lib/pdk/module/templatedir.rb +313 -0
  47. data/lib/pdk/module/update.rb +111 -0
  48. data/lib/pdk/module/update_manager.rb +210 -0
  49. data/lib/pdk/report.rb +112 -0
  50. data/lib/pdk/report/event.rb +357 -0
  51. data/lib/pdk/template_file.rb +89 -0
  52. data/lib/pdk/tests/unit.rb +213 -0
  53. data/lib/pdk/util.rb +271 -0
  54. data/lib/pdk/util/bundler.rb +253 -0
  55. data/lib/pdk/util/filesystem.rb +12 -0
  56. data/lib/pdk/util/git.rb +74 -0
  57. data/lib/pdk/util/puppet_version.rb +242 -0
  58. data/lib/pdk/util/ruby_version.rb +147 -0
  59. data/lib/pdk/util/vendored_file.rb +88 -0
  60. data/lib/pdk/util/version.rb +42 -0
  61. data/lib/pdk/util/windows.rb +13 -0
  62. data/lib/pdk/util/windows/api_types.rb +57 -0
  63. data/lib/pdk/util/windows/file.rb +36 -0
  64. data/lib/pdk/util/windows/string.rb +16 -0
  65. data/lib/pdk/validate.rb +14 -0
  66. data/lib/pdk/validate/base_validator.rb +209 -0
  67. data/lib/pdk/validate/metadata/metadata_json_lint.rb +86 -0
  68. data/lib/pdk/validate/metadata/metadata_syntax.rb +109 -0
  69. data/lib/pdk/validate/metadata_validator.rb +30 -0
  70. data/lib/pdk/validate/puppet/puppet_lint.rb +67 -0
  71. data/lib/pdk/validate/puppet/puppet_syntax.rb +112 -0
  72. data/lib/pdk/validate/puppet_validator.rb +30 -0
  73. data/lib/pdk/validate/ruby/rubocop.rb +77 -0
  74. data/lib/pdk/validate/ruby_validator.rb +29 -0
  75. data/lib/pdk/validate/tasks/metadata_lint.rb +126 -0
  76. data/lib/pdk/validate/tasks/name.rb +88 -0
  77. data/lib/pdk/validate/tasks_validator.rb +33 -0
  78. data/lib/pdk/version.rb +4 -0
  79. data/locales/config.yaml +21 -0
  80. data/locales/pdk.pot +1283 -0
  81. metadata +304 -0
data/lib/pdk/cli.rb ADDED
@@ -0,0 +1,113 @@
1
+ require 'cri'
2
+
3
+ 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
+
41
+ def self.template_url_option(dsl)
42
+ desc = _('Specifies the URL to the template to use when creating new modules or classes. (default: %{default_url})') % { default_url: PDK::Util.default_template_url }
43
+
44
+ dsl.option nil, 'template-url', desc, argument: :required
45
+ end
46
+
47
+ def self.skip_interview_option(dsl)
48
+ dsl.option nil, 'skip-interview', _('When specified, skips interactive querying of metadata.')
49
+ end
50
+
51
+ def self.full_interview_option(dsl)
52
+ dsl.option nil, 'full-interview', _('When specified, interactive querying of metadata will include all optional questions.')
53
+ end
54
+
55
+ def self.puppet_version_options(dsl)
56
+ dsl.option nil, 'puppet-version', _('Puppet version to run tests or validations against.'), argument: :required
57
+ dsl.option nil, 'pe-version', _('Puppet Enterprise version to run tests or validations against.'), argument: :required
58
+ end
59
+
60
+ def self.puppet_dev_option(dsl)
61
+ dsl.option nil,
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
65
+
66
+ @base_cmd = Cri::Command.define do
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'
72
+
73
+ flag nil, :version, _('Show version of pdk.') do |_, _|
74
+ puts PDK::Util::Version.version_string
75
+ exit 0
76
+ end
77
+
78
+ flag :h, :help, _('Show help for this command.') do |_, c|
79
+ puts c.help
80
+ exit 0
81
+ end
82
+
83
+ format_desc = _(
84
+ "Specify desired output format. Valid formats are '%{available_formats}'. " \
85
+ 'You may also specify a file to which the formatted output is sent, ' \
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("', '") }
89
+
90
+ option :f, :format, format_desc, argument: :required, multiple: true do |values|
91
+ PDK::CLI::Util::OptionNormalizer.report_formats(values.compact)
92
+ end
93
+
94
+ flag :d, :debug, _('Enable debug output.') do |_, _|
95
+ PDK.logger.enable_debug_output
96
+ end
97
+
98
+ option nil, 'answer-file', _('Path to an answer file.'), argument: :required, hidden: true do |value|
99
+ PDK.answer_file = value
100
+ end
101
+ end
102
+
103
+ require 'pdk/cli/bundle'
104
+ require 'pdk/cli/build'
105
+ require 'pdk/cli/convert'
106
+ require 'pdk/cli/new'
107
+ require 'pdk/cli/test'
108
+ require 'pdk/cli/update'
109
+ require 'pdk/cli/validate'
110
+ require 'pdk/cli/module'
111
+
112
+ @base_cmd.add_command Cri::Command.new_basic_help
113
+ end
@@ -0,0 +1,76 @@
1
+ require 'pdk/cli/util'
2
+
3
+ module PDK::CLI
4
+ @build_cmd = @base_cmd.define_command do
5
+ name 'build'
6
+ usage _('build [options]')
7
+ summary _('Builds a package from the module that can be published to the Puppet Forge.')
8
+
9
+ option nil, 'target-dir',
10
+ _('The target directory where you want PDK to write the package.'),
11
+ argument: :required, default: File.join(Dir.pwd, 'pkg')
12
+
13
+ option nil, 'force', _('Skips the prompts and builds the module package.')
14
+
15
+ run do |opts, _args, _cmd|
16
+ require 'pdk/module/build'
17
+
18
+ # Make sure build is being run in a valid module directory with a metadata.json
19
+ PDK::CLI::Util.ensure_in_module!(
20
+ message: _('`pdk build` can only be run from inside a valid module with a metadata.json.'),
21
+ log_level: :info,
22
+ )
23
+
24
+ module_metadata = PDK::Module::Metadata.from_file('metadata.json')
25
+
26
+ # TODO: Ensure forge metadata has been set, or call out to interview
27
+ # to set it.
28
+ #
29
+ unless module_metadata.forge_ready?
30
+ if opts[:force]
31
+ PDK.logger.error _('This module is missing required fields in the metadata.json. Re-run the build command without --force to add this information.')
32
+ exit 1
33
+ else
34
+ module_metadata.interview_for_forge!
35
+ module_metadata.write!('metadata.json')
36
+ end
37
+ end
38
+
39
+ builder = PDK::Module::Build.new(opts)
40
+
41
+ unless opts[:force]
42
+ if builder.package_already_exists?
43
+ PDK.logger.info _("The file '%{package}' already exists.") % { package: builder.package_file }
44
+
45
+ unless PDK::CLI::Util.prompt_for_yes(_('Overwrite?'), default: false)
46
+ PDK.logger.info _('Build cancelled; exiting.')
47
+ exit 0
48
+ end
49
+ end
50
+
51
+ unless builder.module_pdk_compatible?
52
+ PDK.logger.info _('This module is not compatible with PDK, so PDK can not validate or test this build. ' \
53
+ 'Unvalidated modules may have errors when uploading to the Forge. ' \
54
+ 'To make this module PDK compatible and use validate features, cancel the build and run `pdk convert`.')
55
+
56
+ unless PDK::CLI::Util.prompt_for_yes(_('Continue build without converting?'))
57
+ PDK.logger.info _('Build cancelled; exiting.')
58
+ exit 0
59
+ end
60
+ end
61
+ end
62
+
63
+ PDK.logger.info _('Building %{module_name} version %{module_version}') % {
64
+ module_name: module_metadata.data['name'],
65
+ module_version: module_metadata.data['version'],
66
+ }
67
+
68
+ builder.build
69
+
70
+ PDK.logger.info _('Build of %{package_name} has completed successfully. Built package can be found here: %{package_path}') % {
71
+ package_name: module_metadata.data['name'],
72
+ package_path: builder.package_file,
73
+ }
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,42 @@
1
+
2
+ module PDK::CLI
3
+ @bundle_cmd = @base_cmd.define_command do
4
+ name 'bundle'
5
+ usage _('bundle [bundler_options]')
6
+ summary _('(Experimental) Command pass-through to bundler')
7
+ description _(<<-EOF
8
+ [experimental] For advanced users, pdk bundle runs arbitrary commands in the bundler environment that pdk manages.
9
+ Careless use of this command can lead to errors that pdk can't help recover from.
10
+
11
+ Note that for PowerShell the '--' needs to be escaped using a backtick: '`--' to avoid it being parsed by the shell.
12
+ EOF
13
+ )
14
+ skip_option_parsing
15
+
16
+ run do |_opts, args, _cmd|
17
+ PDK::CLI::Util.ensure_in_module!(
18
+ message: _('`pdk bundle` can only be run from inside a valid module directory.'),
19
+ )
20
+
21
+ PDK::CLI::Util.validate_puppet_version_opts({})
22
+
23
+ # Ensure that the correct Ruby is activated before running commend.
24
+ puppet_env = PDK::CLI::Util.puppet_from_opts_or_env({})
25
+ PDK::Util::RubyVersion.use(puppet_env[:ruby_version])
26
+
27
+ gemfile_env = PDK::Util::Bundler::BundleHelper.gemfile_env(puppet_env[:gemset])
28
+
29
+ command = PDK::CLI::Exec::Command.new(PDK::CLI::Exec.bundle_bin, *args).tap do |c|
30
+ c.context = :module
31
+ c.update_environment(gemfile_env)
32
+ end
33
+
34
+ result = command.execute!
35
+
36
+ $stderr.puts result[:stdout]
37
+ $stderr.puts result[:stderr]
38
+
39
+ exit result[:exit_code]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,41 @@
1
+ require 'pdk/cli/util'
2
+
3
+ module PDK::CLI
4
+ @convert_cmd = @base_cmd.define_command do
5
+ name 'convert'
6
+ usage _('convert [options]')
7
+ summary _('Convert an existing module to be compatible with the PDK.')
8
+
9
+ PDK::CLI.template_url_option(self)
10
+ PDK::CLI.skip_interview_option(self)
11
+ PDK::CLI.full_interview_option(self)
12
+ flag nil, :noop, _('Do not convert the module, just output what would be done.')
13
+ flag nil, :force, _('Convert the module automatically, with no prompts.')
14
+
15
+ run do |opts, _args, _cmd|
16
+ require 'pdk/module/convert'
17
+
18
+ PDK::CLI::Util.ensure_in_module!(
19
+ check_module_layout: true,
20
+ message: _('`pdk convert` can only be run from inside a valid module directory.'),
21
+ log_level: :info,
22
+ )
23
+
24
+ if opts[:noop] && opts[:force]
25
+ raise PDK::CLI::ExitWithError, _('You can not specify --noop and --force when converting a module')
26
+ end
27
+
28
+ if opts[:'skip-interview'] && opts[:'full-interview']
29
+ PDK.logger.info _('Ignoring --full-interview and continuing with --skip-interview.')
30
+ opts[:'full-interview'] = false
31
+ end
32
+
33
+ if opts[:force] && opts[:'full-interview']
34
+ PDK.logger.info _('Ignoring --full-interview and continuing with --force.')
35
+ opts[:'full-interview'] = false
36
+ end
37
+
38
+ PDK::Module::Convert.invoke(opts)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ module PDK
2
+ module CLI
3
+ class FatalError < StandardError
4
+ attr_reader :exit_code
5
+
6
+ def initialize(msg = _('An unexpected error has occurred. Try running the command again with --debug'), opts = {})
7
+ @exit_code = opts.fetch(:exit_code, 1)
8
+ super(msg)
9
+ end
10
+ end
11
+
12
+ class ExitWithError < StandardError
13
+ attr_reader :exit_code
14
+ attr_reader :log_level
15
+
16
+ def initialize(msg, opts = {})
17
+ @exit_code = opts.fetch(:exit_code, 1)
18
+ @log_level = opts.fetch(:log_level, :error)
19
+ super(msg)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,246 @@
1
+ require 'bundler'
2
+ require 'childprocess'
3
+ require 'tempfile'
4
+ require 'tty-spinner'
5
+ require 'tty-which'
6
+
7
+ require 'pdk/util'
8
+ require 'pdk/util/git'
9
+ require 'pdk/util/ruby_version'
10
+
11
+ module PDK
12
+ module CLI
13
+ module Exec
14
+ def self.execute(*cmd)
15
+ Command.new(*cmd).execute!
16
+ end
17
+
18
+ def self.execute_with_env(env, *cmd)
19
+ Command.new(*cmd).tap { |c| c.environment = env }.execute!
20
+ end
21
+
22
+ def self.ensure_bin_present!(bin_path, bin_name)
23
+ message = _('Unable to find `%{name}`. Check that it is installed and try again.') % {
24
+ name: bin_name,
25
+ }
26
+
27
+ raise PDK::CLI::FatalError, message unless TTY::Which.exist?(bin_path)
28
+ end
29
+
30
+ def self.bundle(*args)
31
+ ensure_bin_present!(bundle_bin, 'bundler')
32
+
33
+ execute(bundle_bin, *args)
34
+ end
35
+
36
+ def self.bundle_bin
37
+ bundle_bin = Gem.win_platform? ? 'bundle.bat' : 'bundle'
38
+ vendored_bin_path = File.join('private', 'ruby', PDK::Util::RubyVersion.active_ruby_version, 'bin', bundle_bin)
39
+
40
+ try_vendored_bin(vendored_bin_path, bundle_bin)
41
+ end
42
+
43
+ def self.try_vendored_bin(vendored_bin_path, fallback)
44
+ unless PDK::Util.package_install?
45
+ PDK.logger.debug(_("PDK package installation not found. Trying '%{fallback}' from the system PATH instead.") % {
46
+ fallback: fallback,
47
+ })
48
+ return fallback
49
+ end
50
+
51
+ vendored_bin_full_path = File.join(PDK::Util.pdk_package_basedir, vendored_bin_path)
52
+
53
+ unless File.exist?(vendored_bin_full_path)
54
+ PDK.logger.debug(_("Could not find '%{vendored_bin}' in PDK package. Trying '%{fallback}' from the system PATH instead.") % {
55
+ fallback: fallback,
56
+ vendored_bin: vendored_bin_full_path,
57
+ })
58
+ return fallback
59
+ end
60
+
61
+ PDK.logger.debug(_("Using '%{vendored_bin}' from PDK package.") % { vendored_bin: vendored_bin_full_path })
62
+ vendored_bin_full_path
63
+ end
64
+
65
+ # TODO: decide how/when to connect stdin to child process for things like pry
66
+ # TODO: need a way to set callbacks on new stdout/stderr data
67
+ class Command
68
+ attr_reader :argv
69
+ attr_reader :context
70
+ attr_accessor :timeout
71
+ attr_accessor :environment
72
+ attr_writer :exec_group
73
+
74
+ def initialize(*argv)
75
+ @argv = argv
76
+
77
+ @process = ChildProcess.build(*@argv)
78
+ @process.leader = true
79
+
80
+ @stdout = Tempfile.new('stdout').tap { |io| io.sync = true }
81
+ @stderr = Tempfile.new('stderr').tap { |io| io.sync = true }
82
+
83
+ @process.io.stdout = @stdout
84
+ @process.io.stderr = @stderr
85
+
86
+ # Default to running things in the system context.
87
+ @context = :system
88
+
89
+ # Extra environment vars to add to base set.
90
+ @environment = {}
91
+
92
+ # Register the ExecGroup when running in parallel
93
+ @exec_group = nil
94
+ end
95
+
96
+ def context=(new_context)
97
+ unless [:system, :module].include?(new_context)
98
+ raise ArgumentError, _("Expected execution context to be :system or :module but got '%{context}'.") % { context: new_context }
99
+ end
100
+
101
+ @context = new_context
102
+ end
103
+
104
+ def register_spinner(spinner, opts = {})
105
+ return unless PDK::CLI::Util.interactive?
106
+ @success_message = opts.delete(:success)
107
+ @failure_message = opts.delete(:failure)
108
+
109
+ @spinner = spinner
110
+ end
111
+
112
+ def add_spinner(message, opts = {})
113
+ return unless PDK::CLI::Util.interactive?
114
+ @success_message = opts.delete(:success)
115
+ @failure_message = opts.delete(:failure)
116
+
117
+ @spinner = TTY::Spinner.new("[:spinner] #{message}", opts.merge(PDK::CLI::Util.spinner_opts_for_platform))
118
+ end
119
+
120
+ def update_environment(additional_env)
121
+ @environment.merge!(additional_env)
122
+ end
123
+
124
+ def execute!
125
+ # Start spinning if configured.
126
+ @spinner.auto_spin if @spinner
127
+
128
+ # Add custom env vars.
129
+ @environment.each do |k, v|
130
+ @process.environment[k] = v
131
+ end
132
+
133
+ @process.environment['BUNDLE_IGNORE_CONFIG'] = '1'
134
+
135
+ if context == :module
136
+ @process.environment['GEM_HOME'] = PDK::Util::RubyVersion.gem_home
137
+ @process.environment['GEM_PATH'] = PDK::Util::RubyVersion.gem_path
138
+
139
+ # Make sure invocation of Ruby prefers our private installation.
140
+ package_binpath = PDK::Util.package_install? ? File.join(PDK::Util.pdk_package_basedir, 'bin') : nil
141
+ @process.environment['PATH'] = [
142
+ PDK::Util::RubyVersion.bin_path,
143
+ File.join(@process.environment['GEM_HOME'], 'bin'),
144
+ PDK::Util::RubyVersion.gem_paths_raw.map { |gem_path| File.join(gem_path, 'bin') },
145
+ package_binpath,
146
+ ENV['PATH'],
147
+ PDK::Util.package_install? ? PDK::Util::Git.git_paths : nil,
148
+ ].compact.flatten.join(File::PATH_SEPARATOR)
149
+
150
+ mod_root = PDK::Util.module_root
151
+
152
+ unless mod_root
153
+ @spinner.error if @spinner
154
+
155
+ raise PDK::CLI::FatalError, _('Current working directory is not part of a module. (No metadata.json was found.)')
156
+ end
157
+
158
+ if Dir.pwd == mod_root
159
+ run_process_in_clean_env!
160
+ else
161
+ Dir.chdir(mod_root) do
162
+ run_process_in_clean_env!
163
+ end
164
+ end
165
+ else
166
+ run_process!
167
+ end
168
+
169
+ # Stop spinning when done (if configured).
170
+ stop_spinner
171
+
172
+ @stdout.rewind
173
+ @stderr.rewind
174
+
175
+ process_data = {
176
+ stdout: @stdout.read,
177
+ stderr: @stderr.read,
178
+ exit_code: @process.exit_code,
179
+ duration: @duration,
180
+ }
181
+
182
+ return process_data
183
+ ensure
184
+ @stdout.close
185
+ @stderr.close
186
+ end
187
+
188
+ protected
189
+
190
+ def stop_spinner
191
+ return unless @spinner
192
+
193
+ # If it is a single spinner, we need to send it a success/error message
194
+ if @process.exit_code.zero?
195
+ @spinner.success(@success_message || '')
196
+ else
197
+ @spinner.error(@failure_message || '')
198
+ end
199
+ end
200
+
201
+ def run_process_in_clean_env!
202
+ ::Bundler.with_clean_env do
203
+ run_process!
204
+ end
205
+ end
206
+
207
+ def run_process!
208
+ command_string = argv.join(' ')
209
+
210
+ PDK.logger.debug(_("Executing '%{command}'") % { command: command_string })
211
+
212
+ if context == :module
213
+ PDK.logger.debug(_('Command environment:'))
214
+ @process.environment.each do |var, val|
215
+ PDK.logger.debug(" #{var}: #{val}")
216
+ end
217
+ end
218
+
219
+ start_time = Time.now
220
+
221
+ begin
222
+ @process.start
223
+ rescue ChildProcess::LaunchError => e
224
+ raise PDK::CLI::FatalError, _("Failed to execute '%{command}': %{message}") % { command: command_string, message: e.message }
225
+ end
226
+
227
+ if timeout
228
+ begin
229
+ @process.poll_for_exit(timeout)
230
+ rescue ChildProcess::TimeoutError
231
+ @process.stop # tries increasingly harsher methods to kill the process.
232
+ end
233
+ else
234
+ # Wait indfinitely if no timeout set.
235
+ @process.wait
236
+ end
237
+
238
+ @duration = Time.now - start_time
239
+
240
+ PDK.logger.debug(_("Execution of '%{command}' complete (duration: %{duration_in_seconds}s; exit code: %{exit_code})") %
241
+ { command: command_string, duration_in_seconds: @duration, exit_code: @process.exit_code })
242
+ end
243
+ end
244
+ end
245
+ end
246
+ end