spring 1.3.6 → 1.7.2
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/LICENSE.txt +2 -2
- data/README.md +59 -6
- data/bin/spring +2 -1
- data/lib/spring/application/boot.rb +2 -1
- data/lib/spring/application.rb +25 -6
- data/lib/spring/application_manager.rb +6 -4
- data/lib/spring/boot.rb +2 -0
- data/lib/spring/client/binstub.rb +23 -11
- data/lib/spring/client/run.rb +62 -39
- data/lib/spring/client/server.rb +18 -0
- data/lib/spring/client.rb +11 -1
- data/lib/spring/configuration.rb +3 -1
- data/lib/spring/env.rb +15 -8
- data/lib/spring/failsafe_thread.rb +14 -0
- data/lib/spring/process_title_updater.rb +1 -1
- data/lib/spring/server.rb +28 -8
- data/lib/spring/test/acceptance_test.rb +249 -56
- data/lib/spring/test/application.rb +9 -4
- data/lib/spring/test/application_generator.rb +22 -4
- data/lib/spring/version.rb +1 -1
- data/lib/spring/watcher/polling.rb +0 -2
- data/lib/spring/watcher.rb +1 -1
- metadata +22 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85d4ab3b84aa6f12fb90e262bcd8adf394cb94ef
|
4
|
+
data.tar.gz: 69c83b9fe81004f4c25b9a429bd1222316e1d25e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 491bc17d5c922c974ebe995469c5ebaa099c95351067eab312dad022426feecc006e6dd2211955e390eabb2371392a99e8cdfa39f07dc5b6938f5de73a30d1a7
|
7
|
+
data.tar.gz: 61f6d055f6b22aa94858dbd82227c0c4edbbdd6631a933a8bd5b2ebb0499c3d9c8cff27f1d41c6dca115a084cb0ddbffedef133345385069c87df69673e44ed5
|
data/LICENSE.txt
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2012 Jon Leighton
|
1
|
+
Copyright (c) 2012-2016 Jon Leighton
|
2
2
|
|
3
3
|
MIT License
|
4
4
|
|
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
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.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -16,7 +16,7 @@ boot it every time you run a test, rake task or migration.
|
|
16
16
|
|
17
17
|
## Compatibility
|
18
18
|
|
19
|
-
* Ruby versions: MRI 1.9.3, MRI 2.0, MRI 2.1
|
19
|
+
* Ruby versions: MRI 1.9.3, MRI 2.0, MRI 2.1, MRI 2.2
|
20
20
|
* Rails versions: 4.0+ (in Rails 4.1 and up Spring is included by default)
|
21
21
|
|
22
22
|
Spring makes extensive use of `Process.fork`, so won't be able to
|
@@ -48,7 +48,7 @@ code into relevant existing executables. The snippet looks like this:
|
|
48
48
|
|
49
49
|
``` ruby
|
50
50
|
begin
|
51
|
-
load File.expand_path(
|
51
|
+
load File.expand_path('../spring', __FILE__)
|
52
52
|
rescue LoadError
|
53
53
|
end
|
54
54
|
```
|
@@ -73,6 +73,7 @@ Let's run a test:
|
|
73
73
|
|
74
74
|
```
|
75
75
|
$ time bin/rake test test/controllers/posts_controller_test.rb
|
76
|
+
Running via Spring preloader in process 2734
|
76
77
|
Run options:
|
77
78
|
|
78
79
|
# Running tests:
|
@@ -103,6 +104,7 @@ The next run is faster:
|
|
103
104
|
|
104
105
|
```
|
105
106
|
$ time bin/rake test test/controllers/posts_controller_test.rb
|
107
|
+
Running via Spring preloader in process 8352
|
106
108
|
Run options:
|
107
109
|
|
108
110
|
# Running tests:
|
@@ -147,6 +149,7 @@ environment gets booted up:
|
|
147
149
|
|
148
150
|
```
|
149
151
|
$ bin/rake routes
|
152
|
+
Running via Spring preloader in process 2363
|
150
153
|
posts GET /posts(.:format) posts#index
|
151
154
|
POST /posts(.:format) posts#create
|
152
155
|
new_post GET /posts/new(.:format) posts#new
|
@@ -227,6 +230,8 @@ You can add these to your Gemfile for additional commands:
|
|
227
230
|
running `Test::Unit` tests on Rails 3, since only Rails 4 allows you
|
228
231
|
to use `rake test path/to/test` to run a particular test/directory.
|
229
232
|
* [spring-commands-teaspoon](https://github.com/alejandrobabio/spring-commands-teaspoon.git)
|
233
|
+
* [spring-commands-m](https://github.com/gabrieljoelc/spring-commands-m.git)
|
234
|
+
* [spring-commands-rubocop](https://github.com/p0deje/spring-commands-rubocop)
|
230
235
|
|
231
236
|
## Use without adding to bundle
|
232
237
|
|
@@ -285,6 +290,13 @@ false
|
|
285
290
|
So to avoid this problem, don't save off references to application
|
286
291
|
constants in your initialization code.
|
287
292
|
|
293
|
+
## Using Spring with a containerized development environment
|
294
|
+
|
295
|
+
As of Spring 1.7, there is some support for doing this. See [this
|
296
|
+
example
|
297
|
+
repository](https://github.com/jonleighton/spring-docker-example) for
|
298
|
+
information about how to do it with [Docker](https://www.docker.com/).
|
299
|
+
|
288
300
|
## Configuration
|
289
301
|
|
290
302
|
Spring will read `~/.spring.rb` and `config/spring.rb` for custom
|
@@ -294,6 +306,9 @@ settings. Note that `~/.spring.rb` is loaded *before* bundler, but
|
|
294
306
|
projects without having to be added to the project's Gemfile, require
|
295
307
|
them in your `~/.spring.rb`.
|
296
308
|
|
309
|
+
`config/spring_client.rb` is also loaded before bundler and before a
|
310
|
+
server process is started, it can be used to add new top-level commands.
|
311
|
+
|
297
312
|
### Application root
|
298
313
|
|
299
314
|
Spring must know how to find your Rails application. If you have a
|
@@ -348,13 +363,51 @@ installing the
|
|
348
363
|
[spring-watcher-listen](https://github.com/jonleighton/spring-watcher-listen)
|
349
364
|
gem.
|
350
365
|
|
366
|
+
### Quiet output
|
367
|
+
|
368
|
+
To disable the "Running via Spring preloader" message which is shown each time
|
369
|
+
a command runs:
|
370
|
+
|
371
|
+
``` ruby
|
372
|
+
Spring.quiet = true
|
373
|
+
```
|
374
|
+
|
375
|
+
### Environment variables
|
376
|
+
|
377
|
+
The following environment variables are used by Spring:
|
378
|
+
|
379
|
+
* `DISABLE_SPRING` - If set, Spring will be bypassed and your
|
380
|
+
application will boot in a foreground process
|
381
|
+
* `SPRING_LOG` - The path to a file which Spring will write log messages
|
382
|
+
to.
|
383
|
+
* `SPRING_TMP_PATH` - The directory where Spring should write its temporary
|
384
|
+
files (a pidfile and a socket). By default we use the
|
385
|
+
`XDG_RUNTIME_DIR` environment variable, or else `Dir.tmpdir`, and then
|
386
|
+
create a directory in that named `spring-$UID`. We don't use your
|
387
|
+
Rails application's `tmp/` directory because that may be on a
|
388
|
+
filesystem which doesn't support UNIX sockets.
|
389
|
+
* `SPRING_APPLICATION_ID` - Used to identify distinct Rails
|
390
|
+
applications. By default it is an MD5 hash of the current
|
391
|
+
`RUBY_VERSION`, and the path to your Rails project root.
|
392
|
+
* `SPRING_SOCKET` - The path which should be used for the UNIX socket
|
393
|
+
which Spring uses to communicate with the long-running Spring server
|
394
|
+
process. By default this is `SPRING_TMP_PATH/SPRING_APPLICATION_ID`.
|
395
|
+
* `SPRING_PIDFILE` - The path which should be used to store the pid of
|
396
|
+
the long-running Spring server process. By default this is related to
|
397
|
+
the socket path; if the socket path is `/foo/bar/spring.sock` the
|
398
|
+
pidfile will be `/foo/bar/spring.pid`.
|
399
|
+
* `SPRING_SERVER_COMMAND` - The command to run to start up the spring
|
400
|
+
server when it is not already running. Defaults to `spring _[version]_
|
401
|
+
server --background`.
|
402
|
+
|
351
403
|
## Troubleshooting
|
352
404
|
|
353
405
|
If you want to get more information about what spring is doing, you can
|
354
|
-
|
406
|
+
run spring explicitly in a separate terminal:
|
355
407
|
|
356
408
|
```
|
357
|
-
|
358
|
-
export SPRING_LOG=/tmp/spring.log
|
359
|
-
spring rake -T
|
409
|
+
$ spring server
|
360
410
|
```
|
411
|
+
|
412
|
+
Logging output will be printed to stdout. You can also send log output
|
413
|
+
to a file with the `SPRING_LOG` environment variable.
|
data/bin/spring
CHANGED
@@ -43,6 +43,7 @@ if defined?(Gem)
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
lib = File.expand_path("../../lib", __FILE__)
|
47
|
+
$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib) # enable local development
|
47
48
|
require 'spring/client'
|
48
49
|
Spring::Client.run(ARGV)
|
@@ -5,7 +5,8 @@ require "spring/application"
|
|
5
5
|
|
6
6
|
app = Spring::Application.new(
|
7
7
|
UNIXSocket.for_fd(3),
|
8
|
-
Spring::JSON.load(ENV.delete("SPRING_ORIGINAL_ENV").dup)
|
8
|
+
Spring::JSON.load(ENV.delete("SPRING_ORIGINAL_ENV").dup),
|
9
|
+
Spring::Env.new(log_file: IO.for_fd(4))
|
9
10
|
)
|
10
11
|
|
11
12
|
Signal.trap("TERM") { app.terminate }
|
data/lib/spring/application.rb
CHANGED
@@ -6,10 +6,10 @@ module Spring
|
|
6
6
|
class Application
|
7
7
|
attr_reader :manager, :watcher, :spring_env, :original_env
|
8
8
|
|
9
|
-
def initialize(manager, original_env)
|
9
|
+
def initialize(manager, original_env, spring_env = Env.new)
|
10
10
|
@manager = manager
|
11
11
|
@original_env = original_env
|
12
|
-
@spring_env =
|
12
|
+
@spring_env = spring_env
|
13
13
|
@mutex = Mutex.new
|
14
14
|
@waiting = Set.new
|
15
15
|
@preloaded = false
|
@@ -99,7 +99,7 @@ module Spring
|
|
99
99
|
@preloaded = :success
|
100
100
|
rescue Exception => e
|
101
101
|
@preloaded = :failure
|
102
|
-
watcher.add e.backtrace.map { |line| line
|
102
|
+
watcher.add e.backtrace.map { |line| line[/^(.*)\:\d+/, 1] }
|
103
103
|
raise e unless initialized?
|
104
104
|
ensure
|
105
105
|
watcher.add loaded_application_features
|
@@ -149,14 +149,22 @@ module Spring
|
|
149
149
|
setup command
|
150
150
|
|
151
151
|
if Rails.application.reloaders.any?(&:updated?)
|
152
|
-
|
153
|
-
|
152
|
+
# Rails 5.1 forward-compat. AD::R is deprecated to AS::R in Rails 5.
|
153
|
+
if defined? ActiveSupport::Reloader
|
154
|
+
Rails.application.reloader.reload!
|
155
|
+
else
|
156
|
+
ActionDispatch::Reloader.cleanup!
|
157
|
+
ActionDispatch::Reloader.prepare!
|
158
|
+
end
|
154
159
|
end
|
155
160
|
|
156
161
|
pid = fork {
|
162
|
+
Process.setsid
|
157
163
|
IGNORE_SIGNALS.each { |sig| trap(sig, "DEFAULT") }
|
158
164
|
trap("TERM", "DEFAULT")
|
159
165
|
|
166
|
+
STDERR.puts "Running via Spring preloader in process #{Process.pid}" unless Spring.quiet
|
167
|
+
|
160
168
|
ARGV.replace(args)
|
161
169
|
$0 = command.exec_name
|
162
170
|
|
@@ -298,7 +306,7 @@ module Spring
|
|
298
306
|
@mutex.synchronize { @waiting << pid }
|
299
307
|
|
300
308
|
# Wait in a separate thread so we can run multiple commands at once
|
301
|
-
|
309
|
+
Spring.failsafe_thread {
|
302
310
|
begin
|
303
311
|
_, status = Process.wait2 pid
|
304
312
|
log "#{pid} exited with #{status.exitstatus}"
|
@@ -311,6 +319,17 @@ module Spring
|
|
311
319
|
exit_if_finished
|
312
320
|
end
|
313
321
|
}
|
322
|
+
|
323
|
+
Spring.failsafe_thread {
|
324
|
+
while signal = client.gets.chomp
|
325
|
+
begin
|
326
|
+
Process.kill(signal, -Process.getpgid(pid))
|
327
|
+
client.puts(0)
|
328
|
+
rescue Errno::ESRCH
|
329
|
+
client.puts(1)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
}
|
314
333
|
end
|
315
334
|
|
316
335
|
private
|
@@ -2,9 +2,9 @@ module Spring
|
|
2
2
|
class ApplicationManager
|
3
3
|
attr_reader :pid, :child, :app_env, :spring_env, :status
|
4
4
|
|
5
|
-
def initialize(app_env)
|
5
|
+
def initialize(app_env, spring_env)
|
6
6
|
@app_env = app_env
|
7
|
-
@spring_env =
|
7
|
+
@spring_env = spring_env
|
8
8
|
@mutex = Mutex.new
|
9
9
|
@state = :running
|
10
10
|
end
|
@@ -101,9 +101,11 @@ module Spring
|
|
101
101
|
"SPRING_PRELOAD" => preload ? "1" : "0"
|
102
102
|
},
|
103
103
|
"ruby",
|
104
|
+
"-I", File.expand_path("../..", $LOADED_FEATURES.grep(/bundler\/setup\.rb$/).first),
|
104
105
|
"-I", File.expand_path("../..", __FILE__),
|
105
106
|
"-e", "require 'spring/application/boot'",
|
106
|
-
3 => child_socket
|
107
|
+
3 => child_socket,
|
108
|
+
4 => spring_env.log_file,
|
107
109
|
)
|
108
110
|
end
|
109
111
|
|
@@ -114,7 +116,7 @@ module Spring
|
|
114
116
|
def start_wait_thread(pid, child)
|
115
117
|
Process.detach(pid)
|
116
118
|
|
117
|
-
|
119
|
+
Spring.failsafe_thread {
|
118
120
|
# The recv can raise an ECONNRESET, killing the thread, but that's ok
|
119
121
|
# as if it does we're no longer interested in the child
|
120
122
|
loop do
|
data/lib/spring/boot.rb
CHANGED
@@ -13,8 +13,9 @@ module Spring
|
|
13
13
|
# should cause the "unsprung" version of the command to run.
|
14
14
|
LOADER = <<CODE
|
15
15
|
begin
|
16
|
-
load File.expand_path(
|
17
|
-
rescue LoadError
|
16
|
+
load File.expand_path('../spring', __FILE__)
|
17
|
+
rescue LoadError => e
|
18
|
+
raise unless e.message.include?('spring')
|
18
19
|
end
|
19
20
|
CODE
|
20
21
|
|
@@ -33,19 +34,26 @@ CODE
|
|
33
34
|
# It gets overwritten when you run the `spring binstub` command.
|
34
35
|
|
35
36
|
unless defined?(Spring)
|
36
|
-
require
|
37
|
-
require
|
37
|
+
require 'rubygems'
|
38
|
+
require 'bundler'
|
38
39
|
|
39
|
-
if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)
|
40
|
-
Gem.paths = {
|
41
|
-
gem
|
42
|
-
require
|
40
|
+
if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m))
|
41
|
+
Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) }
|
42
|
+
gem 'spring', match[1]
|
43
|
+
require 'spring/binstub'
|
43
44
|
end
|
44
45
|
end
|
45
46
|
CODE
|
46
47
|
|
47
48
|
OLD_BINSTUB = %{if !Process.respond_to?(:fork) || Gem::Specification.find_all_by_name("spring").empty?}
|
48
49
|
|
50
|
+
BINSTUB_VARIATIONS = Regexp.union [
|
51
|
+
%{begin\n load File.expand_path("../spring", __FILE__)\nrescue LoadError\nend\n},
|
52
|
+
%{begin\n load File.expand_path('../spring', __FILE__)\nrescue LoadError\nend\n},
|
53
|
+
%{begin\n spring_bin_path = File.expand_path('../spring', __FILE__)\n load spring_bin_path\nrescue LoadError => e\n raise unless e.message.end_with? spring_bin_path, 'spring/binstub'\nend\n},
|
54
|
+
LOADER
|
55
|
+
]
|
56
|
+
|
49
57
|
class Item
|
50
58
|
attr_reader :command, :existing
|
51
59
|
|
@@ -72,8 +80,12 @@ CODE
|
|
72
80
|
fallback = nil if fallback.include?("exec")
|
73
81
|
generate(fallback)
|
74
82
|
status "upgraded"
|
75
|
-
elsif existing
|
83
|
+
elsif existing.include?(LOADER)
|
76
84
|
status "spring already present"
|
85
|
+
elsif existing =~ BINSTUB_VARIATIONS
|
86
|
+
upgraded = existing.sub(BINSTUB_VARIATIONS, LOADER)
|
87
|
+
File.write(command.binstub, upgraded)
|
88
|
+
status "upgraded"
|
77
89
|
else
|
78
90
|
head, shebang, tail = existing.partition(SHEBANG)
|
79
91
|
|
@@ -108,7 +120,7 @@ CODE
|
|
108
120
|
|
109
121
|
def remove
|
110
122
|
if existing
|
111
|
-
File.write(command.binstub, existing.sub(
|
123
|
+
File.write(command.binstub, existing.sub(BINSTUB_VARIATIONS, ""))
|
112
124
|
status "spring removed"
|
113
125
|
end
|
114
126
|
end
|
@@ -117,7 +129,7 @@ CODE
|
|
117
129
|
attr_reader :bindir, :items
|
118
130
|
|
119
131
|
def self.description
|
120
|
-
"Generate spring based binstubs. Use --all to generate a binstub for all known commands."
|
132
|
+
"Generate spring based binstubs. Use --all to generate a binstub for all known commands. Use --remove to revert."
|
121
133
|
end
|
122
134
|
|
123
135
|
def self.rails_command
|
data/lib/spring/client/run.rb
CHANGED
@@ -5,32 +5,37 @@ require "bundler"
|
|
5
5
|
module Spring
|
6
6
|
module Client
|
7
7
|
class Run < Command
|
8
|
-
FORWARDED_SIGNALS = %w(INT QUIT USR1 USR2 INFO) & Signal.list.keys
|
9
|
-
|
8
|
+
FORWARDED_SIGNALS = %w(INT QUIT USR1 USR2 INFO WINCH) & Signal.list.keys
|
9
|
+
CONNECT_TIMEOUT = 1
|
10
|
+
BOOT_TIMEOUT = 20
|
11
|
+
|
12
|
+
attr_reader :server
|
10
13
|
|
11
14
|
def initialize(args)
|
12
15
|
super
|
13
|
-
|
16
|
+
|
17
|
+
@signal_queue = []
|
18
|
+
@server_booted = false
|
14
19
|
end
|
15
20
|
|
16
21
|
def log(message)
|
17
22
|
env.log "[client] #{message}"
|
18
23
|
end
|
19
24
|
|
20
|
-
def
|
21
|
-
@server
|
25
|
+
def connect
|
26
|
+
@server = UNIXSocket.open(env.socket_name)
|
22
27
|
end
|
23
28
|
|
24
29
|
def call
|
25
|
-
|
26
|
-
|
27
|
-
|
30
|
+
begin
|
31
|
+
connect
|
32
|
+
rescue Errno::ENOENT, Errno::ECONNRESET, Errno::ECONNREFUSED
|
28
33
|
cold_run
|
34
|
+
else
|
35
|
+
warm_run
|
29
36
|
end
|
30
|
-
rescue Errno::ECONNRESET
|
31
|
-
exit 1
|
32
37
|
ensure
|
33
|
-
server.close if
|
38
|
+
server.close if server
|
34
39
|
end
|
35
40
|
|
36
41
|
def warm_run
|
@@ -49,6 +54,7 @@ module Spring
|
|
49
54
|
|
50
55
|
def cold_run
|
51
56
|
boot_server
|
57
|
+
connect
|
52
58
|
run
|
53
59
|
end
|
54
60
|
|
@@ -60,24 +66,37 @@ module Spring
|
|
60
66
|
queue_signals
|
61
67
|
connect_to_application(client)
|
62
68
|
run_command(client, application)
|
69
|
+
rescue Errno::ECONNRESET
|
70
|
+
exit 1
|
63
71
|
end
|
64
72
|
|
65
73
|
def boot_server
|
66
74
|
env.socket_path.unlink if env.socket_path.exist?
|
67
75
|
|
68
|
-
pid
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
)
|
76
|
+
pid = Process.spawn(gem_env, env.server_command, out: File::NULL)
|
77
|
+
timeout = Time.now + BOOT_TIMEOUT
|
78
|
+
|
79
|
+
@server_booted = true
|
73
80
|
|
74
81
|
until env.socket_path.exist?
|
75
82
|
_, status = Process.waitpid2(pid, Process::WNOHANG)
|
76
|
-
|
83
|
+
|
84
|
+
if status
|
85
|
+
exit status.exitstatus
|
86
|
+
elsif Time.now > timeout
|
87
|
+
$stderr.puts "Starting Spring server with `#{env.server_command}` " \
|
88
|
+
"timed out after #{BOOT_TIMEOUT} seconds"
|
89
|
+
exit 1
|
90
|
+
end
|
91
|
+
|
77
92
|
sleep 0.1
|
78
93
|
end
|
79
94
|
end
|
80
95
|
|
96
|
+
def server_booted?
|
97
|
+
@server_booted
|
98
|
+
end
|
99
|
+
|
81
100
|
def gem_env
|
82
101
|
bundle = Bundler.bundle_path.to_s
|
83
102
|
paths = Gem.path + ENV["GEM_PATH"].to_s.split(File::PATH_SEPARATOR)
|
@@ -97,13 +116,17 @@ module Spring
|
|
97
116
|
def verify_server_version
|
98
117
|
server_version = server.gets.chomp
|
99
118
|
if server_version != env.version
|
100
|
-
$stderr.puts
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
119
|
+
$stderr.puts "There is a version mismatch between the spring client " \
|
120
|
+
"(#{env.version}) and the server (#{server_version})."
|
121
|
+
|
122
|
+
if server_booted?
|
123
|
+
$stderr.puts "We already tried to reboot the server, but the mismatch is still present."
|
124
|
+
exit 1
|
125
|
+
else
|
126
|
+
$stderr.puts "Restarting to resolve."
|
127
|
+
stop_server
|
128
|
+
cold_run
|
129
|
+
end
|
107
130
|
end
|
108
131
|
end
|
109
132
|
|
@@ -111,7 +134,7 @@ ERROR
|
|
111
134
|
server.send_io client
|
112
135
|
send_json server, "args" => args, "default_rails_env" => default_rails_env
|
113
136
|
|
114
|
-
if IO.select([server], [], [],
|
137
|
+
if IO.select([server], [], [], CONNECT_TIMEOUT)
|
115
138
|
server.gets or raise CommandNotFound
|
116
139
|
else
|
117
140
|
raise "Error connecting to Spring server"
|
@@ -138,7 +161,7 @@ ERROR
|
|
138
161
|
if pid && !pid.empty?
|
139
162
|
log "got pid: #{pid}"
|
140
163
|
|
141
|
-
forward_signals(
|
164
|
+
forward_signals(application)
|
142
165
|
status = application.read.to_i
|
143
166
|
|
144
167
|
log "got exit status #{status}"
|
@@ -158,26 +181,26 @@ ERROR
|
|
158
181
|
end
|
159
182
|
end
|
160
183
|
|
161
|
-
def forward_signals(
|
162
|
-
@signal_queue.each { |sig| kill sig,
|
184
|
+
def forward_signals(application)
|
185
|
+
@signal_queue.each { |sig| kill sig, application }
|
163
186
|
|
164
187
|
FORWARDED_SIGNALS.each do |sig|
|
165
|
-
trap(sig) { forward_signal sig,
|
188
|
+
trap(sig) { forward_signal sig, application }
|
166
189
|
end
|
167
|
-
rescue Errno::ESRCH
|
168
190
|
end
|
169
191
|
|
170
|
-
def forward_signal(sig,
|
171
|
-
kill(sig,
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
192
|
+
def forward_signal(sig, application)
|
193
|
+
if kill(sig, application) != 0
|
194
|
+
# If the application process is gone, then don't block the
|
195
|
+
# signal on this process.
|
196
|
+
trap(sig, 'DEFAULT')
|
197
|
+
Process.kill(sig, Process.pid)
|
198
|
+
end
|
177
199
|
end
|
178
200
|
|
179
|
-
def kill(sig,
|
180
|
-
|
201
|
+
def kill(sig, application)
|
202
|
+
application.puts(sig)
|
203
|
+
application.gets.to_i
|
181
204
|
end
|
182
205
|
|
183
206
|
def send_json(socket, data)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Spring
|
2
|
+
module Client
|
3
|
+
class Server < Command
|
4
|
+
def self.description
|
5
|
+
"Explicitly start a Spring server in the foreground"
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
require "spring/server"
|
10
|
+
Spring::Server.boot(foreground: foreground?)
|
11
|
+
end
|
12
|
+
|
13
|
+
def foreground?
|
14
|
+
!args.include?("--background")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/spring/client.rb
CHANGED
@@ -9,17 +9,21 @@ require "spring/client/stop"
|
|
9
9
|
require "spring/client/status"
|
10
10
|
require "spring/client/rails"
|
11
11
|
require "spring/client/version"
|
12
|
+
require "spring/client/server"
|
12
13
|
|
13
14
|
module Spring
|
14
15
|
module Client
|
15
16
|
COMMANDS = {
|
16
17
|
"help" => Client::Help,
|
18
|
+
"-h" => Client::Help,
|
19
|
+
"--help" => Client::Help,
|
17
20
|
"binstub" => Client::Binstub,
|
18
21
|
"stop" => Client::Stop,
|
19
22
|
"status" => Client::Status,
|
20
23
|
"rails" => Client::Rails,
|
21
24
|
"-v" => Client::Version,
|
22
|
-
"--version" => Client::Version
|
25
|
+
"--version" => Client::Version,
|
26
|
+
"server" => Client::Server,
|
23
27
|
}
|
24
28
|
|
25
29
|
def self.run(args)
|
@@ -36,3 +40,9 @@ module Spring
|
|
36
40
|
end
|
37
41
|
end
|
38
42
|
end
|
43
|
+
|
44
|
+
# allow users to add hooks that do not run in the server
|
45
|
+
# or modify start/stop
|
46
|
+
if File.exist?("config/spring_client.rb")
|
47
|
+
require "./config/spring_client.rb"
|
48
|
+
end
|
data/lib/spring/configuration.rb
CHANGED
@@ -2,7 +2,7 @@ require "spring/errors"
|
|
2
2
|
|
3
3
|
module Spring
|
4
4
|
class << self
|
5
|
-
attr_accessor :application_root
|
5
|
+
attr_accessor :application_root, :quiet
|
6
6
|
|
7
7
|
def gemfile
|
8
8
|
ENV['BUNDLE_GEMFILE'] || "Gemfile"
|
@@ -49,4 +49,6 @@ module Spring
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
52
|
+
|
53
|
+
self.quiet = false
|
52
54
|
end
|
data/lib/spring/env.rb
CHANGED
@@ -14,10 +14,10 @@ module Spring
|
|
14
14
|
class Env
|
15
15
|
attr_reader :log_file
|
16
16
|
|
17
|
-
def initialize(
|
18
|
-
@root = root
|
19
|
-
@project_root = root
|
20
|
-
@log_file = File.open(ENV["SPRING_LOG"] || File::NULL, "a")
|
17
|
+
def initialize(options = {})
|
18
|
+
@root = options[:root]
|
19
|
+
@project_root = options[:root]
|
20
|
+
@log_file = options[:log_file] || File.open(ENV["SPRING_LOG"] || File::NULL, "a")
|
21
21
|
end
|
22
22
|
|
23
23
|
def root
|
@@ -33,17 +33,20 @@ module Spring
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def tmp_path
|
36
|
-
path = Pathname.new(
|
36
|
+
path = Pathname.new(
|
37
|
+
ENV["SPRING_TMP_PATH"] ||
|
38
|
+
File.join(ENV['XDG_RUNTIME_DIR'] || Dir.tmpdir, "spring-#{Process.uid}")
|
39
|
+
)
|
37
40
|
FileUtils.mkdir_p(path) unless path.exist?
|
38
41
|
path
|
39
42
|
end
|
40
43
|
|
41
44
|
def application_id
|
42
|
-
Digest::MD5.hexdigest(RUBY_VERSION + project_root.to_s)
|
45
|
+
ENV["SPRING_APPLICATION_ID"] || Digest::MD5.hexdigest(RUBY_VERSION + project_root.to_s)
|
43
46
|
end
|
44
47
|
|
45
48
|
def socket_path
|
46
|
-
tmp_path.join(application_id)
|
49
|
+
Pathname.new(ENV["SPRING_SOCKET"] || tmp_path.join(application_id))
|
47
50
|
end
|
48
51
|
|
49
52
|
def socket_name
|
@@ -51,7 +54,7 @@ module Spring
|
|
51
54
|
end
|
52
55
|
|
53
56
|
def pidfile_path
|
54
|
-
|
57
|
+
Pathname.new(ENV["SPRING_PIDFILE"] || socket_path.dirname.join("#{socket_path.basename(".*")}.pid"))
|
55
58
|
end
|
56
59
|
|
57
60
|
def pid
|
@@ -105,5 +108,9 @@ module Spring
|
|
105
108
|
rescue Errno::ESRCH
|
106
109
|
# already dead
|
107
110
|
end
|
111
|
+
|
112
|
+
def server_command
|
113
|
+
ENV["SPRING_SERVER_COMMAND"] || "#{File.expand_path("../../../bin/spring", __FILE__)} server --background"
|
114
|
+
end
|
108
115
|
end
|
109
116
|
end
|