spring 2.0.2 → 4.2.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.
@@ -1,56 +1,48 @@
1
- require 'set'
2
-
3
1
  module Spring
4
2
  module Client
5
3
  class Binstub < Command
6
- SHEBANG = /\#\!.*\n/
4
+ SHEBANG = /\#\!.*\n(\#.*\n)*/
7
5
 
8
- # If loading the bin/spring file works, it'll run spring which will
6
+ # If loading the bin/spring file works, it'll run Spring which will
9
7
  # 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
8
+ # we will never execute the lines after this block. But if the Spring
11
9
  # client is not invoked for whatever reason, then the Kernel.exit won't
12
10
  # happen, and so we'll fall back to the lines after this block, which
13
11
  # should cause the "unsprung" version of the command to run.
14
- LOADER = <<CODE
15
- begin
16
- load File.expand_path('../spring', __FILE__)
17
- rescue LoadError => e
18
- raise unless e.message.include?('spring')
19
- end
20
- CODE
12
+ LOADER = <<~CODE
13
+ load File.expand_path("spring", __dir__)
14
+ CODE
21
15
 
22
16
  # The defined? check ensures these lines don't execute when we load the
23
17
  # binstub from the application process. Which means that in the application
24
18
  # process we'll execute the lines which come after the LOADER block, which
25
19
  # is what we want.
26
- SPRING = <<'CODE'
27
- #!/usr/bin/env ruby
28
-
29
- # This file loads spring without using Bundler, in order to be fast.
30
- # It gets overwritten when you run the `spring binstub` command.
31
-
32
- unless defined?(Spring)
33
- require 'rubygems'
34
- require 'bundler'
35
-
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
41
- require 'spring/binstub'
42
- end
43
- end
44
- CODE
20
+ SPRING = <<~CODE
21
+ #!/usr/bin/env ruby
22
+
23
+ # This file loads Spring without loading other gems in the Gemfile in order to be fast.
24
+ # It gets overwritten when you run the `spring binstub` command.
25
+
26
+ if !defined?(Spring) && [nil, "development", "test"].include?(ENV["RAILS_ENV"])
27
+ require "bundler"
28
+
29
+ Bundler.locked_gems.specs.find { |spec| spec.name == "spring" }&.tap do |spring|
30
+ Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
31
+ gem "spring", spring.version
32
+ require "spring/binstub"
33
+ end
34
+ end
35
+ CODE
45
36
 
46
37
  OLD_BINSTUB = %{if !Process.respond_to?(:fork) || Gem::Specification.find_all_by_name("spring").empty?}
47
38
 
48
39
  BINSTUB_VARIATIONS = Regexp.union [
49
- %{begin\n load File.expand_path("../spring", __FILE__)\nrescue LoadError\nend\n},
40
+ %{load File.expand_path("spring", __dir__)\n},
41
+ %{begin\n load File.expand_path('../spring', __FILE__)\nrescue LoadError => e\n raise unless e.message.include?('spring')\nend\n},
50
42
  %{begin\n load File.expand_path('../spring', __FILE__)\nrescue LoadError\nend\n},
51
43
  %{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},
52
44
  LOADER
53
- ]
45
+ ].map { |binstub| /#{Regexp.escape(binstub).gsub("'", "['\"]")}/ }
54
46
 
55
47
  class Item
56
48
  attr_reader :command, :existing
@@ -79,7 +71,7 @@ CODE
79
71
  generate(fallback)
80
72
  status "upgraded"
81
73
  elsif existing.include?(LOADER)
82
- status "spring already present"
74
+ status "Spring already present"
83
75
  elsif existing =~ BINSTUB_VARIATIONS
84
76
  upgraded = existing.sub(BINSTUB_VARIATIONS, LOADER)
85
77
  File.write(command.binstub, upgraded)
@@ -94,15 +86,15 @@ CODE
94
86
  end
95
87
 
96
88
  File.write(command.binstub, "#{head}#{shebang}#{LOADER}#{tail}")
97
- status "spring inserted"
89
+ status "Spring inserted"
98
90
  else
99
- status "doesn't appear to be ruby, so cannot use spring", $stderr
91
+ status "doesn't appear to be ruby, so cannot use Spring", $stderr
100
92
  exit 1
101
93
  end
102
94
  end
103
95
  else
104
96
  generate
105
- status "generated with spring"
97
+ status "generated with Spring"
106
98
  end
107
99
  end
108
100
 
@@ -119,7 +111,7 @@ CODE
119
111
  def remove
120
112
  if existing
121
113
  File.write(command.binstub, existing.sub(BINSTUB_VARIATIONS, ""))
122
- status "spring removed"
114
+ status "Spring removed"
123
115
  end
124
116
  end
125
117
  end
@@ -127,7 +119,7 @@ CODE
127
119
  attr_reader :bindir, :items
128
120
 
129
121
  def self.description
130
- "Generate spring based binstubs. Use --all to generate a binstub for all known commands. Use --remove to revert."
122
+ "Generate Spring based binstubs. Use --all to generate a binstub for all known commands. Use --remove to revert."
131
123
  end
132
124
 
133
125
  def self.rails_command
@@ -147,7 +139,7 @@ CODE
147
139
  @mode = :add
148
140
  @items = args.drop(1)
149
141
  .map { |name| find_commands name }
150
- .inject(Set.new, :|)
142
+ .flatten.uniq
151
143
  .map { |command| Item.new(command) }
152
144
  end
153
145
 
@@ -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
@@ -1,9 +1,7 @@
1
- require "set"
2
-
3
1
  module Spring
4
2
  module Client
5
3
  class Rails < Command
6
- COMMANDS = Set.new %w(console runner generate destroy test)
4
+ COMMANDS = %w(console runner generate destroy test)
7
5
 
8
6
  ALIASES = {
9
7
  "c" => "console",
@@ -14,7 +12,7 @@ module Spring
14
12
  }
15
13
 
16
14
  def self.description
17
- "Run a rails command. The following sub commands will use spring: #{COMMANDS.to_a.join ', '}."
15
+ "Run a rails command. The following sub commands will use Spring: #{COMMANDS.to_a.join ', '}."
18
16
  end
19
17
 
20
18
  def call
@@ -22,6 +20,8 @@ module Spring
22
20
 
23
21
  if COMMANDS.include?(command_name)
24
22
  Run.call(["rails_#{command_name}", *args.drop(2)])
23
+ elsif command_name&.start_with?("db:") && !command_name.start_with?("db:system")
24
+ Run.call(["rake", *args.drop(1)])
25
25
  else
26
26
  require "spring/configuration"
27
27
  ARGV.shift
@@ -6,8 +6,6 @@ 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
- CONNECT_TIMEOUT = 1
10
- BOOT_TIMEOUT = 20
11
9
 
12
10
  attr_reader :server
13
11
 
@@ -44,7 +42,7 @@ module Spring
44
42
  require "spring/commands"
45
43
 
46
44
  if Spring.command?(args.first)
47
- # Command installed since spring started
45
+ # Command installed since Spring started
48
46
  stop_server
49
47
  cold_run
50
48
  else
@@ -73,8 +71,8 @@ module Spring
73
71
  def boot_server
74
72
  env.socket_path.unlink if env.socket_path.exist?
75
73
 
76
- pid = Process.spawn(gem_env, env.server_command, out: File::NULL)
77
- timeout = Time.now + BOOT_TIMEOUT
74
+ pid = Process.spawn(server_process_env, env.server_command, out: File::NULL)
75
+ timeout = Time.now + Spring.boot_timeout
78
76
 
79
77
  @server_booted = true
80
78
 
@@ -85,7 +83,7 @@ module Spring
85
83
  exit status.exitstatus
86
84
  elsif Time.now > timeout
87
85
  $stderr.puts "Starting Spring server with `#{env.server_command}` " \
88
- "timed out after #{BOOT_TIMEOUT} seconds"
86
+ "timed out after #{Spring.boot_timeout} seconds"
89
87
  exit 1
90
88
  end
91
89
 
@@ -107,6 +105,14 @@ module Spring
107
105
  }
108
106
  end
109
107
 
108
+ def reset_env
109
+ ENV.slice(*Spring.reset_on_env)
110
+ end
111
+
112
+ def server_process_env
113
+ reset_env.merge(gem_env)
114
+ end
115
+
110
116
  def stop_server
111
117
  server.close
112
118
  @server = nil
@@ -114,9 +120,18 @@ module Spring
114
120
  end
115
121
 
116
122
  def verify_server_version
117
- server_version = server.gets.chomp
123
+ unless IO.select([server], [], [], Spring.connect_timeout)
124
+ raise "Error connecting to Spring server"
125
+ end
126
+
127
+ line = server.gets
128
+ unless line
129
+ raise "Error connecting to Spring server"
130
+ end
131
+
132
+ server_version = line.chomp
118
133
  if server_version != env.version
119
- $stderr.puts "There is a version mismatch between the spring client " \
134
+ $stderr.puts "There is a version mismatch between the Spring client " \
120
135
  "(#{env.version}) and the server (#{server_version})."
121
136
 
122
137
  if server_booted?
@@ -132,9 +147,9 @@ module Spring
132
147
 
133
148
  def connect_to_application(client)
134
149
  server.send_io client
135
- send_json server, "args" => args, "default_rails_env" => default_rails_env
150
+ send_json server, "args" => args, "default_rails_env" => default_rails_env, "spawn_env" => spawn_env, "reset_env" => reset_env
136
151
 
137
- if IO.select([server], [], [], CONNECT_TIMEOUT)
152
+ if IO.select([server], [], [], Spring.connect_timeout)
138
153
  server.gets or raise CommandNotFound
139
154
  else
140
155
  raise "Error connecting to Spring server"
@@ -142,12 +157,17 @@ module Spring
142
157
  end
143
158
 
144
159
  def run_command(client, application)
145
- log "sending command"
146
-
147
160
  application.send_io STDOUT
148
161
  application.send_io STDERR
149
162
  application.send_io STDIN
150
163
 
164
+ log "waiting for the application to be preloaded"
165
+ preload_status = application.gets
166
+ preload_status = preload_status.chomp if preload_status
167
+ log "app preload status: #{preload_status}"
168
+ exit 1 if preload_status == "1"
169
+
170
+ log "sending command"
151
171
  send_json application, "args" => args, "env" => ENV.to_hash
152
172
 
153
173
  pid = server.gets
@@ -161,6 +181,8 @@ module Spring
161
181
  if pid && !pid.empty?
162
182
  log "got pid: #{pid}"
163
183
 
184
+ suspend_resume_on_tstp_cont(pid)
185
+
164
186
  forward_signals(application)
165
187
  status = application.read.to_i
166
188
 
@@ -181,6 +203,18 @@ module Spring
181
203
  end
182
204
  end
183
205
 
206
+ def suspend_resume_on_tstp_cont(pid)
207
+ trap("TSTP") {
208
+ log "suspended"
209
+ Process.kill("STOP", pid.to_i)
210
+ Process.kill("STOP", Process.pid)
211
+ }
212
+ trap("CONT") {
213
+ log "resumed"
214
+ Process.kill("CONT", pid.to_i)
215
+ }
216
+ end
217
+
184
218
  def forward_signals(application)
185
219
  @signal_queue.each { |sig| kill sig, application }
186
220
 
@@ -213,6 +247,10 @@ module Spring
213
247
  def default_rails_env
214
248
  ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
215
249
  end
250
+
251
+ def spawn_env
252
+ ENV.slice(*Spring.spawn_on_env)
253
+ end
216
254
  end
217
255
  end
218
256
  end
@@ -4,7 +4,7 @@ module Spring
4
4
  module Client
5
5
  class Stop < Command
6
6
  def self.description
7
- "Stop all spring processes for this project."
7
+ "Stop all Spring processes for this project."
8
8
  end
9
9
 
10
10
  def call
@@ -28,11 +28,18 @@ module Spring
28
28
  config = File.expand_path("~/.spring.rb")
29
29
  require config if File.exist?(config)
30
30
 
31
- # If the config/spring.rb contains requires for commands from other gems,
32
- # then we need to be under bundler.
33
- require "bundler/setup"
31
+ # We force the TTY so bundler doesn't show a backtrace in case gems are missing.
32
+ old_env = ENV["BUNDLER_FORCE_TTY"]
33
+ ENV["BUNDLER_FORCE_TTY"] = "true"
34
+ begin
35
+ # If the config/spring.rb contains requires for commands from other gems,
36
+ # then we need to be under bundler.
37
+ require "bundler/setup"
38
+ ensure
39
+ ENV["BUNDLER_FORCE_TTY"] = old_env
40
+ end
34
41
 
35
- # Auto-require any spring extensions which are in the Gemfile
42
+ # Auto-require any Spring extensions which are in the Gemfile
36
43
  Gem::Specification.map(&:name).grep(/^spring-/).each do |command|
37
44
  begin
38
45
  require command
@@ -1,11 +1,30 @@
1
1
  require "spring/errors"
2
2
 
3
3
  module Spring
4
+ @connect_timeout = 5
5
+ @boot_timeout = 20
6
+
4
7
  class << self
5
- attr_accessor :application_root, :quiet
8
+ attr_accessor :application_root, :connect_timeout, :boot_timeout
9
+ attr_writer :quiet
6
10
 
7
11
  def gemfile
8
- ENV['BUNDLE_GEMFILE'] || "Gemfile"
12
+ require "bundler"
13
+
14
+ if /\s1.9.[0-9]/ === Bundler.ruby_scope.gsub(/[\/\s]+/,'')
15
+ Pathname.new(ENV["BUNDLE_GEMFILE"] || "Gemfile").expand_path
16
+ else
17
+ Bundler.default_gemfile
18
+ end
19
+ end
20
+
21
+ def gemfile_lock
22
+ case gemfile.to_s
23
+ when /\bgems\.rb\z/
24
+ gemfile.sub_ext('.locked')
25
+ else
26
+ gemfile.sub_ext('.lock')
27
+ end
9
28
  end
10
29
 
11
30
  def after_fork_callbacks
@@ -16,6 +35,14 @@ module Spring
16
35
  after_fork_callbacks << block
17
36
  end
18
37
 
38
+ def spawn_on_env
39
+ @spawn_on_env ||= []
40
+ end
41
+
42
+ def reset_on_env
43
+ @reset_on_env ||= []
44
+ end
45
+
19
46
  def verify_environment
20
47
  application_root_path
21
48
  end
@@ -37,6 +64,10 @@ module Spring
37
64
  @project_root_path ||= find_project_root(Pathname.new(File.expand_path(Dir.pwd)))
38
65
  end
39
66
 
67
+ def quiet
68
+ @quiet || ENV.key?('SPRING_QUIET')
69
+ end
70
+
40
71
  private
41
72
 
42
73
  def find_project_root(current_dir)
data/lib/spring/env.rb CHANGED
@@ -1,10 +1,6 @@
1
1
  require "pathname"
2
- require "fileutils"
3
- require "digest/md5"
4
- require "tmpdir"
5
2
 
6
3
  require "spring/version"
7
- require "spring/sid"
8
4
  require "spring/configuration"
9
5
 
10
6
  module Spring
@@ -33,15 +29,18 @@ module Spring
33
29
  end
34
30
 
35
31
  def tmp_path
32
+ require "tmpdir"
36
33
  path = Pathname.new(
37
34
  ENV["SPRING_TMP_PATH"] ||
38
35
  File.join(ENV['XDG_RUNTIME_DIR'] || Dir.tmpdir, "spring-#{Process.uid}")
39
36
  )
37
+ require "fileutils"
40
38
  FileUtils.mkdir_p(path) unless path.exist?
41
39
  path
42
40
  end
43
41
 
44
42
  def application_id
43
+ require "digest/md5"
45
44
  ENV["SPRING_APPLICATION_ID"] || Digest::MD5.hexdigest(RUBY_VERSION + project_root.to_s)
46
45
  end
47
46
 
data/lib/spring/errors.rb CHANGED
@@ -24,7 +24,7 @@ module Spring
24
24
 
25
25
  def message
26
26
  "Spring was unable to find your config/application.rb file. " \
27
- "Your project root was detected at #{project_root}, so spring " \
27
+ "Your project root was detected at #{project_root}, so Spring " \
28
28
  "looked for #{project_root}/config/application.rb but it doesn't exist. You can " \
29
29
  "configure the root of your application by setting Spring.application_root in " \
30
30
  "config/spring.rb."
data/lib/spring/json.rb CHANGED
@@ -46,11 +46,9 @@ end
46
46
 
47
47
  # See https://github.com/kr/okjson for updates.
48
48
 
49
- require 'stringio'
50
-
51
49
  # Some parts adapted from
52
- # http://golang.org/src/pkg/json/decode.go and
53
- # http://golang.org/src/pkg/utf8/utf8.go
50
+ # https://golang.org/src/pkg/json/decode.go and
51
+ # https://golang.org/src/pkg/utf8/utf8.go
54
52
  module Spring
55
53
  module OkJson
56
54
  Upstream = '43'
@@ -468,19 +466,18 @@ private
468
466
 
469
467
 
470
468
  def strenc(s)
471
- t = StringIO.new
472
- t.putc(?")
469
+ t = '"'.b
473
470
  r = 0
474
471
 
475
472
  while r < s.length
476
473
  case s[r]
477
- when ?" then t.print('\\"')
478
- when ?\\ then t.print('\\\\')
479
- when ?\b then t.print('\\b')
480
- when ?\f then t.print('\\f')
481
- when ?\n then t.print('\\n')
482
- when ?\r then t.print('\\r')
483
- when ?\t then t.print('\\t')
474
+ when ?" then t << '\\"'
475
+ when ?\\ then t << '\\\\'
476
+ when ?\b then t << '\\b'
477
+ when ?\f then t << '\\f'
478
+ when ?\n then t << '\\n'
479
+ when ?\r then t << '\\r'
480
+ when ?\t then t << '\\t'
484
481
  else
485
482
  c = s[r]
486
483
  # In ruby >= 1.9, s[r] is a codepoint, not a byte.
@@ -490,14 +487,14 @@ private
490
487
  if c.ord < Spc.ord
491
488
  c = "\\u%04x" % [c.ord]
492
489
  end
493
- t.write(c)
490
+ t << c
494
491
  rescue
495
- t.write(Ustrerr)
492
+ t << Ustrerr
496
493
  end
497
494
  elsif c < Spc
498
- t.write("\\u%04x" % c)
495
+ t << "\\u%04x" % c
499
496
  elsif Spc <= c && c <= ?~
500
- t.putc(c)
497
+ t << c
501
498
  else
502
499
  n = ucharcopy(t, s, r) # ensure valid UTF-8 output
503
500
  r += n - 1 # r is incremented below
@@ -505,8 +502,8 @@ private
505
502
  end
506
503
  r += 1
507
504
  end
508
- t.putc(?")
509
- t.string
505
+ t << '"'
506
+ t
510
507
  end
511
508
 
512
509
 
@@ -531,7 +528,7 @@ private
531
528
 
532
529
  # 1-byte, 7-bit sequence?
533
530
  if c0 < Utagx
534
- t.putc(c0)
531
+ t << c0
535
532
  return 1
536
533
  end
537
534
 
@@ -544,8 +541,8 @@ private
544
541
  # 2-byte, 11-bit sequence?
545
542
  if c0 < Utag3
546
543
  raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max
547
- t.putc(c0)
548
- t.putc(c1)
544
+ t << c0
545
+ t << c1
549
546
  return 2
550
547
  end
551
548
 
@@ -559,9 +556,9 @@ private
559
556
  if c0 < Utag4
560
557
  u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx)
561
558
  raise Utf8Error if u <= Uchar2max
562
- t.putc(c0)
563
- t.putc(c1)
564
- t.putc(c2)
559
+ t << c0
560
+ t << c1
561
+ t << c2
565
562
  return 3
566
563
  end
567
564
 
@@ -574,16 +571,16 @@ private
574
571
  if c0 < Utag5
575
572
  u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx)
576
573
  raise Utf8Error if u <= Uchar3max
577
- t.putc(c0)
578
- t.putc(c1)
579
- t.putc(c2)
580
- t.putc(c3)
574
+ t << c0
575
+ t << c1
576
+ t << c2
577
+ t << c3
581
578
  return 4
582
579
  end
583
580
 
584
581
  raise Utf8Error
585
582
  rescue Utf8Error
586
- t.write(Ustrerr)
583
+ t << Ustrerr
587
584
  return 1
588
585
  end
589
586
 
@@ -1,6 +1,6 @@
1
1
  module Spring
2
2
  # Yes, I know this reimplements a bunch of stuff in Active Support, but
3
- # I don't want the spring client to depend on AS, in order to keep its
3
+ # I don't want the Spring client to depend on AS, in order to keep its
4
4
  # load time down.
5
5
  class ProcessTitleUpdater
6
6
  SECOND = 1
data/lib/spring/server.rb CHANGED
@@ -19,7 +19,9 @@ module Spring
19
19
  def initialize(options = {})
20
20
  @foreground = options.fetch(:foreground, false)
21
21
  @env = options[:env] || default_env
22
- @applications = Hash.new { |h, k| h[k] = ApplicationManager.new(k, env) }
22
+ @applications = Hash.new do |hash, key|
23
+ hash[key] = ApplicationManager.new(*key, env)
24
+ end
23
25
  @pidfile = env.pidfile_path.open('a')
24
26
  @mutex = Mutex.new
25
27
  end
@@ -57,12 +59,15 @@ module Spring
57
59
  app_client = client.recv_io
58
60
  command = JSON.load(client.read(client.gets.to_i))
59
61
 
60
- args, default_rails_env = command.values_at('args', 'default_rails_env')
62
+ args, default_rails_env, spawn_env, reset_env = command.values_at('args', 'default_rails_env', 'spawn_env', 'reset_env')
61
63
 
62
64
  if Spring.command?(args.first)
65
+ application = @applications[rails_env_for(args, default_rails_env, spawn_env)]
66
+ reset_if_env_changed(application, reset_env)
67
+
63
68
  log "running command #{args.first}"
64
69
  client.puts
65
- client.puts @applications[rails_env_for(args, default_rails_env)].run(app_client)
70
+ client.puts application.run(app_client)
66
71
  else
67
72
  log "command not found #{args.first}"
68
73
  client.close
@@ -73,15 +78,16 @@ module Spring
73
78
  redirect_output
74
79
  end
75
80
 
76
- def rails_env_for(args, default_rails_env)
77
- Spring.command(args.first).env(args.drop(1)) || default_rails_env
81
+ def rails_env_for(args, default_rails_env, spawn_env)
82
+ [Spring.command(args.first).env(args.drop(1)) || default_rails_env, spawn_env]
78
83
  end
79
84
 
80
85
  # Boot the server into the process group of the current session.
81
86
  # This will cause it to be automatically killed once the session
82
87
  # ends (i.e. when the user closes their terminal).
83
88
  def set_pgid
84
- Process.setpgid(0, SID.pgid)
89
+ pgid = Process.getpgid(Process.getsid)
90
+ Process.setpgid(0, pgid)
85
91
  end
86
92
 
87
93
  # Ignore SIGINT and SIGQUIT otherwise the user typing ^C or ^\ on the command line
@@ -135,6 +141,10 @@ module Spring
135
141
 
136
142
  private
137
143
 
144
+ def reset_if_env_changed(application, reset_env)
145
+ application.stop if ENV.slice(*reset_env.keys) != reset_env
146
+ end
147
+
138
148
  def default_env
139
149
  Env.new(log_file: default_log_file)
140
150
  end
@@ -1,3 +1,3 @@
1
1
  module Spring
2
- VERSION = "2.0.2"
2
+ VERSION = "4.2.1"
3
3
  end