daemon 1.1.0 → 1.2.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/Gemfile +4 -9
- data/Gemfile.lock +18 -18
- data/README.rdoc +9 -1
- data/Rakefile +1 -14
- data/VERSION +1 -1
- data/daemon.gemspec +12 -18
- data/lib/daemon.rb +89 -16
- data/spec/daemon_spec.rb +271 -12
- metadata +62 -103
data/Gemfile
CHANGED
@@ -1,15 +1,10 @@
|
|
1
|
-
source
|
2
|
-
# Add dependencies required to use your gem here.
|
3
|
-
# Example:
|
4
|
-
# gem "activesupport", ">= 2.3.5"
|
1
|
+
source 'http://rubygems.org'
|
5
2
|
|
6
3
|
# Add dependencies to develop your gem here.
|
7
4
|
# Include everything needed to run rake, tests, features, etc.
|
8
5
|
group :development do
|
9
|
-
gem
|
10
|
-
gem
|
11
|
-
gem
|
12
|
-
gem "jeweler", "~> 1.6.4"
|
13
|
-
gem "rcov", ">= 0"
|
6
|
+
gem 'rspec', '~> 2.13'
|
7
|
+
gem 'jeweler', '~> 1.8.4'
|
8
|
+
gem 'rdoc', '~> 3.9'
|
14
9
|
end
|
15
10
|
|
data/Gemfile.lock
CHANGED
@@ -1,30 +1,30 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
diff-lcs (1.
|
4
|
+
diff-lcs (1.2.4)
|
5
5
|
git (1.2.5)
|
6
|
-
jeweler (1.
|
6
|
+
jeweler (1.8.4)
|
7
7
|
bundler (~> 1.0)
|
8
8
|
git (>= 1.2.5)
|
9
9
|
rake
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
rspec-
|
20
|
-
|
10
|
+
rdoc
|
11
|
+
json (1.7.7)
|
12
|
+
rake (10.0.4)
|
13
|
+
rdoc (3.12.2)
|
14
|
+
json (~> 1.4)
|
15
|
+
rspec (2.13.0)
|
16
|
+
rspec-core (~> 2.13.0)
|
17
|
+
rspec-expectations (~> 2.13.0)
|
18
|
+
rspec-mocks (~> 2.13.0)
|
19
|
+
rspec-core (2.13.1)
|
20
|
+
rspec-expectations (2.13.0)
|
21
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
22
|
+
rspec-mocks (2.13.1)
|
21
23
|
|
22
24
|
PLATFORMS
|
23
25
|
ruby
|
24
26
|
|
25
27
|
DEPENDENCIES
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
rspec (~> 2.3.0)
|
30
|
-
shoulda
|
28
|
+
jeweler (~> 1.8.4)
|
29
|
+
rdoc (~> 3.9)
|
30
|
+
rspec (~> 2.13)
|
data/README.rdoc
CHANGED
@@ -24,8 +24,16 @@ So full usage may look like this:
|
|
24
24
|
Daemon.daemonize('myscript.pid', 'out.log')
|
25
25
|
end
|
26
26
|
|
27
|
+
To spawn a daemon process and keep current process runing:
|
28
|
+
|
29
|
+
pid, wait = Daemon.daemonize('myscript.pid', 'out.log') do |log|
|
30
|
+
# daemon code
|
31
|
+
end
|
32
|
+
|
33
|
+
wait.value # wait for daemon to finish; returns Process::Status
|
34
|
+
|
27
35
|
== Contributing to daemon
|
28
|
-
|
36
|
+
|
29
37
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
30
38
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
31
39
|
* Fork the project
|
data/Rakefile
CHANGED
@@ -31,22 +31,9 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
31
31
|
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
32
|
end
|
33
33
|
|
34
|
-
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
-
spec.rcov = true
|
37
|
-
end
|
38
|
-
|
39
|
-
require 'rcov/rcovtask'
|
40
|
-
Rcov::RcovTask.new do |test|
|
41
|
-
test.libs << 'test'
|
42
|
-
test.pattern = 'test/**/test_*.rb'
|
43
|
-
test.verbose = true
|
44
|
-
test.rcov_opts << '--exclude "gems/*"'
|
45
|
-
end
|
46
|
-
|
47
34
|
task :default => :spec
|
48
35
|
|
49
|
-
require '
|
36
|
+
require 'rdoc/task'
|
50
37
|
Rake::RDocTask.new do |rdoc|
|
51
38
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
52
39
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
data/daemon.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "daemon"
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jakub Pastuszek"]
|
12
|
-
s.date = "
|
12
|
+
s.date = "2014-09-01"
|
13
13
|
s.description = "Make calling script to become a daemon with pid file locking support and stdout/stderr redirection"
|
14
14
|
s.email = "jpastuszek@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -32,31 +32,25 @@ Gem::Specification.new do |s|
|
|
32
32
|
s.homepage = "http://github.com/jpastuszek/daemon"
|
33
33
|
s.licenses = ["MIT"]
|
34
34
|
s.require_paths = ["lib"]
|
35
|
-
s.rubygems_version = "1.8.
|
35
|
+
s.rubygems_version = "1.8.23"
|
36
36
|
s.summary = "Daemonize your script with a single line of code"
|
37
37
|
|
38
38
|
if s.respond_to? :specification_version then
|
39
39
|
s.specification_version = 3
|
40
40
|
|
41
41
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
42
|
-
s.add_development_dependency(%q<rspec>, ["~> 2.
|
43
|
-
s.add_development_dependency(%q<
|
44
|
-
s.add_development_dependency(%q<
|
45
|
-
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
46
|
-
s.add_development_dependency(%q<rcov>, [">= 0"])
|
42
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.13"])
|
43
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
44
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.9"])
|
47
45
|
else
|
48
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
49
|
-
s.add_dependency(%q<
|
50
|
-
s.add_dependency(%q<
|
51
|
-
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
52
|
-
s.add_dependency(%q<rcov>, [">= 0"])
|
46
|
+
s.add_dependency(%q<rspec>, ["~> 2.13"])
|
47
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
48
|
+
s.add_dependency(%q<rdoc>, ["~> 3.9"])
|
53
49
|
end
|
54
50
|
else
|
55
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
56
|
-
s.add_dependency(%q<
|
57
|
-
s.add_dependency(%q<
|
58
|
-
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
59
|
-
s.add_dependency(%q<rcov>, [">= 0"])
|
51
|
+
s.add_dependency(%q<rspec>, ["~> 2.13"])
|
52
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
53
|
+
s.add_dependency(%q<rdoc>, ["~> 3.9"])
|
60
54
|
end
|
61
55
|
end
|
62
56
|
|
data/lib/daemon.rb
CHANGED
@@ -6,35 +6,108 @@ class Daemon
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.daemonize(pid_file, log_file = nil, sync = true)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
if block_given?
|
10
|
+
spawn do |send_ok, send_error|
|
11
|
+
log = begin
|
12
|
+
# try to lock before we kill stdin/out
|
13
|
+
lock(pid_file)
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
# close I/O
|
16
|
+
disconnect(log_file, sync)
|
17
|
+
rescue => error
|
18
|
+
send_error.call(error)
|
19
|
+
end
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
|
21
|
+
send_ok.call
|
22
|
+
|
23
|
+
yield log
|
24
|
+
end # => pid, wait
|
20
25
|
else
|
21
|
-
|
26
|
+
# become new process group leader
|
27
|
+
fence
|
28
|
+
|
29
|
+
# try to lock before we kill stdin/out
|
30
|
+
lock(pid_file)
|
31
|
+
|
32
|
+
# close I/O
|
33
|
+
disconnect(log_file, sync) # => log
|
22
34
|
end
|
35
|
+
end
|
23
36
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
37
|
+
def self.spawn
|
38
|
+
r, w = IO.pipe
|
39
|
+
|
40
|
+
pid = fence do
|
41
|
+
r.close
|
42
|
+
|
43
|
+
yield(
|
44
|
+
->{
|
45
|
+
w.write Marshal.dump(nil) # send OK to parent
|
46
|
+
w.close
|
47
|
+
},
|
48
|
+
->(error){
|
49
|
+
w.write Marshal.dump(error) # send error to parent
|
50
|
+
w.close
|
51
|
+
exit 42
|
52
|
+
}
|
53
|
+
)
|
54
|
+
end
|
55
|
+
thr = Process.detach(pid)
|
56
|
+
|
57
|
+
w.close
|
58
|
+
data = r.read
|
59
|
+
data.empty? and fail 'ok/error handler not called!'
|
60
|
+
|
61
|
+
if error = Marshal.load(data)
|
62
|
+
thr.join # wait for child to die
|
63
|
+
raise error
|
64
|
+
end
|
65
|
+
|
66
|
+
return pid, thr
|
67
|
+
ensure
|
68
|
+
w.close unless w.closed?
|
69
|
+
r.close
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.fence
|
73
|
+
if block_given?
|
74
|
+
fork do
|
75
|
+
Process.setsid # become new session leader
|
76
|
+
# now in child
|
77
|
+
yield
|
78
|
+
end # => pid
|
79
|
+
else
|
80
|
+
exit! 0 if fork
|
81
|
+
Process.setsid # become new session leader
|
82
|
+
# now in child
|
83
|
+
end
|
28
84
|
end
|
29
85
|
|
30
86
|
def self.lock(pid_file)
|
31
87
|
pf = File.open(pid_file, File::RDWR | File::CREAT)
|
32
|
-
raise LockError, pf unless pf.flock(File::LOCK_EX|File::LOCK_NB)
|
88
|
+
raise LockError, pf unless pf.flock(File::LOCK_EX | File::LOCK_NB)
|
33
89
|
pf.truncate(0)
|
34
90
|
pf.write(Process.pid.to_s + "\n")
|
35
91
|
pf.flush
|
36
92
|
|
37
93
|
@pf = pf # keep it open and locked until process exits
|
38
94
|
end
|
39
|
-
end
|
40
95
|
|
96
|
+
def self.disconnect(log_file = nil, sync = true)
|
97
|
+
if log_file
|
98
|
+
log = File.open(log_file, File::WRONLY | File::CREAT | File::APPEND | File::BINARY)
|
99
|
+
log.sync = sync
|
100
|
+
else
|
101
|
+
# don't raise on STDOUT/STDERR write
|
102
|
+
log = File.new('/dev/null', File::WRONLY | File::BINARY)
|
103
|
+
end
|
104
|
+
|
105
|
+
# disconnect
|
106
|
+
STDIN.close # raise IOError on STDIN.read
|
107
|
+
STDOUT.reopen log
|
108
|
+
STDERR.reopen log
|
109
|
+
|
110
|
+
# provide log IO
|
111
|
+
return log
|
112
|
+
end
|
113
|
+
end
|
data/spec/daemon_spec.rb
CHANGED
@@ -1,23 +1,282 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
require 'daemon'
|
3
|
-
|
4
|
-
|
3
|
+
require 'timeout'
|
4
|
+
require 'tempfile'
|
5
5
|
|
6
6
|
describe Daemon do
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
let! :pid_file do
|
8
|
+
Tempfile.new('daemon-pid')
|
9
|
+
end
|
10
|
+
|
11
|
+
let! :log_file do
|
12
|
+
Tempfile.new('daemon-log')
|
10
13
|
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
describe 'locking' do
|
16
|
+
it '#lock should create a pid file with current process pid' do
|
17
|
+
Daemon.lock(pid_file)
|
18
|
+
File.open(pid_file).read.should == "#{Process.pid}\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
it '#lock should raise error if called twice on same pid file' do
|
22
|
+
Daemon.lock(pid_file)
|
23
|
+
lambda {
|
24
|
+
Daemon.lock(pid_file)
|
25
|
+
}.should raise_error Daemon::LockError
|
26
|
+
end
|
17
27
|
end
|
18
28
|
|
19
|
-
|
20
|
-
|
29
|
+
describe 'forking' do
|
30
|
+
it 'forked sub process can be terminated with SIGHUP to whole process group' do
|
31
|
+
cr, cw = *IO.pipe
|
32
|
+
mr, mw = *IO.pipe
|
33
|
+
|
34
|
+
pid = fork do # parent
|
35
|
+
Process.setsid # start new process group
|
36
|
+
|
37
|
+
pid = fork do # child
|
38
|
+
loop{cr.readline and mw.puts 'pong'}
|
39
|
+
end
|
40
|
+
Process.wait(pid)
|
41
|
+
end
|
42
|
+
|
43
|
+
# close our end
|
44
|
+
mw.close
|
45
|
+
cr.close
|
46
|
+
|
47
|
+
# wait for the child to start
|
48
|
+
cw.puts 'ping'
|
49
|
+
mr.readline.strip.should == 'pong'
|
50
|
+
|
51
|
+
Process.kill('HUP', -pid) # kill the group; this should kill the child
|
52
|
+
Process.wait(pid) # parent exit
|
53
|
+
|
54
|
+
expect {
|
55
|
+
Timeout.timeout(2) do
|
56
|
+
# child is dead
|
57
|
+
cw.puts 'ping'
|
58
|
+
end
|
59
|
+
}.to raise_error Errno::EPIPE
|
60
|
+
end
|
61
|
+
|
62
|
+
it '#fence should start new process group to protect the process from HUP signal' do
|
63
|
+
cr, cw = *IO.pipe
|
64
|
+
mr, mw = *IO.pipe
|
65
|
+
|
66
|
+
pid = fork do # parent
|
67
|
+
Process.setsid # start new process group
|
68
|
+
|
69
|
+
Daemon.fence
|
70
|
+
|
71
|
+
# now in protected child
|
72
|
+
loop{cr.readline and mw.puts 'pong'}
|
73
|
+
end
|
74
|
+
Process.wait(pid) # parent exits
|
75
|
+
|
76
|
+
# close our end
|
77
|
+
mw.close
|
78
|
+
cr.close
|
79
|
+
|
80
|
+
# wait for the child to start
|
81
|
+
cw.puts 'ping'
|
82
|
+
mr.readline.strip.should == 'pong'
|
83
|
+
|
84
|
+
expect {
|
85
|
+
Process.kill('HUP', -pid)
|
86
|
+
# the group is gone with the parent process
|
87
|
+
}.to raise_error Errno::ESRCH
|
88
|
+
|
89
|
+
Timeout.timeout(2) do
|
90
|
+
# child still there
|
91
|
+
cw.puts 'ping'
|
92
|
+
mr.readline.strip.should == 'pong'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it '#fence with block should start new process group to protect the process from HUP signal calling provided block within it' do
|
97
|
+
cr, cw = *IO.pipe
|
98
|
+
mr, mw = *IO.pipe
|
99
|
+
|
100
|
+
pid = fork do # parent
|
101
|
+
Process.setsid # start new process group
|
102
|
+
|
103
|
+
pid = Daemon.fence do
|
104
|
+
# now in protected child
|
105
|
+
loop{cr.readline and mw.puts 'pong'}
|
106
|
+
end
|
107
|
+
|
108
|
+
Process.wait(pid)
|
109
|
+
end
|
110
|
+
|
111
|
+
# close our end
|
112
|
+
mw.close
|
113
|
+
cr.close
|
114
|
+
|
115
|
+
# wait for the child to start
|
116
|
+
cw.puts 'ping'
|
117
|
+
mr.readline.strip.should == 'pong'
|
118
|
+
|
119
|
+
Process.kill('HUP', -pid) # kill the group; this would kill the child
|
120
|
+
Process.wait(pid) # parent exit
|
121
|
+
|
122
|
+
Timeout.timeout(2) do
|
123
|
+
# child still there
|
124
|
+
cw.puts 'ping'
|
125
|
+
mr.readline.strip.should == 'pong'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it '#spawn should call block in fenced child process and return child pid and wait thread' do
|
130
|
+
pid, wait = Daemon.spawn do |send_ok, send_error|
|
131
|
+
send_ok.call
|
132
|
+
sleep 0.2
|
133
|
+
end
|
134
|
+
|
135
|
+
pid.should > 0
|
136
|
+
wait.should be_alive
|
137
|
+
|
138
|
+
wait.value.should be_success
|
139
|
+
end
|
140
|
+
|
141
|
+
it '#spawn should call block in fenced child process raising reported errors in master' do
|
142
|
+
expect {
|
143
|
+
Daemon.spawn do |send_ok, send_error|
|
144
|
+
begin
|
145
|
+
fail 'test'
|
146
|
+
rescue => error
|
147
|
+
send_error.call error
|
148
|
+
end
|
149
|
+
end
|
150
|
+
}.to raise_error RuntimeError, 'test'
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe 'IO handling' do
|
155
|
+
it '#disconnect should close STDIN and redirect STDIN and STDERR to given log file' do
|
156
|
+
pid = fork do
|
157
|
+
Daemon.disconnect(log_file)
|
158
|
+
|
159
|
+
puts 'hello world'
|
160
|
+
begin
|
161
|
+
STDIN.read # should raise
|
162
|
+
rescue IOError
|
163
|
+
puts 'foo bar'
|
164
|
+
end
|
165
|
+
end
|
166
|
+
Process.wait(pid)
|
167
|
+
|
168
|
+
log_file.readlines.map(&:strip).should == ['hello world', 'foo bar']
|
169
|
+
end
|
170
|
+
|
171
|
+
it '#disconnect should provide log file IO' do
|
172
|
+
pid = fork do
|
173
|
+
log = Daemon.disconnect(log_file)
|
174
|
+
log.puts 'hello world'
|
175
|
+
puts 'foo bar'
|
176
|
+
end
|
177
|
+
Process.wait(pid)
|
178
|
+
|
179
|
+
log_file.readlines.map(&:strip).should == ['hello world', 'foo bar']
|
180
|
+
end
|
181
|
+
|
182
|
+
it '#disconnect should provide /dev/null file IO when no log file specified' do
|
183
|
+
pid = fork do
|
184
|
+
log = Daemon.disconnect
|
185
|
+
log.puts 'foo bar'
|
186
|
+
log.path.should == '/dev/null'
|
187
|
+
end
|
188
|
+
|
189
|
+
Process.wait2(pid).last.should be_success
|
190
|
+
end
|
191
|
+
|
192
|
+
it '#disconnect should append log file' do
|
193
|
+
pid = fork do
|
194
|
+
Daemon.disconnect(log_file)
|
195
|
+
puts 'hello world'
|
196
|
+
end
|
197
|
+
Process.wait(pid)
|
198
|
+
|
199
|
+
pid = fork do
|
200
|
+
Daemon.disconnect(log_file)
|
201
|
+
puts 'foo bar'
|
202
|
+
end
|
203
|
+
|
204
|
+
Process.wait(pid)
|
205
|
+
log_file.readlines.map(&:strip).should == ['hello world', 'foo bar']
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
it '#deamonize should terminate current process while keeping the script running' do
|
210
|
+
log_file.open do |log|
|
211
|
+
|
212
|
+
pid = fork do
|
213
|
+
puts master_pid = Process.pid
|
214
|
+
Daemon.daemonize(pid_file, log_file, true)
|
215
|
+
Process.pid.should_not == master_pid
|
216
|
+
puts 'hello world'
|
217
|
+
end
|
218
|
+
|
219
|
+
Process.wait2(pid).last.should be_success # wait for master to go away (successfully)
|
220
|
+
|
221
|
+
log.readline.map(&:strip).should == ['hello world']
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
it '#deamonize should return log file IO' do
|
226
|
+
log_file.open do |log|
|
227
|
+
pid = fork do
|
228
|
+
log = Daemon.daemonize(pid_file, log_file, true)
|
229
|
+
log.puts 'hello world'
|
230
|
+
end
|
231
|
+
Process.wait2(pid).last.should be_success # wait for master to go away
|
232
|
+
|
233
|
+
log.readline.map(&:strip).should == ['hello world']
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
it '#daemonize with block should fork new process with pid file and log file and call block with log IO' do
|
238
|
+
pid, wait = Daemon.daemonize(pid_file, log_file) do |log|
|
239
|
+
log.puts 'hello world'
|
240
|
+
puts 'foo bar'
|
241
|
+
end
|
242
|
+
|
243
|
+
# wait for process to finish
|
244
|
+
wait.join
|
245
|
+
|
246
|
+
log_file.readlines.map(&:strip).should == ['hello world', 'foo bar']
|
247
|
+
end
|
248
|
+
|
249
|
+
it '#daemonize with block should raise error when lock file is busy' do
|
250
|
+
pid, wait = Daemon.daemonize(pid_file, log_file) do |log|
|
251
|
+
log.puts 'hello world'
|
252
|
+
puts 'foo bar'
|
253
|
+
sleep 1
|
254
|
+
end
|
255
|
+
|
256
|
+
expect {
|
257
|
+
Daemon.daemonize(pid_file, log_file){|log|}
|
258
|
+
}.to raise_error Daemon::LockError
|
259
|
+
|
260
|
+
Process.kill('TERM', pid)
|
261
|
+
wait.join
|
262
|
+
|
263
|
+
log_file.readlines.map(&:strip).should == ['hello world', 'foo bar']
|
264
|
+
end
|
265
|
+
|
266
|
+
it '#daemnize should not call at_exit handler' do
|
267
|
+
pid = fork do
|
268
|
+
pid = Process.pid
|
269
|
+
at_exit do
|
270
|
+
fail 'at_exit called' if pid != Process.pid
|
271
|
+
end
|
272
|
+
|
273
|
+
fork do
|
274
|
+
Daemon.daemonize(pid_file, '/dev/stdout')
|
275
|
+
exit! # dont call at_exit
|
276
|
+
end
|
277
|
+
Process.wait
|
278
|
+
end
|
279
|
+
Process.wait2(pid).last.should be_success
|
21
280
|
end
|
22
281
|
end
|
23
282
|
|
metadata
CHANGED
@@ -1,108 +1,73 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: daemon
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 1
|
9
|
-
- 0
|
10
|
-
version: 1.1.0
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Jakub Pastuszek
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
requirement:
|
12
|
+
date: 2014-09-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
22
17
|
none: false
|
23
|
-
requirements:
|
18
|
+
requirements:
|
24
19
|
- - ~>
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
|
27
|
-
segments:
|
28
|
-
- 2
|
29
|
-
- 3
|
30
|
-
- 0
|
31
|
-
version: 2.3.0
|
32
|
-
version_requirements: *id001
|
33
|
-
name: rspec
|
34
|
-
prerelease: false
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.13'
|
35
22
|
type: :development
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
-
none: false
|
39
|
-
requirements:
|
40
|
-
- - ">="
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
hash: 3
|
43
|
-
segments:
|
44
|
-
- 0
|
45
|
-
version: "0"
|
46
|
-
version_requirements: *id002
|
47
|
-
name: shoulda
|
48
23
|
prerelease: false
|
49
|
-
|
50
|
-
- !ruby/object:Gem::Dependency
|
51
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
25
|
none: false
|
53
|
-
requirements:
|
26
|
+
requirements:
|
54
27
|
- - ~>
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
- 0
|
61
|
-
version: 1.0.0
|
62
|
-
version_requirements: *id003
|
63
|
-
name: bundler
|
64
|
-
prerelease: false
|
65
|
-
type: :development
|
66
|
-
- !ruby/object:Gem::Dependency
|
67
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.13'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: jeweler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
68
33
|
none: false
|
69
|
-
requirements:
|
34
|
+
requirements:
|
70
35
|
- - ~>
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
|
73
|
-
segments:
|
74
|
-
- 1
|
75
|
-
- 6
|
76
|
-
- 4
|
77
|
-
version: 1.6.4
|
78
|
-
version_requirements: *id004
|
79
|
-
name: jeweler
|
80
|
-
prerelease: false
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.8.4
|
81
38
|
type: :development
|
82
|
-
- !ruby/object:Gem::Dependency
|
83
|
-
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
-
none: false
|
85
|
-
requirements:
|
86
|
-
- - ">="
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
hash: 3
|
89
|
-
segments:
|
90
|
-
- 0
|
91
|
-
version: "0"
|
92
|
-
version_requirements: *id005
|
93
|
-
name: rcov
|
94
39
|
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.8.4
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rdoc
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.9'
|
95
54
|
type: :development
|
96
|
-
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.9'
|
62
|
+
description: Make calling script to become a daemon with pid file locking support
|
63
|
+
and stdout/stderr redirection
|
97
64
|
email: jpastuszek@gmail.com
|
98
65
|
executables: []
|
99
|
-
|
100
66
|
extensions: []
|
101
|
-
|
102
|
-
extra_rdoc_files:
|
67
|
+
extra_rdoc_files:
|
103
68
|
- LICENSE.txt
|
104
69
|
- README.rdoc
|
105
|
-
files:
|
70
|
+
files:
|
106
71
|
- .document
|
107
72
|
- Gemfile
|
108
73
|
- Gemfile.lock
|
@@ -115,37 +80,31 @@ files:
|
|
115
80
|
- spec/daemon_spec.rb
|
116
81
|
- spec/spec_helper.rb
|
117
82
|
homepage: http://github.com/jpastuszek/daemon
|
118
|
-
licenses:
|
83
|
+
licenses:
|
119
84
|
- MIT
|
120
85
|
post_install_message:
|
121
86
|
rdoc_options: []
|
122
|
-
|
123
|
-
require_paths:
|
87
|
+
require_paths:
|
124
88
|
- lib
|
125
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
90
|
none: false
|
127
|
-
requirements:
|
128
|
-
- -
|
129
|
-
- !ruby/object:Gem::Version
|
130
|
-
|
131
|
-
segments:
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
segments:
|
132
96
|
- 0
|
133
|
-
|
134
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
hash: -3235773960414260177
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
99
|
none: false
|
136
|
-
requirements:
|
137
|
-
- -
|
138
|
-
- !ruby/object:Gem::Version
|
139
|
-
|
140
|
-
segments:
|
141
|
-
- 0
|
142
|
-
version: "0"
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
143
104
|
requirements: []
|
144
|
-
|
145
105
|
rubyforge_project:
|
146
|
-
rubygems_version: 1.8.
|
106
|
+
rubygems_version: 1.8.23
|
147
107
|
signing_key:
|
148
108
|
specification_version: 3
|
149
109
|
summary: Daemonize your script with a single line of code
|
150
110
|
test_files: []
|
151
|
-
|