spring 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,6 @@
1
1
  require "rbconfig"
2
2
  require "socket"
3
3
  require "pty"
4
- require "io/console"
5
4
 
6
5
  require "spring/version"
7
6
  require "spring/sid"
@@ -16,6 +15,8 @@ class Spring
16
15
  "-e", "Spring::Server.boot"
17
16
  ]
18
17
 
18
+ FORWARDED_SIGNALS = %w(INT QUIT USR1 USR2 INFO)
19
+
19
20
  def self.run(args)
20
21
  exit new.run(args)
21
22
  end
@@ -58,13 +59,6 @@ class Spring
58
59
  server.send_io client
59
60
  server.puts rails_env_for(args.first)
60
61
 
61
- status = server.read(1)
62
-
63
- server.close
64
- client.close
65
-
66
- return false unless status == "0"
67
-
68
62
  application.send_io STDOUT
69
63
  application.send_io STDERR
70
64
  application.send_io stdin_slave
@@ -76,13 +70,25 @@ class Spring
76
70
  application.write arg
77
71
  end
78
72
 
79
- # FIXME: receive exit status from server
80
- application.read
81
- true
73
+ pid = server.gets.chomp
74
+
75
+ # We must not close the client socket until we are sure that the application has
76
+ # received the FD. Otherwise the FD can end up getting closed while it's in the server
77
+ # socket buffer on OS X. This doesn't happen on Linux.
78
+ client.close
79
+
80
+ if pid.empty?
81
+ false
82
+ else
83
+ forward_signals(pid.to_i)
84
+ application.read # FIXME: receive exit status from server
85
+ true
86
+ end
82
87
  rescue Errno::ECONNRESET
83
88
  false
84
89
  ensure
85
90
  application.close if application
91
+ server.close if server
86
92
  end
87
93
 
88
94
  private
@@ -97,21 +103,24 @@ class Spring
97
103
  end
98
104
  end
99
105
 
100
- # FIXME: need to make special chars (e.g. arrow keys) work
101
106
  def stdin_slave
102
107
  master, slave = PTY.open
103
- master.raw!
104
108
 
105
- Thread.new {
106
- until STDIN.closed?
107
- # This makes special chars work, but has some weird side-effects that
108
- # I need to figure out.
109
- # master.write STDIN.getch
109
+ # Sadly I cannot find a way to achieve this without shelling out to stty, or
110
+ # using a C extension library. [Ruby does not have direct support for calling
111
+ # tcsetattr().] We don't want to use a C extension library so
112
+ # that spring can be used by Rails in the future.
113
+ system "stty -icanon -echo"
114
+ at_exit { system "stty sane" }
110
115
 
111
- master.write STDIN.read(1)
112
- end
113
- }
116
+ Thread.new { master.write STDIN.read(1) until STDIN.closed? }
114
117
 
115
118
  slave
116
119
  end
120
+
121
+ def forward_signals(pid)
122
+ (FORWARDED_SIGNALS & Signal.list.keys).each do |sig|
123
+ trap(sig) { Process.kill(sig, pid) }
124
+ end
125
+ end
117
126
  end
@@ -21,7 +21,9 @@ class Spring
21
21
 
22
22
  @stdout = IO.new(STDOUT.fileno)
23
23
  @stderr = IO.new(STDERR.fileno)
24
- @stdin = IO.new(STDIN.fileno)
24
+ @stdin = File.open('/dev/null', 'r')
25
+
26
+ STDIN.reopen(@stdin)
25
27
  end
26
28
 
27
29
  def start
@@ -46,17 +48,7 @@ class Spring
46
48
  def run
47
49
  loop do
48
50
  watch_application
49
-
50
- client = manager.recv_io(UNIXSocket)
51
-
52
- # Confirm that we have received the client socket. This is necessary on OS X
53
- # to prevent a timing error. The client needs to keep the FD that we are receiving
54
- # open until it has been received here. Unlike on Linux, it's not sufficient for
55
- # the FD to just be in the socket buffer, it has to actually get received at this
56
- # end before it can be closed by the client.
57
- manager.puts
58
-
59
- serve client
51
+ serve manager.recv_io(UNIXSocket)
60
52
  end
61
53
  end
62
54
 
@@ -77,7 +69,13 @@ class Spring
77
69
  ActionDispatch::Reloader.cleanup!
78
70
  ActionDispatch::Reloader.prepare!
79
71
 
80
- Process.wait(fork { command.call(args) })
72
+ pid = fork {
73
+ IGNORE_SIGNALS.each { |sig| trap(sig, "DEFAULT") }
74
+ command.call(args)
75
+ }
76
+
77
+ manager.puts pid
78
+ Process.wait pid
81
79
  end
82
80
  ensure
83
81
  client.puts
@@ -29,10 +29,7 @@ class Spring
29
29
  @pid
30
30
  end
31
31
 
32
- # The return value of this method indicates whether or not the application
33
- # successfully received the client. It might not successfully receive the
34
- # client if e.g. the application has an exception during initialization, causing
35
- # the application process to die.
32
+ # Returns the pid of the process running the command, or nil if the application process died.
36
33
  def run(client)
37
34
  @client = client
38
35
 
@@ -49,11 +46,11 @@ class Spring
49
46
  start
50
47
  child.send_io @client
51
48
  end
52
-
53
- child.gets
54
49
  end
50
+
51
+ child.gets.chomp.to_i # get the pid
55
52
  rescue Errno::ECONNRESET, Errno::EPIPE
56
- false
53
+ nil
57
54
  ensure
58
55
  @client.close
59
56
  @client = nil
@@ -3,6 +3,8 @@ require "spring/sid"
3
3
  require "fileutils"
4
4
 
5
5
  class Spring
6
+ IGNORE_SIGNALS = %w(INT QUIT)
7
+
6
8
  class Env
7
9
  attr_reader :root
8
10
 
@@ -18,9 +18,9 @@ class Spring
18
18
  end
19
19
 
20
20
  def boot
21
- # Ignore SIGINT, otherwise the user typing ^C on the command line
22
- # will kill the background server.
23
- trap("INT", "IGNORE")
21
+ # Ignore SIGINT and SIGQUIT otherwise the user typing ^C or ^\ on the command line
22
+ # will kill the server/application.
23
+ IGNORE_SIGNALS.each { |sig| trap(sig, "IGNORE") }
24
24
 
25
25
  set_exit_hook
26
26
  write_pidfile
@@ -33,11 +33,7 @@ class Spring
33
33
  app_client = client.recv_io
34
34
  rails_env = client.gets.chomp
35
35
 
36
- if @applications[rails_env].run(app_client)
37
- client.write "0"
38
- else
39
- client.write "1"
40
- end
36
+ client.puts @applications[rails_env].run(app_client)
41
37
  end
42
38
 
43
39
  def set_exit_hook
@@ -1,3 +1,3 @@
1
1
  class Spring
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spring
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-11 00:00:00.000000000 Z
12
+ date: 2013-01-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport