spring-jruby 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +364 -0
  4. data/bin/spring +49 -0
  5. data/lib/spring-jruby/application.rb +283 -0
  6. data/lib/spring-jruby/application/boot.rb +19 -0
  7. data/lib/spring-jruby/binstub.rb +13 -0
  8. data/lib/spring-jruby/boot.rb +9 -0
  9. data/lib/spring-jruby/client.rb +46 -0
  10. data/lib/spring-jruby/client/binstub.rb +188 -0
  11. data/lib/spring-jruby/client/command.rb +18 -0
  12. data/lib/spring-jruby/client/help.rb +62 -0
  13. data/lib/spring-jruby/client/rails.rb +34 -0
  14. data/lib/spring-jruby/client/run.rb +167 -0
  15. data/lib/spring-jruby/client/status.rb +30 -0
  16. data/lib/spring-jruby/client/stop.rb +22 -0
  17. data/lib/spring-jruby/client/version.rb +11 -0
  18. data/lib/spring-jruby/command_wrapper.rb +82 -0
  19. data/lib/spring-jruby/commands.rb +51 -0
  20. data/lib/spring-jruby/commands/rails.rb +112 -0
  21. data/lib/spring-jruby/commands/rake.rb +30 -0
  22. data/lib/spring-jruby/configuration.rb +60 -0
  23. data/lib/spring-jruby/env.rb +109 -0
  24. data/lib/spring-jruby/errors.rb +36 -0
  25. data/lib/spring-jruby/impl/application.rb +7 -0
  26. data/lib/spring-jruby/impl/application_manager.rb +7 -0
  27. data/lib/spring-jruby/impl/fork/application.rb +69 -0
  28. data/lib/spring-jruby/impl/fork/application_manager.rb +137 -0
  29. data/lib/spring-jruby/impl/fork/run.rb +47 -0
  30. data/lib/spring-jruby/impl/pool/application.rb +47 -0
  31. data/lib/spring-jruby/impl/pool/application_manager.rb +226 -0
  32. data/lib/spring-jruby/impl/pool/run.rb +27 -0
  33. data/lib/spring-jruby/impl/run.rb +7 -0
  34. data/lib/spring-jruby/io_helpers.rb +92 -0
  35. data/lib/spring-jruby/json.rb +626 -0
  36. data/lib/spring-jruby/platform.rb +23 -0
  37. data/lib/spring-jruby/process_title_updater.rb +65 -0
  38. data/lib/spring-jruby/server.rb +130 -0
  39. data/lib/spring-jruby/sid.rb +42 -0
  40. data/lib/spring-jruby/test.rb +18 -0
  41. data/lib/spring-jruby/test/acceptance_test.rb +371 -0
  42. data/lib/spring-jruby/test/application.rb +217 -0
  43. data/lib/spring-jruby/test/application_generator.rb +134 -0
  44. data/lib/spring-jruby/test/rails_version.rb +40 -0
  45. data/lib/spring-jruby/test/watcher_test.rb +167 -0
  46. data/lib/spring-jruby/version.rb +3 -0
  47. data/lib/spring-jruby/watcher.rb +30 -0
  48. data/lib/spring-jruby/watcher/abstract.rb +86 -0
  49. data/lib/spring-jruby/watcher/polling.rb +61 -0
  50. metadata +137 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b99ce59145a28c1dc4d73025347f9158c552d467
4
+ data.tar.gz: bda2cd1aa00702f9f1076d0acaf2fac62e634912
5
+ SHA512:
6
+ metadata.gz: 47265df7a11d37b58319107153223527763fc7b5c35f46d8f1d03f2c9e657250659fae309eb213bda5d29d96c0d82e528aa3a42ab1fec0307e97a226f757ec1f
7
+ data.tar.gz: 92965eeb3c5c9ef83ef4b5761428ddb18b20bebbc5c3170308eb06ab5efefde6f470f788524bef5aebdbaccefeb5da48fd68041770d37e1c0e5af8aa1c5625f8
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Jon Leighton
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,364 @@
1
+ # Spring
2
+
3
+ [![Build Status](https://travis-ci.org/rails/spring.svg?branch=master)](https://travis-ci.org/rails/spring)
4
+ [![Gem Version](https://badge.fury.io/rb/spring.svg)](http://badge.fury.io/rb/spring)
5
+
6
+ Spring is a Rails application preloader. It speeds up development by
7
+ keeping your application running in the background so you don't need to
8
+ boot it every time you run a test, rake task or migration.
9
+
10
+ ## Features
11
+
12
+ * Totally automatic; no need to explicitly start and stop the background process
13
+ * Reloads your application code on each run
14
+ * Restarts your application when configs / initializers / gem
15
+ dependencies are changed
16
+
17
+ ## Compatibility
18
+
19
+ * Ruby versions: MRI 1.9.3, MRI 2.0, MRI 2.1
20
+ * Rails versions: 4.0+ (in Rails 4.1 and up Spring is included by default)
21
+
22
+ Spring makes extensive use of `Process.fork`, so won't be able to
23
+ provide a speed up on platforms which don't support forking (Windows, JRuby).
24
+
25
+ ## Walkthrough
26
+
27
+ ### Setup
28
+
29
+ Add spring to your Gemfile:
30
+
31
+ ``` ruby
32
+ gem "spring", group: :development
33
+ ```
34
+
35
+ (Note: using `gem "spring", git: "..."` *won't* work and is not a
36
+ supported way of using spring.)
37
+
38
+ It's recommended to 'springify' the executables in your `bin/`
39
+ directory:
40
+
41
+ ```
42
+ $ bundle install
43
+ $ bundle exec spring binstub --all
44
+ ```
45
+
46
+ This generates a `bin/spring` executable, and inserts a small snippet of
47
+ code into relevant existing executables. The snippet looks like this:
48
+
49
+ ``` ruby
50
+ begin
51
+ load File.expand_path('../spring', __FILE__)
52
+ rescue LoadError
53
+ end
54
+ ```
55
+
56
+ On platforms where spring is installed and supported, this snippet
57
+ hooks spring into the execution of commands. In other cases, the snippet
58
+ will just be silently ignored and the lines after it will be executed as
59
+ normal.
60
+
61
+ If you don't want to prefix every command you type with `bin/`, you
62
+ can [use direnv](https://github.com/zimbatm/direnv#the-stdlib) to
63
+ automatically add `./bin` to your `PATH` when you `cd` into your application.
64
+ Simply create an `.envrc` file with the command `PATH_add bin` in your
65
+ Rails directory.
66
+
67
+ ### Usage
68
+
69
+ For this walkthrough I've generated a new Rails application, and run
70
+ `rails generate scaffold post name:string`.
71
+
72
+ Let's run a test:
73
+
74
+ ```
75
+ $ time bin/rake test test/controllers/posts_controller_test.rb
76
+ Run options:
77
+
78
+ # Running tests:
79
+
80
+ .......
81
+
82
+ Finished tests in 0.127245s, 55.0121 tests/s, 78.5887 assertions/s.
83
+
84
+ 7 tests, 10 assertions, 0 failures, 0 errors, 0 skips
85
+
86
+ real 0m2.165s
87
+ user 0m0.281s
88
+ sys 0m0.066s
89
+ ```
90
+
91
+ That wasn't particularly fast because it was the first run, so spring
92
+ had to boot the application. It's now running:
93
+
94
+ ```
95
+ $ bin/spring status
96
+ Spring is running:
97
+
98
+ 26150 spring server | spring-demo-app | started 3 secs ago
99
+ 26155 spring app | spring-demo-app | started 3 secs ago | test mode
100
+ ```
101
+
102
+ The next run is faster:
103
+
104
+ ```
105
+ $ time bin/rake test test/controllers/posts_controller_test.rb
106
+ Run options:
107
+
108
+ # Running tests:
109
+
110
+ .......
111
+
112
+ Finished tests in 0.176896s, 39.5714 tests/s, 56.5305 assertions/s.
113
+
114
+ 7 tests, 10 assertions, 0 failures, 0 errors, 0 skips
115
+
116
+ real 0m0.610s
117
+ user 0m0.276s
118
+ sys 0m0.059s
119
+ ```
120
+
121
+ If we edit any of the application files, or test files, the changes will
122
+ be picked up on the next run without the background process having to
123
+ restart. This works in exactly the same way as the code reloading
124
+ which allows you to refresh your browser and instantly see changes during
125
+ development.
126
+
127
+ But if we edit any of the files which were used to start the application
128
+ (configs, initializers, your gemfile), the application needs to be fully
129
+ restarted. This happens automatically.
130
+
131
+ Let's "edit" `config/application.rb`:
132
+
133
+ ```
134
+ $ touch config/application.rb
135
+ $ bin/spring status
136
+ Spring is running:
137
+
138
+ 26150 spring server | spring-demo-app | started 36 secs ago
139
+ 26556 spring app | spring-demo-app | started 1 sec ago | test mode
140
+ ```
141
+
142
+ The application detected that `config/application.rb` changed and
143
+ automatically restarted itself.
144
+
145
+ If we run a command that uses a different environment, then that
146
+ environment gets booted up:
147
+
148
+ ```
149
+ $ bin/rake routes
150
+ posts GET /posts(.:format) posts#index
151
+ POST /posts(.:format) posts#create
152
+ new_post GET /posts/new(.:format) posts#new
153
+ edit_post GET /posts/:id/edit(.:format) posts#edit
154
+ post GET /posts/:id(.:format) posts#show
155
+ PUT /posts/:id(.:format) posts#update
156
+ DELETE /posts/:id(.:format) posts#destroy
157
+
158
+ $ bin/spring status
159
+ Spring is running:
160
+
161
+ 26150 spring server | spring-demo-app | started 1 min ago
162
+ 26556 spring app | spring-demo-app | started 42 secs ago | test mode
163
+ 26707 spring app | spring-demo-app | started 2 secs ago | development mode
164
+ ```
165
+
166
+ There's no need to "shut down" spring. This will happen automatically
167
+ when you close your terminal. However if you do want to do a manual shut
168
+ down, use the `stop` command:
169
+
170
+ ```
171
+ $ bin/spring stop
172
+ Spring stopped.
173
+ ```
174
+
175
+ ### Removal
176
+
177
+ To remove spring:
178
+
179
+ * 'Unspring' your bin/ executables: `bin/spring binstub --remove --all`
180
+ * Remove spring from your Gemfile
181
+
182
+ ### Deployment
183
+
184
+ You must not install Spring on your production environment. To prevent it from
185
+ being installed, provide the `--without development test` argument to the
186
+ `bundle install` command which is used to install gems on your production
187
+ machines:
188
+
189
+ ```
190
+ $ bundle install --without development test
191
+ ```
192
+
193
+ ## Commands
194
+
195
+ ### `rake`
196
+
197
+ Runs a rake task. Rake tasks run in the `development` environment by
198
+ default. You can change this on the fly by using the `RAILS_ENV`
199
+ environment variable. The environment is also configurable with the
200
+ `Spring::Commands::Rake.environment_matchers` hash. This has sensible
201
+ defaults, but if you need to match a specific task to a specific
202
+ environment, you'd do it like this:
203
+
204
+ ``` ruby
205
+ Spring::Commands::Rake.environment_matchers["perf_test"] = "test"
206
+ Spring::Commands::Rake.environment_matchers[/^perf/] = "test"
207
+
208
+ # To change the environment when you run `rake` with no arguments
209
+ Spring::Commands::Rake.environment_matchers[:default] = "development"
210
+ ```
211
+
212
+ ### `rails console`, `rails generate`, `rails runner`
213
+
214
+ These execute the rails command you already know and love. If you run
215
+ a different sub command (e.g. `rails server`) then spring will automatically
216
+ pass it through to the underlying `rails` executable (without the
217
+ speed-up).
218
+
219
+ ### Additional commands
220
+
221
+ You can add these to your Gemfile for additional commands:
222
+
223
+ * [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)
224
+ * [spring-commands-cucumber](https://github.com/jonleighton/spring-commands-cucumber)
225
+ * [spring-commands-spinach](https://github.com/jvanbaarsen/spring-commands-spinach)
226
+ * [spring-commands-testunit](https://github.com/jonleighton/spring-commands-testunit) - useful for
227
+ running `Test::Unit` tests on Rails 3, since only Rails 4 allows you
228
+ to use `rake test path/to/test` to run a particular test/directory.
229
+ * [spring-commands-teaspoon](https://github.com/alejandrobabio/spring-commands-teaspoon.git)
230
+ * [spring-commands-m](https://github.com/gabrieljoelc/spring-commands-m.git)
231
+
232
+ ## Use without adding to bundle
233
+
234
+ If you don't want spring-related code checked into your source
235
+ repository, it's possible to use spring without adding to your Gemfile.
236
+ However, using spring binstubs without adding spring to the Gemfile is not
237
+ supported.
238
+
239
+ To use spring like this, do a `gem install spring` and then prefix
240
+ commands with `spring`. For example, rather than running `bin/rake -T`,
241
+ you'd run `spring rake -T`.
242
+
243
+ ## Temporarily disabling Spring
244
+
245
+ If you're using Spring binstubs, but temporarily don't want commands to
246
+ run through Spring, set the `DISABLE_SPRING` environment variable.
247
+
248
+ ## Class reloading
249
+
250
+ Spring uses Rails' class reloading mechanism
251
+ (`ActiveSupport::Dependencies`) to keep your code up to date between
252
+ test runs. This is the same mechanism which allows you to see changes
253
+ during development when you refresh the page. However, you may never
254
+ have used this mechanism with your `test` environment before, and this
255
+ can cause problems.
256
+
257
+ It's important to realise that code reloading means that the constants
258
+ in your application are *different objects* after files have changed:
259
+
260
+ ```
261
+ $ bin/rails runner 'puts User.object_id'
262
+ 70127987886040
263
+ $ touch app/models/user.rb
264
+ $ bin/rails runner 'puts User.object_id'
265
+ 70127976764620
266
+ ```
267
+
268
+ Suppose you have an initializer `config/initializers/save_user_class.rb`
269
+ like so:
270
+
271
+ ``` ruby
272
+ USER_CLASS = User
273
+ ```
274
+
275
+ This saves off the *first* version of the `User` class, which will not
276
+ be the same object as `User` after the code has been reloaded:
277
+
278
+ ```
279
+ $ bin/rails runner 'puts User == USER_CLASS'
280
+ true
281
+ $ touch app/models/user.rb
282
+ $ bin/rails runner 'puts User == USER_CLASS'
283
+ false
284
+ ```
285
+
286
+ So to avoid this problem, don't save off references to application
287
+ constants in your initialization code.
288
+
289
+ ## Configuration
290
+
291
+ Spring will read `~/.spring.rb` and `config/spring.rb` for custom
292
+ settings. Note that `~/.spring.rb` is loaded *before* bundler, but
293
+ `config/spring.rb` is loaded *after* bundler. So if you have any
294
+ `spring-commands-*` gems installed that you want to be available in all
295
+ projects without having to be added to the project's Gemfile, require
296
+ them in your `~/.spring.rb`.
297
+
298
+ `config/spring_client.rb` is also loaded before bundler and before a
299
+ server process is started, it can be used to add new top-level commands.
300
+
301
+ ### Application root
302
+
303
+ Spring must know how to find your Rails application. If you have a
304
+ normal app everything works out of the box. If you are working on a
305
+ project with a special setup (an engine for example), you must tell
306
+ Spring where your app is located:
307
+
308
+ ```ruby
309
+ Spring.application_root = './test/dummy'
310
+ ```
311
+
312
+ ### Running code before forking
313
+
314
+ There is no `Spring.before_fork` callback. To run something before the
315
+ fork, you can place it in `~/.spring.rb` or `config/spring.rb` or in any of the files
316
+ which get run when your application initializes, such as
317
+ `config/application.rb`, `config/environments/*.rb` or
318
+ `config/initializers/*.rb`.
319
+
320
+ ### Running code after forking
321
+
322
+ You might want to run code after Spring forked off the process but
323
+ before the actual command is run. You might want to use an
324
+ `after_fork` callback if you have to connect to an external service,
325
+ do some general cleanup or set up dynamic configuration.
326
+
327
+ ```ruby
328
+ Spring.after_fork do
329
+ # run arbitrary code
330
+ end
331
+ ```
332
+
333
+ If you want to register multiple callbacks you can simply call
334
+ `Spring.after_fork` multiple times with different blocks.
335
+
336
+ ### Watching files and directories
337
+
338
+ Spring will automatically detect file changes to any file loaded when the server
339
+ boots. Changes will cause the affected environments to be restarted.
340
+
341
+ If there are additional files or directories which should trigger an
342
+ application restart, you can specify them with `Spring.watch`:
343
+
344
+ ```ruby
345
+ Spring.watch "config/some_config_file.yml"
346
+ ```
347
+
348
+ By default Spring polls the filesystem for changes once every 0.2 seconds. This
349
+ method requires zero configuration, but if you find that it's using too
350
+ much CPU, then you can use event-based file system listening by
351
+ installing the
352
+ [spring-watcher-listen](https://github.com/jonleighton/spring-watcher-listen)
353
+ gem.
354
+
355
+ ## Troubleshooting
356
+
357
+ If you want to get more information about what spring is doing, you can
358
+ specify a log file with the `SPRING_LOG` environment variable:
359
+
360
+ ```
361
+ spring stop # if spring is already running
362
+ export SPRING_LOG=/tmp/spring.log
363
+ spring rake -T
364
+ ```
data/bin/spring ADDED
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if defined?(Spring)
4
+ $stderr.puts "You've tried to invoke Spring when it's already loaded (i.e. the Spring " \
5
+ "constant is defined)."
6
+ $stderr.puts
7
+ $stderr.puts "This is probably because you generated binstubs with " \
8
+ "Spring 1.0, and you now have a Spring version > 1.0 on your system. To solve " \
9
+ "this, upgrade your bundle to the latest Spring version and then run " \
10
+ "`bundle exec spring binstub --all` to regenerate your binstubs. This is a one-time " \
11
+ "step necessary to upgrade from 1.0 to 1.1."
12
+ $stderr.puts
13
+ $stderr.puts "Here's the backtrace:"
14
+ $stderr.puts
15
+ $stderr.puts caller
16
+ exit 1
17
+ end
18
+
19
+ if defined?(Gem)
20
+ if Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.1.0")
21
+ warn "Warning: You're using Rubygems #{Gem::VERSION} with Spring. " \
22
+ "Upgrade to at least Rubygems 2.1.0 and run `gem pristine --all` for better " \
23
+ "startup performance."
24
+ else
25
+ stubs = Gem::Specification.stubs.grep(Gem::StubSpecification)
26
+
27
+ # stubbed? method added in https://github.com/rubygems/rubygems/pull/694
28
+ if Gem::Specification.stubs.first.respond_to?(:stubbed?)
29
+ unstubbed = stubs.reject(&:stubbed?)
30
+ else
31
+ unstubbed = stubs.reject { |s| s.send(:data).is_a?(Gem::StubSpecification::StubLine) }
32
+ end
33
+
34
+ # `gem pristine --all` ignores default gems. it doesn't really matter,
35
+ # as there are probably not many of them on the system.
36
+ unstubbed.reject!(&:default_gem?)
37
+
38
+ if unstubbed.any?
39
+ warn "Warning: Running `gem pristine --all` to regenerate your installed gemspecs " \
40
+ "(and deleting then reinstalling your bundle if you use bundle --path) " \
41
+ "will improve the startup performance of Spring."
42
+ end
43
+ end
44
+ end
45
+
46
+ lib = File.expand_path("../../lib", __FILE__)
47
+ $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib) # enable local development
48
+ require 'spring-jruby/client'
49
+ Spring::Client.run(ARGV)
@@ -0,0 +1,283 @@
1
+ require "spring-jruby/boot"
2
+ require "set"
3
+ require "pty"
4
+ require "spring-jruby/impl/application"
5
+
6
+ module Spring
7
+ class Application
8
+ include ApplicationImpl
9
+ attr_reader :manager, :watcher, :spring_env, :original_env
10
+
11
+ def initialize(manager, original_env)
12
+ @manager = manager
13
+ @original_env = original_env
14
+ @spring_env = Env.new
15
+ @mutex = Mutex.new
16
+ @waiting = Set.new
17
+ @preloaded = false
18
+ @state = :initialized
19
+ @interrupt = IO.pipe
20
+ end
21
+
22
+ def state(val)
23
+ return if exiting?
24
+ log "#{@state} -> #{val}"
25
+ @state = val
26
+ end
27
+
28
+ def state!(val)
29
+ state val
30
+ @interrupt.last.write "."
31
+ end
32
+
33
+ def app_env
34
+ ENV['RAILS_ENV']
35
+ end
36
+
37
+ def app_name
38
+ spring_env.app_name
39
+ end
40
+
41
+ def log(message)
42
+ spring_env.log "[application:#{app_env}] #{message}"
43
+ end
44
+
45
+ def preloaded?
46
+ @preloaded
47
+ end
48
+
49
+ def preload_failed?
50
+ @preloaded == :failure
51
+ end
52
+
53
+ def exiting?
54
+ @state == :exiting
55
+ end
56
+
57
+ def terminating?
58
+ @state == :terminating
59
+ end
60
+
61
+ def watcher_stale?
62
+ @state == :watcher_stale
63
+ end
64
+
65
+ def initialized?
66
+ @state == :initialized
67
+ end
68
+
69
+ def start_watcher
70
+ @watcher = Spring.watcher
71
+ @watcher.on_stale { state! :watcher_stale }
72
+ @watcher.start
73
+ end
74
+
75
+ def preload
76
+ log "preloading app"
77
+
78
+ begin
79
+ require "spring-jruby/commands"
80
+ ensure
81
+ start_watcher
82
+ end
83
+
84
+ require Spring.application_root_path.join("config", "application")
85
+
86
+ # config/environments/test.rb will have config.cache_classes = true. However
87
+ # we want it to be false so that we can reload files. This is a hack to
88
+ # override the effect of config.cache_classes = true. We can then actually
89
+ # set config.cache_classes = false after loading the environment.
90
+ Rails::Application.initializer :initialize_dependency_mechanism, group: :all do
91
+ ActiveSupport::Dependencies.mechanism = :load
92
+ end
93
+
94
+ require Spring.application_root_path.join("config", "environment")
95
+
96
+ @original_cache_classes = Rails.application.config.cache_classes
97
+ Rails.application.config.cache_classes = false
98
+
99
+ disconnect_database
100
+
101
+ @preloaded = :success
102
+ rescue Exception => e
103
+ @preloaded = :failure
104
+ watcher.add e.backtrace.map { |line| line.match(/^(.*)\:\d+\:in /)[1] }
105
+ raise e unless initialized?
106
+ ensure
107
+ watcher.add loaded_application_features
108
+ watcher.add Spring.gemfile, "#{Spring.gemfile}.lock"
109
+
110
+ if defined?(Rails) && Rails.application
111
+ watcher.add Rails.application.paths["config/initializers"]
112
+ watcher.add Rails.application.paths["config/database"]
113
+ if secrets_path = Rails.application.paths["config/secrets"]
114
+ watcher.add secrets_path
115
+ end
116
+ end
117
+ end
118
+
119
+ def run
120
+ state :running
121
+ notify_manager_ready
122
+
123
+ loop do
124
+ IO.select [manager, @interrupt.first]
125
+
126
+ if terminating? || watcher_stale? || preload_failed?
127
+ exit
128
+ else
129
+ serve IOWrapper.recv_io(manager, UNIXSocket).to_io
130
+ end
131
+ end
132
+ end
133
+
134
+ def serve(client)
135
+ child_started = [false]
136
+ log "got client"
137
+ manager.puts
138
+
139
+ stdout, stderr, stdin = streams = receive_streams(client)
140
+ reopen_streams(streams)
141
+
142
+ preload unless preloaded?
143
+
144
+ args, env = JSON.load(client.read(client.gets.to_i)).values_at("args", "env")
145
+ command = Spring.command(args.shift)
146
+
147
+ connect_database
148
+ setup command
149
+
150
+ if Rails.application.reloaders.any?(&:updated?)
151
+ ActionDispatch::Reloader.cleanup!
152
+ ActionDispatch::Reloader.prepare!
153
+ end
154
+
155
+ fork_child(client, streams, child_started) {
156
+ IGNORE_SIGNALS.each { |sig| trap(sig, "DEFAULT") }
157
+ trap("TERM", "DEFAULT")
158
+
159
+ ARGV.replace(args)
160
+ $0 = command.exec_name
161
+
162
+ # Delete all env vars which are unchanged from before spring started
163
+ original_env.each { |k, v| ENV.delete k if ENV[k] == v }
164
+
165
+ # Load in the current env vars, except those which *were* changed when spring started
166
+ env.each { |k, v| ENV[k] ||= v }
167
+
168
+ # requiring is faster, so if config.cache_classes was true in
169
+ # the environment's config file, then we can respect that from
170
+ # here on as we no longer need constant reloading.
171
+ if @original_cache_classes
172
+ ActiveSupport::Dependencies.mechanism = :require
173
+ Rails.application.config.cache_classes = true
174
+ end
175
+
176
+ connect_database
177
+ srand
178
+
179
+ invoke_after_fork_callbacks
180
+ shush_backtraces
181
+
182
+ before_command
183
+ command.call
184
+ }
185
+ rescue Exception => e
186
+ Kernel.exit if exiting? && e.is_a?(SystemExit)
187
+
188
+ log "exception: #{e}"
189
+ manager.puts unless child_started[0]
190
+
191
+ if streams && !e.is_a?(SystemExit)
192
+ print_exception(stderr || STDERR, e)
193
+ streams.each(&:close)
194
+ end
195
+
196
+ client.puts(1) if child_started[0]
197
+ client.close
198
+ end
199
+
200
+ def terminate
201
+ if exiting?
202
+ # Ensure that we do not ignore subsequent termination attempts
203
+ log "forced exit"
204
+ @waiting.each { |pid| Process.kill("TERM", pid) }
205
+ Kernel.exit
206
+ else
207
+ state! :terminating
208
+ end
209
+ end
210
+
211
+ def exit
212
+ state :exiting
213
+ manager.shutdown(:RDWR)
214
+ exit_if_finished
215
+ sleep
216
+ end
217
+
218
+ def exit_if_finished
219
+ @mutex.synchronize {
220
+ Kernel.exit if exiting? && @waiting.empty?
221
+ }
222
+ end
223
+
224
+ # The command might need to require some files in the
225
+ # main process so that they are cached. For example a test command wants to
226
+ # load the helper file once and have it cached.
227
+ def setup(command)
228
+ if command.setup
229
+ watcher.add loaded_application_features # loaded features may have changed
230
+ end
231
+ end
232
+
233
+ def invoke_after_fork_callbacks
234
+ Spring.after_fork_callbacks.each do |callback|
235
+ callback.call
236
+ end
237
+ end
238
+
239
+ def loaded_application_features
240
+ root = Spring.application_root_path.to_s
241
+ $LOADED_FEATURES.select { |f| f.start_with?(root) }
242
+ end
243
+
244
+ def disconnect_database
245
+ ActiveRecord::Base.remove_connection if active_record_configured?
246
+ end
247
+
248
+ def connect_database
249
+ ActiveRecord::Base.establish_connection if active_record_configured?
250
+ end
251
+
252
+ # This feels very naughty
253
+ def shush_backtraces
254
+ Kernel.module_eval do
255
+ old_raise = Kernel.method(:raise)
256
+ remove_method :raise
257
+ define_method :raise do |*args|
258
+ begin
259
+ old_raise.call(*args)
260
+ ensure
261
+ if $!
262
+ lib = File.expand_path("..", __FILE__)
263
+ $!.backtrace.reject! { |line| line.start_with?(lib) }
264
+ end
265
+ end
266
+ end
267
+ private :raise
268
+ end
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
276
+
277
+ private
278
+
279
+ def active_record_configured?
280
+ defined?(ActiveRecord::Base) && ActiveRecord::Base.configurations.any?
281
+ end
282
+ end
283
+ end