engineyard-serverside 1.5.23.ruby19.8 → 1.5.23.ruby19.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/lib/engineyard-serverside.rb +3 -1
  2. data/lib/engineyard-serverside/cli.rb +11 -19
  3. data/lib/engineyard-serverside/deploy.rb +3 -3
  4. data/lib/engineyard-serverside/future.rb +33 -0
  5. data/lib/engineyard-serverside/futures/celluloid.rb +25 -0
  6. data/lib/engineyard-serverside/futures/dataflow.rb +25 -0
  7. data/lib/engineyard-serverside/logged_output.rb +8 -3
  8. data/lib/engineyard-serverside/task.rb +9 -12
  9. data/lib/engineyard-serverside/version.rb +1 -1
  10. data/lib/vendor/celluloid/lib/celluloid.rb +261 -0
  11. data/lib/vendor/celluloid/lib/celluloid/actor.rb +242 -0
  12. data/lib/vendor/celluloid/lib/celluloid/actor_pool.rb +54 -0
  13. data/lib/vendor/celluloid/lib/celluloid/actor_proxy.rb +75 -0
  14. data/lib/vendor/celluloid/lib/celluloid/application.rb +78 -0
  15. data/lib/vendor/celluloid/lib/celluloid/calls.rb +94 -0
  16. data/lib/vendor/celluloid/lib/celluloid/core_ext.rb +14 -0
  17. data/lib/vendor/celluloid/lib/celluloid/events.rb +14 -0
  18. data/lib/vendor/celluloid/lib/celluloid/fiber.rb +33 -0
  19. data/lib/vendor/celluloid/lib/celluloid/fsm.rb +141 -0
  20. data/lib/vendor/celluloid/lib/celluloid/future.rb +60 -0
  21. data/lib/vendor/celluloid/lib/celluloid/links.rb +61 -0
  22. data/lib/vendor/celluloid/lib/celluloid/logger.rb +32 -0
  23. data/lib/vendor/celluloid/lib/celluloid/mailbox.rb +124 -0
  24. data/lib/vendor/celluloid/lib/celluloid/receivers.rb +66 -0
  25. data/lib/vendor/celluloid/lib/celluloid/registry.rb +33 -0
  26. data/lib/vendor/celluloid/lib/celluloid/responses.rb +26 -0
  27. data/lib/vendor/celluloid/lib/celluloid/rspec.rb +2 -0
  28. data/lib/vendor/celluloid/lib/celluloid/signals.rb +50 -0
  29. data/lib/vendor/celluloid/lib/celluloid/supervisor.rb +57 -0
  30. data/lib/vendor/celluloid/lib/celluloid/task.rb +73 -0
  31. data/lib/vendor/celluloid/lib/celluloid/tcp_server.rb +33 -0
  32. data/lib/vendor/celluloid/lib/celluloid/timers.rb +109 -0
  33. data/lib/vendor/celluloid/lib/celluloid/version.rb +4 -0
  34. data/lib/vendor/dataflow/dataflow.rb +124 -0
  35. data/lib/vendor/dataflow/dataflow/actor.rb +22 -0
  36. data/lib/vendor/dataflow/dataflow/equality.rb +44 -0
  37. data/lib/vendor/dataflow/dataflow/future_queue.rb +24 -0
  38. data/lib/vendor/dataflow/dataflow/port.rb +54 -0
  39. data/lib/vendor/open4/lib/open4.rb +432 -0
  40. data/lib/vendor/thor/lib/thor.rb +244 -0
  41. data/lib/vendor/thor/lib/thor/actions.rb +275 -0
  42. data/lib/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  43. data/lib/vendor/thor/lib/thor/actions/directory.rb +91 -0
  44. data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
  45. data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
  46. data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
  47. data/lib/vendor/thor/lib/thor/base.rb +540 -0
  48. data/lib/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
  49. data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  50. data/lib/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
  51. data/lib/vendor/thor/lib/thor/error.rb +30 -0
  52. data/lib/vendor/thor/lib/thor/group.rb +271 -0
  53. data/lib/vendor/thor/lib/thor/invocation.rb +180 -0
  54. data/lib/vendor/thor/lib/thor/parser.rb +4 -0
  55. data/lib/vendor/thor/lib/thor/parser/argument.rb +67 -0
  56. data/lib/vendor/thor/lib/thor/parser/arguments.rb +150 -0
  57. data/lib/vendor/thor/lib/thor/parser/option.rb +128 -0
  58. data/lib/vendor/thor/lib/thor/parser/options.rb +169 -0
  59. data/lib/vendor/thor/lib/thor/rake_compat.rb +66 -0
  60. data/lib/vendor/thor/lib/thor/runner.rb +314 -0
  61. data/lib/vendor/thor/lib/thor/shell.rb +83 -0
  62. data/lib/vendor/thor/lib/thor/shell/basic.rb +239 -0
  63. data/lib/vendor/thor/lib/thor/shell/color.rb +108 -0
  64. data/lib/vendor/thor/lib/thor/task.rb +102 -0
  65. data/lib/vendor/thor/lib/thor/util.rb +230 -0
  66. data/lib/vendor/thor/lib/thor/version.rb +3 -0
  67. metadata +70 -10
@@ -0,0 +1,109 @@
1
+ module Celluloid
2
+ # Low precision timers implemented in pure Ruby
3
+ class Timers
4
+ def initialize
5
+ @timers = []
6
+ end
7
+
8
+ # Call the given block after the given interval
9
+ def add(interval, &block)
10
+ Timer.new(self, interval, block)
11
+ end
12
+
13
+ # Wait for the next timer and fire it
14
+ def wait
15
+ return if @timers.empty?
16
+
17
+ interval = wait_interval
18
+ sleep interval if interval >= Timer::QUANTUM
19
+ fire
20
+ end
21
+
22
+ # Interval to wait until when the next timer will fire
23
+ def wait_interval
24
+ @timers.first.time - Time.now unless empty?
25
+ end
26
+
27
+ # Fire all timers that are ready
28
+ def fire
29
+ return if @timers.empty?
30
+
31
+ time = Time.now + Timer::QUANTUM
32
+ while not empty? and time > @timers.first.time
33
+ timer = @timers.shift
34
+ timer.call
35
+ end
36
+ end
37
+
38
+ # Insert a timer into the active timers
39
+ def insert(timer)
40
+ @timers.insert(index(timer), timer)
41
+ end
42
+
43
+ # Remove a given timer from the set we're monitoring
44
+ def cancel(timer)
45
+ @timers.delete timer
46
+ end
47
+
48
+ # Are there any timers pending?
49
+ def empty?
50
+ @timers.empty?
51
+ end
52
+
53
+ # Index where a timer would be located in the sorted timers array
54
+ def index(timer)
55
+ l, r = 0, @timers.size - 1
56
+
57
+ while l <= r
58
+ m = (r + l) / 2
59
+ if timer < @timers.at(m)
60
+ r = m - 1
61
+ else
62
+ l = m + 1
63
+ end
64
+ end
65
+ l
66
+ end
67
+ end
68
+
69
+ # An individual timer set to fire a given proc at a given time
70
+ class Timer
71
+ include Comparable
72
+
73
+ # The timer system is guaranteed (at least by the specs) to be this precise
74
+ # during normal operation. Long blocking calls within actors will delay the
75
+ # firing of timers
76
+ QUANTUM = 0.02
77
+
78
+ attr_reader :interval, :time
79
+
80
+ def initialize(timers, interval, block)
81
+ @timers, @interval = timers, interval
82
+ @block = block
83
+
84
+ reset
85
+ end
86
+
87
+ def <=>(other)
88
+ @time <=> other.time
89
+ end
90
+
91
+ # Cancel this timer
92
+ def cancel
93
+ @timers.cancel self
94
+ end
95
+
96
+ # Reset this timer
97
+ def reset
98
+ @timers.cancel self if defined?(@time)
99
+ @time = Time.now + @interval
100
+ @timers.insert self
101
+ end
102
+
103
+ # Fire the block
104
+ def fire
105
+ @block.call
106
+ end
107
+ alias_method :call, :fire
108
+ end
109
+ end
@@ -0,0 +1,4 @@
1
+ module Celluloid
2
+ VERSION = '0.7.1'
3
+ def self.version; VERSION; end
4
+ end
@@ -0,0 +1,124 @@
1
+ require 'monitor'
2
+
3
+ module Dataflow
4
+ VERSION = "0.3.1"
5
+ class << self
6
+ attr_accessor :forker
7
+ end
8
+ self.forker = Thread.method(:fork)
9
+
10
+ def self.included(cls)
11
+ class << cls
12
+ def declare(*readers)
13
+ readers.each do |name|
14
+ class_eval <<-RUBY
15
+ def #{name}
16
+ return @__dataflow_#{name}__ if defined? @__dataflow_#{name}__
17
+ Variable::LOCK.synchronize { @__dataflow_#{name}__ ||= Variable.new }
18
+ end
19
+ RUBY
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ def local(&block)
26
+ return Variable.new unless block_given?
27
+ vars = Array.new(block.arity) { Variable.new }
28
+ block.call *vars
29
+ end
30
+
31
+ def unify(variable, value)
32
+ variable.__unify__ value
33
+ end
34
+
35
+ def by_need(&block)
36
+ Variable.new &block
37
+ end
38
+
39
+ def barrier(*variables)
40
+ variables.each{|v| v.__wait__ }
41
+ end
42
+
43
+ def flow(output=nil, &block)
44
+ Dataflow.forker.call do
45
+ result = block.call
46
+ unify output, result if output
47
+ end
48
+ end
49
+
50
+ def need_later(&block)
51
+ local do |future|
52
+ flow(future) { block.call }
53
+ future
54
+ end
55
+ end
56
+
57
+ extend self
58
+
59
+ # Note that this class uses instance variables directly rather than nicely
60
+ # initialized instance variables in get/set methods for memory and
61
+ # performance reasons
62
+ class Variable
63
+ # Briefly disable the warning we would get when undefining object_id.
64
+ # We actually rely on the ability to do that, so...
65
+ v = $VERBOSE; $VERBOSE = nil
66
+ instance_methods.each { |m| undef_method(m) unless m =~ /^__|instance_eval/ }
67
+ $VERBOSE = v # back to sanity
68
+ LOCK = Monitor.new
69
+ def initialize(&block) @__trigger__ = block if block_given? end
70
+
71
+ # Lazy-load conditions to be nice on memory usage
72
+ def __binding_condition__() @__binding_condition__ ||= LOCK.new_cond end
73
+
74
+ def __unify__(value)
75
+ LOCK.synchronize do
76
+ __activate_trigger__ if @__trigger__
77
+ if @__bound__
78
+ return @__value__.__unify__(value) if @__value__.__dataflow__? rescue nil
79
+ raise UnificationError, "#{@__value__.inspect} != #{value.inspect}" if self != value
80
+ else
81
+ @__value__ = value
82
+ @__bound__ = true
83
+ __binding_condition__.broadcast # wakeup all method callers
84
+ @__binding_condition__ = nil # GC
85
+ end
86
+ end
87
+ @__value__
88
+ end
89
+
90
+ def __activate_trigger__
91
+ @__value__ = @__trigger__.call
92
+ @__bound__ = true
93
+ @__trigger__ = nil # GC
94
+ end
95
+
96
+ def __wait__
97
+ LOCK.synchronize do
98
+ unless @__bound__
99
+ if @__trigger__
100
+ __activate_trigger__
101
+ else
102
+ __binding_condition__.wait
103
+ end
104
+ end
105
+ end unless @__bound__
106
+ end
107
+
108
+ def method_missing(name, *args, &block)
109
+ return "#<Dataflow::Variable:#{__id__} unbound>" if !@__bound__ && name == :inspect
110
+ __wait__
111
+ @__value__.__send__(name, *args, &block)
112
+ end
113
+
114
+ def __dataflow__?
115
+ true
116
+ end
117
+ end
118
+
119
+ UnificationError = Class.new StandardError
120
+ end
121
+
122
+ require "#{File.dirname(__FILE__)}/dataflow/port"
123
+ require "#{File.dirname(__FILE__)}/dataflow/actor"
124
+ require "#{File.dirname(__FILE__)}/dataflow/future_queue"
@@ -0,0 +1,22 @@
1
+ module Dataflow
2
+ class Actor < Thread
3
+ def initialize(&block)
4
+ @stream = Variable.new
5
+ @port = Port.new(@stream)
6
+ # Run this block in a new thread
7
+ super { instance_eval &block }
8
+ end
9
+
10
+ def send message
11
+ @port.send message
12
+ end
13
+
14
+ private
15
+
16
+ def receive
17
+ result = @stream.head
18
+ @stream = @stream.tail
19
+ result
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,44 @@
1
+ # The purpose of this file is to make equality use method calls in as
2
+ # many Ruby implementations as possible. If method calls are used,
3
+ # then equality operations using dataflow variaables becomes seemless
4
+ # I realize overriding core classes is a pretty nasty hack, but if you
5
+ # have a better idea that also passes the equality_specs then I'm all
6
+ # ears. Please run the rubyspec before committing changes to this file.
7
+
8
+ class Object
9
+ alias original_equality ==
10
+
11
+ def ==(other)
12
+ object_id == other.object_id
13
+ end
14
+ end
15
+
16
+ class Symbol
17
+ alias original_equality ==
18
+
19
+ def ==(other)
20
+ object_id == other.object_id
21
+ end
22
+ end
23
+
24
+ class Regexp
25
+ alias original_equality ==
26
+
27
+ if /lol/.respond_to?(:encoding)
28
+ def ==(other)
29
+ other.is_a?(Regexp) &&
30
+ casefold? == other.casefold? &&
31
+ encoding == other.encoding &&
32
+ options == other.options &&
33
+ source == other.source
34
+ end
35
+ else
36
+ def ==(other)
37
+ other.is_a?(Regexp) &&
38
+ casefold? == other.casefold? &&
39
+ kcode == other.kcode &&
40
+ options == other.options &&
41
+ source == other.source
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,24 @@
1
+ module Dataflow
2
+ class FutureQueue
3
+ include Dataflow
4
+ declare :push_port, :pop_port
5
+
6
+ def initialize
7
+ local do |pushed, popped|
8
+ unify push_port, Dataflow::Port.new(pushed)
9
+ unify pop_port, Dataflow::Port.new(popped)
10
+
11
+ Thread.new {
12
+ loop do
13
+ barrier pushed.head, popped.head
14
+ unify popped.head, pushed.head
15
+ pushed, popped = pushed.tail, popped.tail
16
+ end
17
+ }
18
+ end
19
+ end
20
+
21
+ def push(x) push_port.send x end
22
+ def pop(x) pop_port.send x end
23
+ end
24
+ end
@@ -0,0 +1,54 @@
1
+ require 'thread'
2
+
3
+ module Dataflow
4
+ class Port
5
+ include Dataflow
6
+ LOCK = Mutex.new
7
+
8
+ class Stream
9
+ include Dataflow
10
+ declare :head, :tail
11
+
12
+ # Defining each allows us to use the enumerable mixin
13
+ # None of the list can be garbage collected less the head is
14
+ # garbage collected, so it will grow indefinitely even though
15
+ # the function isn't recursive.
16
+ include Enumerable
17
+ def each
18
+ s = self
19
+ loop do
20
+ yield s.head
21
+ s = s.tail
22
+ end
23
+ end
24
+
25
+ # Backported Enumerable#take for any 1.8.6 compatible Ruby
26
+ unless method_defined?(:take)
27
+ def take(num)
28
+ result = []
29
+ each_with_index do |x, i|
30
+ return result if num == i
31
+ result << x
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ # Create a stream object, bind it to the input variable
38
+ # Instance variables are necessary because @end is state
39
+ def initialize(x)
40
+ @end = Stream.new
41
+ unify x, @end
42
+ end
43
+
44
+ # This needs to be synchronized because it uses @end as state
45
+ def send value
46
+ LOCK.synchronize do
47
+ unify @end.head, value
48
+ unify @end.tail, Stream.new
49
+ @end = @end.tail
50
+ end
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,432 @@
1
+ # vim: ts=2:sw=2:sts=2:et:fdm=marker
2
+ require 'fcntl'
3
+ require 'timeout'
4
+ require 'thread'
5
+
6
+ module Open4
7
+ VERSION = '1.3.0'
8
+ def self.version() VERSION end
9
+
10
+ class Error < ::StandardError; end
11
+
12
+ def pfork4(fun, &b)
13
+ Open4.do_popen(b, :block) do |ps_read, _|
14
+ ps_read.close
15
+ begin
16
+ fun.call
17
+ rescue SystemExit => e
18
+ # Make it seem to the caller that calling Kernel#exit in +fun+ kills
19
+ # the child process normally. Kernel#exit! bypasses this rescue
20
+ # block.
21
+ exit! e.status
22
+ else
23
+ exit! 0
24
+ end
25
+ end
26
+ end
27
+ module_function :pfork4
28
+
29
+ def popen4(*cmd, &b)
30
+ Open4.do_popen(b, :init) do |ps_read, ps_write|
31
+ ps_read.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
32
+ ps_write.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
33
+ exec(*cmd)
34
+ raise 'forty-two' # Is this really needed?
35
+ end
36
+ end
37
+ alias open4 popen4
38
+ module_function :popen4
39
+ module_function :open4
40
+
41
+ def popen4ext(closefds=false, *cmd, &b)
42
+ Open4.do_popen(b, :init, closefds) do |ps_read, ps_write|
43
+ ps_read.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
44
+ ps_write.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
45
+ exec(*cmd)
46
+ raise 'forty-two' # Is this really needed?
47
+ end
48
+ end
49
+ module_function :popen4ext
50
+
51
+ def self.do_popen(b = nil, exception_propagation_at = nil, closefds=false, &cmd)
52
+ pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe
53
+
54
+ verbose = $VERBOSE
55
+ begin
56
+ $VERBOSE = nil
57
+
58
+ cid = fork {
59
+ if closefds
60
+ exlist = [0, 1, 2] | [pw,pr,pe,ps].map{|p| [p.first.fileno, p.last.fileno] }.flatten
61
+ ObjectSpace.each_object(IO){|io|
62
+ io.close if (not io.closed?) and (not exlist.include? io.fileno)
63
+ }
64
+ end
65
+
66
+ pw.last.close
67
+ STDIN.reopen pw.first
68
+ pw.first.close
69
+
70
+ pr.first.close
71
+ STDOUT.reopen pr.last
72
+ pr.last.close
73
+
74
+ pe.first.close
75
+ STDERR.reopen pe.last
76
+ pe.last.close
77
+
78
+ STDOUT.sync = STDERR.sync = true
79
+
80
+ begin
81
+ cmd.call(ps)
82
+ rescue Exception => e
83
+ Marshal.dump(e, ps.last)
84
+ ps.last.flush
85
+ ensure
86
+ ps.last.close unless ps.last.closed?
87
+ end
88
+
89
+ exit!
90
+ }
91
+ ensure
92
+ $VERBOSE = verbose
93
+ end
94
+
95
+ [ pw.first, pr.last, pe.last, ps.last ].each { |fd| fd.close }
96
+
97
+ Open4.propagate_exception cid, ps.first if exception_propagation_at == :init
98
+
99
+ pw.last.sync = true
100
+
101
+ pi = [ pw.last, pr.first, pe.first ]
102
+
103
+ begin
104
+ return [cid, *pi] unless b
105
+
106
+ begin
107
+ b.call(cid, *pi)
108
+ ensure
109
+ pi.each { |fd| fd.close unless fd.closed? }
110
+ end
111
+
112
+ Open4.propagate_exception cid, ps.first if exception_propagation_at == :block
113
+
114
+ Process.waitpid2(cid).last
115
+ ensure
116
+ ps.first.close unless ps.first.closed?
117
+ end
118
+ end
119
+
120
+ def self.propagate_exception(cid, ps_read)
121
+ e = Marshal.load ps_read
122
+ raise Exception === e ? e : "unknown failure!"
123
+ rescue EOFError
124
+ # Child process did not raise exception.
125
+ rescue
126
+ # Child process raised exception; wait it in order to avoid a zombie.
127
+ Process.waitpid2 cid
128
+ raise
129
+ ensure
130
+ ps_read.close
131
+ end
132
+
133
+ class SpawnError < Error
134
+ attr 'cmd'
135
+ attr 'status'
136
+ attr 'signals'
137
+ def exitstatus
138
+ @status.exitstatus
139
+ end
140
+ def initialize cmd, status
141
+ @cmd, @status = cmd, status
142
+ @signals = {}
143
+ if status.signaled?
144
+ @signals['termsig'] = status.termsig
145
+ @signals['stopsig'] = status.stopsig
146
+ end
147
+ sigs = @signals.map{|k,v| "#{ k }:#{ v.inspect }"}.join(' ')
148
+ super "cmd <#{ cmd }> failed with status <#{ exitstatus.inspect }> signals <#{ sigs }>"
149
+ end
150
+ end
151
+
152
+ class ThreadEnsemble
153
+ attr 'threads'
154
+
155
+ def initialize cid
156
+ @cid, @threads, @argv, @done, @running = cid, [], [], Queue.new, false
157
+ @killed = false
158
+ end
159
+
160
+ def add_thread *a, &b
161
+ @running ? raise : (@argv << [a, b])
162
+ end
163
+
164
+ #
165
+ # take down process more nicely
166
+ #
167
+ def killall
168
+ c = Thread.critical
169
+ return nil if @killed
170
+ Thread.critical = true
171
+ (@threads - [Thread.current]).each{|t| t.kill rescue nil}
172
+ @killed = true
173
+ ensure
174
+ Thread.critical = c
175
+ end
176
+
177
+ def run
178
+ @running = true
179
+
180
+ begin
181
+ @argv.each do |a, b|
182
+ @threads << Thread.new(*a) do |*a|
183
+ begin
184
+ b[*a]
185
+ ensure
186
+ killall rescue nil if $!
187
+ @done.push Thread.current
188
+ end
189
+ end
190
+ end
191
+ rescue
192
+ killall
193
+ raise
194
+ ensure
195
+ all_done
196
+ end
197
+
198
+ @threads.map{|t| t.value}
199
+ end
200
+
201
+ def all_done
202
+ @threads.size.times{ @done.pop }
203
+ end
204
+ end
205
+
206
+ def to timeout = nil
207
+ Timeout.timeout(timeout){ yield }
208
+ end
209
+ module_function :to
210
+
211
+ def new_thread *a, &b
212
+ cur = Thread.current
213
+ Thread.new(*a) do |*a|
214
+ begin
215
+ b[*a]
216
+ rescue Exception => e
217
+ cur.raise e
218
+ end
219
+ end
220
+ end
221
+ module_function :new_thread
222
+
223
+ def getopts opts = {}
224
+ lambda do |*args|
225
+ keys, default, ignored = args
226
+ catch(:opt) do
227
+ [keys].flatten.each do |key|
228
+ [key, key.to_s, key.to_s.intern].each do |key|
229
+ throw :opt, opts[key] if opts.has_key?(key)
230
+ end
231
+ end
232
+ default
233
+ end
234
+ end
235
+ end
236
+ module_function :getopts
237
+
238
+ def relay src, dst = nil, t = nil
239
+ send_dst =
240
+ if dst.respond_to?(:call)
241
+ lambda{|buf| dst.call(buf)}
242
+ elsif dst.respond_to?(:<<)
243
+ lambda{|buf| dst << buf }
244
+ else
245
+ lambda{|buf| buf }
246
+ end
247
+
248
+ unless src.nil?
249
+ if src.respond_to? :gets
250
+ while buf = to(t){ src.gets }
251
+ send_dst[buf]
252
+ end
253
+
254
+ elsif src.respond_to? :each
255
+ q = Queue.new
256
+ th = nil
257
+
258
+ timer_set = lambda do |t|
259
+ th = new_thread{ to(t){ q.pop } }
260
+ end
261
+
262
+ timer_cancel = lambda do |t|
263
+ th.kill if th rescue nil
264
+ end
265
+
266
+ timer_set[t]
267
+ begin
268
+ src.each do |buf|
269
+ timer_cancel[t]
270
+ send_dst[buf]
271
+ timer_set[t]
272
+ end
273
+ ensure
274
+ timer_cancel[t]
275
+ end
276
+
277
+ elsif src.respond_to? :read
278
+ buf = to(t){ src.read }
279
+ send_dst[buf]
280
+
281
+ else
282
+ buf = to(t){ src.to_s }
283
+ send_dst[buf]
284
+ end
285
+ end
286
+ end
287
+ module_function :relay
288
+
289
+ def spawn arg, *argv
290
+ argv.unshift(arg)
291
+ opts = ((argv.size > 1 and Hash === argv.last) ? argv.pop : {})
292
+ argv.flatten!
293
+ cmd = argv.join(' ')
294
+
295
+
296
+ getopt = getopts opts
297
+
298
+ ignore_exit_failure = getopt[ 'ignore_exit_failure', getopt['quiet', false] ]
299
+ ignore_exec_failure = getopt[ 'ignore_exec_failure', !getopt['raise', true] ]
300
+ exitstatus = getopt[ %w( exitstatus exit_status status ) ]
301
+ stdin = getopt[ %w( stdin in i 0 ) << 0 ]
302
+ stdout = getopt[ %w( stdout out o 1 ) << 1 ]
303
+ stderr = getopt[ %w( stderr err e 2 ) << 2 ]
304
+ pid = getopt[ 'pid' ]
305
+ timeout = getopt[ %w( timeout spawn_timeout ) ]
306
+ stdin_timeout = getopt[ %w( stdin_timeout ) ]
307
+ stdout_timeout = getopt[ %w( stdout_timeout io_timeout ) ]
308
+ stderr_timeout = getopt[ %w( stderr_timeout ) ]
309
+ status = getopt[ %w( status ) ]
310
+ cwd = getopt[ %w( cwd dir ) ]
311
+
312
+ exitstatus =
313
+ case exitstatus
314
+ when TrueClass, FalseClass
315
+ ignore_exit_failure = true if exitstatus
316
+ [0]
317
+ else
318
+ [*(exitstatus || 0)].map{|i| Integer i}
319
+ end
320
+
321
+ stdin ||= '' if stdin_timeout
322
+ stdout ||= '' if stdout_timeout
323
+ stderr ||= '' if stderr_timeout
324
+
325
+ started = false
326
+
327
+ status =
328
+ begin
329
+ chdir(cwd) do
330
+ Timeout::timeout(timeout) do
331
+ popen4(*argv) do |c, i, o, e|
332
+ started = true
333
+
334
+ %w( replace pid= << push update ).each do |msg|
335
+ break(pid.send(msg, c)) if pid.respond_to? msg
336
+ end
337
+
338
+ te = ThreadEnsemble.new c
339
+
340
+ te.add_thread(i, stdin) do |i, stdin|
341
+ relay stdin, i, stdin_timeout
342
+ i.close rescue nil
343
+ end
344
+
345
+ te.add_thread(o, stdout) do |o, stdout|
346
+ relay o, stdout, stdout_timeout
347
+ end
348
+
349
+ te.add_thread(e, stderr) do |o, stderr|
350
+ relay e, stderr, stderr_timeout
351
+ end
352
+
353
+ te.run
354
+ end
355
+ end
356
+ end
357
+ rescue
358
+ raise unless(not started and ignore_exec_failure)
359
+ end
360
+
361
+ raise SpawnError.new(cmd, status) unless
362
+ (ignore_exit_failure or (status.nil? and ignore_exec_failure) or exitstatus.include?(status.exitstatus))
363
+
364
+ status
365
+ end
366
+ module_function :spawn
367
+
368
+ def chdir cwd, &block
369
+ return(block.call Dir.pwd) unless cwd
370
+ Dir.chdir cwd, &block
371
+ end
372
+ module_function :chdir
373
+
374
+ def background arg, *argv
375
+ require 'thread'
376
+ q = Queue.new
377
+ opts = { 'pid' => q, :pid => q }
378
+ case argv.last
379
+ when Hash
380
+ argv.last.update opts
381
+ else
382
+ argv.push opts
383
+ end
384
+ thread = Thread.new(arg, argv){|arg, argv| spawn arg, *argv}
385
+ sc = class << thread; self; end
386
+ sc.module_eval {
387
+ define_method(:pid){ @pid ||= q.pop }
388
+ define_method(:spawn_status){ @spawn_status ||= value }
389
+ define_method(:exitstatus){ @exitstatus ||= spawn_status.exitstatus }
390
+ }
391
+ thread
392
+ end
393
+ alias bg background
394
+ module_function :background
395
+ module_function :bg
396
+
397
+ def maim pid, opts = {}
398
+ getopt = getopts opts
399
+ sigs = getopt[ 'signals', %w(SIGTERM SIGQUIT SIGKILL) ]
400
+ suspend = getopt[ 'suspend', 4 ]
401
+ pid = Integer pid
402
+ existed = false
403
+ sigs.each do |sig|
404
+ begin
405
+ Process.kill sig, pid
406
+ existed = true
407
+ rescue Errno::ESRCH
408
+ return(existed ? nil : true)
409
+ end
410
+ return true unless alive? pid
411
+ sleep suspend
412
+ return true unless alive? pid
413
+ end
414
+ return(not alive?(pid))
415
+ end
416
+ module_function :maim
417
+
418
+ def alive pid
419
+ pid = Integer pid
420
+ begin
421
+ Process.kill 0, pid
422
+ true
423
+ rescue Errno::ESRCH
424
+ false
425
+ end
426
+ end
427
+ alias alive? alive
428
+ module_function :alive
429
+ module_function :'alive?'
430
+ end
431
+
432
+ def open4(*cmd, &b) cmd.size == 0 ? Open4 : Open4::popen4(*cmd, &b) end