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.
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