spring 1.3.6 → 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: 53e40e388796f0694f931b786ba678246e64bb51
4
- data.tar.gz: fce7e7274cf3155517ca3f11411fb7f90d3ce1a6
3
+ metadata.gz: 85d4ab3b84aa6f12fb90e262bcd8adf394cb94ef
4
+ data.tar.gz: 69c83b9fe81004f4c25b9a429bd1222316e1d25e
5
5
  SHA512:
6
- metadata.gz: ea9be374bc7b1dec0ada6cb6aec41990fb872e96272c0536562a1c884fdc93016bd3d3b2abed67d0bcd36af739419bd2332f2add3699d3944a5a8f6f2cb9e763
7
- data.tar.gz: f9f8ca0814f602e7ce30f05ee39e8c6d7313e38e1302c55d28ce30c10269974da5ca214709d4ec5c61df67053117aba92c066956c8c79bc92720363b61f0c1f4
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("../spring", __FILE__)
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
- specify a log file with the `SPRING_LOG` environment variable:
406
+ run spring explicitly in a separate terminal:
355
407
 
356
408
  ```
357
- spring stop # if spring is already running
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
- $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
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 }
@@ -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
@@ -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.match(/^(.*)\:\d+\:in /)[1] }
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
- 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
 
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
- Thread.new {
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 = 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
+
@@ -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("../spring", __FILE__)
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 "rubygems"
37
- require "bundler"
37
+ require 'rubygems'
38
+ require 'bundler'
38
39
 
39
- if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)
40
- Gem.paths = { "GEM_PATH" => [Bundler.bundle_path.to_s, *Gem.path].uniq }
41
- gem "spring", match[1]
42
- require "spring/binstub"
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 =~ /load .*spring/
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(LOADER, ""))
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
@@ -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
- TIMEOUT = 1
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
- @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,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
@@ -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(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"))
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