spring 1.6.2 → 1.7.2

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
2
  SHA1:
3
- metadata.gz: bde56190c414de761d3907f24e40ba5d8db5357d
4
- data.tar.gz: ecf9a9762eda7467df6c49a93904576e451583ef
3
+ metadata.gz: 85d4ab3b84aa6f12fb90e262bcd8adf394cb94ef
4
+ data.tar.gz: 69c83b9fe81004f4c25b9a429bd1222316e1d25e
5
5
  SHA512:
6
- metadata.gz: e55818211b5e112aaf57d29dc8b63e20d92a30ca0b9464641065ba047c69345d35ed17e498b9e12d344a3293f5d4442cbe268821995668a99cbd076e60e3fb45
7
- data.tar.gz: 65c0b87b5e5cfe75cb6a1abb1edf6b05424bedd48d4ffeb3c452943184b329cdd38ea5e29230b0a552c4927daa8366ef4f2a9be563812051abe71421411c40a6
6
+ metadata.gz: 491bc17d5c922c974ebe995469c5ebaa099c95351067eab312dad022426feecc006e6dd2211955e390eabb2371392a99e8cdfa39f07dc5b6938f5de73a30d1a7
7
+ data.tar.gz: 61f6d055f6b22aa94858dbd82227c0c4edbbdd6631a933a8bd5b2ebb0499c3d9c8cff27f1d41c6dca115a084cb0ddbffedef133345385069c87df69673e44ed5
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
@@ -290,6 +290,13 @@ false
290
290
  So to avoid this problem, don't save off references to application
291
291
  constants in your initialization code.
292
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
+
293
300
  ## Configuration
294
301
 
295
302
  Spring will read `~/.spring.rb` and `config/spring.rb` for custom
@@ -365,13 +372,42 @@ a command runs:
365
372
  Spring.quiet = true
366
373
  ```
367
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
+
368
403
  ## Troubleshooting
369
404
 
370
405
  If you want to get more information about what spring is doing, you can
371
- specify a log file with the `SPRING_LOG` environment variable:
406
+ run spring explicitly in a separate terminal:
372
407
 
373
408
  ```
374
- spring stop # if spring is already running
375
- export SPRING_LOG=/tmp/spring.log
376
- spring rake -T
409
+ $ spring server
377
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.
@@ -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 }
@@ -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 = Env.new
12
+ @spring_env = spring_env
13
13
  @mutex = Mutex.new
14
14
  @waiting = Set.new
15
15
  @preloaded = false
@@ -149,11 +149,17 @@ module Spring
149
149
  setup command
150
150
 
151
151
  if Rails.application.reloaders.any?(&:updated?)
152
- ActionDispatch::Reloader.cleanup!
153
- ActionDispatch::Reloader.prepare!
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
 
@@ -300,7 +306,7 @@ module Spring
300
306
  @mutex.synchronize { @waiting << pid }
301
307
 
302
308
  # Wait in a separate thread so we can run multiple commands at once
303
- Thread.new {
309
+ Spring.failsafe_thread {
304
310
  begin
305
311
  _, status = Process.wait2 pid
306
312
  log "#{pid} exited with #{status.exitstatus}"
@@ -313,6 +319,17 @@ module Spring
313
319
  exit_if_finished
314
320
  end
315
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
+ }
316
333
  end
317
334
 
318
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 = Env.new
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
- Thread.new {
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
@@ -6,3 +6,5 @@ require "spring/env"
6
6
  require "spring/process_title_updater"
7
7
  require "spring/json"
8
8
  require "spring/watcher"
9
+ require "spring/failsafe_thread"
10
+
@@ -38,7 +38,7 @@ unless defined?(Spring)
38
38
  require 'bundler'
39
39
 
40
40
  if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m))
41
- Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq }
41
+ Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) }
42
42
  gem 'spring', match[1]
43
43
  require 'spring/binstub'
44
44
  end
@@ -6,31 +6,36 @@ module Spring
6
6
  module Client
7
7
  class Run < Command
8
8
  FORWARDED_SIGNALS = %w(INT QUIT USR1 USR2 INFO WINCH) & Signal.list.keys
9
- TIMEOUT = 1
9
+ CONNECT_TIMEOUT = 1
10
+ BOOT_TIMEOUT = 20
11
+
12
+ attr_reader :server
10
13
 
11
14
  def initialize(args)
12
15
  super
13
- @signal_queue = []
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 server
21
- @server ||= UNIXSocket.open(env.socket_name)
25
+ def connect
26
+ @server = UNIXSocket.open(env.socket_name)
22
27
  end
23
28
 
24
29
  def call
25
- if env.server_running?
26
- warm_run
27
- else
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 @server
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 = Process.spawn(
69
- gem_env,
70
- "ruby",
71
- "-e", "gem 'spring', '#{Spring::VERSION}'; require 'spring/server'; Spring::Server.boot"
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
- exit status.exitstatus if status
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 <<-ERROR
101
- There is a version mismatch between the spring client and the server.
102
- You should restart the server and make sure to use the same version.
103
-
104
- CLIENT: #{env.version}, SERVER: #{server_version}
105
- ERROR
106
- exit 1
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], [], [], TIMEOUT)
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(pid.to_i)
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(pid)
162
- @signal_queue.each { |sig| kill sig, pid }
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, pid }
188
+ trap(sig) { forward_signal sig, application }
166
189
  end
167
- rescue Errno::ESRCH
168
190
  end
169
191
 
170
- def forward_signal(sig, pid)
171
- kill(sig, pid)
172
- rescue Errno::ESRCH
173
- # If the application process is gone, then don't block the
174
- # signal on this process.
175
- trap(sig, 'DEFAULT')
176
- Process.kill(sig, Process.pid)
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, pid)
180
- Process.kill(sig, -Process.getpgid(pid))
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,6 +9,7 @@ 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
@@ -22,6 +23,7 @@ module Spring
22
23
  "rails" => Client::Rails,
23
24
  "-v" => Client::Version,
24
25
  "--version" => Client::Version,
26
+ "server" => Client::Server,
25
27
  }
26
28
 
27
29
  def self.run(args)
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(root = nil)
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(File.join(ENV['XDG_RUNTIME_DIR'] || Dir.tmpdir, "spring-#{Process.uid}"))
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
- tmp_path.join("#{application_id}.pid")
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
@@ -0,0 +1,14 @@
1
+ require 'thread'
2
+
3
+ module Spring
4
+ class << self
5
+ def failsafe_thread
6
+ Thread.new {
7
+ begin
8
+ yield
9
+ rescue
10
+ end
11
+ }
12
+ end
13
+ end
14
+ end
@@ -10,7 +10,7 @@ module Spring
10
10
  def self.run(&block)
11
11
  updater = new(&block)
12
12
 
13
- Thread.new {
13
+ Spring.failsafe_thread {
14
14
  $0 = updater.value
15
15
  loop { $0 = updater.next }
16
16
  }
data/lib/spring/server.rb CHANGED
@@ -10,19 +10,24 @@ require "spring/commands"
10
10
 
11
11
  module Spring
12
12
  class Server
13
- def self.boot
14
- new.boot
13
+ def self.boot(options = {})
14
+ new(options).boot
15
15
  end
16
16
 
17
17
  attr_reader :env
18
18
 
19
- def initialize(env = Env.new)
20
- @env = env
21
- @applications = Hash.new { |h, k| h[k] = ApplicationManager.new(k) }
19
+ def initialize(options = {})
20
+ @foreground = options.fetch(:foreground, false)
21
+ @env = options[:env] || default_env
22
+ @applications = Hash.new { |h, k| h[k] = ApplicationManager.new(k, env) }
22
23
  @pidfile = env.pidfile_path.open('a')
23
24
  @mutex = Mutex.new
24
25
  end
25
26
 
27
+ def foreground?
28
+ @foreground
29
+ end
30
+
26
31
  def log(message)
27
32
  env.log "[server] #{message}"
28
33
  end
@@ -31,8 +36,8 @@ module Spring
31
36
  Spring.verify_environment
32
37
 
33
38
  write_pidfile
34
- set_pgid
35
- ignore_signals
39
+ set_pgid unless foreground?
40
+ ignore_signals unless foreground?
36
41
  set_exit_hook
37
42
  set_process_title
38
43
  start_server
@@ -42,6 +47,7 @@ module Spring
42
47
  server = UNIXServer.open(env.socket_name)
43
48
  log "started on #{env.socket_name}"
44
49
  loop { serve server.accept }
50
+ rescue Interrupt
45
51
  end
46
52
 
47
53
  def serve(client)
@@ -100,7 +106,7 @@ module Spring
100
106
  end
101
107
  end
102
108
 
103
- @applications.values.map { |a| Thread.new { a.stop } }.map(&:join)
109
+ @applications.values.map { |a| Spring.failsafe_thread { a.stop } }.map(&:join)
104
110
  end
105
111
 
106
112
  def write_pidfile
@@ -126,5 +132,19 @@ module Spring
126
132
  "spring server | #{env.app_name} | started #{distance} ago"
127
133
  }
128
134
  end
135
+
136
+ private
137
+
138
+ def default_env
139
+ Env.new(log_file: default_log_file)
140
+ end
141
+
142
+ def default_log_file
143
+ if foreground? && !ENV["SPRING_LOG"]
144
+ $stdout
145
+ else
146
+ nil
147
+ end
148
+ end
129
149
  end
130
150
  end
@@ -28,6 +28,10 @@ module Spring
28
28
  @app ||= Spring::Test::Application.new("#{Spring::Test.root}/apps/tmp")
29
29
  end
30
30
 
31
+ def spring_env
32
+ app.spring_env
33
+ end
34
+
31
35
  def assert_output(artifacts, expected)
32
36
  expected.each do |stream, output|
33
37
  assert artifacts[stream].include?(output),
@@ -92,14 +96,14 @@ module Spring
92
96
 
93
97
  test "help message when called without arguments" do
94
98
  assert_success "bin/spring", stdout: 'Usage: spring COMMAND [ARGS]'
95
- assert app.spring_env.server_running?
99
+ assert spring_env.server_running?
96
100
  end
97
101
 
98
102
  test "shows help" do
99
103
  assert_success "bin/spring help", stdout: 'Usage: spring COMMAND [ARGS]'
100
104
  assert_success "bin/spring -h", stdout: 'Usage: spring COMMAND [ARGS]'
101
105
  assert_success "bin/spring --help", stdout: 'Usage: spring COMMAND [ARGS]'
102
- refute app.spring_env.server_running?
106
+ refute spring_env.server_running?
103
107
  end
104
108
 
105
109
  test "tells the user that spring is being used when used automatically via binstubs" do
@@ -184,10 +188,10 @@ module Spring
184
188
 
185
189
  test "stop command kills server" do
186
190
  app.run app.spring_test_command
187
- assert app.spring_env.server_running?, "The server should be running but it isn't"
191
+ assert spring_env.server_running?, "The server should be running but it isn't"
188
192
 
189
193
  assert_success "bin/spring stop"
190
- assert !app.spring_env.server_running?, "The server should not be running but it is"
194
+ assert !spring_env.server_running?, "The server should not be running but it is"
191
195
  end
192
196
 
193
197
  test "custom commands" do
@@ -400,7 +404,7 @@ module Spring
400
404
  end
401
405
 
402
406
  test "can define client tasks" do
403
- File.write("#{app.spring_config.sub('.rb', '_client.rb')}", <<-RUBY)
407
+ File.write("#{app.spring_client_config}", <<-RUBY)
404
408
  Spring::Client::COMMANDS["foo"] = lambda { |args| puts "bar -- \#{args.inspect}" }
405
409
  RUBY
406
410
  assert_success "bin/spring foo --baz", stdout: "bar -- [\"foo\", \"--baz\"]\n"
@@ -461,11 +465,11 @@ module Spring
461
465
  test "changing the Gemfile works when spring calls into itself" do
462
466
  File.write(app.path("script.rb"), <<-RUBY.strip_heredoc)
463
467
  gemfile = Rails.root.join("Gemfile")
464
- File.write(gemfile, "\#{gemfile.read}gem 'devise'\\n")
468
+ File.write(gemfile, "\#{gemfile.read}gem 'text'\\n")
465
469
  Bundler.with_clean_env do
466
470
  system(#{app.env.inspect}, "bundle install")
467
471
  end
468
- output = `\#{Rails.root.join('bin/rails')} runner 'require "devise"; puts "done";'`
472
+ output = `\#{Rails.root.join('bin/rails')} runner 'require "text"; puts "done";'`
469
473
  exit output.include? "done\n"
470
474
  RUBY
471
475
 
@@ -495,6 +499,41 @@ module Spring
495
499
  expr = "p Kernel.private_instance_methods.include?(:raise)"
496
500
  assert_success %(bin/rails runner '#{expr}'), stdout: "true"
497
501
  end
502
+
503
+ test "custom bundle path" do
504
+ bundle_path = app.path(".bundle/#{Bundler.ruby_scope}")
505
+ bundle_path.dirname.mkpath
506
+
507
+ FileUtils.cp_r "#{app.gem_home}/", bundle_path.to_s
508
+
509
+ app.run! "bundle install --path .bundle --clean --local"
510
+
511
+ assert_speedup do
512
+ 2.times { assert_success "bundle exec rails runner ''" }
513
+ end
514
+ end
515
+
516
+ test "booting a foreground server" do
517
+ FileUtils.cd(app.root) do
518
+ assert !spring_env.server_running?
519
+ assert_success "bin/spring server &"
520
+
521
+ Timeout.timeout(10) do
522
+ sleep 0.1 until spring_env.server_running? && spring_env.socket_path.exist?
523
+ end
524
+
525
+ assert_success app.spring_test_command
526
+ end
527
+ end
528
+
529
+ test "server boot timeout" do
530
+ app.env["SPRING_SERVER_COMMAND"] = "sleep 1"
531
+ File.write("#{app.spring_client_config}", %(
532
+ Spring::Client::Run.const_set(:BOOT_TIMEOUT, 0.1)
533
+ ))
534
+
535
+ assert_failure "bin/rails runner ''", stderr: "timed out"
536
+ end
498
537
  end
499
538
  end
500
539
  end
@@ -9,7 +9,8 @@ module Spring
9
9
 
10
10
  def initialize(root)
11
11
  @root = Pathname.new(root)
12
- @spring_env = Spring::Env.new(root)
12
+ @spring_env = Spring::Env.new(root: root)
13
+ @times = nil
13
14
  end
14
15
 
15
16
  def exists?
@@ -88,6 +89,10 @@ module Spring
88
89
  path "config/spring.rb"
89
90
  end
90
91
 
92
+ def spring_client_config
93
+ path "config/spring_client.rb"
94
+ end
95
+
91
96
  def run(command, opts = {})
92
97
  start_time = Time.now
93
98
 
@@ -116,8 +121,8 @@ module Spring
116
121
  @times << (Time.now - start_time) if @times
117
122
 
118
123
  output.merge(status: status, command: command)
119
- rescue Timeout::Error => e
120
- raise e, "Output:\n\n#{dump_streams(command, read_streams)}"
124
+ rescue Timeout::Error
125
+ raise Timeout::Error, "While running command:\n\n#{dump_streams(command, read_streams)}"
121
126
  end
122
127
 
123
128
  def with_timing
@@ -8,6 +8,7 @@ module Spring
8
8
  @version = RailsVersion.new(version_constraint.split(' ').last)
9
9
  @application = Application.new(root)
10
10
  @bundled = false
11
+ @installed = false
11
12
  end
12
13
 
13
14
  def test_root
@@ -58,6 +59,10 @@ module Spring
58
59
  append_to_file(application.gemfile, "gem 'spring-commands-testunit'")
59
60
  end
60
61
 
62
+ if RUBY_VERSION == "1.9.3"
63
+ append_to_file(application.gemfile, "gem 'mime-types', '~> 2'")
64
+ end
65
+
61
66
  rewrite_file(application.gemfile) do |c|
62
67
  c.sub!("https://rubygems.org", "http://rubygems.org")
63
68
  c.gsub!(/(gem '(byebug|web-console|sdoc|jbuilder)')/, "# \\1")
@@ -1,3 +1,3 @@
1
1
  module Spring
2
- VERSION = "1.6.2"
2
+ VERSION = "1.7.2"
3
3
  end
@@ -1,5 +1,3 @@
1
- require "spring/watcher"
2
-
3
1
  module Spring
4
2
  module Watcher
5
3
  class Polling < Abstract
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spring
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.2
4
+ version: 1.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Leighton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-08 00:00:00.000000000 Z
11
+ date: 2016-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -75,6 +75,7 @@ files:
75
75
  - lib/spring/client/help.rb
76
76
  - lib/spring/client/rails.rb
77
77
  - lib/spring/client/run.rb
78
+ - lib/spring/client/server.rb
78
79
  - lib/spring/client/status.rb
79
80
  - lib/spring/client/stop.rb
80
81
  - lib/spring/client/version.rb
@@ -85,6 +86,7 @@ files:
85
86
  - lib/spring/configuration.rb
86
87
  - lib/spring/env.rb
87
88
  - lib/spring/errors.rb
89
+ - lib/spring/failsafe_thread.rb
88
90
  - lib/spring/json.rb
89
91
  - lib/spring/process_title_updater.rb
90
92
  - lib/spring/server.rb
@@ -119,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
121
  version: '0'
120
122
  requirements: []
121
123
  rubyforge_project:
122
- rubygems_version: 2.4.8
124
+ rubygems_version: 2.5.1
123
125
  signing_key:
124
126
  specification_version: 4
125
127
  summary: Rails application preloader