module FunkySystem
Constants
- VERSION
Public Class Methods
find_exec(name)
click to toggle source
# File lib/funkysystem.rb, line 50 def self.find_exec(name) ENV["PATH"].split(/:/).each do |bin| path = File.join(File.expand_path(bin), name) begin stat = File.stat(path) if stat.executable? && stat.file? return path end rescue Errno::ENOENT end end nil end
output_to_writeable_io(out) { |out| ... }
click to toggle source
# File lib/funkysystem.rb, line 24 def self.output_to_writeable_io(out, &block) case out when String File.open(out, 'w', &block) when IO yield(out) #when nil else File.open('/dev/null', 'w', &block) end end
redirect_output(options = {}, &block)
click to toggle source
Run block, but with output redirected to elsewhere
@param outputs [Hash] :stdout & :stderr - either an IO object, a filename or nil to redirect stream to /dev/null
# File lib/funkysystem.rb, line 8 def self.redirect_output(options = {}, &block) stderr_dup = STDERR.dup stdout_dup = STDOUT.dup begin output_to_writeable_io(options[:stdout]) do |out| STDOUT.reopen(out) output_to_writeable_io(options[:stderr]) do |err| STDERR.reopen(err) block.call end end ensure STDERR.reopen(stderr_dup) STDOUT.reopen(stdout_dup) end end
run(cmd, stdin=nil)
click to toggle source
# File lib/funkysystem.rb, line 63 def self.run(cmd, stdin=nil) fps = { :stdout => IO.pipe, :stderr => IO.pipe } fps[:stdin] = IO.pipe if stdin fps.each do |key,fpa| class << fpa alias :reader :first alias :writer :last end end pid = fork do keep = [STDERR, STDOUT, STDIN] + fps.values.flatten ObjectSpace.each_object(IO) { |io| begin io.close() unless keep.include?(io) rescue Exception end } if fps[:stdin] fps[:stdin].writer.close STDIN.reopen(fps[:stdin].reader) fps[:stdin].reader.close else # No input - child shouldn't # be allowed to expect any... STDIN.close() end fps[:stdout].reader.close STDOUT.reopen(fps[:stdout].writer) fps[:stdout].writer.close fps[:stderr].reader.close STDERR.reopen(fps[:stderr].writer) fps[:stderr].writer.close exec(* ( cmd.is_a?(Array) ? cmd : [cmd] ) ) end fps[:stderr].writer.close fps[:stdout].writer.close if fps[:stdin] fps[:stdin].reader.close out_fds = [fps[:stdin].writer] else out_fds = [] end in_fds = [fps[:stderr].reader, fps[:stdout].reader] all_fds = in_fds + out_fds all_fds.each { |fd| fd.nonblock = true } stdout = '' stderr = '' exited = nil exit_time = nil until exited && (in_fds.all? { |fd| fd.closed? or fd.eof? } || exit_time < (Time.now.to_i - 3) ) exited ||= Process.waitpid2(pid, Process::WNOHANG) exit_time ||= Time.now.to_i if exited begin rd, wr, er = select(in_fds, out_fds, all_fds, 0.05) rescue IOError [in_fds, out_fds, all_fds].each { |grp| grp.reject!{ |fd| fd.closed? } } rd = wr = er = nil end wr.each do |fd| begin case fd when fps[:stdin].writer size = fd.syswrite(stdin) stdin = stdin[size..-1] if stdin.empty? fd.close out_fds = [] stdin = nil end end rescue Errno::EPIPE, IOError end end if wr.respond_to?(:each) rd.each do |fd| begin case fd when fps[:stderr].reader stderr << fd.sysread(4096 * 4) when fps[:stdout].reader stdout << fd.sysread(4096 * 4) end rescue Errno::EPIPE, IOError end end if rd.respond_to?(:each) end ProgramOutput.new(pid, exited.last, stdout, stderr, stdin) end