lib/tty/command/execute.rb in tty-command-0.5.0 vs lib/tty/command/execute.rb in tty-command-0.6.0

- old
+ new

@@ -1,6 +1,7 @@ # encoding: utf-8 +# frozen_string_literal: true require 'tempfile' require 'securerandom' module TTY @@ -27,15 +28,15 @@ out_rd, out_wr = IO.pipe # writing err_rd, err_wr = IO.pipe # error in_wr.sync = true # redirect fds - opts = ({ + opts = { :in => in_rd, in_wr => :close, :out => out_wr, out_rd => :close, :err => err_wr, err_rd => :close - }).merge(process_opts) + }.merge(process_opts) pid = Process.spawn(cmd.to_command, opts) # close in parent process [in_rd, out_wr, err_wr].each { |fd| fd.close if fd } @@ -53,81 +54,113 @@ end end private + # Normalize spawn fd into :in, :out, :err keys. + # + # @return [Hash] + # + # @api private def normalize_redirect_options(options) options.reduce({}) do |opts, (key, value)| if fd?(key) - process_key = fd_to_process_key(key) - if process_key.to_s == 'in' - value = convert_to_fd(value) + spawn_key, spawn_value = convert(key, value) + opts[spawn_key] = spawn_value + elsif key.is_a?(Array) && key.all?(&method(:fd?)) + key.each do |k| + spawn_key, spawn_value = convert(k, value) + opts[spawn_key] = spawn_value end - opts[process_key] = value end opts end end + # Convert option pari to recognized spawn option pair + # # @api private + def convert(spawn_key, spawn_value) + key = fd_to_process_key(spawn_key) + value = spawn_value + + if key.to_s == 'in' + value = convert_to_fd(spawn_value) + end + + if fd?(spawn_value) + value = fd_to_process_key(spawn_value) + value = [:child, value] # redirect in child process + end + [key, value] + end + + # Determine if object is a fd + # + # @return [Boolean] + # + # @api private def fd?(object) case object - when :stdin, :stdout, :stderr, :in, :out, :err + when :stdin, :stdout, :stderr, :in, :out, :err, + STDIN, STDOUT, STDERR, $stdin, $stdout, $stderr, ::IO true - when STDIN, STDOUT, STDERR, $stdin, $stdout, $stderr, ::IO - true - when ::IO - true when ::Integer object >= 0 - when respond_to?(:to_i) && !object.to_io.nil? - true else - false + respond_to?(:to_i) && !object.to_io.nil? end end - def try_reading(object) - if object.respond_to?(:read) - object.read - elsif object.respond_to?(:to_s) - object.to_s - else + # Convert fd to name :in, :out, :err + # + # @api private + def fd_to_process_key(object) + case object + when STDIN, $stdin, :in, :stdin, 0 + :in + when STDOUT, $stdout, :out, :stdout, 1 + :out + when STDERR, $stderr, :err, :stderr, 2 + :err + when Integer + object >= 0 ? IO.for_fd(object) : nil + when IO object + when respond_to?(:to_io) + object.to_io + else + raise ExecuteError, "Wrong execute redirect: #{object.inspect}" end end + # Convert file name to file handle + # + # @api private def convert_to_fd(object) return object if fd?(object) if object.is_a?(::String) && ::File.exist?(object) return object end tmp = ::Tempfile.new(::SecureRandom.uuid.split('-')[0]) - content = try_reading(object) tmp.write(content) tmp.rewind tmp end - def fd_to_process_key(object) - case object - when STDIN, $stdin, :in, :stdin, 0 - :in - when STDOUT, $stdout, :out, :stdout, 1 - :out - when STDERR, $stderr, :err, :stderr, 2 - :err - when Integer - object >= 0 ? IO.for_fd(object) : nil - when IO - object - when respond_to?(:to_io) - object.to_io + # Attempts to read object content + # + # @api private + def try_reading(object) + if object.respond_to?(:read) + object.read + elsif object.respond_to?(:to_s) + object.to_s else - raise ExecuteError, "Wrong execute redirect: #{object.inspect}" + object end end end # Execute end # Command end # TTY