| Class | SystemUniversal |
| In: |
lib/systemu.rb
|
| Parent: | Object |
| VERSION | = | '1.2.0' unless defined? SystemUniversal::VERSION |
instance methods
# File lib/systemu.rb, line 44
44: def initialize argv, opts = {}, &block
45: getopt = getopts opts
46:
47: @argv = argv
48: @block = block
49:
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' ]
55:
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 ]
60: end
# File lib/systemu.rb, line 164
164: def child_program config
165: "PIPE = STDOUT.dup\nbegin\nrequire 'yaml'\n\nconfig = YAML.load(IO.read('\#{ config }'))\n\nargv = config['argv']\nenv = config['env']\ncwd = config['cwd']\nstdin = config['stdin']\nstdout = config['stdout']\nstderr = config['stderr']\n\nDir.chdir cwd if cwd\nenv.each{|k,v| ENV[k.to_s] = v.to_s} if env\n\nSTDIN.reopen stdin\nSTDOUT.reopen stdout\nSTDERR.reopen stderr\n\nPIPE.puts \"pid: \\\#{ Process.pid }\"\nPIPE.flush ### the process is ready yo!\nPIPE.close\n\nexec *argv\nrescue Exception => e\nPIPE.write Marshal.dump(e) rescue nil\nexit 42\nend\n"
166: end
# File lib/systemu.rb, line 126
126: def child_setup tmp
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'))
132:
133: if @stdin
134: open(stdin, 'w'){|f| relay @stdin => f}
135: else
136: FileUtils.touch stdin
137: end
138: FileUtils.touch stdout
139: FileUtils.touch stderr
140:
141: c = {}
142: c['argv'] = @argv
143: c['env'] = @env
144: c['cwd'] = @cwd
145: c['stdin'] = stdin
146: c['stdout'] = stdout
147: c['stderr'] = stderr
148: c['program'] = program
149: open(config, 'w'){|f| YAML.dump c, f}
150:
151: open(program, 'w'){|f| f.write child_program(config)}
152:
153: c
154: end
# File lib/systemu.rb, line 235
235: def getopts opts = {}
236: lambda do |*args|
237: keys, default, ignored = args
238: catch('opt') do
239: [keys].flatten.each do |key|
240: [key, key.to_s, key.to_s.intern].each do |key|
241: throw 'opt', opts[key] if opts.has_key?(key)
242: end
243: end
244: default
245: end
246: end
247: end
# File lib/systemu.rb, line 115
115: def new_thread cid, block
116: q = Queue.new
117: Thread.new(cid) do |cid|
118: current = Thread.current
119: current.abort_on_exception = true
120: q.push current
121: block.call cid
122: end
123: q.pop
124: end
# File lib/systemu.rb, line 156
156: def quietly
157: v = $VERBOSE
158: $VERBOSE = nil
159: yield
160: ensure
161: $VERBOSE = v
162: end
# File lib/systemu.rb, line 199
199: def relay srcdst
200: src, dst, ignored = srcdst.to_a.first
201: if src.respond_to? 'read'
202: while((buf = src.read(8192))); dst << buf; end
203: else
204: src.each{|buf| dst << buf}
205: end
206: end
# File lib/systemu.rb, line 62
62: def systemu
63: tmpdir do |tmp|
64: c = child_setup tmp
65: status = nil
66:
67: begin
68: thread = nil
69:
70: quietly{
71: IO.popen "#{ @ruby } #{ c['program'] }", 'r+' do |pipe|
72: line = pipe.gets
73: case line
74: when %r/^pid: \d+$/
75: cid = Integer line[%r/\d+/]
76: else
77: begin
78: buf = pipe.read
79: buf = "#{ line }#{ buf }"
80: e = Marshal.load buf
81: raise unless Exception === e
82: raise e
83: rescue
84: raise "wtf?\n#{ buf }\n"
85: end
86: end
87: thread = new_thread cid, @block if @block
88: pipe.read rescue nil
89: end
90: }
91: status = $?
92: ensure
93: if thread
94: begin
95: class << status
96: attr 'thread'
97: end
98: status.instance_eval{ @thread = thread }
99: rescue
100: 42
101: end
102: end
103: end
104:
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
108: status
109: else
110: [status, IO.read(c['stdout']), IO.read(c['stderr'])]
111: end
112: end
113: end
# File lib/systemu.rb, line 208
208: def tmpdir d = Dir.tmpdir, max = 42, &b
209: i = -1 and loop{
210: i += 1
211:
212: tmp = File.join d, "systemu_#{ @host }_#{ @ppid }_#{ @pid }_#{ rand }_#{ i += 1 }"
213:
214: begin
215: Dir.mkdir tmp
216: rescue Errno::EEXIST
217: raise if i >= max
218: next
219: end
220:
221: break(
222: if b
223: begin
224: b.call tmp
225: ensure
226: FileUtils.rm_rf tmp unless SystemU.turd
227: end
228: else
229: tmp
230: end
231: )
232: }
233: end