spring 1.6.4 → 1.7.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7188079e7e8285351c6d8a0604cc9198a2052bfd
4
- data.tar.gz: 2a0d6caceb3960e1ecd88ed86ec7f786b94aa388
3
+ metadata.gz: bf3b9b590f0a6bce1bf2b23dc01cd32884a8d992
4
+ data.tar.gz: 6fd9d0cd5224af34ff7cec5b485140eba506463d
5
5
  SHA512:
6
- metadata.gz: 294d493fe0500ef7e1265fabc0586ecc77be34f95b56504e9c972468eb3378ec8fad63c4793bfcad330274e269aad000463b8d161a3054bede5bbf3514f3a881
7
- data.tar.gz: fe2b858e97d0553e7bcb0b3b1a960587e29a090d584878a7b5cde6622bda0d9bb3920f2610dfb1a767db755ae4f5bf661de212b4405e68e63efb766a8b0ba70e
6
+ metadata.gz: b6c32c4667c1cb86d499332953b78b6933bb5f34d527701e64f52ba00b5155ee89e1d78e552b9c3fec81d827fd5923dfc37ba00910df87f7d9ebca7a698a96e5
7
+ data.tar.gz: 8aa47cb7a911eac35f9eb25db622bddcdc3df93ea1d0f947f160e2e564daff71a2485fa6f3346c66b1c7c813e28ffc2c206c00f248a7ae55cb6a0689e25a1bff
data/README.md CHANGED
@@ -365,13 +365,42 @@ a command runs:
365
365
  Spring.quiet = true
366
366
  ```
367
367
 
368
+ ### Environment variables
369
+
370
+ The following environment variables are used by Spring:
371
+
372
+ * `DISABLE_SPRING` - If set, Spring will be bypassed and your
373
+ application will boot in a foreground process
374
+ * `SPRING_LOG` - The path to a file which Spring will write log messages
375
+ to.
376
+ * `SPRING_TMP_PATH` - The directory where Spring should write its temporary
377
+ files (a pidfile and a socket). By default we use the
378
+ `XDG_RUNTIME_DIR` environment variable, or else `Dir.tmpdir`, and then
379
+ create a directory in that named `spring-$UID`. We don't use your
380
+ Rails application's `tmp/` directory because that may be on a
381
+ filesystem which doesn't support UNIX sockets.
382
+ * `SPRING_APPLICATION_ID` - Used to identify distinct Rails
383
+ applications. By default it is an MD5 hash of the current
384
+ `RUBY_VERSION`, and the path to your Rails project root.
385
+ * `SPRING_SOCKET` - The path which should be used for the UNIX socket
386
+ which Spring uses to communicate with the long-running Spring server
387
+ process. By default this is `SPRING_TMP_PATH/SPRING_APPLICATION_ID`.
388
+ * `SPRING_PIDFILE` - The path which should be used to store the pid of
389
+ the long-running Spring server process. By default this is related to
390
+ the socket path; if the socket path is `/foo/bar/spring.sock` the
391
+ pidfile will be `/foo/bar/spring.pid`.
392
+ * `SPRING_SERVER_COMMAND` - The command to run to start up the spring
393
+ server when it is not already running. Defaults to `spring _[version]_
394
+ server --background`.
395
+
368
396
  ## Troubleshooting
369
397
 
370
398
  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:
399
+ run spring explicitly in a separate terminal:
372
400
 
373
401
  ```
374
- spring stop # if spring is already running
375
- export SPRING_LOG=/tmp/spring.log
376
- spring rake -T
402
+ $ spring server
377
403
  ```
404
+
405
+ Logging output will be printed to stdout. You can also send log output
406
+ to a file with the `SPRING_LOG` environment variable.
@@ -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
 
@@ -313,6 +319,17 @@ module Spring
313
319
  exit_if_finished
314
320
  end
315
321
  }
322
+
323
+ Thread.new {
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
@@ -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 }
@@ -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
@@ -104,7 +104,8 @@ module Spring
104
104
  "-I", File.expand_path("../..", $LOADED_FEATURES.grep(/bundler\/setup\.rb$/).first),
105
105
  "-I", File.expand_path("../..", __FILE__),
106
106
  "-e", "require 'spring/application/boot'",
107
- 3 => child_socket
107
+ 3 => child_socket,
108
+ 4 => spring_env.log_file,
108
109
  )
109
110
  end
110
111
 
@@ -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)
@@ -8,6 +8,8 @@ module Spring
8
8
  FORWARDED_SIGNALS = %w(INT QUIT USR1 USR2 INFO WINCH) & Signal.list.keys
9
9
  TIMEOUT = 1
10
10
 
11
+ attr_reader :server
12
+
11
13
  def initialize(args)
12
14
  super
13
15
  @signal_queue = []
@@ -17,20 +19,20 @@ module Spring
17
19
  env.log "[client] #{message}"
18
20
  end
19
21
 
20
- def server
21
- @server ||= UNIXSocket.open(env.socket_name)
22
+ def connect
23
+ @server = UNIXSocket.open(env.socket_name)
22
24
  end
23
25
 
24
26
  def call
25
- if env.server_running?
26
- warm_run
27
- else
27
+ begin
28
+ connect
29
+ rescue Errno::ENOENT, Errno::ECONNRESET, Errno::ECONNREFUSED
28
30
  cold_run
31
+ else
32
+ warm_run
29
33
  end
30
- rescue Errno::ECONNRESET
31
- exit 1
32
34
  ensure
33
- server.close if @server
35
+ server.close if server
34
36
  end
35
37
 
36
38
  def warm_run
@@ -49,6 +51,7 @@ module Spring
49
51
 
50
52
  def cold_run
51
53
  boot_server
54
+ connect
52
55
  run
53
56
  end
54
57
 
@@ -60,16 +63,13 @@ module Spring
60
63
  queue_signals
61
64
  connect_to_application(client)
62
65
  run_command(client, application)
66
+ rescue Errno::ECONNRESET
67
+ exit 1
63
68
  end
64
69
 
65
70
  def boot_server
66
71
  env.socket_path.unlink if env.socket_path.exist?
67
-
68
- pid = Process.spawn(
69
- gem_env,
70
- "ruby",
71
- "-e", "gem 'spring', '#{Spring::VERSION}'; require 'spring/server'; Spring::Server.boot"
72
- )
72
+ pid = Process.spawn(gem_env, env.server_command, out: File::NULL)
73
73
 
74
74
  until env.socket_path.exist?
75
75
  _, status = Process.waitpid2(pid, Process::WNOHANG)
@@ -98,12 +98,12 @@ module Spring
98
98
  server_version = server.gets.chomp
99
99
  if server_version != env.version
100
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}
101
+ There is a version mismatch between the spring client (#{env.version}) and the server (#{server_version}).
102
+ Restarting to resolve.
105
103
  ERROR
106
- exit 1
104
+
105
+ stop_server
106
+ cold_run
107
107
  end
108
108
  end
109
109
 
@@ -138,7 +138,7 @@ ERROR
138
138
  if pid && !pid.empty?
139
139
  log "got pid: #{pid}"
140
140
 
141
- forward_signals(pid.to_i)
141
+ forward_signals(application)
142
142
  status = application.read.to_i
143
143
 
144
144
  log "got exit status #{status}"
@@ -158,26 +158,26 @@ ERROR
158
158
  end
159
159
  end
160
160
 
161
- def forward_signals(pid)
162
- @signal_queue.each { |sig| kill sig, pid }
161
+ def forward_signals(application)
162
+ @signal_queue.each { |sig| kill sig, application }
163
163
 
164
164
  FORWARDED_SIGNALS.each do |sig|
165
- trap(sig) { forward_signal sig, pid }
165
+ trap(sig) { forward_signal sig, application }
166
166
  end
167
- rescue Errno::ESRCH
168
167
  end
169
168
 
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)
169
+ def forward_signal(sig, application)
170
+ if kill(sig, application) != 0
171
+ # If the application process is gone, then don't block the
172
+ # signal on this process.
173
+ trap(sig, 'DEFAULT')
174
+ Process.kill(sig, Process.pid)
175
+ end
177
176
  end
178
177
 
179
- def kill(sig, pid)
180
- Process.kill(sig, -Process.getpgid(pid))
178
+ def kill(sig, application)
179
+ application.puts(sig)
180
+ application.gets.to_i
181
181
  end
182
182
 
183
183
  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
@@ -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"] || "spring _#{Spring::VERSION}_ server --background"
114
+ end
108
115
  end
109
116
  end
@@ -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)
@@ -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
@@ -508,6 +512,19 @@ module Spring
508
512
  2.times { assert_success "bundle exec rails runner ''" }
509
513
  end
510
514
  end
515
+
516
+ test "booting a foreground server" do
517
+ FileUtils.cd(app.root) do
518
+ assert !spring_env.server_running?
519
+ app.run "spring server &"
520
+
521
+ Timeout.timeout(1) do
522
+ sleep 0.1 until spring_env.server_running?
523
+ end
524
+
525
+ assert_success app.spring_test_command
526
+ end
527
+ end
511
528
  end
512
529
  end
513
530
  end
@@ -9,7 +9,7 @@ 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
13
  end
14
14
 
15
15
  def exists?
@@ -117,7 +117,7 @@ module Spring
117
117
 
118
118
  output.merge(status: status, command: command)
119
119
  rescue Timeout::Error => e
120
- raise e, "Output:\n\n#{dump_streams(command, read_streams)}"
120
+ raise Timeout::Error, "While running command:\n\n#{dump_streams(command, read_streams)}"
121
121
  end
122
122
 
123
123
  def with_timing
@@ -58,6 +58,10 @@ module Spring
58
58
  append_to_file(application.gemfile, "gem 'spring-commands-testunit'")
59
59
  end
60
60
 
61
+ if RUBY_VERSION == "1.9.3"
62
+ append_to_file(application.gemfile, "gem 'mime-types', '~> 2'")
63
+ end
64
+
61
65
  rewrite_file(application.gemfile) do |c|
62
66
  c.sub!("https://rubygems.org", "http://rubygems.org")
63
67
  c.gsub!(/(gem '(byebug|web-console|sdoc|jbuilder)')/, "# \\1")
@@ -1,3 +1,3 @@
1
1
  module Spring
2
- VERSION = "1.6.4"
2
+ VERSION = "1.7.0"
3
3
  end
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.4
4
+ version: 1.7.0
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-02-26 00:00:00.000000000 Z
11
+ date: 2016-04-10 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