* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / lib / shell / system-command.rb
blobda5d4cb898909af04b92cf7020c683b6a3474dd2
2 #   shell/system-command.rb - 
3 #       $Release Version: 0.7 $
4 #       $Revision$
5 #       by Keiju ISHITSUKA(keiju@ruby-lang.org)
7 # --
9 #   
12 require "shell/filter"
14 class Shell
15   class SystemCommand < Filter
16     def initialize(sh, command, *opts)
17       if t = opts.find{|opt| !opt.kind_of?(String) && opt.class}
18         Shell.Fail Error::TypeError, t.class, "String"
19       end
20       super(sh)
21       @command = command
22       @opts = opts
23       
24       @input_queue = Queue.new
25       @pid = nil
27       sh.process_controller.add_schedule(self)
28     end
30     attr_reader :command
31     alias name command
33     def wait?
34       @shell.process_controller.waiting_job?(self)
35     end
37     def active?
38       @shell.process_controller.active_job?(self)
39     end
41     def input=(inp)
42       super
43       if active?
44         start_export
45       end
46     end
48     def start
49       notify([@command, *@opts].join(" "))
51       @pid, @pipe_in, @pipe_out = @shell.process_controller.sfork(self) {
52         Dir.chdir @shell.pwd
53         $0 = @command
54         exec(@command, *@opts)
55       }
56       if @input
57         start_export
58       end
59       start_import
60     end
62     def flush
63       @pipe_out.flush if @pipe_out and !@pipe_out.closed?
64     end
66     def terminate
67       begin
68         @pipe_in.close
69       rescue IOError
70       end
71       begin
72         @pipe_out.close
73       rescue IOError
74       end
75     end
77     def kill(sig)
78       if @pid
79         Process.kill(sig, @pid)
80       end
81     end
83     def start_import
84       notify "Job(%id) start imp-pipe.", @shell.debug?
85       rs = @shell.record_separator unless rs
86       _eop = true
87       th = Thread.start {
88         begin
89           while l = @pipe_in.gets
90             @input_queue.push l
91           end
92           _eop = false
93         rescue Errno::EPIPE
94           _eop = false
95         ensure
96           if !ProcessController::USING_AT_EXIT_WHEN_PROCESS_EXIT and _eop
97             notify("warn: Process finishing...",
98                    "wait for Job[%id] to finish pipe importing.",
99                    "You can use Shell#transact or Shell#check_point for more safe execution.")
100             redo
101           end
102           notify "job(%id}) close imp-pipe.", @shell.debug?
103           @input_queue.push :EOF
104           @pipe_in.close
105         end
106       }
107     end
109     def start_export
110       notify "job(%id) start exp-pipe.", @shell.debug?
111       _eop = true
112       th = Thread.start{
113         begin
114           @input.each do |l|
115             ProcessController::block_output_synchronize do
116               @pipe_out.print l
117             end
118           end
119           _eop = false
120         rescue Errno::EPIPE, Errno::EIO
121           _eop = false
122         ensure
123           if !ProcessController::USING_AT_EXIT_WHEN_PROCESS_EXIT and _eop
124             notify("shell: warn: Process finishing...",
125                    "wait for Job(%id) to finish pipe exporting.",
126                    "You can use Shell#transact or Shell#check_point for more safe execution.")
127             redo
128           end
129           notify "job(%id) close exp-pipe.", @shell.debug?
130           @pipe_out.close
131         end
132       }
133     end
135     alias super_each each
136     def each(rs = nil)
137       while (l = @input_queue.pop) != :EOF
138         yield l
139       end
140     end
142     # ex)
143     #    if you wish to output: 
144     #       "shell: job(#{@command}:#{@pid}) close pipe-out."
145     #    then 
146     #       mes: "job(%id) close pipe-out."
147     #    yorn: Boolean(@shell.debug? or @shell.verbose?)
148     def notify(*opts, &block)
149       @shell.notify(*opts) do |mes|
150         yield mes if iterator?
152         mes.gsub!("%id", "#{@command}:##{@pid}")
153         mes.gsub!("%name", "#{@command}")
154         mes.gsub!("%pid", "#{@pid}")
155         mes
156       end
157     end
158   end