lib/shell/system-command.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  #   shell/system-command.rb - 
   3  #       $Release Version: 0.6.0 $
   4  #       $Revision: 1.1 $
   5  #       $Date: 2001/05/17 10:02:48 $
   6  #       by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd)
   7  #
   8  # --
   9  #
  10  #   
  11  #
  12  
  13  require "shell/filter"
  14  
  15  class Shell
  16    class SystemCommand < Filter
  17      def initialize(sh, command, *opts)
  18        if t = opts.find{|opt| !opt.kind_of?(String) && opt.type}
  19          Shell.Fail TypeError, t.type, "String"
  20        end
  21        super(sh)
  22        @command = command
  23        @opts = opts
  24        
  25        @input_queue = Queue.new
  26        @pid = nil
  27  
  28        sh.process_controller.add_schedule(self)
  29      end
  30  
  31      attr_reader :command
  32      alias name command
  33  
  34      def wait?
  35        @shell.process_controller.waiting_job?(self)
  36      end
  37  
  38      def active?
  39        @shell.process_controller.active_job?(self)
  40      end
  41  
  42      def input=(inp)
  43        super
  44        if active?
  45          start_export
  46        end
  47      end
  48  
  49      def start
  50        @pid, @pipe_in, @pipe_out = @shell.process_controller.sfork(self) {
  51          Dir.chdir @shell.pwd
  52          exec(@command, *@opts)
  53        }
  54        if @input
  55          start_export
  56        end
  57        start_import
  58      end
  59  
  60      def flush
  61        @pipe_out.flush if @pipe_out and !@pipe_out.closed?
  62      end
  63  
  64      def terminate
  65        begin
  66          @pipe_in.close
  67        rescue IOError
  68        end
  69        begin
  70          @pipe_out.close
  71        rescue IOError
  72        end
  73      end
  74  
  75      def kill(sig)
  76        if @pid
  77          Process.kill(sig, @pid)
  78        end
  79      end
  80  
  81  
  82      def start_import
  83  #      Thread.critical = true
  84        notify "Job(%id) start imp-pipe.", @shell.debug?
  85        rs = @shell.record_separator unless rs
  86        _eop = true
  87  #      Thread.critical = false
  88        th = Thread.start {
  89          Thread.critical = true
  90          begin
  91            Thread.critical = false
  92            while l = @pipe_in.gets
  93              @input_queue.push l
  94            end
  95            _eop = false
  96          rescue Errno::EPIPE
  97            _eop = false
  98          ensure
  99            if _eop
 100              notify("warn: Process finishing...",
 101                     "wait for Job[%id] to finish pipe importing.",
 102                     "You can use Shell#transact or Shell#check_point for more safe execution.")
 103  #           Tracer.on
 104              Thread.current.run
 105              redo
 106            end
 107            Thread.exclusive do
 108              notify "job(%id}) close imp-pipe.", @shell.debug?
 109              @input_queue.push :EOF
 110              @pipe_in.close
 111            end
 112          end
 113        }
 114      end
 115  
 116      def start_export
 117        notify "job(%id) start exp-pipe.", @shell.debug?
 118        _eop = true
 119        th = Thread.start{
 120          Thread.critical = true
 121          begin
 122            Thread.critical = false
 123            @input.each{|l| @pipe_out.print l}
 124            _eop = false
 125          rescue Errno::EPIPE
 126            _eop = false
 127          ensure
 128            if _eop
 129              notify("shell: warn: Process finishing...",
 130                     "wait for Job(%id) to finish pipe exporting.",
 131                     "You can use Shell#transact or Shell#check_point for more safe execution.")
 132  #           Tracer.on
 133              redo
 134            end
 135            Thread.exclusive do
 136              notify "job(%id) close exp-pipe.", @shell.debug?
 137              @pipe_out.close
 138            end
 139          end
 140        }
 141      end
 142  
 143      alias super_each each
 144      def each(rs = nil)
 145        while (l = @input_queue.pop) != :EOF
 146          yield l
 147        end
 148      end
 149  
 150      # ex)
 151      #    if you wish to output: 
 152      #       "shell: job(#{@command}:#{@pid}) close pipe-out."
 153      #    then 
 154      #       mes: "job(%id) close pipe-out."
 155      #    yorn: Boolean(@shell.debug? or @shell.verbose?)
 156      def notify(*opts, &block)
 157        Thread.exclusive do
 158          @shell.notify(*opts) {|mes|
 159            yield mes if iterator?
 160  
 161            mes.gsub!("%id", "#{@command}:##{@pid}")
 162            mes.gsub!("%name", "#{@command}")
 163            mes.gsub!("%pid", "#{@pid}")
 164          }
 165        end
 166      end
 167    end
 168  end