tork 19.4.0 → 19.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -2
- data/VERSION.md +191 -102
- data/bin/tork +4 -3
- data/bin/tork-driver +5 -2
- data/bin/tork-engine +5 -2
- data/bin/tork-herald +3 -3
- data/bin/tork-master +5 -2
- data/bin/tork-notify +3 -2
- data/bin/tork-remote +4 -9
- data/bin/tork-runner +86 -0
- data/lib/tork/bridge.rb +66 -0
- data/lib/tork/cliapp.rb +21 -13
- data/lib/tork/config/rails/worker.rb +1 -1
- data/lib/tork/engine.rb +3 -12
- data/lib/tork/server.rb +31 -37
- data/lib/tork/version.rb +1 -1
- data/man/index.html +1 -1
- data/man/man0/README.html +5 -3
- data/man/man0/README.md +6 -2
- data/man/man0/VERSION.html +156 -102
- data/man/man0/VERSION.md +191 -102
- data/man/man1/tork-driver.1 +7 -2
- data/man/man1/tork-driver.1.html +5 -2
- data/man/man1/tork-engine.1 +7 -2
- data/man/man1/tork-engine.1.html +5 -2
- data/man/man1/tork-herald.1 +1 -1
- data/man/man1/tork-herald.1.html +1 -1
- data/man/man1/tork-master.1 +7 -2
- data/man/man1/tork-master.1.html +5 -2
- data/man/man1/tork-notify.1 +1 -1
- data/man/man1/tork-notify.1.html +1 -1
- data/man/man1/tork-remote.1 +4 -10
- data/man/man1/tork-remote.1.html +4 -5
- data/man/man1/tork-runner.1 +44 -0
- data/man/man1/tork-runner.1.html +14 -0
- data/man/man1/tork.1 +5 -3
- data/man/man1/tork.1.html +3 -2
- data/man/style.css +1 -1
- data/tork.gemspec +2 -1
- metadata +11 -5
data/bin/tork
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
=begin =======================================================================
|
3
3
|
|
4
|
-
# TORK 1 2013-11-
|
4
|
+
# TORK 1 2013-11-30 19.5.0
|
5
5
|
|
6
6
|
## NAME
|
7
7
|
|
@@ -13,7 +13,8 @@ tork - Continuous testing tool for Ruby
|
|
13
13
|
|
14
14
|
## DESCRIPTION
|
15
15
|
|
16
|
-
This program
|
16
|
+
This program can be thought of as an interactive version of tork-runner(1).
|
17
|
+
It functions as a rudimentary command-line user interface to tork-driver(1).
|
17
18
|
|
18
19
|
First, it applies the given *CONFIG* values, which are either (1) paths to
|
19
20
|
directories that contain configuration files or (2) names of configuration
|
@@ -111,7 +112,7 @@ This program can be controlled remotely by multiple tork-remote(1) instances.
|
|
111
112
|
|
112
113
|
## SEE ALSO
|
113
114
|
|
114
|
-
tork(1), tork-driver(1), tork-master(1)
|
115
|
+
tork-runner(1), tork-driver(1), tork-master(1)
|
115
116
|
|
116
117
|
[factory_girl]: https://github.com/thoughtbot/factory_girl
|
117
118
|
[memory_test_fix]: https://github.com/stepahn/memory_test_fix
|
data/bin/tork-driver
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
=begin =======================================================================
|
3
3
|
|
4
|
-
# TORK-DRIVER 1 2013-11-
|
4
|
+
# TORK-DRIVER 1 2013-11-30 19.5.0
|
5
5
|
|
6
6
|
## NAME
|
7
7
|
|
@@ -20,7 +20,10 @@ This program can be controlled remotely by multiple tork-remote(1) instances.
|
|
20
20
|
### Input
|
21
21
|
|
22
22
|
This program reads the following commands, which are single-line JSON arrays,
|
23
|
-
from stdin and performs the actions
|
23
|
+
from stdin and then performs the associated actions. For lines read from
|
24
|
+
stdin that are single-line JSON arrays, it splits each of them into an array
|
25
|
+
of words, using the same word-splitting algorithm as sh(1), before processing
|
26
|
+
them. For example, the line `a "b c"` is split into the `["a", "b c"]` array.
|
24
27
|
|
25
28
|
`["run_all_test_files"]`
|
26
29
|
Runs all test files found within and beneath the current working directory.
|
data/bin/tork-engine
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
=begin =======================================================================
|
3
3
|
|
4
|
-
# TORK-ENGINE 1 2013-11-
|
4
|
+
# TORK-ENGINE 1 2013-11-30 19.5.0
|
5
5
|
|
6
6
|
## NAME
|
7
7
|
|
@@ -20,7 +20,10 @@ This program can be controlled remotely by multiple tork-remote(1) instances.
|
|
20
20
|
### Input
|
21
21
|
|
22
22
|
This program reads the following commands, which are single-line JSON arrays,
|
23
|
-
from stdin and performs the actions
|
23
|
+
from stdin and then performs the associated actions. For lines read from
|
24
|
+
stdin that are single-line JSON arrays, it splits each of them into an array
|
25
|
+
of words, using the same word-splitting algorithm as sh(1), before processing
|
26
|
+
them. For example, the line `a "b c"` is split into the `["a", "b c"]` array.
|
24
27
|
|
25
28
|
`["reabsorb_overhead"]`
|
26
29
|
Stops any test files that are currently running, reabsorbs the test
|
data/bin/tork-herald
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
=begin =======================================================================
|
3
3
|
|
4
|
-
# TORK-HERALD 1 2013-11-
|
4
|
+
# TORK-HERALD 1 2013-11-30 19.5.0
|
5
5
|
|
6
6
|
## NAME
|
7
7
|
|
@@ -37,7 +37,7 @@ require 'json'
|
|
37
37
|
STDOUT.sync = true # flush puts() output immediately after writing
|
38
38
|
|
39
39
|
require 'listen'
|
40
|
-
Listen.to
|
40
|
+
Listen.to! '.', :relative_paths => true do |modified, added, removed|
|
41
41
|
files = modified + added
|
42
42
|
puts JSON.dump(files) unless files.empty?
|
43
|
-
end
|
43
|
+
end
|
data/bin/tork-master
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
=begin =======================================================================
|
3
3
|
|
4
|
-
# TORK-MASTER 1 2013-11-
|
4
|
+
# TORK-MASTER 1 2013-11-30 19.5.0
|
5
5
|
|
6
6
|
## NAME
|
7
7
|
|
@@ -23,7 +23,10 @@ This program can be controlled remotely by multiple tork-remote(1) instances.
|
|
23
23
|
### Input
|
24
24
|
|
25
25
|
This program reads the following commands, which are single-line JSON arrays,
|
26
|
-
from stdin and performs the actions
|
26
|
+
from stdin and then performs the associated actions. For lines read from
|
27
|
+
stdin that are single-line JSON arrays, it splits each of them into an array
|
28
|
+
of words, using the same word-splitting algorithm as sh(1), before processing
|
29
|
+
them. For example, the line `a "b c"` is split into the `["a", "b c"]` array.
|
27
30
|
|
28
31
|
`["test",` *test_file*`,` *line_numbers*`]`
|
29
32
|
Forks a worker process to run tests that correspond to the given
|
data/bin/tork-notify
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
=begin =======================================================================
|
3
3
|
|
4
|
-
# TORK-NOTIFY 1 2013-11-
|
4
|
+
# TORK-NOTIFY 1 2013-11-30 19.5.0
|
5
5
|
|
6
6
|
## NAME
|
7
7
|
|
@@ -58,7 +58,8 @@ IO.popen('tork-remote tork-engine', 'r+') do |remote|
|
|
58
58
|
statistics = File.readlines(log_file).grep(/^\d+ \w+,/).join.
|
59
59
|
gsub(/\e\[\d+(;\d+)?m/, '') # strip ANSI SGR escape codes
|
60
60
|
|
61
|
-
|
61
|
+
# run in background; see http://stackoverflow.com/q/16745840
|
62
|
+
Thread.new(icon, title, statistics) do |icon, title, statistics|
|
62
63
|
system 'notify-send', '-i', icon, title, statistics or
|
63
64
|
system 'growlnotify', '-a', 'Xcode', '-m', statistics, title or
|
64
65
|
system 'xmessage', '-timeout', '5', '-title', title, statistics or
|
data/bin/tork-remote
CHANGED
@@ -13,15 +13,10 @@ tork-remote - controls tork(1) programs
|
|
13
13
|
|
14
14
|
## DESCRIPTION
|
15
15
|
|
16
|
-
This program
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
split into an array of words, using the same word-splitting algorithm as
|
21
|
-
sh(1), before being sent to the *PROGRAM* as a single-line JSON message.
|
22
|
-
|
23
|
-
If the *PROGRAM* sends any messages in response, then they are printed to
|
24
|
-
stdout if they are valid single-line JSON messages or to stderr otherwise.
|
16
|
+
This program reads lines from its stdin and sends them to the given *PROGRAM*,
|
17
|
+
which must already be running in the same working directory as this program.
|
18
|
+
It also prints lines, received in response, from the given *PROGRAM* either
|
19
|
+
to stdout if they are valid single-line JSON arrays or to stderr otherwise.
|
25
20
|
|
26
21
|
## OPTIONS
|
27
22
|
|
data/bin/tork-runner
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
=begin =======================================================================
|
3
|
+
|
4
|
+
# TORK-RUNNER 1 2013-11-30 19.5.0
|
5
|
+
|
6
|
+
## NAME
|
7
|
+
|
8
|
+
tork-runner - runs tests once, non-interactively
|
9
|
+
|
10
|
+
## SYNOPSIS
|
11
|
+
|
12
|
+
`tork-runner` [*OPTION*]... [*TEST\_FILE\_GLOB*]...
|
13
|
+
|
14
|
+
## DESCRIPTION
|
15
|
+
|
16
|
+
This program can be thought of as a non-interactive version of tork(1). It
|
17
|
+
runs all test files that match the given *TEST\_FILE\_GLOB*s and then exits
|
18
|
+
with a nonzero status if any tests failed. If none are given, it runs all
|
19
|
+
test files known to `Tork::Driver::TEST_FILE_GLOBBERS` in tork-driver(1).
|
20
|
+
|
21
|
+
### Output
|
22
|
+
|
23
|
+
This program prints the following messages to stdout.
|
24
|
+
|
25
|
+
`>>` *failed\_test\_log\_file* `<<`
|
26
|
+
This message will be followed by the content of *failed\_test\_log\_file*.
|
27
|
+
|
28
|
+
*T* `tested,` *P* `passed,` *F* `failed`
|
29
|
+
*T* test files were tested and *P* of them passed but *F* of them failed.
|
30
|
+
|
31
|
+
## OPTIONS
|
32
|
+
|
33
|
+
`-h`, `--help`
|
34
|
+
Show this help manual.
|
35
|
+
|
36
|
+
## EXIT STATUS
|
37
|
+
|
38
|
+
0
|
39
|
+
All test files passed.
|
40
|
+
|
41
|
+
1
|
42
|
+
One or more test files failed.
|
43
|
+
|
44
|
+
## ENVIRONMENT
|
45
|
+
|
46
|
+
See tork(1).
|
47
|
+
|
48
|
+
## SEE ALSO
|
49
|
+
|
50
|
+
tork(1), tork-driver(1)
|
51
|
+
|
52
|
+
=end =========================================================================
|
53
|
+
|
54
|
+
$0 = File.basename(__FILE__) # for easier identification in ps(1) output
|
55
|
+
|
56
|
+
require 'binman'
|
57
|
+
BinMan.help
|
58
|
+
|
59
|
+
require 'json'
|
60
|
+
IO.popen('tork-driver', 'w+') do |driver|
|
61
|
+
# tell tork to run the given test files
|
62
|
+
# or run known test files if none given
|
63
|
+
test_files = Dir[*ARGV]
|
64
|
+
command =
|
65
|
+
if test_files.empty?
|
66
|
+
[:run_all_test_files]
|
67
|
+
else
|
68
|
+
[:run_test_files, test_files]
|
69
|
+
end
|
70
|
+
driver.puts JSON.dump(command)
|
71
|
+
|
72
|
+
# track test runs & exit when finished
|
73
|
+
tested, passed, failed = 0, 0, []
|
74
|
+
while line = driver.gets
|
75
|
+
response = JSON.load(line)
|
76
|
+
case response.first.to_sym
|
77
|
+
when :test then tested += 1
|
78
|
+
when :pass then passed += 1
|
79
|
+
when :fail then failed << response[3]
|
80
|
+
when :idle then
|
81
|
+
puts failed.map {|log| [nil, ">> #{log} <<", File.read(log)] }, nil,
|
82
|
+
"#{tested} tested, #{passed} passed, #{failed.count} failed"
|
83
|
+
exit failed.empty?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/tork/bridge.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module Tork
|
2
|
+
# Wrapper for IO.popen() that automatically re-establishes itself
|
3
|
+
# whenever the child process terminates extraneously, on its own.
|
4
|
+
class Bridge
|
5
|
+
|
6
|
+
def initialize command
|
7
|
+
@command = command
|
8
|
+
connect
|
9
|
+
end
|
10
|
+
|
11
|
+
def disconnect
|
12
|
+
return unless @guardian.alive?
|
13
|
+
|
14
|
+
# prevent guardian from reconnecting bridge while we disconnect it
|
15
|
+
@guardian.exit
|
16
|
+
|
17
|
+
# this should be enough to stop programs that use Tork::Server#loop
|
18
|
+
# because their IO.select() loop terminates on the closing of STDIN
|
19
|
+
@io.close_write
|
20
|
+
|
21
|
+
# but some programs like tork-herald(1) need to be killed explicitly
|
22
|
+
# because they do not follow our convention of exiting on STDIN close
|
23
|
+
Process.kill :SIGTERM, @io.pid
|
24
|
+
Process.waitpid @io.pid
|
25
|
+
|
26
|
+
# this will block until the child process has exited so we must kill it
|
27
|
+
# explicitly (as above) to ensure that this program does not hang here
|
28
|
+
@io.close_read
|
29
|
+
|
30
|
+
rescue IOError, SystemCallError
|
31
|
+
# IOError happens if the child process' pipes are already closed
|
32
|
+
# SystemCallError happens if the child process is already dead
|
33
|
+
end
|
34
|
+
|
35
|
+
def reconnect
|
36
|
+
disconnect
|
37
|
+
connect
|
38
|
+
end
|
39
|
+
|
40
|
+
# Allows this object to be passed directly
|
41
|
+
# into IO.select() and Tork::Server#tell().
|
42
|
+
def to_io
|
43
|
+
@io
|
44
|
+
end
|
45
|
+
|
46
|
+
# Allows this object to be treated as IO.
|
47
|
+
def method_missing *args, &block
|
48
|
+
@io.__send__ *args, &block
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def connect
|
54
|
+
@io = IO.popen(@command, 'r+')
|
55
|
+
|
56
|
+
# automatically reconnect the bridge when the child process terminates
|
57
|
+
@guardian = Thread.new do
|
58
|
+
Process.waitpid @io.pid
|
59
|
+
warn "#{$0}: repairing collapsed bridge: #{@command} #{$?}"
|
60
|
+
sleep 1 # avoid spamming the CPU by waiting a bit before reconnecting
|
61
|
+
connect # no need to disconnect because child process is already dead
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
data/lib/tork/cliapp.rb
CHANGED
@@ -24,6 +24,11 @@ class CLIApp < Server
|
|
24
24
|
|
25
25
|
protected
|
26
26
|
|
27
|
+
def join client
|
28
|
+
super
|
29
|
+
help client
|
30
|
+
end
|
31
|
+
|
27
32
|
def recv client, message
|
28
33
|
case client
|
29
34
|
when @driver
|
@@ -51,23 +56,26 @@ protected
|
|
51
56
|
tell @clients, message, false
|
52
57
|
end
|
53
58
|
else
|
54
|
-
key
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
quit if cmd == :quit
|
59
|
-
call = Array(cmd) + args
|
60
|
-
tell @clients, "Sending #{call.inspect} command...", false
|
61
|
-
send @driver, call
|
59
|
+
key = message.shift.lstrip[0,1].downcase
|
60
|
+
cmd = Array(COMMANDS.fetch(key, [:help, client])) + message
|
61
|
+
if respond_to? cmd.first, true
|
62
|
+
__send__(*cmd)
|
62
63
|
else
|
63
|
-
|
64
|
-
|
65
|
-
desc = Array(cmd).join(' with ').to_s.tr('_', ' ')
|
66
|
-
tell @client, "Type #{key} then ENTER to #{desc}.", false
|
67
|
-
end
|
64
|
+
tell @clients, "Sending #{cmd.inspect} command...", false
|
65
|
+
send @driver, cmd
|
68
66
|
end
|
69
67
|
end
|
70
68
|
end
|
71
69
|
|
70
|
+
private
|
71
|
+
|
72
|
+
def help client
|
73
|
+
COMMANDS.each do |key, cmd|
|
74
|
+
desc = Array(cmd).join(' with ').to_s.tr('_', ' ')
|
75
|
+
tell client, "Type #{key} then ENTER to #{desc}.", false
|
76
|
+
end
|
77
|
+
tell client, 'Type h then ENTER to see this message.', false
|
78
|
+
end
|
79
|
+
|
72
80
|
end
|
73
81
|
end
|
@@ -10,7 +10,7 @@ if defined? ActiveRecord::Base
|
|
10
10
|
elsif base.respond_to? :connection_pool # rails >= 2.2.1
|
11
11
|
base.connection_pool.spec.config
|
12
12
|
else
|
13
|
-
warn "#{$0}: config/rails/worker:
|
13
|
+
warn "#{$0}: config/rails/worker: could not read connection information"
|
14
14
|
{}
|
15
15
|
end
|
16
16
|
|
data/lib/tork/engine.rb
CHANGED
@@ -17,15 +17,14 @@ class Engine < Server
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def loop
|
20
|
-
|
20
|
+
@master = popen('tork-master')
|
21
21
|
super
|
22
22
|
ensure
|
23
|
-
|
23
|
+
pclose @master
|
24
24
|
end
|
25
25
|
|
26
26
|
def reabsorb_overhead
|
27
|
-
|
28
|
-
create_master
|
27
|
+
@master.reconnect
|
29
28
|
|
30
29
|
# re-dispatch the previously dispatched files to the new master
|
31
30
|
previous = @queued_test_files.to_a
|
@@ -122,13 +121,5 @@ private
|
|
122
121
|
map {|change| change.position + 1 }.uniq
|
123
122
|
end
|
124
123
|
|
125
|
-
def create_master
|
126
|
-
@master = popen('tork-master')
|
127
|
-
end
|
128
|
-
|
129
|
-
def destroy_master
|
130
|
-
pclose @master
|
131
|
-
end
|
132
|
-
|
133
124
|
end
|
134
125
|
end
|
data/lib/tork/server.rb
CHANGED
@@ -2,6 +2,7 @@ require 'socket'
|
|
2
2
|
require 'json'
|
3
3
|
require 'shellwords'
|
4
4
|
require 'set'
|
5
|
+
require 'tork/bridge'
|
5
6
|
|
6
7
|
module Tork
|
7
8
|
class Server
|
@@ -11,46 +12,42 @@ class Server
|
|
11
12
|
end
|
12
13
|
|
13
14
|
def initialize
|
15
|
+
begin
|
16
|
+
@welcome = UNIXServer.open(address = Server.address)
|
17
|
+
# UNIX domain socket files are not automatically deleted on close
|
18
|
+
at_exit { File.delete address if File.socket? address }
|
19
|
+
rescue Errno::EADDRINUSE
|
20
|
+
# another instance of this program is already running in the same
|
21
|
+
# directory so become a remote control for it rather than exiting
|
22
|
+
warn "#{$0}: remotely controlling existing instance..."
|
23
|
+
exec 'tork-remote', $0
|
24
|
+
end
|
25
|
+
|
14
26
|
# only JSON messages are supposed to be emitted on STDOUT
|
15
27
|
# so make puts() in the user code write to STDERR instead
|
16
28
|
@stdout = STDOUT.dup
|
17
29
|
STDOUT.reopen STDERR
|
18
30
|
|
19
|
-
@
|
20
|
-
@
|
21
|
-
@address = Server.address
|
31
|
+
@servers = Set.new.add(@welcome)
|
32
|
+
@clients = Set.new; join STDIN # parent process connected on STDIN
|
22
33
|
end
|
23
34
|
|
24
35
|
def loop
|
25
|
-
begin
|
26
|
-
server = UNIXServer.open(@address)
|
27
|
-
rescue SystemCallError => error
|
28
|
-
warn "#{$0}: #{error}; retrying in #{timeout = 1 + rand(10)} seconds..."
|
29
|
-
sleep timeout
|
30
|
-
retry
|
31
|
-
end
|
32
|
-
|
33
36
|
catch :quit do
|
34
|
-
@servers.add server
|
35
37
|
while @clients.include? STDIN
|
36
38
|
IO.select((@servers + @clients).to_a).first.each do |stream|
|
37
|
-
|
38
|
-
|
39
|
-
if stream == server
|
40
|
-
@clients.add stream.accept
|
39
|
+
if stream == @welcome
|
40
|
+
join stream.accept
|
41
41
|
|
42
42
|
elsif (stream.eof? rescue true)
|
43
|
-
|
43
|
+
part stream
|
44
44
|
|
45
|
-
elsif @command = hear(stream, stream.gets)
|
45
|
+
elsif @command = hear(stream, stream.gets) and not @command.empty?
|
46
46
|
recv stream, @command
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
51
|
-
ensure
|
52
|
-
# UNIX domain socket files are not deleted automatically upon closing
|
53
|
-
File.delete @address if File.socket? @address
|
54
51
|
end
|
55
52
|
|
56
53
|
def quit
|
@@ -59,6 +56,14 @@ class Server
|
|
59
56
|
|
60
57
|
protected
|
61
58
|
|
59
|
+
def join client
|
60
|
+
@clients.add client
|
61
|
+
end
|
62
|
+
|
63
|
+
def part client
|
64
|
+
@clients.delete client
|
65
|
+
end
|
66
|
+
|
62
67
|
# Returns nil if the message received was not meant for processing.
|
63
68
|
def hear sender, message
|
64
69
|
JSON.load message
|
@@ -73,7 +78,9 @@ protected
|
|
73
78
|
end
|
74
79
|
end
|
75
80
|
|
81
|
+
# Sets the @client variable to the client we are currently serving.
|
76
82
|
def recv client, command
|
83
|
+
@client = client
|
77
84
|
__send__(*command)
|
78
85
|
rescue => error
|
79
86
|
tell client, error
|
@@ -93,7 +100,7 @@ protected
|
|
93
100
|
end
|
94
101
|
|
95
102
|
targets =
|
96
|
-
if one_or_more_clients.
|
103
|
+
if one_or_more_clients.respond_to? :to_io
|
97
104
|
[one_or_more_clients]
|
98
105
|
else
|
99
106
|
Array(one_or_more_clients)
|
@@ -113,26 +120,13 @@ protected
|
|
113
120
|
end
|
114
121
|
|
115
122
|
def popen command
|
116
|
-
child =
|
123
|
+
child = Bridge.new(command)
|
117
124
|
@servers.add child
|
118
125
|
child
|
119
126
|
end
|
120
127
|
|
121
128
|
def pclose child
|
122
|
-
|
123
|
-
|
124
|
-
# this should be enough to stop programs that use Tork::Server#loop
|
125
|
-
# because their IO.select() loop terminates on the closing of STDIN
|
126
|
-
child.close_write
|
127
|
-
|
128
|
-
# but some programs like tork-herald(1) need to be killed explicitly
|
129
|
-
# because they do not follow our convention of exiting on STDIN close
|
130
|
-
Process.kill :SIGTERM, child.pid
|
131
|
-
Process.waitpid child.pid
|
132
|
-
|
133
|
-
# this will block until the child process has exited so we must kill it
|
134
|
-
# explicitly (as above) to ensure that this program does not hang here
|
135
|
-
child.close_read
|
129
|
+
child.disconnect if @servers.delete? child
|
136
130
|
end
|
137
131
|
|
138
132
|
end
|