diff --git a/CHANGELOG.md b/CHANGELOG.md index 71cda33..745c20e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ This release ends support for ruby < 2.3.0. If you're on 2.2.x or earlier, we strongly suggest that you find the time to upgrade, because [official support for Ruby 2.2 ended on 2018-03-31](https://www.ruby-lang.org/en/news/2018/06/20/support-of-ruby-2-2-has-ended/). +#### Enhancements + +* `MiniPortile.execute` now takes an optional `:env` hash, which is merged into the environment variables for the subprocess. Likely this is only useful for specialized use cases. [#99] + ### 2.5.0 / 2020-02-24 diff --git a/lib/mini_portile2/mini_portile.rb b/lib/mini_portile2/mini_portile.rb index 109de5b..e99935b 100644 --- a/lib/mini_portile2/mini_portile.rb +++ b/lib/mini_portile2/mini_portile.rb @@ -380,29 +380,41 @@ def extract_file(file, target) execute('extract', [tar_exe, "#{tar_compression_switch(filename)}xf", file, "-C", target], {:cd => Dir.pwd, :initial_message => false}) end - def execute(action, command, options={}) - log_out = log_file(action) + # command could be an array of args, or one string containing a command passed to the shell. See + # Process.spawn for more information. + def execute(action, command, command_opts={}) + opt_message = command_opts.fetch(:initial_message, true) + opt_debug = command_opts.fetch(:debug, false) + opt_cd = command_opts.fetch(:cd) { work_path } + opt_env = command_opts.fetch(:env) { Hash.new } - Dir.chdir (options.fetch(:cd){ work_path }) do - if options.fetch(:initial_message){ true } - message "Running '#{action}' for #{@name} #{@version}... " - end + log_out = log_file(action) + + Dir.chdir(opt_cd) do + output "DEBUG: env is #{opt_env.inspect}" if opt_debug + output "DEBUG: command is #{command.inspect}" if opt_debug + message "Running '#{action}' for #{@name} #{@version}... " if opt_message if Process.respond_to?(:spawn) && ! RbConfig.respond_to?(:java) - args = [command].flatten + [{[:out, :err]=>[log_out, "a"]}] + options = {[:out, :err]=>[log_out, "a"]} + output "DEBUG: options are #{options.inspect}" if opt_debug + args = [opt_env, command, options].flatten pid = spawn(*args) Process.wait(pid) else - redirected = if command.kind_of?(Array) - %Q{#{command.map(&:shellescape).join(" ")} > #{log_out.shellescape} 2>&1} - else - %Q{#{command} > #{log_out.shellescape} 2>&1} - end + env_args = opt_env.map { |k,v| "#{k}=#{v}".shellescape }.join(" ") + c = if command.kind_of?(Array) + command.map(&:shellescape).join(" ") + else + command + end + redirected = %Q{env #{env_args} #{c} > #{log_out.shellescape} 2>&1} + output "DEBUG: final command is #{redirected.inspect}" if opt_debug system redirected end if $?.success? - output "OK" + output "OK" if opt_message return true else if File.exist? log_out diff --git a/test/test_execute.rb b/test/test_execute.rb new file mode 100644 index 0000000..1564d53 --- /dev/null +++ b/test/test_execute.rb @@ -0,0 +1,39 @@ +require_relative "helper" + +class TestExecute < TestCase + def setup + super + @env = {"TEST_ENV_VAR1" => "VAR1_VALUE", "TEST_ENV_VAR2" => "VAR2_VALUE"} + @recipe = MiniPortile.new("test_execute", "1.0.0") + @log_path = @recipe.send(:tmp_path) + FileUtils.mkdir_p File.join(@log_path, "subdir") # normally created by `download` + end + + def test_execute_one_big_string_arg + class << @recipe + def execute_with_env(env) + execute("testenv1", + %Q(ruby -e "puts ENV['TEST_ENV_VAR1'].inspect ; exit 0"), + {:env => env, :initial_message => false, :debug => true}) + end + end + + @recipe.execute_with_env(@env) + + assert_equal("VAR1_VALUE".inspect, IO.read(File.join(@log_path, "testenv1.log")).chomp) + end + + def test_execute_array_args + class << @recipe + def execute_with_env(env) + execute("testenv2", + ["ruby", "-e", "puts ENV['TEST_ENV_VAR2'].inspect"], + {:env => env, :initial_message => false, :debug => true}) + end + end + + @recipe.execute_with_env(@env) + + assert_equal("VAR2_VALUE".inspect, IO.read(File.join(@log_path, "testenv2.log")).chomp) + end +end