systemu 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/a.rb +15 -0
  2. data/lib/systemu.rb +51 -24
  3. data/systemu-1.1.0.gem +0 -0
  4. metadata +33 -25
  5. 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
- VERSION = '1.0.0'
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
- cid = pipe.gets.to_i
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| Marshal.dump c, 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
- config = Marshal.load(IO.read('#{ config }'))
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
- STDOUT.puts Process.pid
157
- STDOUT.flush
175
+ STDIN.reopen stdin
176
+ STDOUT.reopen stdout
177
+ STDERR.reopen stderr
158
178
 
159
- STDIN.reopen stdin
160
- STDOUT.reopen stdout
161
- STDERR.reopen stderr
179
+ PIPE.puts "pid: #{ Process.pid }"
180
+ PIPE.flush ### the process is ready yo!
181
+ PIPE.close
162
182
 
163
- exec *argv
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; b[ tmp ]; ensure; scrub[ tmp ]; end
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.8.11
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.0.0
7
- date: 2006-11-03 00:00:00.000000 -07:00
6
+ version: 1.1.0
7
+ date: 2007-07-19 00:00:00 -06:00
8
8
  summary: systemu
9
9
  require_paths:
10
- - lib
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
- - !ruby/object:Gem::Version
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
- - Ara T. Howard
30
+ - Ara T. Howard
31
31
  files:
32
- - lib
33
- - samples
34
- - gen_readme.rb
35
- - gemspec.rb
36
- - install.rb
37
- - README
38
- - README.tmpl
39
- - lib/systemu.rb
40
- - lib/systemu-1.0.0.rb
41
- - samples/a.rb
42
- - samples/b.rb
43
- - samples/c.rb
44
- - samples/d.rb
45
- - samples/e.rb
46
- - samples/f.rb
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
- dependencies: []
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