Skip to content

Commit

Permalink
handle abnormal exits generically
Browse files Browse the repository at this point in the history
  • Loading branch information
Howard Yeh authored and Howard Yeh committed Mar 6, 2009
1 parent 0a4be61 commit db7f55a
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 39 deletions.
29 changes: 2 additions & 27 deletions command.rb
@@ -1,19 +1,6 @@

class Rubish::Command < Rubish::Executable
class CommandError < RuntimeError
end

class BadStatus < CommandError
attr_reader :status
def initialize(status)
@status = status
end

def to_s
"<##{self.class}: #{status}>"
end
end


class ShellCommand < Rubish::Command
attr_reader :cmd, :opts
def initialize(cmd,args)
Expand All @@ -26,16 +13,6 @@ def initialize(cmd,args)
attr_reader :status
attr_reader :input, :output

# def exec
# pid = self.exec_(io_in,io_out,io_err)

# _pid, @status = Process.waitpid2(pid) # sync
# if @status != 0
# raise BadStatus.new(@status)
# end
# return nil
# end

def exec_with(i,o,e)
unless pid = Kernel.fork
# child
Expand All @@ -47,9 +24,7 @@ def exec_with(i,o,e)
Kernel.exec(self.cmd)
rescue
puts $!
cmd_name = self.cmd.split.first
$stderr.puts "#{cmd_name}: command not found"
Kernel.exit(127) # that's the bash exit status.
Kernel.exit(1)
end
end
return pid
Expand Down
9 changes: 7 additions & 2 deletions pipe.rb
Expand Up @@ -62,8 +62,13 @@ def exec_with(pipe_in,pipe_out,pipe_err)
o.close unless tail
else
# Rubish.set_stdioe((cmd.i || i),(cmd.o || o),(cmd.err || pipe_err))
Rubish.set_stdioe(i,o,pipe_err)
Kernel.exec cmd.cmd
begin
Rubish.set_stdioe(i,o,pipe_err)
Kernel.exec cmd.cmd
rescue
puts $!
Kernel.exit(1)
end
end
end
return pids
Expand Down
29 changes: 19 additions & 10 deletions rubish.rb
Expand Up @@ -36,6 +36,18 @@ def set_stdioe(i,o,e)
# Rubish::Pipe < Rubish::Executable
class Rubish::Executable

class AbnormalExits < RuntimeError
attr_reader :statuses
def initialize(statuses)
@statuses = statuses
end

def to_s
report = statuses.map { |s| "#{s.pid} => #{s.exitstatus}"}.join ";"
"<##{self.class}: #{report}>"
end
end

# an io could be
# String: interpreted as file name
# Number: file descriptor
Expand All @@ -49,7 +61,13 @@ def exec
e, close_e, thread_e = __prepare_io(e,"w")
# exec_with forks processes that communicate with Rubish via IPCs
exec_with((i || $stdin), (o || $stdout), (e || $stderr))
Process.waitall
statuses = Process.waitall.map { |r| r[1] }
bads = statuses.select do |s|
s if s.to_i != 0
end
if !bads.empty?
raise AbnormalExits.new(bads)
end
ensure
# i,o,e could've already been closed by an IO thread (when a block is used).
i.close if close_i && !i.closed?
Expand Down Expand Up @@ -99,15 +117,6 @@ def each_
r.each_line do |l|
yield(l)
end
# or we could do the following:
## except it spawns a thread per iteration if we have nested calls.
# e.g. cmd.each_ {|l| cmd2(l).map }
# self.o do |p|
# p.each_line do |l|
# yield(l)
# end
# end

ensure
self.o(old_o)
w.close if !w.closed?
Expand Down

0 comments on commit db7f55a

Please sign in to comment.