spring 1.7.2 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 85d4ab3b84aa6f12fb90e262bcd8adf394cb94ef
4
- data.tar.gz: 69c83b9fe81004f4c25b9a429bd1222316e1d25e
2
+ SHA256:
3
+ metadata.gz: 90758ca717a756e672dfeaaf8295f17fcfa38f3ea3bc8bd27093a4354d45b82f
4
+ data.tar.gz: 82533f3a3e3f5dc53c3f89d3b2734557bfefcf06b5cbe714238dba64160d56a3
5
5
  SHA512:
6
- metadata.gz: 491bc17d5c922c974ebe995469c5ebaa099c95351067eab312dad022426feecc006e6dd2211955e390eabb2371392a99e8cdfa39f07dc5b6938f5de73a30d1a7
7
- data.tar.gz: 61f6d055f6b22aa94858dbd82227c0c4edbbdd6631a933a8bd5b2ebb0499c3d9c8cff27f1d41c6dca115a084cb0ddbffedef133345385069c87df69673e44ed5
6
+ metadata.gz: 80d8a7138fa74ad857a43671e54234da3a9b6265727f170c21905694397ebe5ec9b1102dbce3098835157e49e808cbbc52d74e1894a228ab0b25e521987cc4ca
7
+ data.tar.gz: 4366760559dfa2bae19ce7478302b35ca050cd431e39241427dfb5666de3a4eb704039ccdc4b02634556041aba71cebe22a053f4553e63db9d7ecdfbb980bf66
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-2016 Jon Leighton
1
+ Copyright (c) 2012-2017 Jon Leighton
2
2
 
3
3
  MIT License
4
4
 
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 1.9.3, MRI 2.0, MRI 2.1, MRI 2.2
20
- * Rails versions: 4.0+ (in Rails 4.1 and up Spring is included by default)
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 spring to your Gemfile:
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 spring.)
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 spring is installed and supported, this snippet
57
- hooks spring into the execution of commands. In other cases, the snippet
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/zimbatm/direnv#the-stdlib) to
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 spring
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" spring. This will happen automatically
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 spring:
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 spring will automatically
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 spring-related code checked into your source
239
- repository, it's possible to use spring without adding to your Gemfile.
240
- However, using spring binstubs without adding spring to the Gemfile is not
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 spring like this, do a `gem install spring` and then prefix
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 spring
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 spring is doing, you can
406
- run spring explicitly in a separate terminal:
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
@@ -66,7 +66,17 @@ module Spring
66
66
 
67
67
  def start_watcher
68
68
  @watcher = Spring.watcher
69
- @watcher.on_stale { state! :watcher_stale }
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
- stdout, stderr, stdin = streams = 3.times.map { client.recv_io }
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
- STDERR.puts "Running via Spring preloader in process #{Process.pid}" unless Spring.quiet
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 spring started
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 spring started
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
- Thread.new { master.read }
295
- yield
296
- reset_streams
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.with_clean_env do
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
- "-I", File.expand_path("../..", $LOADED_FEATURES.grep(/bundler\/setup\.rb$/).first),
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 spring which will
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 spring
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 spring without using Bundler, in order to be fast.
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
- 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]
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 "spring already present"
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 "spring inserted"
96
+ status "Spring inserted"
100
97
  else
101
- status "doesn't appear to be ruby, so cannot use spring", $stderr
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 spring"
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 "spring removed"
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 spring based binstubs. Use --all to generate a binstub for all known commands. Use --remove to revert."
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
@@ -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("spring itself", spring_commands),
35
+ *command_help("Spring itself", spring_commands),
36
36
  '',
37
37
  *command_help("your application", application_commands)].join("\n")
38
38
  end
@@ -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 spring: #{COMMANDS.to_a.join ', '}."
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
@@ -44,7 +44,7 @@ module Spring
44
44
  require "spring/commands"
45
45
 
46
46
  if Spring.command?(args.first)
47
- # Command installed since spring started
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 spring client " \
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