spring 1.2.0 → 4.7.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.
- checksums.yaml +5 -5
- data/LICENSE.txt +3 -2
- data/README.md +148 -42
- data/bin/spring +2 -1
- data/lib/spring/application/boot.rb +11 -4
- data/lib/spring/application.rb +178 -50
- data/lib/spring/application_manager.rb +17 -9
- data/lib/spring/boot.rb +2 -0
- data/lib/spring/client/binstub.rb +44 -45
- data/lib/spring/client/help.rb +1 -1
- data/lib/spring/client/rails.rb +6 -5
- data/lib/spring/client/run.rb +187 -41
- data/lib/spring/client/server.rb +18 -0
- data/lib/spring/client/status.rb +2 -2
- data/lib/spring/client/stop.rb +7 -22
- data/lib/spring/client.rb +11 -1
- data/lib/spring/command_wrapper.rb +0 -4
- data/lib/spring/commands/rails.rb +21 -0
- data/lib/spring/commands.rb +11 -4
- data/lib/spring/configuration.rb +49 -2
- data/lib/spring/env.rb +43 -12
- data/lib/spring/errors.rb +1 -1
- data/lib/spring/failsafe_thread.rb +14 -0
- data/lib/spring/json.rb +30 -33
- data/lib/spring/process_title_updater.rb +2 -2
- data/lib/spring/server.rb +45 -13
- data/lib/spring/version.rb +1 -1
- data/lib/spring/watcher/abstract.rb +44 -13
- data/lib/spring/watcher/polling.rb +48 -11
- data/lib/spring/watcher.rb +1 -1
- metadata +14 -71
- data/.gitignore +0 -19
- data/.travis.yml +0 -11
- data/CHANGELOG.md +0 -188
- data/CONTRIBUTING.md +0 -52
- data/Gemfile +0 -4
- data/Rakefile +0 -21
- data/lib/spring/sid.rb +0 -42
- data/lib/spring/test/acceptance_test.rb +0 -333
- data/lib/spring/test/application.rb +0 -217
- data/lib/spring/test/application_generator.rb +0 -121
- data/lib/spring/test/rails_version.rb +0 -40
- data/lib/spring/test/watcher_test.rb +0 -167
- data/lib/spring/test.rb +0 -15
- data/spring.gemspec +0 -23
- data/test/acceptance_test.rb +0 -4
- data/test/apps/.gitignore +0 -3
- data/test/helper.rb +0 -7
- data/test/unit/client/help_test.rb +0 -60
- data/test/unit/client/version_test.rb +0 -14
- data/test/unit/commands_test.rb +0 -59
- data/test/unit/process_title_updater_test.rb +0 -24
- data/test/unit/watcher_test.rb +0 -9
data/lib/spring/client/run.rb
CHANGED
|
@@ -1,27 +1,63 @@
|
|
|
1
1
|
require "rbconfig"
|
|
2
2
|
require "socket"
|
|
3
|
+
require "bundler"
|
|
3
4
|
|
|
4
5
|
module Spring
|
|
5
6
|
module Client
|
|
6
7
|
class Run < Command
|
|
7
|
-
FORWARDED_SIGNALS = %w(INT QUIT USR1 USR2 INFO) & Signal.list.keys
|
|
8
|
-
|
|
8
|
+
FORWARDED_SIGNALS = %w(INT QUIT USR1 USR2 INFO WINCH) & Signal.list.keys
|
|
9
|
+
ServerReadTimeout = Class.new(StandardError)
|
|
10
|
+
|
|
11
|
+
attr_reader :server
|
|
9
12
|
|
|
10
13
|
def initialize(args)
|
|
11
14
|
super
|
|
12
|
-
|
|
15
|
+
|
|
16
|
+
@signal_queue = []
|
|
17
|
+
@server_booted = false
|
|
13
18
|
end
|
|
14
19
|
|
|
15
20
|
def log(message)
|
|
16
21
|
env.log "[client] #{message}"
|
|
17
22
|
end
|
|
18
23
|
|
|
19
|
-
def
|
|
20
|
-
@server
|
|
24
|
+
def connect
|
|
25
|
+
@server = UNIXSocket.open(env.socket_name)
|
|
21
26
|
end
|
|
22
27
|
|
|
23
28
|
def call
|
|
24
|
-
|
|
29
|
+
begin
|
|
30
|
+
connect
|
|
31
|
+
rescue Errno::ENOENT, Errno::ECONNRESET, Errno::ECONNREFUSED
|
|
32
|
+
cold_run
|
|
33
|
+
else
|
|
34
|
+
warm_run
|
|
35
|
+
end
|
|
36
|
+
ensure
|
|
37
|
+
server.close if server
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def warm_run
|
|
41
|
+
run
|
|
42
|
+
rescue CommandNotFound
|
|
43
|
+
require "spring/commands"
|
|
44
|
+
|
|
45
|
+
if Spring.command?(args.first)
|
|
46
|
+
# Command installed since Spring started
|
|
47
|
+
stop_server
|
|
48
|
+
cold_run
|
|
49
|
+
else
|
|
50
|
+
raise
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def cold_run
|
|
55
|
+
boot_server
|
|
56
|
+
connect
|
|
57
|
+
run
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def run
|
|
25
61
|
verify_server_version
|
|
26
62
|
|
|
27
63
|
application, client = UNIXSocket.pair
|
|
@@ -31,43 +67,123 @@ module Spring
|
|
|
31
67
|
run_command(client, application)
|
|
32
68
|
rescue Errno::ECONNRESET
|
|
33
69
|
exit 1
|
|
34
|
-
ensure
|
|
35
|
-
server.close if @server
|
|
36
70
|
end
|
|
37
71
|
|
|
38
72
|
def boot_server
|
|
39
73
|
env.socket_path.unlink if env.socket_path.exist?
|
|
40
74
|
|
|
41
|
-
pid
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
75
|
+
pid = Process.spawn(server_process_env, env.server_command, out: File::NULL)
|
|
76
|
+
timeout = Time.now + Spring.boot_timeout
|
|
77
|
+
|
|
78
|
+
@server_booted = true
|
|
45
79
|
|
|
46
80
|
until env.socket_path.exist?
|
|
47
81
|
_, status = Process.waitpid2(pid, Process::WNOHANG)
|
|
48
|
-
|
|
82
|
+
|
|
83
|
+
if status
|
|
84
|
+
exit status.exitstatus
|
|
85
|
+
elsif Time.now > timeout
|
|
86
|
+
$stderr.puts "Starting Spring server with `#{env.server_command}` " \
|
|
87
|
+
"timed out after #{Spring.boot_timeout} seconds"
|
|
88
|
+
exit 1
|
|
89
|
+
end
|
|
90
|
+
|
|
49
91
|
sleep 0.1
|
|
50
92
|
end
|
|
51
93
|
end
|
|
52
94
|
|
|
95
|
+
def server_booted?
|
|
96
|
+
@server_booted
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def gem_env
|
|
100
|
+
bundle = Bundler.bundle_path.to_s
|
|
101
|
+
paths = Gem.path + ENV["GEM_PATH"].to_s.split(File::PATH_SEPARATOR)
|
|
102
|
+
|
|
103
|
+
{
|
|
104
|
+
"GEM_PATH" => [bundle, *paths].uniq.join(File::PATH_SEPARATOR),
|
|
105
|
+
"GEM_HOME" => bundle
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def reset_env
|
|
110
|
+
ENV.slice(*Spring.reset_on_env)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def server_process_env
|
|
114
|
+
reset_env.merge(gem_env)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def stop_server
|
|
118
|
+
server.close
|
|
119
|
+
@server = nil
|
|
120
|
+
env.stop
|
|
121
|
+
end
|
|
122
|
+
|
|
53
123
|
def verify_server_version
|
|
54
|
-
|
|
124
|
+
begin
|
|
125
|
+
line = read_server_line
|
|
126
|
+
rescue ServerReadTimeout
|
|
127
|
+
if waiting_for_server_boot?
|
|
128
|
+
begin
|
|
129
|
+
# Try again, but with same timeout as booting, as server might still be booting
|
|
130
|
+
# from another client starting it.
|
|
131
|
+
line = read_server_line(Spring.boot_timeout)
|
|
132
|
+
rescue ServerReadTimeout
|
|
133
|
+
reboot_or_raise_connection_error
|
|
134
|
+
return
|
|
135
|
+
end
|
|
136
|
+
else
|
|
137
|
+
reboot_or_raise_connection_error
|
|
138
|
+
return
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
if line.nil?
|
|
143
|
+
reboot_or_raise_connection_error
|
|
144
|
+
return
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
server_version = line.chomp
|
|
55
148
|
if server_version != env.version
|
|
56
|
-
$stderr.puts
|
|
57
|
-
|
|
58
|
-
You should restart the server and make sure to use the same version.
|
|
149
|
+
$stderr.puts "There is a version mismatch between the Spring client " \
|
|
150
|
+
"(#{env.version}) and the server (#{server_version})."
|
|
59
151
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
152
|
+
if server_booted?
|
|
153
|
+
$stderr.puts "We already tried to reboot the server, but the mismatch is still present."
|
|
154
|
+
exit 1
|
|
155
|
+
else
|
|
156
|
+
$stderr.puts "Restarting to resolve."
|
|
157
|
+
stop_server
|
|
158
|
+
cold_run
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def read_server_line(timeout = Spring.connect_timeout)
|
|
164
|
+
raise ServerReadTimeout if IO.select([server], [], [], timeout).nil?
|
|
165
|
+
|
|
166
|
+
server.gets
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def waiting_for_server_boot?
|
|
170
|
+
!server_booted? && env.server_running?
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def reboot_or_raise_connection_error
|
|
174
|
+
if server_booted?
|
|
175
|
+
raise "Error connecting to Spring server"
|
|
176
|
+
else
|
|
177
|
+
stop_server
|
|
178
|
+
cold_run
|
|
63
179
|
end
|
|
64
180
|
end
|
|
65
181
|
|
|
66
182
|
def connect_to_application(client)
|
|
67
183
|
server.send_io client
|
|
68
|
-
send_json server, "args" => args, "default_rails_env" => default_rails_env
|
|
184
|
+
send_json server, "args" => args, "default_rails_env" => default_rails_env, "spawn_env" => spawn_env, "reset_env" => reset_env
|
|
69
185
|
|
|
70
|
-
if IO.select([server], [], [],
|
|
186
|
+
if IO.select([server], [], [], Spring.connect_timeout)
|
|
71
187
|
server.gets or raise CommandNotFound
|
|
72
188
|
else
|
|
73
189
|
raise "Error connecting to Spring server"
|
|
@@ -75,12 +191,17 @@ ERROR
|
|
|
75
191
|
end
|
|
76
192
|
|
|
77
193
|
def run_command(client, application)
|
|
78
|
-
log "sending command"
|
|
79
|
-
|
|
80
194
|
application.send_io STDOUT
|
|
81
195
|
application.send_io STDERR
|
|
82
196
|
application.send_io STDIN
|
|
83
197
|
|
|
198
|
+
log "waiting for the application to be preloaded"
|
|
199
|
+
preload_status = application.gets
|
|
200
|
+
preload_status = preload_status.chomp if preload_status
|
|
201
|
+
log "app preload status: #{preload_status}"
|
|
202
|
+
exit 1 if preload_status == "1"
|
|
203
|
+
|
|
204
|
+
log "sending command"
|
|
84
205
|
send_json application, "args" => args, "env" => ENV.to_hash
|
|
85
206
|
|
|
86
207
|
pid = server.gets
|
|
@@ -94,12 +215,19 @@ ERROR
|
|
|
94
215
|
if pid && !pid.empty?
|
|
95
216
|
log "got pid: #{pid}"
|
|
96
217
|
|
|
97
|
-
|
|
98
|
-
|
|
218
|
+
suspend_resume_on_tstp_cont(pid)
|
|
219
|
+
|
|
220
|
+
forward_signals(application)
|
|
221
|
+
status = application.read
|
|
222
|
+
log "got exit status #{status.inspect}"
|
|
99
223
|
|
|
100
|
-
|
|
224
|
+
# Status should always be an integer. If it is empty, something unexpected must have happened to the server.
|
|
225
|
+
if status.to_s.strip.empty?
|
|
226
|
+
log "unexpected empty exit status, app crashed?"
|
|
227
|
+
exit 1
|
|
228
|
+
end
|
|
101
229
|
|
|
102
|
-
exit status
|
|
230
|
+
exit status.to_i
|
|
103
231
|
else
|
|
104
232
|
log "got no pid"
|
|
105
233
|
exit 1
|
|
@@ -114,26 +242,38 @@ ERROR
|
|
|
114
242
|
end
|
|
115
243
|
end
|
|
116
244
|
|
|
117
|
-
def
|
|
118
|
-
|
|
245
|
+
def suspend_resume_on_tstp_cont(pid)
|
|
246
|
+
trap("TSTP") {
|
|
247
|
+
log "suspended"
|
|
248
|
+
Process.kill("STOP", pid.to_i)
|
|
249
|
+
Process.kill("STOP", Process.pid)
|
|
250
|
+
}
|
|
251
|
+
trap("CONT") {
|
|
252
|
+
log "resumed"
|
|
253
|
+
Process.kill("CONT", pid.to_i)
|
|
254
|
+
}
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def forward_signals(application)
|
|
258
|
+
@signal_queue.each { |sig| kill sig, application }
|
|
119
259
|
|
|
120
260
|
FORWARDED_SIGNALS.each do |sig|
|
|
121
|
-
trap(sig) { forward_signal sig,
|
|
261
|
+
trap(sig) { forward_signal sig, application }
|
|
122
262
|
end
|
|
123
|
-
rescue Errno::ESRCH
|
|
124
263
|
end
|
|
125
264
|
|
|
126
|
-
def forward_signal(sig,
|
|
127
|
-
kill(sig,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
265
|
+
def forward_signal(sig, application)
|
|
266
|
+
if kill(sig, application) != 0
|
|
267
|
+
# If the application process is gone, then don't block the
|
|
268
|
+
# signal on this process.
|
|
269
|
+
trap(sig, 'DEFAULT')
|
|
270
|
+
Process.kill(sig, Process.pid)
|
|
271
|
+
end
|
|
133
272
|
end
|
|
134
273
|
|
|
135
|
-
def kill(sig,
|
|
136
|
-
|
|
274
|
+
def kill(sig, application)
|
|
275
|
+
application.puts(sig)
|
|
276
|
+
application.gets.to_i
|
|
137
277
|
end
|
|
138
278
|
|
|
139
279
|
def send_json(socket, data)
|
|
@@ -146,6 +286,12 @@ ERROR
|
|
|
146
286
|
def default_rails_env
|
|
147
287
|
ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
|
148
288
|
end
|
|
289
|
+
|
|
290
|
+
def spawn_env
|
|
291
|
+
Spring.spawn_on_env.to_h do |key|
|
|
292
|
+
[key, ENV[key]]
|
|
293
|
+
end
|
|
294
|
+
end
|
|
149
295
|
end
|
|
150
296
|
end
|
|
151
297
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Spring
|
|
2
|
+
module Client
|
|
3
|
+
class Server < Command
|
|
4
|
+
def self.description
|
|
5
|
+
"Explicitly start a Spring server in the foreground"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
require "spring/server"
|
|
10
|
+
Spring::Server.boot(foreground: foreground?)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def foreground?
|
|
14
|
+
!args.include?("--background")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/spring/client/status.rb
CHANGED
|
@@ -17,11 +17,11 @@ module Spring
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def print_process(pid)
|
|
20
|
-
puts `ps -p #{pid} -o pid= -o
|
|
20
|
+
puts `ps -p #{pid} -o pid= -o command=`
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def application_pids
|
|
24
|
-
candidates = `ps -
|
|
24
|
+
candidates = `ps -ax -o ppid= -o pid=`.lines
|
|
25
25
|
candidates.select { |l| l =~ /^(\s+)?#{env.pid} / }
|
|
26
26
|
.map { |l| l.split(" ").last }
|
|
27
27
|
end
|
data/lib/spring/client/stop.rb
CHANGED
|
@@ -3,35 +3,20 @@ require "spring/version"
|
|
|
3
3
|
module Spring
|
|
4
4
|
module Client
|
|
5
5
|
class Stop < Command
|
|
6
|
-
TIMEOUT = 2 # seconds
|
|
7
|
-
|
|
8
6
|
def self.description
|
|
9
|
-
"Stop all
|
|
7
|
+
"Stop all Spring processes for this project."
|
|
10
8
|
end
|
|
11
9
|
|
|
12
10
|
def call
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
$stderr.puts "Spring did not stop; killing forcibly."
|
|
20
|
-
kill 'KILL'
|
|
21
|
-
else
|
|
22
|
-
puts "Spring stopped."
|
|
23
|
-
end
|
|
24
|
-
else
|
|
11
|
+
case env.stop
|
|
12
|
+
when :stopped
|
|
13
|
+
puts "Spring stopped."
|
|
14
|
+
when :killed
|
|
15
|
+
$stderr.puts "Spring did not stop; killing forcibly."
|
|
16
|
+
when :not_running
|
|
25
17
|
puts "Spring is not running"
|
|
26
18
|
end
|
|
27
19
|
end
|
|
28
|
-
|
|
29
|
-
def kill(sig)
|
|
30
|
-
pid = env.pid
|
|
31
|
-
Process.kill(sig, pid) if pid
|
|
32
|
-
rescue Errno::ESRCH
|
|
33
|
-
# already dead
|
|
34
|
-
end
|
|
35
20
|
end
|
|
36
21
|
end
|
|
37
22
|
end
|
data/lib/spring/client.rb
CHANGED
|
@@ -9,17 +9,21 @@ require "spring/client/stop"
|
|
|
9
9
|
require "spring/client/status"
|
|
10
10
|
require "spring/client/rails"
|
|
11
11
|
require "spring/client/version"
|
|
12
|
+
require "spring/client/server"
|
|
12
13
|
|
|
13
14
|
module Spring
|
|
14
15
|
module Client
|
|
15
16
|
COMMANDS = {
|
|
16
17
|
"help" => Client::Help,
|
|
18
|
+
"-h" => Client::Help,
|
|
19
|
+
"--help" => Client::Help,
|
|
17
20
|
"binstub" => Client::Binstub,
|
|
18
21
|
"stop" => Client::Stop,
|
|
19
22
|
"status" => Client::Status,
|
|
20
23
|
"rails" => Client::Rails,
|
|
21
24
|
"-v" => Client::Version,
|
|
22
|
-
"--version" => Client::Version
|
|
25
|
+
"--version" => Client::Version,
|
|
26
|
+
"server" => Client::Server,
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
def self.run(args)
|
|
@@ -36,3 +40,9 @@ module Spring
|
|
|
36
40
|
end
|
|
37
41
|
end
|
|
38
42
|
end
|
|
43
|
+
|
|
44
|
+
# allow users to add hooks that do not run in the server
|
|
45
|
+
# or modify start/stop
|
|
46
|
+
if File.exist?("config/spring_client.rb")
|
|
47
|
+
require "./config/spring_client.rb"
|
|
48
|
+
end
|
|
@@ -83,9 +83,30 @@ module Spring
|
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
+
class RailsTest < Rails
|
|
87
|
+
def env(args)
|
|
88
|
+
environment = "test"
|
|
89
|
+
|
|
90
|
+
args.each.with_index do |arg, i|
|
|
91
|
+
if arg =~ /--environment=(\w+)/
|
|
92
|
+
environment = $1
|
|
93
|
+
elsif i > 0 && args[i - 1] == "-e"
|
|
94
|
+
environment = arg
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
environment
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def command_name
|
|
102
|
+
"test"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
86
106
|
Spring.register_command "rails_console", RailsConsole.new
|
|
87
107
|
Spring.register_command "rails_generate", RailsGenerate.new
|
|
88
108
|
Spring.register_command "rails_destroy", RailsDestroy.new
|
|
89
109
|
Spring.register_command "rails_runner", RailsRunner.new
|
|
110
|
+
Spring.register_command "rails_test", RailsTest.new
|
|
90
111
|
end
|
|
91
112
|
end
|
data/lib/spring/commands.rb
CHANGED
|
@@ -28,11 +28,18 @@ module Spring
|
|
|
28
28
|
config = File.expand_path("~/.spring.rb")
|
|
29
29
|
require config if File.exist?(config)
|
|
30
30
|
|
|
31
|
-
#
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
# We force the TTY so bundler doesn't show a backtrace in case gems are missing.
|
|
32
|
+
old_env = ENV["BUNDLER_FORCE_TTY"]
|
|
33
|
+
ENV["BUNDLER_FORCE_TTY"] = "true"
|
|
34
|
+
begin
|
|
35
|
+
# If the config/spring.rb contains requires for commands from other gems,
|
|
36
|
+
# then we need to be under bundler.
|
|
37
|
+
require "bundler/setup"
|
|
38
|
+
ensure
|
|
39
|
+
ENV["BUNDLER_FORCE_TTY"] = old_env
|
|
40
|
+
end
|
|
34
41
|
|
|
35
|
-
# Auto-require any
|
|
42
|
+
# Auto-require any Spring extensions which are in the Gemfile
|
|
36
43
|
Gem::Specification.map(&:name).grep(/^spring-/).each do |command|
|
|
37
44
|
begin
|
|
38
45
|
require command
|
data/lib/spring/configuration.rb
CHANGED
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
require "spring/errors"
|
|
2
2
|
|
|
3
3
|
module Spring
|
|
4
|
+
@connect_timeout = 5
|
|
5
|
+
@boot_timeout = 20
|
|
6
|
+
@dangerously_allow_disabling_reloading = false
|
|
7
|
+
|
|
4
8
|
class << self
|
|
5
|
-
attr_accessor :application_root
|
|
9
|
+
attr_accessor :application_root, :connect_timeout, :boot_timeout
|
|
10
|
+
attr_writer :quiet
|
|
11
|
+
|
|
12
|
+
# Opt-in: skip the `:ensure_reloading_is_enabled` initializer so Spring
|
|
13
|
+
# boots with `config.enable_reloading = false`. Default `false`. See
|
|
14
|
+
# README "Running Spring with reloading disabled" for what this gives up.
|
|
15
|
+
attr_accessor :dangerously_allow_disabling_reloading
|
|
6
16
|
|
|
7
17
|
def gemfile
|
|
8
|
-
|
|
18
|
+
require "bundler"
|
|
19
|
+
|
|
20
|
+
if /\s1.9.[0-9]/ === Bundler.ruby_scope.gsub(/[\/\s]+/,'')
|
|
21
|
+
Pathname.new(ENV["BUNDLE_GEMFILE"] || "Gemfile").expand_path
|
|
22
|
+
else
|
|
23
|
+
Bundler.default_gemfile
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def gemfile_lock
|
|
28
|
+
case gemfile.to_s
|
|
29
|
+
when /\bgems\.rb\z/
|
|
30
|
+
gemfile.sub_ext('.locked')
|
|
31
|
+
else
|
|
32
|
+
gemfile.sub_ext('.lock')
|
|
33
|
+
end
|
|
9
34
|
end
|
|
10
35
|
|
|
11
36
|
def after_fork_callbacks
|
|
@@ -16,6 +41,22 @@ module Spring
|
|
|
16
41
|
after_fork_callbacks << block
|
|
17
42
|
end
|
|
18
43
|
|
|
44
|
+
def after_environment_load_callbacks
|
|
45
|
+
@after_environment_load_callbacks ||= []
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def after_environment_load(&block)
|
|
49
|
+
after_environment_load_callbacks << block
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def spawn_on_env
|
|
53
|
+
@spawn_on_env ||= []
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def reset_on_env
|
|
57
|
+
@reset_on_env ||= []
|
|
58
|
+
end
|
|
59
|
+
|
|
19
60
|
def verify_environment
|
|
20
61
|
application_root_path
|
|
21
62
|
end
|
|
@@ -37,6 +78,10 @@ module Spring
|
|
|
37
78
|
@project_root_path ||= find_project_root(Pathname.new(File.expand_path(Dir.pwd)))
|
|
38
79
|
end
|
|
39
80
|
|
|
81
|
+
def quiet
|
|
82
|
+
@quiet || ENV.key?('SPRING_QUIET')
|
|
83
|
+
end
|
|
84
|
+
|
|
40
85
|
private
|
|
41
86
|
|
|
42
87
|
def find_project_root(current_dir)
|
|
@@ -49,4 +94,6 @@ module Spring
|
|
|
49
94
|
end
|
|
50
95
|
end
|
|
51
96
|
end
|
|
97
|
+
|
|
98
|
+
self.quiet = false
|
|
52
99
|
end
|
data/lib/spring/env.rb
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
require "pathname"
|
|
2
|
-
require "fileutils"
|
|
3
|
-
require "digest/md5"
|
|
4
|
-
require "tmpdir"
|
|
5
2
|
|
|
6
3
|
require "spring/version"
|
|
7
|
-
require "spring/sid"
|
|
8
4
|
require "spring/configuration"
|
|
9
5
|
|
|
10
6
|
module Spring
|
|
11
7
|
IGNORE_SIGNALS = %w(INT QUIT)
|
|
8
|
+
STOP_TIMEOUT = 2 # seconds
|
|
12
9
|
|
|
13
10
|
class Env
|
|
14
11
|
attr_reader :log_file
|
|
15
12
|
|
|
16
|
-
def initialize(
|
|
17
|
-
@root = root
|
|
18
|
-
@project_root = root
|
|
19
|
-
@log_file = File.open(ENV["SPRING_LOG"] || File::NULL, "a")
|
|
13
|
+
def initialize(options = {})
|
|
14
|
+
@root = options[:root]
|
|
15
|
+
@project_root = options[:root]
|
|
16
|
+
@log_file = options[:log_file] || File.open(ENV["SPRING_LOG"] || File::NULL, "a")
|
|
20
17
|
end
|
|
21
18
|
|
|
22
19
|
def root
|
|
@@ -32,17 +29,23 @@ module Spring
|
|
|
32
29
|
end
|
|
33
30
|
|
|
34
31
|
def tmp_path
|
|
35
|
-
|
|
32
|
+
require "tmpdir"
|
|
33
|
+
path = Pathname.new(
|
|
34
|
+
ENV["SPRING_TMP_PATH"] ||
|
|
35
|
+
File.join(ENV['XDG_RUNTIME_DIR'] || Dir.tmpdir, "spring-#{Process.uid}")
|
|
36
|
+
)
|
|
37
|
+
require "fileutils"
|
|
36
38
|
FileUtils.mkdir_p(path) unless path.exist?
|
|
37
39
|
path
|
|
38
40
|
end
|
|
39
41
|
|
|
40
42
|
def application_id
|
|
41
|
-
|
|
43
|
+
require "digest/md5"
|
|
44
|
+
ENV["SPRING_APPLICATION_ID"] || Digest::MD5.hexdigest(RUBY_VERSION + project_root.to_s)
|
|
42
45
|
end
|
|
43
46
|
|
|
44
47
|
def socket_path
|
|
45
|
-
tmp_path.join(application_id)
|
|
48
|
+
Pathname.new(ENV["SPRING_SOCKET"] || tmp_path.join(application_id))
|
|
46
49
|
end
|
|
47
50
|
|
|
48
51
|
def socket_name
|
|
@@ -50,7 +53,7 @@ module Spring
|
|
|
50
53
|
end
|
|
51
54
|
|
|
52
55
|
def pidfile_path
|
|
53
|
-
|
|
56
|
+
Pathname.new(ENV["SPRING_PIDFILE"] || socket_path.dirname.join("#{socket_path.basename(".*")}.pid"))
|
|
54
57
|
end
|
|
55
58
|
|
|
56
59
|
def pid
|
|
@@ -80,5 +83,33 @@ module Spring
|
|
|
80
83
|
log_file.puts "[#{Time.now}] [#{Process.pid}] #{message}"
|
|
81
84
|
log_file.flush
|
|
82
85
|
end
|
|
86
|
+
|
|
87
|
+
def stop
|
|
88
|
+
if server_running?
|
|
89
|
+
timeout = Time.now + STOP_TIMEOUT
|
|
90
|
+
kill 'TERM'
|
|
91
|
+
sleep 0.1 until !server_running? || Time.now >= timeout
|
|
92
|
+
|
|
93
|
+
if server_running?
|
|
94
|
+
kill 'KILL'
|
|
95
|
+
:killed
|
|
96
|
+
else
|
|
97
|
+
:stopped
|
|
98
|
+
end
|
|
99
|
+
else
|
|
100
|
+
:not_running
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def kill(sig)
|
|
105
|
+
pid = self.pid
|
|
106
|
+
Process.kill(sig, pid) if pid
|
|
107
|
+
rescue Errno::ESRCH
|
|
108
|
+
# already dead
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def server_command
|
|
112
|
+
ENV["SPRING_SERVER_COMMAND"] || "#{File.expand_path("../../../bin/spring", __FILE__)} server --background"
|
|
113
|
+
end
|
|
83
114
|
end
|
|
84
115
|
end
|
data/lib/spring/errors.rb
CHANGED
|
@@ -24,7 +24,7 @@ module Spring
|
|
|
24
24
|
|
|
25
25
|
def message
|
|
26
26
|
"Spring was unable to find your config/application.rb file. " \
|
|
27
|
-
"Your project root was detected at #{project_root}, so
|
|
27
|
+
"Your project root was detected at #{project_root}, so Spring " \
|
|
28
28
|
"looked for #{project_root}/config/application.rb but it doesn't exist. You can " \
|
|
29
29
|
"configure the root of your application by setting Spring.application_root in " \
|
|
30
30
|
"config/spring.rb."
|