spring 1.7.2 → 2.1.1
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 +5 -5
- data/LICENSE.txt +1 -1
- data/README.md +24 -18
- data/lib/spring/application.rb +47 -9
- data/lib/spring/application_manager.rb +4 -2
- data/lib/spring/client/binstub.rb +16 -19
- data/lib/spring/client/help.rb +1 -1
- data/lib/spring/client/rails.rb +1 -1
- data/lib/spring/client/run.rb +16 -2
- data/lib/spring/client/stop.rb +1 -1
- data/lib/spring/commands.rb +1 -1
- data/lib/spring/configuration.rb +5 -1
- data/lib/spring/errors.rb +1 -1
- data/lib/spring/process_title_updater.rb +1 -1
- data/lib/spring/version.rb +1 -1
- data/lib/spring/watcher/abstract.rb +33 -2
- data/lib/spring/watcher/polling.rb +48 -9
- metadata +11 -18
- data/lib/spring/test.rb +0 -18
- data/lib/spring/test/acceptance_test.rb +0 -539
- data/lib/spring/test/application.rb +0 -222
- data/lib/spring/test/application_generator.rb +0 -139
- data/lib/spring/test/rails_version.rb +0 -40
- data/lib/spring/test/watcher_test.rb +0 -167
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 90758ca717a756e672dfeaaf8295f17fcfa38f3ea3bc8bd27093a4354d45b82f
|
4
|
+
data.tar.gz: 82533f3a3e3f5dc53c3f89d3b2734557bfefcf06b5cbe714238dba64160d56a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80d8a7138fa74ad857a43671e54234da3a9b6265727f170c21905694397ebe5ec9b1102dbce3098835157e49e808cbbc52d74e1894a228ab0b25e521987cc4ca
|
7
|
+
data.tar.gz: 4366760559dfa2bae19ce7478302b35ca050cd431e39241427dfb5666de3a4eb704039ccdc4b02634556041aba71cebe22a053f4553e63db9d7ecdfbb980bf66
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -16,8 +16,9 @@ boot it every time you run a test, rake task or migration.
|
|
16
16
|
|
17
17
|
## Compatibility
|
18
18
|
|
19
|
-
* Ruby versions: MRI
|
20
|
-
* Rails versions: 4.0
|
19
|
+
* Ruby versions: MRI 2.4, MRI 2.5, MRI 2.6
|
20
|
+
* Rails versions: 4.2, 5.0, 5.1, 5.2, 6.0 (Spring is installed by default when you do
|
21
|
+
`rails new` to generate your application)
|
21
22
|
|
22
23
|
Spring makes extensive use of `Process.fork`, so won't be able to
|
23
24
|
provide a speed up on platforms which don't support forking (Windows, JRuby).
|
@@ -26,14 +27,14 @@ provide a speed up on platforms which don't support forking (Windows, JRuby).
|
|
26
27
|
|
27
28
|
### Setup
|
28
29
|
|
29
|
-
Add
|
30
|
+
Add Spring to your Gemfile:
|
30
31
|
|
31
32
|
``` ruby
|
32
33
|
gem "spring", group: :development
|
33
34
|
```
|
34
35
|
|
35
36
|
(Note: using `gem "spring", git: "..."` *won't* work and is not a
|
36
|
-
supported way of using
|
37
|
+
supported way of using Spring.)
|
37
38
|
|
38
39
|
It's recommended to 'springify' the executables in your `bin/`
|
39
40
|
directory:
|
@@ -53,13 +54,13 @@ rescue LoadError
|
|
53
54
|
end
|
54
55
|
```
|
55
56
|
|
56
|
-
On platforms where
|
57
|
-
hooks
|
57
|
+
On platforms where Spring is installed and supported, this snippet
|
58
|
+
hooks Spring into the execution of commands. In other cases, the snippet
|
58
59
|
will just be silently ignored and the lines after it will be executed as
|
59
60
|
normal.
|
60
61
|
|
61
62
|
If you don't want to prefix every command you type with `bin/`, you
|
62
|
-
can [use direnv](https://github.com/
|
63
|
+
can [use direnv](https://github.com/direnv/direnv#the-stdlib) to
|
63
64
|
automatically add `./bin` to your `PATH` when you `cd` into your application.
|
64
65
|
Simply create an `.envrc` file with the command `PATH_add bin` in your
|
65
66
|
Rails directory.
|
@@ -89,7 +90,7 @@ user 0m0.281s
|
|
89
90
|
sys 0m0.066s
|
90
91
|
```
|
91
92
|
|
92
|
-
That wasn't particularly fast because it was the first run, so
|
93
|
+
That wasn't particularly fast because it was the first run, so Spring
|
93
94
|
had to boot the application. It's now running:
|
94
95
|
|
95
96
|
```
|
@@ -166,7 +167,7 @@ Spring is running:
|
|
166
167
|
26707 spring app | spring-demo-app | started 2 secs ago | development mode
|
167
168
|
```
|
168
169
|
|
169
|
-
There's no need to "shut down"
|
170
|
+
There's no need to "shut down" Spring. This will happen automatically
|
170
171
|
when you close your terminal. However if you do want to do a manual shut
|
171
172
|
down, use the `stop` command:
|
172
173
|
|
@@ -175,9 +176,11 @@ $ bin/spring stop
|
|
175
176
|
Spring stopped.
|
176
177
|
```
|
177
178
|
|
179
|
+
From within your code, you can check whether Spring is active with `if defined?(Spring)`.
|
180
|
+
|
178
181
|
### Removal
|
179
182
|
|
180
|
-
To remove
|
183
|
+
To remove Spring:
|
181
184
|
|
182
185
|
* 'Unspring' your bin/ executables: `bin/spring binstub --remove --all`
|
183
186
|
* Remove spring from your Gemfile
|
@@ -215,7 +218,7 @@ Spring::Commands::Rake.environment_matchers[:default] = "development"
|
|
215
218
|
### `rails console`, `rails generate`, `rails runner`
|
216
219
|
|
217
220
|
These execute the rails command you already know and love. If you run
|
218
|
-
a different sub command (e.g. `rails server`) then
|
221
|
+
a different sub command (e.g. `rails server`) then Spring will automatically
|
219
222
|
pass it through to the underlying `rails` executable (without the
|
220
223
|
speed-up).
|
221
224
|
|
@@ -229,18 +232,21 @@ You can add these to your Gemfile for additional commands:
|
|
229
232
|
* [spring-commands-testunit](https://github.com/jonleighton/spring-commands-testunit) - useful for
|
230
233
|
running `Test::Unit` tests on Rails 3, since only Rails 4 allows you
|
231
234
|
to use `rake test path/to/test` to run a particular test/directory.
|
235
|
+
* [spring-commands-parallel-tests](https://github.com/DocSpring/spring-commands-parallel-tests) - Adds the `parallel_*` commands from [`parallel_tests`](https://github.com/grosser/parallel_tests).
|
232
236
|
* [spring-commands-teaspoon](https://github.com/alejandrobabio/spring-commands-teaspoon.git)
|
233
237
|
* [spring-commands-m](https://github.com/gabrieljoelc/spring-commands-m.git)
|
234
238
|
* [spring-commands-rubocop](https://github.com/p0deje/spring-commands-rubocop)
|
239
|
+
* [spring-commands-rackup](https://github.com/wintersolutions/spring-commands-rackup)
|
240
|
+
* [spring-commands-rack-console](https://github.com/wintersolutions/spring-commands-rack-console)
|
235
241
|
|
236
242
|
## Use without adding to bundle
|
237
243
|
|
238
|
-
If you don't want
|
239
|
-
repository, it's possible to use
|
240
|
-
However, using
|
244
|
+
If you don't want Spring-related code checked into your source
|
245
|
+
repository, it's possible to use Spring without adding to your Gemfile.
|
246
|
+
However, using Spring binstubs without adding Spring to the Gemfile is not
|
241
247
|
supported.
|
242
248
|
|
243
|
-
To use
|
249
|
+
To use Spring like this, do a `gem install spring` and then prefix
|
244
250
|
commands with `spring`. For example, rather than running `bin/rake -T`,
|
245
251
|
you'd run `spring rake -T`.
|
246
252
|
|
@@ -396,14 +402,14 @@ The following environment variables are used by Spring:
|
|
396
402
|
the long-running Spring server process. By default this is related to
|
397
403
|
the socket path; if the socket path is `/foo/bar/spring.sock` the
|
398
404
|
pidfile will be `/foo/bar/spring.pid`.
|
399
|
-
* `SPRING_SERVER_COMMAND` - The command to run to start up the
|
405
|
+
* `SPRING_SERVER_COMMAND` - The command to run to start up the Spring
|
400
406
|
server when it is not already running. Defaults to `spring _[version]_
|
401
407
|
server --background`.
|
402
408
|
|
403
409
|
## Troubleshooting
|
404
410
|
|
405
|
-
If you want to get more information about what
|
406
|
-
run
|
411
|
+
If you want to get more information about what Spring is doing, you can
|
412
|
+
run Spring explicitly in a separate terminal:
|
407
413
|
|
408
414
|
```
|
409
415
|
$ spring server
|
data/lib/spring/application.rb
CHANGED
@@ -66,7 +66,17 @@ module Spring
|
|
66
66
|
|
67
67
|
def start_watcher
|
68
68
|
@watcher = Spring.watcher
|
69
|
-
|
69
|
+
|
70
|
+
@watcher.on_stale do
|
71
|
+
state! :watcher_stale
|
72
|
+
end
|
73
|
+
|
74
|
+
if @watcher.respond_to? :on_debug
|
75
|
+
@watcher.on_debug do |message|
|
76
|
+
spring_env.log "[watcher:#{app_env}] #{message}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
70
80
|
@watcher.start
|
71
81
|
end
|
72
82
|
|
@@ -81,6 +91,10 @@ module Spring
|
|
81
91
|
|
82
92
|
require Spring.application_root_path.join("config", "application")
|
83
93
|
|
94
|
+
unless Rails.respond_to?(:gem_version) && Rails.gem_version >= Gem::Version.new('4.2.0')
|
95
|
+
raise "Spring only supports Rails >= 4.2.0"
|
96
|
+
end
|
97
|
+
|
84
98
|
# config/environments/test.rb will have config.cache_classes = true. However
|
85
99
|
# we want it to be false so that we can reload files. This is a hack to
|
86
100
|
# override the effect of config.cache_classes = true. We can then actually
|
@@ -137,7 +151,7 @@ module Spring
|
|
137
151
|
log "got client"
|
138
152
|
manager.puts
|
139
153
|
|
140
|
-
|
154
|
+
_stdout, stderr, _stdin = streams = 3.times.map { client.recv_io }
|
141
155
|
[STDOUT, STDERR, STDIN].zip(streams).each { |a, b| a.reopen(b) }
|
142
156
|
|
143
157
|
preload unless preloaded?
|
@@ -158,20 +172,35 @@ module Spring
|
|
158
172
|
end
|
159
173
|
end
|
160
174
|
|
175
|
+
# Ensure we boot the process in the directory the command was called from,
|
176
|
+
# not from the directory Spring started in
|
177
|
+
original_dir = Dir.pwd
|
178
|
+
Dir.chdir(env['PWD'] || original_dir)
|
179
|
+
|
161
180
|
pid = fork {
|
162
181
|
Process.setsid
|
163
182
|
IGNORE_SIGNALS.each { |sig| trap(sig, "DEFAULT") }
|
164
183
|
trap("TERM", "DEFAULT")
|
165
184
|
|
166
|
-
|
185
|
+
unless Spring.quiet
|
186
|
+
STDERR.puts "Running via Spring preloader in process #{Process.pid}"
|
187
|
+
|
188
|
+
if Rails.env.production?
|
189
|
+
STDERR.puts "WARNING: Spring is running in production. To fix " \
|
190
|
+
"this make sure the spring gem is only present " \
|
191
|
+
"in `development` and `test` groups in your Gemfile " \
|
192
|
+
"and make sure you always use " \
|
193
|
+
"`bundle install --without development test` in production"
|
194
|
+
end
|
195
|
+
end
|
167
196
|
|
168
197
|
ARGV.replace(args)
|
169
198
|
$0 = command.exec_name
|
170
199
|
|
171
|
-
# Delete all env vars which are unchanged from before
|
200
|
+
# Delete all env vars which are unchanged from before Spring started
|
172
201
|
original_env.each { |k, v| ENV.delete k if ENV[k] == v }
|
173
202
|
|
174
|
-
# Load in the current env vars, except those which *were* changed when
|
203
|
+
# Load in the current env vars, except those which *were* changed when Spring started
|
175
204
|
env.each { |k, v| ENV[k] ||= v }
|
176
205
|
|
177
206
|
# requiring is faster, so if config.cache_classes was true in
|
@@ -192,7 +221,6 @@ module Spring
|
|
192
221
|
}
|
193
222
|
|
194
223
|
disconnect_database
|
195
|
-
reset_streams
|
196
224
|
|
197
225
|
log "forked #{pid}"
|
198
226
|
manager.puts pid
|
@@ -209,6 +237,12 @@ module Spring
|
|
209
237
|
|
210
238
|
client.puts(1) if pid
|
211
239
|
client.close
|
240
|
+
ensure
|
241
|
+
# Redirect STDOUT and STDERR to prevent from keeping the original FDs
|
242
|
+
# (i.e. to prevent `spring rake -T | grep db` from hanging forever),
|
243
|
+
# even when exception is raised before forking (i.e. preloading).
|
244
|
+
reset_streams
|
245
|
+
Dir.chdir(original_dir)
|
212
246
|
end
|
213
247
|
|
214
248
|
def terminate
|
@@ -291,9 +325,13 @@ module Spring
|
|
291
325
|
def with_pty
|
292
326
|
PTY.open do |master, slave|
|
293
327
|
[STDOUT, STDERR, STDIN].each { |s| s.reopen slave }
|
294
|
-
|
295
|
-
|
296
|
-
|
328
|
+
reader_thread = Spring.failsafe_thread { master.read }
|
329
|
+
begin
|
330
|
+
yield
|
331
|
+
ensure
|
332
|
+
reader_thread.kill
|
333
|
+
reset_streams
|
334
|
+
end
|
297
335
|
end
|
298
336
|
end
|
299
337
|
|
@@ -7,6 +7,7 @@ module Spring
|
|
7
7
|
@spring_env = spring_env
|
8
8
|
@mutex = Mutex.new
|
9
9
|
@state = :running
|
10
|
+
@pid = nil
|
10
11
|
end
|
11
12
|
|
12
13
|
def log(message)
|
@@ -92,7 +93,8 @@ module Spring
|
|
92
93
|
def start_child(preload = false)
|
93
94
|
@child, child_socket = UNIXSocket.pair
|
94
95
|
|
95
|
-
Bundler.
|
96
|
+
Bundler.with_original_env do
|
97
|
+
bundler_dir = File.expand_path("../..", $LOADED_FEATURES.grep(/bundler\/setup\.rb$/).first)
|
96
98
|
@pid = Process.spawn(
|
97
99
|
{
|
98
100
|
"RAILS_ENV" => app_env,
|
@@ -101,7 +103,7 @@ module Spring
|
|
101
103
|
"SPRING_PRELOAD" => preload ? "1" : "0"
|
102
104
|
},
|
103
105
|
"ruby",
|
104
|
-
"
|
106
|
+
*(bundler_dir != RbConfig::CONFIG["rubylibdir"] ? ["-I", bundler_dir] : []),
|
105
107
|
"-I", File.expand_path("../..", __FILE__),
|
106
108
|
"-e", "require 'spring/application/boot'",
|
107
109
|
3 => child_socket,
|
@@ -3,11 +3,11 @@ require 'set'
|
|
3
3
|
module Spring
|
4
4
|
module Client
|
5
5
|
class Binstub < Command
|
6
|
-
SHEBANG = /\#\!.*\n
|
6
|
+
SHEBANG = /\#\!.*\n(\#.*\n)*/
|
7
7
|
|
8
|
-
# If loading the bin/spring file works, it'll run
|
8
|
+
# If loading the bin/spring file works, it'll run Spring which will
|
9
9
|
# eventually call Kernel.exit. This means that in the client process
|
10
|
-
# we will never execute the lines after this block. But if the
|
10
|
+
# we will never execute the lines after this block. But if the Spring
|
11
11
|
# client is not invoked for whatever reason, then the Kernel.exit won't
|
12
12
|
# happen, and so we'll fall back to the lines after this block, which
|
13
13
|
# should cause the "unsprung" version of the command to run.
|
@@ -23,23 +23,21 @@ CODE
|
|
23
23
|
# binstub from the application process. Which means that in the application
|
24
24
|
# process we'll execute the lines which come after the LOADER block, which
|
25
25
|
# is what we want.
|
26
|
-
#
|
27
|
-
# Parsing the lockfile in this way is pretty nasty but reliable enough
|
28
|
-
# The regex ensures that the match must be between a GEM line and an empty
|
29
|
-
# line, so it won't go on to the next section.
|
30
26
|
SPRING = <<'CODE'
|
31
27
|
#!/usr/bin/env ruby
|
32
28
|
|
33
|
-
# This file loads
|
29
|
+
# This file loads Spring without using Bundler, in order to be fast.
|
34
30
|
# It gets overwritten when you run the `spring binstub` command.
|
35
31
|
|
36
32
|
unless defined?(Spring)
|
37
33
|
require 'rubygems'
|
38
34
|
require 'bundler'
|
39
35
|
|
40
|
-
|
41
|
-
|
42
|
-
|
36
|
+
lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
|
37
|
+
spring = lockfile.specs.detect { |spec| spec.name == 'spring' }
|
38
|
+
if spring
|
39
|
+
Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
|
40
|
+
gem 'spring', spring.version
|
43
41
|
require 'spring/binstub'
|
44
42
|
end
|
45
43
|
end
|
@@ -48,11 +46,10 @@ CODE
|
|
48
46
|
OLD_BINSTUB = %{if !Process.respond_to?(:fork) || Gem::Specification.find_all_by_name("spring").empty?}
|
49
47
|
|
50
48
|
BINSTUB_VARIATIONS = Regexp.union [
|
51
|
-
%{begin\n load File.expand_path("../spring", __FILE__)\nrescue LoadError\nend\n},
|
52
49
|
%{begin\n load File.expand_path('../spring', __FILE__)\nrescue LoadError\nend\n},
|
53
50
|
%{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
51
|
LOADER
|
55
|
-
]
|
52
|
+
].map { |binstub| /#{Regexp.escape(binstub).gsub("'", "['\"]")}/ }
|
56
53
|
|
57
54
|
class Item
|
58
55
|
attr_reader :command, :existing
|
@@ -81,7 +78,7 @@ CODE
|
|
81
78
|
generate(fallback)
|
82
79
|
status "upgraded"
|
83
80
|
elsif existing.include?(LOADER)
|
84
|
-
status "
|
81
|
+
status "Spring already present"
|
85
82
|
elsif existing =~ BINSTUB_VARIATIONS
|
86
83
|
upgraded = existing.sub(BINSTUB_VARIATIONS, LOADER)
|
87
84
|
File.write(command.binstub, upgraded)
|
@@ -96,15 +93,15 @@ CODE
|
|
96
93
|
end
|
97
94
|
|
98
95
|
File.write(command.binstub, "#{head}#{shebang}#{LOADER}#{tail}")
|
99
|
-
status "
|
96
|
+
status "Spring inserted"
|
100
97
|
else
|
101
|
-
status "doesn't appear to be ruby, so cannot use
|
98
|
+
status "doesn't appear to be ruby, so cannot use Spring", $stderr
|
102
99
|
exit 1
|
103
100
|
end
|
104
101
|
end
|
105
102
|
else
|
106
103
|
generate
|
107
|
-
status "generated with
|
104
|
+
status "generated with Spring"
|
108
105
|
end
|
109
106
|
end
|
110
107
|
|
@@ -121,7 +118,7 @@ CODE
|
|
121
118
|
def remove
|
122
119
|
if existing
|
123
120
|
File.write(command.binstub, existing.sub(BINSTUB_VARIATIONS, ""))
|
124
|
-
status "
|
121
|
+
status "Spring removed"
|
125
122
|
end
|
126
123
|
end
|
127
124
|
end
|
@@ -129,7 +126,7 @@ CODE
|
|
129
126
|
attr_reader :bindir, :items
|
130
127
|
|
131
128
|
def self.description
|
132
|
-
"Generate
|
129
|
+
"Generate Spring based binstubs. Use --all to generate a binstub for all known commands. Use --remove to revert."
|
133
130
|
end
|
134
131
|
|
135
132
|
def self.rails_command
|
data/lib/spring/client/help.rb
CHANGED
@@ -32,7 +32,7 @@ module Spring
|
|
32
32
|
def formatted_help
|
33
33
|
["Version: #{env.version}\n",
|
34
34
|
"Usage: spring COMMAND [ARGS]\n",
|
35
|
-
*command_help("
|
35
|
+
*command_help("Spring itself", spring_commands),
|
36
36
|
'',
|
37
37
|
*command_help("your application", application_commands)].join("\n")
|
38
38
|
end
|
data/lib/spring/client/rails.rb
CHANGED
@@ -14,7 +14,7 @@ module Spring
|
|
14
14
|
}
|
15
15
|
|
16
16
|
def self.description
|
17
|
-
"Run a rails command. The following sub commands will use
|
17
|
+
"Run a rails command. The following sub commands will use Spring: #{COMMANDS.to_a.join ', '}."
|
18
18
|
end
|
19
19
|
|
20
20
|
def call
|
data/lib/spring/client/run.rb
CHANGED
@@ -44,7 +44,7 @@ module Spring
|
|
44
44
|
require "spring/commands"
|
45
45
|
|
46
46
|
if Spring.command?(args.first)
|
47
|
-
# Command installed since
|
47
|
+
# Command installed since Spring started
|
48
48
|
stop_server
|
49
49
|
cold_run
|
50
50
|
else
|
@@ -116,7 +116,7 @@ module Spring
|
|
116
116
|
def verify_server_version
|
117
117
|
server_version = server.gets.chomp
|
118
118
|
if server_version != env.version
|
119
|
-
$stderr.puts "There is a version mismatch between the
|
119
|
+
$stderr.puts "There is a version mismatch between the Spring client " \
|
120
120
|
"(#{env.version}) and the server (#{server_version})."
|
121
121
|
|
122
122
|
if server_booted?
|
@@ -161,6 +161,8 @@ module Spring
|
|
161
161
|
if pid && !pid.empty?
|
162
162
|
log "got pid: #{pid}"
|
163
163
|
|
164
|
+
suspend_resume_on_tstp_cont(pid)
|
165
|
+
|
164
166
|
forward_signals(application)
|
165
167
|
status = application.read.to_i
|
166
168
|
|
@@ -181,6 +183,18 @@ module Spring
|
|
181
183
|
end
|
182
184
|
end
|
183
185
|
|
186
|
+
def suspend_resume_on_tstp_cont(pid)
|
187
|
+
trap("TSTP") {
|
188
|
+
log "suspended"
|
189
|
+
Process.kill("STOP", pid.to_i)
|
190
|
+
Process.kill("STOP", Process.pid)
|
191
|
+
}
|
192
|
+
trap("CONT") {
|
193
|
+
log "resumed"
|
194
|
+
Process.kill("CONT", pid.to_i)
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
184
198
|
def forward_signals(application)
|
185
199
|
@signal_queue.each { |sig| kill sig, application }
|
186
200
|
|