/ Published in: Ruby
Lets you run shell commands in an extensible way.
Expand |
Embed | Plain Text
class CommandError < RuntimeError end class BaseCmd attr_accessor :uid, :done, :status end class Sheller attr_accessor :continious def initialize(bin = "bash") @sleep_time = 0.001 @input_pipe = IO.pipe @output_pipe = IO.pipe @error_pipe = IO.pipe @invalid = false fork do @input_pipe[1].close @output_pipe[0].close @error_pipe[0].close $stdin.reopen(@input_pipe[0]) $stdout.reopen(@output_pipe[1]) $stderr.reopen(@error_pipe[1]) exec(bin) end @input_pipe[0].close @output_pipe[1].close @error_pipe[1].close end def low_write(data) printf "#{data}" if $DEBUG @input_pipe[1].write(data) end def write(data) low_write(data) low_write("echo -e \"\027:$?\" > /dev/stderr\n") end def poll clean = true if svrs = IO.select([@output_pipe[0]], nil, nil, 0) svrs[0].each { |io| clean = false line = io.readline.chomp got_stdout(line) } end if svrs = IO.select([@error_pipe[0]], nil, nil, 0) svrs[0].each { |io| clean = false line = io.readline if line[0] == 23 md = line.match(/^.:(\d+)$/) if md @pending_cmd.status = md[1].to_i raise CommandError if @pending_cmd.status != 0 && @continious end else got_stderr(line) end } end if @pending_cmd.status and clean @pending_cmd.done = true end end def read_loop while !@pending_cmd.done poll sleep(@sleep_time) end end def do(string) @pending_cmd = BaseCmd.new begin write("%s\n" % string) read_loop rescue EOFError,Errno::EPIPE => error Process.wait # $?.exitstatus @invalid = true return nil end return @pending_cmd end def info(string) puts "# %s" % [string] end def got_stdout(line) end def got_stderr(line) end end
You need to login to post a comment.
