spring 0.9.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 38ac640c7514d41f28205416b110496f5ddb14d2
4
- data.tar.gz: 89b956912fee2b1b75e20c9f06986c33671a4b27
3
+ metadata.gz: a2357648d0fc0f884098f352ab693e66556de6df
4
+ data.tar.gz: df070385ccdf9fbbb6d48770f21886dbab93516e
5
5
  SHA512:
6
- metadata.gz: 1251675f9d073842dc030e0855161594a31807b80ef64b530d2b8a759b9c6bf075a3cb6eb330e108b19483dcb8fb5d50a19a7e0be7a5c777d55326c56577e767
7
- data.tar.gz: a96b76e7742eda3aa9a07ce69f6dc6d6f9de1d6bed809a2b7fc2f165dc49c282214015c229f21e9a157024bc14a4c3a81b2edd596377cee93f7dad70527a0cde
6
+ metadata.gz: cc65ad0c92b3a134505805c9b8ed999029b49030ab0ca8e46473c47c18a6ff17804de47897a7493e28765dc3fa6dc18df2de5beb4be7b8f6bdf04bd979d2a7da
7
+ data.tar.gz: 1b408b559590cf9a1b13da2d390d191964809107edc00c4b67e6c54384d05df1a5f9673fcc796318e1962c1f3c4e9fd49141596a3692c80b831d9cc933dd67c5
data/.travis.yml CHANGED
@@ -2,6 +2,8 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
+ - 2.1.0
5
6
  env:
6
7
  - RAILS_VERSION="~> 3.2.0"
7
8
  - RAILS_VERSION="~> 4.0.0"
9
+ - RAILS_VERSION="~> 4.1.0.beta1"
data/CHANGELOG.md CHANGED
@@ -1,3 +1,54 @@
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
+
28
+ ## 1.0.0
29
+
30
+ * Enterprise ready secret sauce added
31
+
32
+ ## 0.9.2
33
+
34
+ * Bugfix: environment variables set by bundler (`BUNDLE_GEMFILE`,
35
+ `RUBYOPT`, etc...) were being removed from the environment.
36
+ * Ensure we only run the code reloader when files have actually changed.
37
+ This issue became more prominent with Rails 4, since Rails 4 will now
38
+ reload routes whenever the code is reloaded (see
39
+ https://github.com/rails/rails/commit/b9b06daa915fdc4d11e8cfe11a7175e5cd8f104f).
40
+ * Allow spring to be used in a descendant directory of the application
41
+ root
42
+ * Use the system tmpdir for our temporary files. Previously we used
43
+ `APP_ROOT/tmp/spring`, which caused problems on filesystems which did
44
+ not support sockets, and also caused problems if `APP_ROOT` was
45
+ sufficiently deep in the filesystem to exhaust the operating system's
46
+ socket name limit. Hence we had a `SPRING_TMP_PATH` environment
47
+ variable for configuration. We now use `/tmp/spring/[md5(APP_ROOT)]`
48
+ for the socket and `/tmp/spring/[md5(APP_ROOT)].pid` for the pid file.
49
+ Thanks @Kriechi for the suggestion. Setting `SPRING_TMP_PATH` no longer
50
+ has any effect.
51
+
1
52
  ## 0.9.1
2
53
 
3
54
  * Environment variables which were created during application startup are no
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Spring
2
2
 
3
- [![Build Status](https://travis-ci.org/jonleighton/spring.png?branch=master)](https://travis-ci.org/jonleighton/spring)
3
+ [![Build Status](https://travis-ci.org/rails/spring.png?branch=master)](https://travis-ci.org/rails/spring)
4
+ [![Gem Version](https://badge.fury.io/rb/spring.png)](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.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#fork`, so won't be able to
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
- Either `gem install spring` or add it to your Gemfile:
27
+ ### Setup
28
+
29
+ Add spring to your Gemfile:
30
+
31
+ ``` ruby
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:
27
45
 
28
46
  ``` ruby
29
- group :development do
30
- gem "spring"
47
+ begin
48
+ load File.expand_path("../spring", __FILE__)
49
+ rescue LoadError
31
50
  end
32
51
  ```
33
52
 
34
- Spring is designed to be used *without* bundle exec, so use `spring
35
- [command]` rather than `bundle exec spring [command]`.
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 spring rake test test/functional/posts_controller_test.rb
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 spring rake test test/functional/posts_controller_test.rb
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
- ## Commands
170
+ ### Removal
158
171
 
159
- The following commands are shipped by default.
172
+ To remove spring:
160
173
 
161
- Custom commands can be specified in the Spring config file. See
162
- [`lib/spring/commands/`](https://github.com/jonleighton/spring/blob/master/lib/spring/commands/)
163
- for examples.
174
+ * 'Unspring' your bin/ executables: `bin/spring binstub --remove --all`
175
+ * Remove spring from your Gemfile
164
176
 
165
- You can also install the following gems for additional commands:
166
-
167
- * [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)
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,13 +200,82 @@ 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
200
274
  settings. Note that `~/.spring.rb` is loaded *before* bundler, but
201
- `config/spring.rb` is loaded *after* bundler. This means that in
202
- `~/.spring.rb` you are able to load extra commands without them having
203
- to be in the bundle of the project you are working on.
275
+ `config/spring.rb` is loaded *after* bundler. So if you have any
276
+ `spring-commands-*` gems installed that you want to be available in all
277
+ projects without having to be added to the project's Gemfile, require
278
+ them in your `~/.spring.rb`.
204
279
 
205
280
  ### Application root
206
281
 
@@ -221,11 +296,6 @@ which get run when your application initializers, such as
221
296
  `config/application.rb`, `config/environments/*.rb` or
222
297
  `config/initializers/*.rb`.
223
298
 
224
- For example, if loading your test helper is slow, you might like to
225
- preload it to speed up your test runs. To do this you could put a
226
- `require Rails.root.join("test/helper")` in
227
- `config/environments/test.rb`.
228
-
229
299
  ### Running code after forking
230
300
 
231
301
  You might want to run code after Spring forked off the process but
@@ -264,11 +334,6 @@ Spring.watch_method = :listen
264
334
 
265
335
  You may need to add the [`listen` gem](https://github.com/guard/listen) to your `Gemfile`.
266
336
 
267
- ### tmp directory
268
-
269
- Spring needs a tmp directory. This will default to `Rails.root.join('tmp', 'spring')`.
270
- You can set your own configuration directory by setting the `SPRING_TMP_PATH` environment variable.
271
-
272
337
  ## Troubleshooting
273
338
 
274
339
  If you want to get more information about what spring is doing, you can
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
@@ -1,42 +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 initialize(manager, watcher = Spring.watcher)
10
- @manager = manager
11
- @watcher = watcher
12
- @setup = Set.new
13
- @spring_env = Env.new
14
- @preloaded = false
15
- @mutex = Mutex.new
16
- @waiting = 0
17
- @exiting = false
18
- @env_keys = ENV.keys
25
+ def state!(val)
26
+ state val
27
+ @interrupt.last.write "."
28
+ end
29
+
30
+ def app_env
31
+ ENV['RAILS_ENV']
32
+ end
19
33
 
20
- # Workaround for GC bug in Ruby 2 which causes segfaults if watcher.to_io
21
- # instances get dereffed.
22
- @fds = [manager, watcher.to_io]
34
+ def app_name
35
+ spring_env.app_name
23
36
  end
24
37
 
25
38
  def log(message)
26
- spring_env.log "[application:#{ENV['RAILS_ENV']}] #{message}"
39
+ spring_env.log "[application:#{app_env}] #{message}"
27
40
  end
28
41
 
29
42
  def preloaded?
30
43
  @preloaded
31
44
  end
32
45
 
46
+ def preload_failed?
47
+ @preloaded == :failure
48
+ end
49
+
33
50
  def exiting?
34
- @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
35
70
  end
36
71
 
37
72
  def preload
38
73
  log "preloading app"
39
74
 
75
+ begin
76
+ require "spring/commands"
77
+ ensure
78
+ start_watcher
79
+ end
80
+
40
81
  require Spring.application_root_path.join("config", "application")
41
82
 
42
83
  # config/environments/test.rb will have config.cache_classes = true. However
@@ -52,44 +93,42 @@ module Spring
52
93
  Rails.application.config.cache_classes = false
53
94
  disconnect_database
54
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
55
102
  watcher.add loaded_application_features
56
103
  watcher.add Spring.gemfile, "#{Spring.gemfile}.lock"
57
- watcher.add Rails.application.paths["config/initializers"]
58
104
 
59
- @preloaded = true
105
+ if defined?(Rails)
106
+ watcher.add Rails.application.paths["config/initializers"]
107
+ watcher.add Rails.application.paths["config/database"]
108
+ end
60
109
  end
61
110
 
62
111
  def run
63
- log "running"
64
- watcher.start
112
+ state :running
113
+ manager.puts
65
114
 
66
115
  loop do
67
- IO.select(@fds)
68
-
69
- if watcher.stale?
70
- log "watcher stale; exiting"
71
- manager.close
72
- @exiting = true
73
- try_exit
74
- sleep
116
+ IO.select [manager, @interrupt.first]
117
+
118
+ if terminating? || watcher_stale? || preload_failed?
119
+ exit
75
120
  else
76
121
  serve manager.recv_io(UNIXSocket)
77
122
  end
78
123
  end
79
124
  end
80
125
 
81
- def try_exit
82
- @mutex.synchronize {
83
- exit if exiting? && @waiting == 0
84
- }
85
- end
86
-
87
126
  def serve(client)
88
127
  log "got client"
89
128
  manager.puts
90
129
 
91
- streams = 3.times.map { client.recv_io }
92
- [STDOUT, STDERR].zip(streams).each { |a, b| a.reopen(b) }
130
+ stdout, stderr, stdin = streams = 3.times.map { client.recv_io }
131
+ [STDOUT, STDERR].zip([stdout, stderr]).each { |a, b| a.reopen(b) }
93
132
 
94
133
  preload unless preloaded?
95
134
 
@@ -99,17 +138,29 @@ module Spring
99
138
  connect_database
100
139
  setup command
101
140
 
102
- ActionDispatch::Reloader.cleanup!
103
- ActionDispatch::Reloader.prepare!
141
+ if Rails.application.reloaders.any?(&:updated?)
142
+ ActionDispatch::Reloader.cleanup!
143
+ ActionDispatch::Reloader.prepare!
144
+ end
104
145
 
105
146
  pid = fork {
106
147
  Process.setsid
107
- STDIN.reopen(streams.last)
148
+ STDIN.reopen(stdin)
108
149
  IGNORE_SIGNALS.each { |sig| trap(sig, "DEFAULT") }
150
+ trap("TERM", "DEFAULT")
109
151
 
110
152
  ARGV.replace(args)
111
- @env_keys.each { |k| ENV.delete k }
112
- ENV.update(env)
153
+ $0 = command.process_title
154
+
155
+ # Delete all env vars which are unchanged from before spring started
156
+ original_env.each { |k, v| ENV.delete k if ENV[k] == v }
157
+
158
+ # Load in the current env vars, except those which *were* changed when spring started
159
+ env.each { |k, v| ENV[k] ||= v }
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
113
164
 
114
165
  connect_database
115
166
  srand
@@ -117,16 +168,7 @@ module Spring
117
168
  invoke_after_fork_callbacks
118
169
  shush_backtraces
119
170
 
120
- if command.respond_to?(:call)
121
- command.call
122
- else
123
- exec_name = command.exec_name
124
- gem_name = command.gem_name if command.respond_to?(:gem_name)
125
-
126
- exec = Gem.bin_path(gem_name || exec_name, exec_name)
127
- $0 = exec
128
- load exec
129
- end
171
+ command.call
130
172
  }
131
173
 
132
174
  disconnect_database
@@ -147,26 +189,44 @@ module Spring
147
189
  client.close
148
190
 
149
191
  @mutex.synchronize { @waiting -= 1 }
150
- try_exit
192
+ exit_if_finished
151
193
  }
152
194
 
153
- rescue => e
195
+ rescue Exception => e
154
196
  log "exception: #{e}"
155
- streams.each(&:close) if streams
156
- client.puts(1)
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
157
205
  client.close
158
- raise
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
+ }
159
223
  end
160
224
 
161
225
  # The command might need to require some files in the
162
226
  # main process so that they are cached. For example a test command wants to
163
227
  # load the helper file once and have it cached.
164
228
  def setup(command)
165
- return if @setup.include?(command.class)
166
- @setup << command.class
167
-
168
- if command.respond_to?(:setup)
169
- command.setup
229
+ if command.setup
170
230
  watcher.add loaded_application_features # loaded features may have changed
171
231
  end
172
232
  end
@@ -178,7 +238,8 @@ module Spring
178
238
  end
179
239
 
180
240
  def loaded_application_features
181
- $LOADED_FEATURES.select { |f| f.start_with?(File.realpath(Rails.root)) }
241
+ root = Spring.application_root_path.to_s
242
+ $LOADED_FEATURES.select { |f| f.start_with?(root) }
182
243
  end
183
244
 
184
245
  def disconnect_database
@@ -206,5 +267,11 @@ module Spring
206
267
  end
207
268
  end
208
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
209
276
  end
210
277
  end