Skip to content

Commit 6e0a6e8

Browse files
committed
Connect a PTY when preloading in background
Readline + libedit gets messed up if it loads when not connected to a terminal. This resolves that problem. Fixes #244.
1 parent 250edaa commit 6e0a6e8

File tree

3 files changed

+27
-6
lines changed

3 files changed

+27
-6
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
* Fix `$0` so that it is no longer prefixed with "spring ", as doing
44
this cause issues with rspec when running just `rspec` with no
55
arguments.
6+
* Ensure we're always connected to a tty when preloading the
7+
application in the background, in order to avoid loading issues
8+
with readline + libedit which affected pry-rails.
69

710
## 1.1.0
811

lib/spring/application.rb

+20-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require "spring/boot"
22
require "set"
3+
require "pty"
34

45
module Spring
56
class Application
@@ -108,6 +109,10 @@ def preload
108109
end
109110
end
110111

112+
def eager_preload
113+
with_pty { preload }
114+
end
115+
111116
def run
112117
state :running
113118
manager.puts
@@ -128,7 +133,7 @@ def serve(client)
128133
manager.puts
129134

130135
stdout, stderr, stdin = streams = 3.times.map { client.recv_io }
131-
[STDOUT, STDERR].zip([stdout, stderr]).each { |a, b| a.reopen(b) }
136+
[STDOUT, STDERR, STDIN].zip(streams).each { |a, b| a.reopen(b) }
132137

133138
preload unless preloaded?
134139

@@ -144,8 +149,6 @@ def serve(client)
144149
end
145150

146151
pid = fork {
147-
Process.setsid
148-
STDIN.reopen(stdin)
149152
IGNORE_SIGNALS.each { |sig| trap(sig, "DEFAULT") }
150153
trap("TERM", "DEFAULT")
151154

@@ -172,7 +175,7 @@ def serve(client)
172175
}
173176

174177
disconnect_database
175-
[STDOUT, STDERR].each { |stream| stream.reopen(spring_env.log_file) }
178+
reset_streams
176179

177180
log "forked #{pid}"
178181
manager.puts pid
@@ -273,5 +276,18 @@ def print_exception(stream, error)
273276
stream.puts("#{first}: #{error} (#{error.class})")
274277
rest.each { |line| stream.puts("\tfrom #{line}") }
275278
end
279+
280+
def with_pty
281+
PTY.open do |master, slave|
282+
[STDOUT, STDERR, STDIN].each { |s| s.reopen slave }
283+
yield
284+
reset_streams
285+
end
286+
end
287+
288+
def reset_streams
289+
[STDOUT, STDERR].each { |stream| stream.reopen(spring_env.log_file) }
290+
STDIN.reopen("/dev/null")
291+
end
276292
end
277293
end

lib/spring/application/boot.rb

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# This is necessary for the terminal to work correctly when we reopen stdin.
2+
Process.setsid
3+
14
require "spring/application"
25

36
app = Spring::Application.new(
@@ -6,11 +9,10 @@
69
)
710

811
Signal.trap("TERM") { app.terminate }
9-
Signal.trap("TTOU", "IGNORE")
1012

1113
Spring::ProcessTitleUpdater.run { |distance|
1214
"spring app | #{app.app_name} | started #{distance} ago | #{app.app_env} mode"
1315
}
1416

15-
app.preload if ENV.delete("SPRING_PRELOAD") == "1"
17+
app.eager_preload if ENV.delete("SPRING_PRELOAD") == "1"
1618
app.run

0 commit comments

Comments
 (0)