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