Skip to content

Commit ae175de

Browse files
committed
Prevent the user having to run spring stop after adding commands
Too many people are getting confused by this
1 parent 5cad689 commit ae175de

File tree

6 files changed

+81
-32
lines changed

6 files changed

+81
-32
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## Next version
22

3+
* Automatically restart spring after new commands are added. This means
4+
that you can add spring-commands-rspec to your Gemfile and then
5+
immediately start using it, without having to run `spring stop`.
6+
(Spring will effectively run `spring stop` for you.)
37
* Make app reloading work in apps which spew out lots of output on
48
startup (previously a buffer would fill up and cause the process to
59
hang). Issue #332.

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,7 @@ speed-up).
218218

219219
### Additional commands
220220

221-
You can add these to your Gemfile for additional commands (run `spring stop` afterwards
222-
to pick up the changes):
221+
You can add these to your Gemfile for additional commands:
223222

224223
* [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)
225224
* [spring-commands-cucumber](https://github.com/jonleighton/spring-commands-cucumber)

lib/spring/client/run.rb

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,54 @@ def server
2121
end
2222

2323
def call
24-
boot_server unless env.server_running?
24+
if env.server_running?
25+
warm_run
26+
else
27+
cold_run
28+
end
29+
rescue Errno::ECONNRESET
30+
exit 1
31+
ensure
32+
server.close if @server
33+
end
34+
35+
def warm_run
36+
run
37+
rescue CommandNotFound
38+
require "spring/commands"
39+
40+
if Spring.command?(args.first)
41+
# Command installed since spring started
42+
stop_server
43+
cold_run
44+
else
45+
raise
46+
end
47+
end
48+
49+
def cold_run
50+
boot_server
51+
run
52+
end
53+
54+
def run
2555
verify_server_version
2656

2757
application, client = UNIXSocket.pair
2858

2959
queue_signals
3060
connect_to_application(client)
3161
run_command(client, application)
32-
rescue Errno::ECONNRESET
33-
exit 1
34-
ensure
35-
server.close if @server
3662
end
3763

3864
def boot_server
3965
env.socket_path.unlink if env.socket_path.exist?
4066

41-
pid = fork {
42-
require "spring/server"
43-
Spring::Server.boot
44-
}
67+
pid = Process.spawn(
68+
"ruby",
69+
"-r", "spring/server",
70+
"-e", "Spring::Server.boot"
71+
)
4572

4673
until env.socket_path.exist?
4774
_, status = Process.waitpid2(pid, Process::WNOHANG)
@@ -50,6 +77,12 @@ def boot_server
5077
end
5178
end
5279

80+
def stop_server
81+
server.close
82+
@server = nil
83+
env.stop
84+
end
85+
5386
def verify_server_version
5487
server_version = server.gets.chomp
5588
if server_version != env.version

lib/spring/client/stop.rb

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,20 @@
33
module Spring
44
module Client
55
class Stop < Command
6-
TIMEOUT = 2 # seconds
7-
86
def self.description
97
"Stop all spring processes for this project."
108
end
119

1210
def call
13-
if env.server_running?
14-
timeout = Time.now + TIMEOUT
15-
kill 'TERM'
16-
sleep 0.1 until !env.server_running? || Time.now >= timeout
17-
18-
if env.server_running?
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
2517
puts "Spring is not running"
2618
end
2719
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
3520
end
3621
end
3722
end

lib/spring/env.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
module Spring
1111
IGNORE_SIGNALS = %w(INT QUIT)
12+
STOP_TIMEOUT = 2 # seconds
1213

1314
class Env
1415
attr_reader :log_file
@@ -80,5 +81,29 @@ def log(message)
8081
log_file.puts "[#{Time.now}] [#{Process.pid}] #{message}"
8182
log_file.flush
8283
end
84+
85+
def stop
86+
if server_running?
87+
timeout = Time.now + STOP_TIMEOUT
88+
kill 'TERM'
89+
sleep 0.1 until !server_running? || Time.now >= timeout
90+
91+
if server_running?
92+
kill 'KILL'
93+
:killed
94+
else
95+
:stopped
96+
end
97+
else
98+
:not_running
99+
end
100+
end
101+
102+
def kill(sig)
103+
pid = self.pid
104+
Process.kill(sig, pid) if pid
105+
rescue Errno::ESRCH
106+
# already dead
107+
end
83108
end
84109
end

lib/spring/test/acceptance_test.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ def self.omg
157157
end
158158

159159
test "custom commands" do
160+
# Start spring before setting up the command, to test that it gracefully upgrades itself
161+
assert_success "bin/rails runner ''"
162+
160163
File.write(app.spring_config, <<-CODE)
161164
class CustomCommand
162165
def call

0 commit comments

Comments
 (0)