spring 1.0.0 → 1.1.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 +4 -4
- data/.travis.yml +2 -0
- data/CHANGELOG.md +27 -0
- data/README.md +114 -45
- data/bin/spring +1 -0
- data/lib/spring/application/boot.rb +16 -0
- data/lib/spring/application.rb +122 -60
- data/lib/spring/application_manager.rb +51 -40
- data/lib/spring/binstub.rb +13 -0
- data/lib/spring/boot.rb +8 -0
- data/lib/spring/client/binstub.rb +150 -39
- data/lib/spring/client/help.rb +4 -12
- data/lib/spring/client/rails.rb +1 -3
- data/lib/spring/client/version.rb +11 -0
- data/lib/spring/client.rb +8 -5
- data/lib/spring/command_wrapper.rb +86 -0
- data/lib/spring/commands/rails.rb +1 -2
- data/lib/spring/commands/rake.rb +0 -4
- data/lib/spring/commands.rb +3 -2
- data/lib/spring/configuration.rb +11 -2
- data/lib/spring/env.rb +10 -9
- data/lib/spring/server.rb +8 -36
- data/lib/spring/version.rb +1 -1
- data/lib/spring/watcher/abstract.rb +7 -8
- data/spring.gemspec +1 -1
- data/test/acceptance/app_test.rb +178 -355
- data/test/acceptance/helper.rb +329 -0
- data/test/unit/client/version_test.rb +14 -0
- data/test/unit/watcher_test.rb +12 -8
- metadata +13 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a2357648d0fc0f884098f352ab693e66556de6df
|
|
4
|
+
data.tar.gz: df070385ccdf9fbbb6d48770f21886dbab93516e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cc65ad0c92b3a134505805c9b8ed999029b49030ab0ca8e46473c47c18a6ff17804de47897a7493e28765dc3fa6dc18df2de5beb4be7b8f6bdf04bd979d2a7da
|
|
7
|
+
data.tar.gz: 1b408b559590cf9a1b13da2d390d191964809107edc00c4b67e6c54384d05df1a5f9673fcc796318e1962c1f3c4e9fd49141596a3692c80b831d9cc933dd67c5
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
## 1.1.0
|
|
2
|
+
|
|
3
|
+
* A `bin/spring` binstub is now generated. This allows us to load spring
|
|
4
|
+
correctly if you have it installed locally with a `BUNDLE_PATH`, so
|
|
5
|
+
it's no longer necessary to install spring system-wide. We also
|
|
6
|
+
activate the correct version from your Gemfile.lock. Note that you
|
|
7
|
+
still can't have spring in your Gemfile as a git repository or local
|
|
8
|
+
path; it must be a proper gem.
|
|
9
|
+
* Various changes to how springified binstubs are implemented. Existing
|
|
10
|
+
binstubs will continue to work, but it's recommended to run `spring binstub`
|
|
11
|
+
again to upgrade them to the new format.
|
|
12
|
+
* `spring binstub --remove` option added for removing spring from
|
|
13
|
+
binstubs. This won't work unless you have upgraded your binstubs to
|
|
14
|
+
the new format.
|
|
15
|
+
* `config/database.yml` is watched
|
|
16
|
+
* Better application restarts - if you introduce an error, for example
|
|
17
|
+
by editing `config/application.rb`, spring will now continue to watch
|
|
18
|
+
your files and will immediately try to restart the application when
|
|
19
|
+
you edit `config/application.rb` again (hopefully to correct the error).
|
|
20
|
+
This means that by the time you come to run a command the application
|
|
21
|
+
may well already be running.
|
|
22
|
+
* Gemfile changes are now gracefully handled. Previously they would
|
|
23
|
+
cause spring to simply quit, meaning that you'd incur the full startup
|
|
24
|
+
penalty on the next run. Now spring doesn't quit, and will try to load
|
|
25
|
+
up your new bundle in the background.
|
|
26
|
+
* Fix support for using spring with Rails engines/plugins
|
|
27
|
+
|
|
1
28
|
## 1.0.0
|
|
2
29
|
|
|
3
30
|
* Enterprise ready secret sauce added
|
data/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Spring
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.org/rails/spring)
|
|
4
|
+
[](http://badge.fury.io/rb/spring)
|
|
4
5
|
|
|
5
6
|
Spring is a Rails application preloader. It speeds up development by
|
|
6
7
|
keeping your application running in the background so you don't need to
|
|
@@ -15,24 +16,50 @@ boot it every time you run a test, rake task or migration.
|
|
|
15
16
|
|
|
16
17
|
## Compatibility
|
|
17
18
|
|
|
18
|
-
* Ruby versions: MRI 1.9.3, MRI 2.0.
|
|
19
|
+
* Ruby versions: MRI 1.9.3, MRI 2.0, MRI 2.1
|
|
19
20
|
* Rails versions: 3.2, 4.0
|
|
20
21
|
|
|
21
|
-
Spring makes extensive use of `Process
|
|
22
|
+
Spring makes extensive use of `Process.fork`, so won't be able to
|
|
22
23
|
provide a speed up on platforms which don't support forking (Windows, JRuby).
|
|
23
24
|
|
|
24
25
|
## Walkthrough
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
### Setup
|
|
28
|
+
|
|
29
|
+
Add spring to your Gemfile:
|
|
27
30
|
|
|
28
31
|
``` ruby
|
|
29
|
-
group :development
|
|
30
|
-
|
|
32
|
+
gem "spring", group: :development
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
It's recommended to 'springify' the executables in your `bin/`
|
|
36
|
+
directory:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
$ bundle install
|
|
40
|
+
$ bundle exec spring binstub --all
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This generates a `bin/spring` executable, and inserts a small snippet of
|
|
44
|
+
code into relevant existing executables. The snippet looks like this:
|
|
45
|
+
|
|
46
|
+
``` ruby
|
|
47
|
+
begin
|
|
48
|
+
load File.expand_path("../spring", __FILE__)
|
|
49
|
+
rescue LoadError
|
|
31
50
|
end
|
|
32
51
|
```
|
|
33
52
|
|
|
34
|
-
|
|
35
|
-
|
|
53
|
+
On platforms where spring is installed and supported, this snippet
|
|
54
|
+
hooks spring into the execution of commands. In other cases, the snippet
|
|
55
|
+
will just be silently ignored and the lines after it will be executed as
|
|
56
|
+
normal.
|
|
57
|
+
|
|
58
|
+
If you don't want to prefix every command you type with `bin/`, you
|
|
59
|
+
can [use direnv](https://github.com/zimbatm/direnv) to automatically add
|
|
60
|
+
`./bin` to your `PATH` when you `cd` into your application.
|
|
61
|
+
|
|
62
|
+
### Usage
|
|
36
63
|
|
|
37
64
|
For this walkthrough I've generated a new Rails application, and run
|
|
38
65
|
`rails generate scaffold posts name:string`.
|
|
@@ -40,7 +67,7 @@ For this walkthrough I've generated a new Rails application, and run
|
|
|
40
67
|
Let's run a test:
|
|
41
68
|
|
|
42
69
|
```
|
|
43
|
-
$ time
|
|
70
|
+
$ time bin/rake test test/functional/posts_controller_test.rb
|
|
44
71
|
Run options:
|
|
45
72
|
|
|
46
73
|
# Running tests:
|
|
@@ -60,7 +87,7 @@ That wasn't particularly fast because it was the first run, so spring
|
|
|
60
87
|
had to boot the application. It's now running:
|
|
61
88
|
|
|
62
89
|
```
|
|
63
|
-
$ spring status
|
|
90
|
+
$ bin/spring status
|
|
64
91
|
Spring is running:
|
|
65
92
|
|
|
66
93
|
26150 spring server | spring-demo-app | started 3 secs ago
|
|
@@ -70,7 +97,7 @@ Spring is running:
|
|
|
70
97
|
The next run is faster:
|
|
71
98
|
|
|
72
99
|
```
|
|
73
|
-
$ time
|
|
100
|
+
$ time bin/rake test test/functional/posts_controller_test.rb
|
|
74
101
|
Run options:
|
|
75
102
|
|
|
76
103
|
# Running tests:
|
|
@@ -86,20 +113,6 @@ user 0m0.276s
|
|
|
86
113
|
sys 0m0.059s
|
|
87
114
|
```
|
|
88
115
|
|
|
89
|
-
Writing `spring` before every command gets a bit tedious. Spring binstubs solve this:
|
|
90
|
-
|
|
91
|
-
```
|
|
92
|
-
$ spring binstub rake rails
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
This will generate `bin/rake` and `bin/rails`. They
|
|
96
|
-
replace any binstubs that you might already have in your `bin/`
|
|
97
|
-
directory. Check them in to source control.
|
|
98
|
-
|
|
99
|
-
If you don't want to prefix every command you type with `bin/`, you
|
|
100
|
-
can [use direnv](https://github.com/zimbatm/direnv) to automatically add
|
|
101
|
-
`./bin` to your `PATH` when you `cd` into your application.
|
|
102
|
-
|
|
103
116
|
If we edit any of the application files, or test files, the changes will
|
|
104
117
|
be picked up on the next run without the background process having to
|
|
105
118
|
restart. This works in exactly the same way as the code reloading
|
|
@@ -114,7 +127,7 @@ Let's "edit" `config/application.rb`:
|
|
|
114
127
|
|
|
115
128
|
```
|
|
116
129
|
$ touch config/application.rb
|
|
117
|
-
$ spring status
|
|
130
|
+
$ bin/spring status
|
|
118
131
|
Spring is running:
|
|
119
132
|
|
|
120
133
|
26150 spring server | spring-demo-app | started 36 secs ago
|
|
@@ -137,7 +150,7 @@ edit_post GET /posts/:id/edit(.:format) posts#edit
|
|
|
137
150
|
PUT /posts/:id(.:format) posts#update
|
|
138
151
|
DELETE /posts/:id(.:format) posts#destroy
|
|
139
152
|
|
|
140
|
-
$ spring status
|
|
153
|
+
$ bin/spring status
|
|
141
154
|
Spring is running:
|
|
142
155
|
|
|
143
156
|
26150 spring server | spring-demo-app | started 1 min ago
|
|
@@ -150,25 +163,18 @@ when you close your terminal. However if you do want to do a manual shut
|
|
|
150
163
|
down, use the `stop` command:
|
|
151
164
|
|
|
152
165
|
```
|
|
153
|
-
$ spring stop
|
|
166
|
+
$ bin/spring stop
|
|
154
167
|
Spring stopped.
|
|
155
168
|
```
|
|
156
169
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
The following commands are shipped by default.
|
|
170
|
+
### Removal
|
|
160
171
|
|
|
161
|
-
|
|
162
|
-
[`lib/spring/commands/`](https://github.com/jonleighton/spring/blob/master/lib/spring/commands/)
|
|
163
|
-
for examples.
|
|
172
|
+
To remove spring:
|
|
164
173
|
|
|
165
|
-
|
|
174
|
+
* 'Unspring' your bin/ executables: `bin/spring binstub --remove --all`
|
|
175
|
+
* Remove spring from your Gemfile
|
|
166
176
|
|
|
167
|
-
|
|
168
|
-
* [spring-commands-cucumber](https://github.com/jonleighton/spring-commands-cucumber)
|
|
169
|
-
* [spring-commands-testunit](https://github.com/jonleighton/spring-commands-testunit) - useful for
|
|
170
|
-
running `Test::Unit` tests on Rails 3, since only Rails 4 allows you
|
|
171
|
-
to use `rake test path/to/test` to run a particular test/directory.
|
|
177
|
+
## Commands
|
|
172
178
|
|
|
173
179
|
### `rake`
|
|
174
180
|
|
|
@@ -194,6 +200,74 @@ a different sub command (e.g. `rails server`) then spring will automatically
|
|
|
194
200
|
pass it through to the underlying `rails` executable (without the
|
|
195
201
|
speed-up).
|
|
196
202
|
|
|
203
|
+
### Additional commands
|
|
204
|
+
|
|
205
|
+
You can add these to your Gemfile for additional commands (run `spring stop` afterwards
|
|
206
|
+
to pick up the changes):
|
|
207
|
+
|
|
208
|
+
* [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)
|
|
209
|
+
* [spring-commands-cucumber](https://github.com/jonleighton/spring-commands-cucumber)
|
|
210
|
+
* [spring-commands-testunit](https://github.com/jonleighton/spring-commands-testunit) - useful for
|
|
211
|
+
running `Test::Unit` tests on Rails 3, since only Rails 4 allows you
|
|
212
|
+
to use `rake test path/to/test` to run a particular test/directory.
|
|
213
|
+
|
|
214
|
+
## Use without adding to bundle
|
|
215
|
+
|
|
216
|
+
If you don't want spring-related code checked into your source
|
|
217
|
+
repository, it's possible to use spring without adding to your Gemfile.
|
|
218
|
+
However, using spring binstubs without adding spring to the Gemfile is not
|
|
219
|
+
supported.
|
|
220
|
+
|
|
221
|
+
To use spring like this, do a `gem install spring` and then prefix
|
|
222
|
+
commands with `spring`. For example, rather than running `bin/rake -T`,
|
|
223
|
+
you'd run `spring rake -T`.
|
|
224
|
+
|
|
225
|
+
## Temporarily disabling Spring
|
|
226
|
+
|
|
227
|
+
If you're using Spring binstubs, but temporarily don't want commands to
|
|
228
|
+
run through Spring, set the `DISABLE_SPRING` environment variable.
|
|
229
|
+
|
|
230
|
+
## Class reloading
|
|
231
|
+
|
|
232
|
+
Spring uses Rails' class reloading mechanism
|
|
233
|
+
(`ActiveSupport::Dependencies`) to keep your code up to date between
|
|
234
|
+
test runs. This is the same mechanism which allows you to see changes
|
|
235
|
+
during development when you refresh the page. However, you may never
|
|
236
|
+
have used this mechanism with your `test` environment before, and this
|
|
237
|
+
can cause problems.
|
|
238
|
+
|
|
239
|
+
It's important to realise that code reloading means that the constants
|
|
240
|
+
in your application are *different objects* after files have changed:
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
$ bin/rails runner 'puts User.object_id'
|
|
244
|
+
70127987886040
|
|
245
|
+
$ touch app/models/user.rb
|
|
246
|
+
$ bin/rails runner 'puts User.object_id'
|
|
247
|
+
70127976764620
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Suppose you have an initializer `config/initializers/save_user_class.rb`
|
|
251
|
+
like so:
|
|
252
|
+
|
|
253
|
+
``` ruby
|
|
254
|
+
USER_CLASS = User
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
This saves off the *first* version of the `User` class, which will not
|
|
258
|
+
be the same object as `User` after the code has been reloaded:
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
$ bin/rails runner 'puts User == USER_CLASS'
|
|
262
|
+
true
|
|
263
|
+
$ touch app/models/user.rb
|
|
264
|
+
$ bin/rails runner 'puts User == USER_CLASS'
|
|
265
|
+
false
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
So to avoid this problem, don't save off references to application
|
|
269
|
+
constants in your initialization code.
|
|
270
|
+
|
|
197
271
|
## Configuration
|
|
198
272
|
|
|
199
273
|
Spring will read `~/.spring.rb` and `config/spring.rb` for custom
|
|
@@ -222,11 +296,6 @@ which get run when your application initializers, such as
|
|
|
222
296
|
`config/application.rb`, `config/environments/*.rb` or
|
|
223
297
|
`config/initializers/*.rb`.
|
|
224
298
|
|
|
225
|
-
For example, if loading your test helper is slow, you might like to
|
|
226
|
-
preload it to speed up your test runs. To do this you could put a
|
|
227
|
-
`require Rails.root.join("test/helper")` in
|
|
228
|
-
`config/environments/test.rb`.
|
|
229
|
-
|
|
230
299
|
### Running code after forking
|
|
231
300
|
|
|
232
301
|
You might want to run code after Spring forked off the process but
|
data/bin/spring
CHANGED
|
@@ -21,6 +21,7 @@ if defined?(Gem)
|
|
|
21
21
|
|
|
22
22
|
if unstubbed.any?
|
|
23
23
|
warn "Warning: Running `gem pristine --all` to regenerate your installed gemspecs " \
|
|
24
|
+
"(and deleting then reinstalling your bundle if you use bundle --path) " \
|
|
24
25
|
"will improve the startup performance of Spring."
|
|
25
26
|
end
|
|
26
27
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require "spring/application"
|
|
2
|
+
|
|
3
|
+
app = Spring::Application.new(
|
|
4
|
+
UNIXSocket.for_fd(3),
|
|
5
|
+
Spring::JSON.load(ENV.delete("SPRING_ORIGINAL_ENV").dup)
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
Signal.trap("TERM") { app.terminate }
|
|
9
|
+
Signal.trap("TTOU", "IGNORE")
|
|
10
|
+
|
|
11
|
+
Spring::ProcessTitleUpdater.run { |distance|
|
|
12
|
+
"spring app | #{app.app_name} | started #{distance} ago | #{app.app_env} mode"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
app.preload if ENV.delete("SPRING_PRELOAD") == "1"
|
|
16
|
+
app.run
|
data/lib/spring/application.rb
CHANGED
|
@@ -1,41 +1,83 @@
|
|
|
1
|
+
require "spring/boot"
|
|
1
2
|
require "set"
|
|
2
|
-
require "spring/watcher"
|
|
3
|
-
require "thread"
|
|
4
3
|
|
|
5
4
|
module Spring
|
|
6
5
|
class Application
|
|
7
|
-
attr_reader :manager, :watcher, :spring_env
|
|
6
|
+
attr_reader :manager, :watcher, :spring_env, :original_env
|
|
7
|
+
|
|
8
|
+
def initialize(manager, original_env)
|
|
9
|
+
@manager = manager
|
|
10
|
+
@original_env = original_env
|
|
11
|
+
@spring_env = Env.new
|
|
12
|
+
@mutex = Mutex.new
|
|
13
|
+
@waiting = 0
|
|
14
|
+
@preloaded = false
|
|
15
|
+
@state = :initialized
|
|
16
|
+
@interrupt = IO.pipe
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def state(val)
|
|
20
|
+
return if exiting?
|
|
21
|
+
log "#{@state} -> #{val}"
|
|
22
|
+
@state = val
|
|
23
|
+
end
|
|
8
24
|
|
|
9
|
-
def
|
|
10
|
-
|
|
11
|
-
@
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
@exiting = false
|
|
25
|
+
def state!(val)
|
|
26
|
+
state val
|
|
27
|
+
@interrupt.last.write "."
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def app_env
|
|
31
|
+
ENV['RAILS_ENV']
|
|
32
|
+
end
|
|
18
33
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@fds = [manager, watcher.to_io]
|
|
34
|
+
def app_name
|
|
35
|
+
spring_env.app_name
|
|
22
36
|
end
|
|
23
37
|
|
|
24
38
|
def log(message)
|
|
25
|
-
spring_env.log "[application:#{
|
|
39
|
+
spring_env.log "[application:#{app_env}] #{message}"
|
|
26
40
|
end
|
|
27
41
|
|
|
28
42
|
def preloaded?
|
|
29
43
|
@preloaded
|
|
30
44
|
end
|
|
31
45
|
|
|
46
|
+
def preload_failed?
|
|
47
|
+
@preloaded == :failure
|
|
48
|
+
end
|
|
49
|
+
|
|
32
50
|
def exiting?
|
|
33
|
-
@exiting
|
|
51
|
+
@state == :exiting
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def terminating?
|
|
55
|
+
@state == :terminating
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def watcher_stale?
|
|
59
|
+
@state == :watcher_stale
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def initialized?
|
|
63
|
+
@state == :initialized
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def start_watcher
|
|
67
|
+
@watcher = Spring.watcher
|
|
68
|
+
@watcher.on_stale { state! :watcher_stale }
|
|
69
|
+
@watcher.start
|
|
34
70
|
end
|
|
35
71
|
|
|
36
72
|
def preload
|
|
37
73
|
log "preloading app"
|
|
38
74
|
|
|
75
|
+
begin
|
|
76
|
+
require "spring/commands"
|
|
77
|
+
ensure
|
|
78
|
+
start_watcher
|
|
79
|
+
end
|
|
80
|
+
|
|
39
81
|
require Spring.application_root_path.join("config", "application")
|
|
40
82
|
|
|
41
83
|
# config/environments/test.rb will have config.cache_classes = true. However
|
|
@@ -51,44 +93,42 @@ module Spring
|
|
|
51
93
|
Rails.application.config.cache_classes = false
|
|
52
94
|
disconnect_database
|
|
53
95
|
|
|
96
|
+
@preloaded = :success
|
|
97
|
+
rescue Exception => e
|
|
98
|
+
@preloaded = :failure
|
|
99
|
+
watcher.add e.backtrace.map { |line| line.match(/^(.*)\:\d+\:in /)[1] }
|
|
100
|
+
raise e unless initialized?
|
|
101
|
+
ensure
|
|
54
102
|
watcher.add loaded_application_features
|
|
55
103
|
watcher.add Spring.gemfile, "#{Spring.gemfile}.lock"
|
|
56
|
-
watcher.add Rails.application.paths["config/initializers"]
|
|
57
104
|
|
|
58
|
-
|
|
105
|
+
if defined?(Rails)
|
|
106
|
+
watcher.add Rails.application.paths["config/initializers"]
|
|
107
|
+
watcher.add Rails.application.paths["config/database"]
|
|
108
|
+
end
|
|
59
109
|
end
|
|
60
110
|
|
|
61
111
|
def run
|
|
62
|
-
|
|
63
|
-
|
|
112
|
+
state :running
|
|
113
|
+
manager.puts
|
|
64
114
|
|
|
65
115
|
loop do
|
|
66
|
-
IO.select
|
|
67
|
-
|
|
68
|
-
if
|
|
69
|
-
|
|
70
|
-
manager.close
|
|
71
|
-
@exiting = true
|
|
72
|
-
try_exit
|
|
73
|
-
sleep
|
|
116
|
+
IO.select [manager, @interrupt.first]
|
|
117
|
+
|
|
118
|
+
if terminating? || watcher_stale? || preload_failed?
|
|
119
|
+
exit
|
|
74
120
|
else
|
|
75
121
|
serve manager.recv_io(UNIXSocket)
|
|
76
122
|
end
|
|
77
123
|
end
|
|
78
124
|
end
|
|
79
125
|
|
|
80
|
-
def try_exit
|
|
81
|
-
@mutex.synchronize {
|
|
82
|
-
exit if exiting? && @waiting == 0
|
|
83
|
-
}
|
|
84
|
-
end
|
|
85
|
-
|
|
86
126
|
def serve(client)
|
|
87
127
|
log "got client"
|
|
88
128
|
manager.puts
|
|
89
129
|
|
|
90
|
-
streams = 3.times.map { client.recv_io }
|
|
91
|
-
[STDOUT, STDERR].zip(
|
|
130
|
+
stdout, stderr, stdin = streams = 3.times.map { client.recv_io }
|
|
131
|
+
[STDOUT, STDERR].zip([stdout, stderr]).each { |a, b| a.reopen(b) }
|
|
92
132
|
|
|
93
133
|
preload unless preloaded?
|
|
94
134
|
|
|
@@ -105,33 +145,30 @@ module Spring
|
|
|
105
145
|
|
|
106
146
|
pid = fork {
|
|
107
147
|
Process.setsid
|
|
108
|
-
STDIN.reopen(
|
|
148
|
+
STDIN.reopen(stdin)
|
|
109
149
|
IGNORE_SIGNALS.each { |sig| trap(sig, "DEFAULT") }
|
|
150
|
+
trap("TERM", "DEFAULT")
|
|
110
151
|
|
|
111
152
|
ARGV.replace(args)
|
|
153
|
+
$0 = command.process_title
|
|
112
154
|
|
|
113
155
|
# Delete all env vars which are unchanged from before spring started
|
|
114
|
-
|
|
156
|
+
original_env.each { |k, v| ENV.delete k if ENV[k] == v }
|
|
115
157
|
|
|
116
158
|
# Load in the current env vars, except those which *were* changed when spring started
|
|
117
159
|
env.each { |k, v| ENV[k] ||= v }
|
|
118
160
|
|
|
161
|
+
# requiring is faster, and we don't need constant reloading in this process
|
|
162
|
+
ActiveSupport::Dependencies.mechanism = :require
|
|
163
|
+
Rails.application.config.cache_classes = true
|
|
164
|
+
|
|
119
165
|
connect_database
|
|
120
166
|
srand
|
|
121
167
|
|
|
122
168
|
invoke_after_fork_callbacks
|
|
123
169
|
shush_backtraces
|
|
124
170
|
|
|
125
|
-
|
|
126
|
-
command.call
|
|
127
|
-
else
|
|
128
|
-
exec_name = command.exec_name
|
|
129
|
-
gem_name = command.gem_name if command.respond_to?(:gem_name)
|
|
130
|
-
|
|
131
|
-
exec = Gem.bin_path(gem_name || exec_name, exec_name)
|
|
132
|
-
$0 = exec
|
|
133
|
-
load exec
|
|
134
|
-
end
|
|
171
|
+
command.call
|
|
135
172
|
}
|
|
136
173
|
|
|
137
174
|
disconnect_database
|
|
@@ -152,26 +189,44 @@ module Spring
|
|
|
152
189
|
client.close
|
|
153
190
|
|
|
154
191
|
@mutex.synchronize { @waiting -= 1 }
|
|
155
|
-
|
|
192
|
+
exit_if_finished
|
|
156
193
|
}
|
|
157
194
|
|
|
158
|
-
rescue => e
|
|
195
|
+
rescue Exception => e
|
|
159
196
|
log "exception: #{e}"
|
|
160
|
-
|
|
161
|
-
|
|
197
|
+
manager.puts unless pid
|
|
198
|
+
|
|
199
|
+
if streams && !e.is_a?(SystemExit)
|
|
200
|
+
print_exception(stderr, e)
|
|
201
|
+
streams.each(&:close)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
client.puts(1) if pid
|
|
162
205
|
client.close
|
|
163
|
-
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def terminate
|
|
209
|
+
state! :terminating
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def exit
|
|
213
|
+
state :exiting
|
|
214
|
+
manager.shutdown(:RDWR)
|
|
215
|
+
exit_if_finished
|
|
216
|
+
sleep
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def exit_if_finished
|
|
220
|
+
@mutex.synchronize {
|
|
221
|
+
Kernel.exit if exiting? && @waiting == 0
|
|
222
|
+
}
|
|
164
223
|
end
|
|
165
224
|
|
|
166
225
|
# The command might need to require some files in the
|
|
167
226
|
# main process so that they are cached. For example a test command wants to
|
|
168
227
|
# load the helper file once and have it cached.
|
|
169
228
|
def setup(command)
|
|
170
|
-
|
|
171
|
-
@setup << command.class
|
|
172
|
-
|
|
173
|
-
if command.respond_to?(:setup)
|
|
174
|
-
command.setup
|
|
229
|
+
if command.setup
|
|
175
230
|
watcher.add loaded_application_features # loaded features may have changed
|
|
176
231
|
end
|
|
177
232
|
end
|
|
@@ -183,7 +238,8 @@ module Spring
|
|
|
183
238
|
end
|
|
184
239
|
|
|
185
240
|
def loaded_application_features
|
|
186
|
-
|
|
241
|
+
root = Spring.application_root_path.to_s
|
|
242
|
+
$LOADED_FEATURES.select { |f| f.start_with?(root) }
|
|
187
243
|
end
|
|
188
244
|
|
|
189
245
|
def disconnect_database
|
|
@@ -211,5 +267,11 @@ module Spring
|
|
|
211
267
|
end
|
|
212
268
|
end
|
|
213
269
|
end
|
|
270
|
+
|
|
271
|
+
def print_exception(stream, error)
|
|
272
|
+
first, rest = error.backtrace.first, error.backtrace.drop(1)
|
|
273
|
+
stream.puts("#{first}: #{error} (#{error.class})")
|
|
274
|
+
rest.each { |line| stream.puts("\tfrom #{line}") }
|
|
275
|
+
end
|
|
214
276
|
end
|
|
215
277
|
end
|