1 # vim: ts=2:sw=2:sts=2:et:fdm=marker
10 def systemu(*a
, &b
) SystemUniversal
.new(*a
, &b
).systemu
end
17 SystemUniversal
::VERSION = '1.2.0' unless defined? SystemUniversal
::VERSION
18 def version() SystemUniversal
::VERSION end
23 @host = Socket
.gethostname
26 @turd = ENV['SYSTEMU_TURD']
29 ruby
= File
.join(c
['bindir'], c
['ruby_install_name']) << c
['EXEEXT']
30 @ruby = if system('%s -e 42' % ruby
)
33 system('%s -e 42' % 'ruby') ? 'ruby' : warn('no ruby in PATH/CONFIG')
37 %w( host ppid pid ruby turd
).each
{|a
| attr_accessor a
}
44 def initialize
argv, opts
= {}, &block
50 @stdin = getopt
[ ['stdin', 'in', '0', 0] ]
51 @stdout = getopt
[ ['stdout', 'out', '1', 1] ]
52 @stderr = getopt
[ ['stderr', 'err', '2', 2] ]
53 @env = getopt
[ 'env' ]
54 @cwd = getopt
[ 'cwd' ]
56 @host = getopt
[ 'host', self.class.host
]
57 @ppid = getopt
[ 'ppid', self.class.ppid
]
58 @pid = getopt
[ 'pid', self.class.pid
]
59 @ruby = getopt
[ 'ruby', self.class.ruby
]
71 IO
.popen
"#{ @ruby } #{ c['program'] }", 'r+' do |pipe
|
75 cid
= Integer line
[%r
/\d+/]
79 buf
= "#{ line }#{ buf }"
81 raise unless Exception
=== e
84 raise "wtf?\n#{ buf }\n"
87 thread
= new_thread cid
, @block if @block
98 status
.instance_eval
{ @thread = thread
}
105 if @stdout or @stderr
106 open(c
['stdout']){|f
| relay f
=> @stdout} if @stdout
107 open(c
['stderr']){|f
| relay f
=> @stderr} if @stderr
110 [status
, IO
.read(c
['stdout']), IO
.read(c
['stderr'])]
115 def new_thread cid
, block
117 Thread
.new(cid
) do |cid
|
118 current
= Thread
.current
119 current
.abort_on_exception
= true
127 stdin = File
.expand_path(File
.join(tmp
, 'stdin'))
128 stdout = File
.expand_path(File
.join(tmp
, 'stdout'))
129 stderr = File
.expand_path(File
.join(tmp
, 'stderr'))
130 program
= File
.expand_path(File
.join(tmp
, 'program'))
131 config
= File
.expand_path(File
.join(tmp
, 'config'))
134 open(stdin, 'w'){|f
| relay
@stdin => f
}
136 FileUtils
.touch
stdin
138 FileUtils
.touch
stdout
139 FileUtils
.touch
stderr
148 c
['program'] = program
149 open(config
, 'w'){|f
| YAML
.dump c
, f
}
151 open(program
, 'w'){|f
| f
.write
child_program(config
)}
164 def child_program config
170 config = YAML.load(IO.read('#{ config }'))
172 argv = config['argv']
175 stdin = config['stdin']
176 stdout = config['stdout']
177 stderr = config['stderr']
180 env.each{|k,v| ENV[k.to_s] = v.to_s} if env
186 PIPE.puts "pid: \#{ Process.pid }"
187 PIPE.flush ### the process is ready yo!
191 rescue Exception => e
192 PIPE.write Marshal.dump(e) rescue nil
199 src
, dst
, ignored
= srcdst
.to_a
.first
200 if src
.respond_to
? 'read'
201 while((buf
= src
.read(8192))); dst
<< buf
; end
203 src
.each
{|buf
| dst
<< buf
}
207 def tmpdir d
= Dir
.tmpdir
, max
= 42, &b
211 tmp
= File
.join d
, "systemu_#{ @host }_#{ @ppid }_#{ @pid }_#{ rand }_#{ i += 1 }"
225 FileUtils
.rm_rf tmp
unless SystemU
.turd
234 def getopts opts
= {}
236 keys
, default
, ignored
= args
238 [keys
].flatten
.each
do |key
|
239 [key
, key
.to_s
, key
.to_s
.intern
].each
do |key
|
240 throw 'opt', opts
[key
] if opts
.has_key
?(key
)
249 SystemU
= SystemUniversal
unless defined? SystemU
267 date
= %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
269 status, stdout, stderr = systemu date
270 p [status, stdout, stderr]
272 status = systemu date, 1=>(stdout = '')
275 status = systemu date, 2=>(stderr = '')
280 sleep = %q( ruby -e" p(sleep(1)) " )
281 status, stdout, stderr = systemu sleep
282 p [status, stdout, stderr]
284 sleep = %q( ruby -e" p(sleep(42)) " )
285 status, stdout, stderr = systemu(sleep){|cid| Process.kill 9, cid}
286 p [status, stdout, stderr]
290 env = %q( ruby -e" p ENV['A'] " )
291 status, stdout, stderr = systemu env, :env => {'A' => 42}
292 p [status, stdout, stderr]
296 env = %q( ruby -e" p Dir.pwd " )
297 status, stdout, stderr = systemu env, :cwd => Dir.tmpdir
298 p [status, stdout, stderr]