From: Corey Jewett Date: 2006-09-26T04:45:56+09:00 Subject: Re: [ANN] open4-0.8.0 $ sudo gem install open4 ERROR: While executing gem ... (OpenURI::HTTPError) 404 Not Found :( Corey On Sep 25, 2006, at 10:24 AM, ara.t.howard@noaa.gov wrote: > > URIS > > http://rubyforge.org/projects/codeforpeople/ > http://www.codeforpeople.com/lib/ruby/ > > SYNOPSIS > > open child process with handles on pid, stdin, stdout, and > stderr: manage > child processes and their io handles easily. > > HISTORY > > 0.8.0: > > - fixed a critical bug whereby a process producing tons of > stdout, but for > which the stdout was not handled, would cause the child > process to > become blocked/hung writing to the pipe. eg, this command > would cause a > hang > > include Open4 > > spawn 'ruby -e" puts Array.new(65536){ 42 } "' > > whereas this one would not > > include Open4 > > spawn 'ruby -e" puts Array.new(65536){ 42 } > "', :stdout=>StringIO.new > > this version handles the former by spawning a 'null' thread > which reads, > but does not process stdout/stderr. that way commands which > generate > tons of output will never become blocked. > > > INSTALL > > ~> gem install open4 > > SAMPLES > > > ---------------------------------------------------------------------- > ------ > simple usage > > ---------------------------------------------------------------------- > ------ > > harp: > cat sample/simple.rb > require "open4" > > pid, stdin, stdout, stderr = Open4::popen4 "sh" > > stdin.puts "echo 42.out" > stdin.puts "echo 42.err 1>&2" > stdin.close > > ignored, status = Process::waitpid2 pid > > puts "pid : #{ pid }" > puts "stdout : #{ stdout.read.strip }" > puts "stderr : #{ stderr.read.strip }" > puts "status : #{ status.inspect }" > puts "exitstatus : #{ status.exitstatus }" > > > harp: > ruby sample/simple.rb > pid : 17273 > stdout : 42.out > stderr : 42.err > status : # > exitstatus : 0 > > > > ---------------------------------------------------------------------- > ------ > in block form - the child process is automatically waited for > > ---------------------------------------------------------------------- > ------ > > harp: > cat sample/block.rb > require 'open4' > > status = > Open4::popen4("sh") do |pid, stdin, stdout, stderr| > stdin.puts "echo 42.out" > stdin.puts "echo 42.err 1>&2" > stdin.close > > puts "pid : #{ pid }" > puts "stdout : #{ stdout.read.strip }" > puts "stderr : #{ stderr.read.strip }" > end > > puts "status : #{ status.inspect }" > puts "exitstatus : #{ status.exitstatus }" > > > harp: > ruby sample/block.rb > pid : 17295 > stdout : 42.out > stderr : 42.err > status : # > exitstatus : 0 > > > ---------------------------------------------------------------------- > ------ > exceptions are marshaled from child to parent if fork/exec fails > > ---------------------------------------------------------------------- > ------ > > harp: > cat sample/exception.rb > require "open4" > Open4::popen4 "noexist" > > > harp: > ruby sample/exception.rb > /dmsp/reference/ruby-1.8.1//lib/ruby/site_ruby/open4.rb:100:in > `popen4': No such file or directory - noexist (Errno::ENOENT) > from sample/exception.rb:3 > > > ---------------------------------------------------------------------- > ------ > the spawn method provides and even more convenient method of > running a > process, allowing any object that supports 'each', 'read', or > 'to_s' to be > given as stdin and any objects that support '<<' to be given as > stdout/stderr. an exception is thrown if the exec'd cmd fails > (nonzero > exitstatus) unless the option 'raise'=>false is given > > ---------------------------------------------------------------------- > ------ > > harp: > cat sample/spawn.rb > require 'open4' > include Open4 > > cat = ' ruby -e" ARGF.each{|line| STDOUT << line} " ' > > stdout, stderr = '', '' > status = spawn cat, 'stdin' => '42', 'stdout' => stdout, > 'stderr' => stderr > p status > p stdout > p stderr > > stdout, stderr = '', '' > status = spawn cat, 0=>'42', 1=>stdout, 2=>stderr > p status > p stdout > p stderr > > > harp: > RUBYLIB=lib ruby sample/spawn.rb > 0 > "42" > "" > 0 > "42" > "" > > > > ---------------------------------------------------------------------- > ------ > the bg/background method is similar to spawn, but the process is > automatically set running in a thread. the returned thread has > several > methods added dynamically which return the pid and blocking calls > to the > exitstatus. > > ---------------------------------------------------------------------- > ------ > > harp: > cat sample/bg.rb > require 'yaml' > require 'open4' > include Open4 > > stdin = '42' > stdout = '' > stderr = '' > > t = bg 'ruby -e"sleep 4; puts ARGF.read"', 0=>stdin, 1=>stdout, > 2=>stderr > > waiter = Thread.new{ y t.pid => t.exitstatus } # t.exitstatus > is a blocking call! > > while((status = t.status)) > y "status" => status > sleep 1 > end > > waiter.join > > y "stdout" => stdout > > > harp: > ruby sample/bg.rb > --- > status: run > --- > status: sleep > --- > status: sleep > --- > status: sleep > --- > 21357: 0 > --- > stdout: "42\n" > > > ---------------------------------------------------------------------- > ------ > the timeout methods can be used to ensure execution is preceding > at the > desired interval. note also how to setup a 'pipeline' > > ---------------------------------------------------------------------- > ------ > > harp: > cat sample/stdin_timeout.rb > require 'open4' > > producer = 'ruby -e" STDOUT.sync = true; loop{sleep(rand+rand) > and puts 42} "' > > consumer = 'ruby -e" STDOUT.sync = true; STDIN.each{|line| puts > line} "' > > open4(producer) do |pid, i, o, e| > > open4.spawn > consumer, :stdin=>o, :stdout=>STDOUT, :stdin_timeout => 1.4 > > end > > > harp: > ruby sample/stdin_timeout.rb > 42 > 42 > 42 > 42 > 42 > /dmsp/reference/ruby-1.8.1//lib/ruby/1.8/timeout.rb:42:in > `relay': execution expired (Timeout::Error) > > AUTHOR > > ara.t.howard@noaa.gov > > LICENSE > > ruby's > > -a > -- > in order to be effective truth must penetrate like an arrow - and > that is > likely to hurt. -- wei wu wei >