systemu 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/a.rb +15 -0
- data/lib/systemu.rb +51 -24
- data/systemu-1.1.0.gem +0 -0
- metadata +33 -25
- data/lib/systemu-1.0.0.rb +0 -262
data/a.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'systemu'
|
3
|
+
|
4
|
+
threads = []
|
5
|
+
|
6
|
+
(ARGV.shift || 10).to_i.times do
|
7
|
+
t = Thread.new do
|
8
|
+
status, stdout, stderr = systemu 'cat', :stdin => ('42' * 1024)
|
9
|
+
[status, stdout[0..15]]
|
10
|
+
end
|
11
|
+
threads << t
|
12
|
+
end
|
13
|
+
|
14
|
+
threads.map{|t| p t.value}
|
15
|
+
|
data/lib/systemu.rb
CHANGED
@@ -3,6 +3,7 @@ require 'socket'
|
|
3
3
|
require 'fileutils'
|
4
4
|
require 'rbconfig'
|
5
5
|
require 'thread'
|
6
|
+
require 'yaml'
|
6
7
|
|
7
8
|
class Object
|
8
9
|
def systemu(*a, &b) SystemUniversal.new(*a, &b).systemu end
|
@@ -10,7 +11,10 @@ end
|
|
10
11
|
|
11
12
|
class SystemUniversal
|
12
13
|
#--{{{
|
13
|
-
|
14
|
+
#
|
15
|
+
# constants
|
16
|
+
#
|
17
|
+
SystemUniversal::VERSION = '1.1.0' unless defined? SystemUniversal::VERSION
|
14
18
|
def version() VERSION end
|
15
19
|
#
|
16
20
|
# class methods
|
@@ -19,6 +23,7 @@ class SystemUniversal
|
|
19
23
|
@host = Socket.gethostname
|
20
24
|
@ppid = Process.ppid
|
21
25
|
@pid = Process.pid
|
26
|
+
@turd = ENV['SYSTEMU_TURD']
|
22
27
|
|
23
28
|
c = ::Config::CONFIG
|
24
29
|
ruby = File.join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
|
@@ -29,7 +34,7 @@ class SystemUniversal
|
|
29
34
|
end
|
30
35
|
|
31
36
|
class << self
|
32
|
-
%w( host ppid pid ruby ).each{|a| attr_accessor a}
|
37
|
+
%w( host ppid pid ruby turd ).each{|a| attr_accessor a}
|
33
38
|
end
|
34
39
|
|
35
40
|
#
|
@@ -64,13 +69,28 @@ class SystemUniversal
|
|
64
69
|
|
65
70
|
if @block
|
66
71
|
q = Queue.new
|
67
|
-
t = Thread.new{ @block[ q.pop ] }
|
72
|
+
t = Thread.new{ Thread.current_abort_on_exception = true; @block[ q.pop ] }
|
68
73
|
end
|
69
74
|
|
70
75
|
begin
|
71
76
|
quietly{
|
72
77
|
IO.popen "#{ @ruby } #{ c['program'] }", 'r+' do |pipe|
|
73
|
-
|
78
|
+
line = pipe.gets
|
79
|
+
case line
|
80
|
+
when %r/^pid: \d+$/
|
81
|
+
cid = Integer line[%r/\d+/]
|
82
|
+
else
|
83
|
+
begin
|
84
|
+
buf = pipe.read
|
85
|
+
buf = "#{ line }#{ buf }"
|
86
|
+
e = Marshal.load buf
|
87
|
+
raise unless Exception === e
|
88
|
+
raise e
|
89
|
+
rescue
|
90
|
+
raise "wtf?\n#{ buf }\n"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
cid = Integer pipe.gets
|
74
94
|
q.push cid if @block
|
75
95
|
pipe.read rescue nil
|
76
96
|
end
|
@@ -115,7 +135,7 @@ class SystemUniversal
|
|
115
135
|
c['stdout'] = stdout
|
116
136
|
c['stderr'] = stderr
|
117
137
|
c['program'] = program
|
118
|
-
open(config, 'w'){|f|
|
138
|
+
open(config, 'w'){|f| YAML.dump c, f}
|
119
139
|
|
120
140
|
open(program, 'w'){|f| f.write child_program(config)}
|
121
141
|
|
@@ -136,8 +156,11 @@ class SystemUniversal
|
|
136
156
|
def child_program config
|
137
157
|
#--{{{
|
138
158
|
<<-program
|
159
|
+
PIPE = STDOUT.dup
|
139
160
|
begin
|
140
|
-
|
161
|
+
require 'yaml'
|
162
|
+
|
163
|
+
config = YAML.load(IO.read('#{ config }'))
|
141
164
|
|
142
165
|
argv = config['argv']
|
143
166
|
env = config['env']
|
@@ -148,19 +171,20 @@ class SystemUniversal
|
|
148
171
|
|
149
172
|
Dir.chdir cwd if cwd
|
150
173
|
env.each{|k,v| ENV[k.to_s] = v.to_s} if env
|
151
|
-
rescue Exception => e
|
152
|
-
STDERR.warn e
|
153
|
-
exit 42
|
154
|
-
end
|
155
174
|
|
156
|
-
|
157
|
-
|
175
|
+
STDIN.reopen stdin
|
176
|
+
STDOUT.reopen stdout
|
177
|
+
STDERR.reopen stderr
|
158
178
|
|
159
|
-
|
160
|
-
|
161
|
-
|
179
|
+
PIPE.puts "pid: #{ Process.pid }"
|
180
|
+
PIPE.flush ### the process is ready yo!
|
181
|
+
PIPE.close
|
162
182
|
|
163
|
-
|
183
|
+
exec *argv
|
184
|
+
rescue Exception => e
|
185
|
+
PIPE.write Marshal.dump(e) rescue nil
|
186
|
+
exit 42
|
187
|
+
end
|
164
188
|
program
|
165
189
|
#--}}}
|
166
190
|
end
|
@@ -176,26 +200,27 @@ class SystemUniversal
|
|
176
200
|
#--}}}
|
177
201
|
end
|
178
202
|
|
179
|
-
def tmpdir d = Dir.tmpdir, &b
|
203
|
+
def tmpdir d = Dir.tmpdir, max = 42, &b
|
180
204
|
#--{{{
|
181
205
|
i = -1 and loop{
|
206
|
+
i += 1
|
207
|
+
|
182
208
|
tmp = File.join d, "systemu_#{ @host }_#{ @ppid }_#{ @pid }_#{ rand }_#{ i += 1 }"
|
183
209
|
|
184
210
|
begin
|
185
211
|
Dir.mkdir tmp
|
186
212
|
rescue Errno::EEXIST
|
213
|
+
raise if i >= max
|
187
214
|
next
|
188
215
|
end
|
189
216
|
|
190
|
-
scrub = lambda do |t|
|
191
|
-
FileUtils.rm_rf t
|
192
|
-
scrub = lambda{ 42 }
|
193
|
-
end
|
194
|
-
at_exit{ scrub[tmp] }
|
195
|
-
|
196
217
|
break(
|
197
218
|
if b
|
198
|
-
begin
|
219
|
+
begin
|
220
|
+
b.call tmp
|
221
|
+
ensure
|
222
|
+
FileUtils.rm_rf tmp unless SystemU.turd
|
223
|
+
end
|
199
224
|
else
|
200
225
|
tmp
|
201
226
|
end
|
@@ -222,6 +247,8 @@ class SystemUniversal
|
|
222
247
|
#--}}}
|
223
248
|
end
|
224
249
|
|
250
|
+
SystemU = SystemUniversal unless defined? SystemU
|
251
|
+
|
225
252
|
|
226
253
|
if $0 == __FILE__
|
227
254
|
#
|
data/systemu-1.1.0.gem
ADDED
File without changes
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.
|
2
|
+
rubygems_version: 0.9.2
|
3
3
|
specification_version: 1
|
4
4
|
name: systemu
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date:
|
6
|
+
version: 1.1.0
|
7
|
+
date: 2007-07-19 00:00:00 -06:00
|
8
8
|
summary: systemu
|
9
9
|
require_paths:
|
10
|
-
|
10
|
+
- lib
|
11
11
|
email: ara.t.howard@noaa.gov
|
12
12
|
homepage: http://codeforpeople.com/lib/ruby/systemu/
|
13
13
|
rubyforge_project:
|
@@ -18,36 +18,44 @@ bindir: bin
|
|
18
18
|
has_rdoc: false
|
19
19
|
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
20
|
requirements:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
version: 0.0.0
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
25
24
|
version:
|
26
25
|
platform: ruby
|
27
26
|
signing_key:
|
28
27
|
cert_chain:
|
28
|
+
post_install_message:
|
29
29
|
authors:
|
30
|
-
|
30
|
+
- Ara T. Howard
|
31
31
|
files:
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
32
|
+
- a.rb
|
33
|
+
- gemspec.rb
|
34
|
+
- gen_readme.rb
|
35
|
+
- install.rb
|
36
|
+
- lib
|
37
|
+
- lib/systemu.rb
|
38
|
+
- README
|
39
|
+
- README.tmpl
|
40
|
+
- samples
|
41
|
+
- samples/a.rb
|
42
|
+
- samples/b.rb
|
43
|
+
- samples/c.rb
|
44
|
+
- samples/d.rb
|
45
|
+
- samples/e.rb
|
46
|
+
- samples/f.rb
|
47
|
+
- systemu-1.1.0.gem
|
47
48
|
test_files: []
|
49
|
+
|
48
50
|
rdoc_options: []
|
51
|
+
|
49
52
|
extra_rdoc_files: []
|
53
|
+
|
50
54
|
executables: []
|
55
|
+
|
51
56
|
extensions: []
|
57
|
+
|
52
58
|
requirements: []
|
53
|
-
|
59
|
+
|
60
|
+
dependencies: []
|
61
|
+
|
data/lib/systemu-1.0.0.rb
DELETED
@@ -1,262 +0,0 @@
|
|
1
|
-
require 'tmpdir'
|
2
|
-
require 'socket'
|
3
|
-
require 'fileutils'
|
4
|
-
require 'rbconfig'
|
5
|
-
require 'thread'
|
6
|
-
|
7
|
-
class Object
|
8
|
-
def systemu(*a, &b) SystemUniversal.new(*a, &b).systemu end
|
9
|
-
end
|
10
|
-
|
11
|
-
class SystemUniversal
|
12
|
-
#--{{{
|
13
|
-
VERSION = '1.0.0'
|
14
|
-
def version() VERSION end
|
15
|
-
#
|
16
|
-
# class methods
|
17
|
-
#
|
18
|
-
|
19
|
-
@host = Socket.gethostname
|
20
|
-
@ppid = Process.ppid
|
21
|
-
@pid = Process.pid
|
22
|
-
|
23
|
-
c = ::Config::CONFIG
|
24
|
-
ruby = File.join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
|
25
|
-
@ruby = if system('%s -e 42' % ruby)
|
26
|
-
ruby
|
27
|
-
else
|
28
|
-
system('%s -e 42' % 'ruby') ? 'ruby' : warn('no ruby in PATH/CONFIG')
|
29
|
-
end
|
30
|
-
|
31
|
-
class << self
|
32
|
-
%w( host ppid pid ruby ).each{|a| attr_accessor a}
|
33
|
-
end
|
34
|
-
|
35
|
-
#
|
36
|
-
# instance methods
|
37
|
-
#
|
38
|
-
|
39
|
-
def initialize argv, opts = {}, &block
|
40
|
-
#--{{{
|
41
|
-
getopt = getopts opts
|
42
|
-
|
43
|
-
@argv = argv
|
44
|
-
@block = block
|
45
|
-
|
46
|
-
@stdin = getopt[ ['stdin', 'in', '0', 0] ]
|
47
|
-
@stdout = getopt[ ['stdout', 'out', '1', 1] ]
|
48
|
-
@stderr = getopt[ ['stderr', 'err', '2', 2] ]
|
49
|
-
@env = getopt[ 'env' ]
|
50
|
-
@cwd = getopt[ 'cwd' ]
|
51
|
-
|
52
|
-
@host = getopt[ 'host', self.class.host ]
|
53
|
-
@ppid = getopt[ 'ppid', self.class.ppid ]
|
54
|
-
@pid = getopt[ 'pid', self.class.pid ]
|
55
|
-
@ruby = getopt[ 'ruby', self.class.ruby ]
|
56
|
-
#--}}}
|
57
|
-
end
|
58
|
-
|
59
|
-
def systemu
|
60
|
-
#--{{{
|
61
|
-
tmpdir do |tmp|
|
62
|
-
c = child_setup tmp
|
63
|
-
status = nil
|
64
|
-
|
65
|
-
if @block
|
66
|
-
q = Queue.new
|
67
|
-
t = Thread.new{ @block[ q.pop ] }
|
68
|
-
end
|
69
|
-
|
70
|
-
begin
|
71
|
-
quietly{
|
72
|
-
IO.popen "#{ @ruby } #{ c['program'] }", 'r+' do |pipe|
|
73
|
-
cid = pipe.gets.to_i
|
74
|
-
q.push cid if @block
|
75
|
-
pipe.read rescue nil
|
76
|
-
end
|
77
|
-
}
|
78
|
-
status = $?
|
79
|
-
ensure
|
80
|
-
t.kill rescue nil if t
|
81
|
-
end
|
82
|
-
|
83
|
-
if @stdout or @stderr
|
84
|
-
open(c['stdout']){|f| relay f => @stdout} if @stdout
|
85
|
-
open(c['stderr']){|f| relay f => @stderr} if @stderr
|
86
|
-
status
|
87
|
-
else
|
88
|
-
[status, IO.read(c['stdout']), IO.read(c['stderr'])]
|
89
|
-
end
|
90
|
-
end
|
91
|
-
#--}}}
|
92
|
-
end
|
93
|
-
|
94
|
-
def child_setup tmp
|
95
|
-
#--{{{
|
96
|
-
stdin = File.expand_path(File.join(tmp, 'stdin'))
|
97
|
-
stdout = File.expand_path(File.join(tmp, 'stdout'))
|
98
|
-
stderr = File.expand_path(File.join(tmp, 'stderr'))
|
99
|
-
program = File.expand_path(File.join(tmp, 'program'))
|
100
|
-
config = File.expand_path(File.join(tmp, 'config'))
|
101
|
-
|
102
|
-
if @stdin
|
103
|
-
open(stdin, 'w'){|f| relay @stdin => f}
|
104
|
-
else
|
105
|
-
FileUtils.touch stdin
|
106
|
-
end
|
107
|
-
FileUtils.touch stdout
|
108
|
-
FileUtils.touch stderr
|
109
|
-
|
110
|
-
c = {}
|
111
|
-
c['argv'] = @argv
|
112
|
-
c['env'] = @env
|
113
|
-
c['cwd'] = @cwd
|
114
|
-
c['stdin'] = stdin
|
115
|
-
c['stdout'] = stdout
|
116
|
-
c['stderr'] = stderr
|
117
|
-
c['program'] = program
|
118
|
-
open(config, 'w'){|f| Marshal.dump c, f}
|
119
|
-
|
120
|
-
open(program, 'w'){|f| f.write child_program(config)}
|
121
|
-
|
122
|
-
c
|
123
|
-
#--}}}
|
124
|
-
end
|
125
|
-
|
126
|
-
def quietly
|
127
|
-
#--{{{
|
128
|
-
v = $VERBOSE
|
129
|
-
$VERBOSE = nil
|
130
|
-
yield
|
131
|
-
ensure
|
132
|
-
$VERBOSE = v
|
133
|
-
#--}}}
|
134
|
-
end
|
135
|
-
|
136
|
-
def child_program config
|
137
|
-
#--{{{
|
138
|
-
<<-program
|
139
|
-
begin
|
140
|
-
config = Marshal.load(IO.read('#{ config }'))
|
141
|
-
|
142
|
-
argv = config['argv']
|
143
|
-
env = config['env']
|
144
|
-
cwd = config['cwd']
|
145
|
-
stdin = config['stdin']
|
146
|
-
stdout = config['stdout']
|
147
|
-
stderr = config['stderr']
|
148
|
-
|
149
|
-
Dir.chdir cwd if cwd
|
150
|
-
env.each{|k,v| ENV[k.to_s] = v.to_s} if env
|
151
|
-
rescue Exception => e
|
152
|
-
STDERR.warn e
|
153
|
-
exit 42
|
154
|
-
end
|
155
|
-
|
156
|
-
STDOUT.puts Process.pid
|
157
|
-
STDOUT.flush
|
158
|
-
|
159
|
-
STDIN.reopen stdin
|
160
|
-
STDOUT.reopen stdout
|
161
|
-
STDERR.reopen stderr
|
162
|
-
|
163
|
-
exec *argv
|
164
|
-
program
|
165
|
-
#--}}}
|
166
|
-
end
|
167
|
-
|
168
|
-
def relay srcdst
|
169
|
-
#--{{{
|
170
|
-
src, dst, ignored = srcdst.to_a.first
|
171
|
-
if src.respond_to? 'read'
|
172
|
-
while((buf = src.read(8192))); dst << buf; end
|
173
|
-
else
|
174
|
-
src.each{|buf| dst << buf}
|
175
|
-
end
|
176
|
-
#--}}}
|
177
|
-
end
|
178
|
-
|
179
|
-
def tmpdir d = Dir.tmpdir, &b
|
180
|
-
#--{{{
|
181
|
-
i = -1 and loop{
|
182
|
-
tmp = File.join d, "systemu_#{ @host }_#{ @ppid }_#{ @pid }_#{ rand }_#{ i += 1 }"
|
183
|
-
|
184
|
-
begin
|
185
|
-
Dir.mkdir tmp
|
186
|
-
rescue Errno::EEXIST
|
187
|
-
next
|
188
|
-
end
|
189
|
-
|
190
|
-
scrub = lambda do |t|
|
191
|
-
FileUtils.rm_rf t
|
192
|
-
scrub = lambda{ 42 }
|
193
|
-
end
|
194
|
-
at_exit{ scrub[tmp] }
|
195
|
-
|
196
|
-
break(
|
197
|
-
if b
|
198
|
-
begin; b[ tmp ]; ensure; scrub[ tmp ]; end
|
199
|
-
else
|
200
|
-
tmp
|
201
|
-
end
|
202
|
-
)
|
203
|
-
}
|
204
|
-
#--}}}
|
205
|
-
end
|
206
|
-
|
207
|
-
def getopts opts = {}
|
208
|
-
#--{{{
|
209
|
-
lambda do |*args|
|
210
|
-
keys, default, ignored = args
|
211
|
-
catch('opt') do
|
212
|
-
[keys].flatten.each do |key|
|
213
|
-
[key, key.to_s, key.to_s.intern].each do |key|
|
214
|
-
throw 'opt', opts[key] if opts.has_key?(key)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
default
|
218
|
-
end
|
219
|
-
end
|
220
|
-
#--}}}
|
221
|
-
end
|
222
|
-
#--}}}
|
223
|
-
end
|
224
|
-
|
225
|
-
|
226
|
-
if $0 == __FILE__
|
227
|
-
#
|
228
|
-
# date
|
229
|
-
#
|
230
|
-
date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
|
231
|
-
|
232
|
-
status, stdout, stderr = systemu date
|
233
|
-
p [status, stdout, stderr]
|
234
|
-
|
235
|
-
status = systemu date, 1=>(stdout = '')
|
236
|
-
p [status, stdout]
|
237
|
-
|
238
|
-
status = systemu date, 2=>(stderr = '')
|
239
|
-
p [status, stderr]
|
240
|
-
#
|
241
|
-
# sleep
|
242
|
-
#
|
243
|
-
sleep = %q( ruby -e" p(sleep(1)) " )
|
244
|
-
status, stdout, stderr = systemu sleep
|
245
|
-
p [status, stdout, stderr]
|
246
|
-
|
247
|
-
sleep = %q( ruby -e" p(sleep(42)) " )
|
248
|
-
status, stdout, stderr = systemu(sleep){|cid| Process.kill 9, cid}
|
249
|
-
p [status, stdout, stderr]
|
250
|
-
#
|
251
|
-
# env
|
252
|
-
#
|
253
|
-
env = %q( ruby -e" p ENV['A'] " )
|
254
|
-
status, stdout, stderr = systemu env, :env => {'A' => 42}
|
255
|
-
p [status, stdout, stderr]
|
256
|
-
#
|
257
|
-
# cwd
|
258
|
-
#
|
259
|
-
env = %q( ruby -e" p Dir.pwd " )
|
260
|
-
status, stdout, stderr = systemu env, :cwd => Dir.tmpdir
|
261
|
-
p [status, stdout, stderr]
|
262
|
-
end
|