/tools/Ruby/lib/ruby/1.8/shell/system-command.rb

http://github.com/agross/netopenspace · Ruby · 168 lines · 129 code · 18 blank · 21 comment · 14 complexity · 85e1e8000d7f8d320b1473b122616089 MD5 · raw file

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