spring 4.1.3 → 4.3.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
  SHA256:
3
- metadata.gz: 1aaab82742a464eba8cafc32761c1f8509c661d3eae8816c7ce37402b1e454ba
4
- data.tar.gz: dca019edd6550c1ce7d514da586df59a3c3838d1f36d113e9870cdf44052a655
3
+ metadata.gz: 3e92617adaa3e6c31e4d466d76894c94ec17a46fd7206864501218795ac8998d
4
+ data.tar.gz: aee2d23a222df8747942652dda1d6a725f59bb68b395fbd37a9084c5ed75fe7b
5
5
  SHA512:
6
- metadata.gz: 52b2c4a44be6f82f5c4877af16c52aacf98cf28641210dde453439e7e2d9ded480bc7ceb1e58465d30e8992b1bd88a8b591246bcfc66708c722fd5692c7c98a6
7
- data.tar.gz: abb5569bb5d37f570003ba7784f181afd0598249cddc3c1519e2df63368b8db3a540119c8fedccb599c095a2b3c07dee5df0e0a09c09c30f551ccdf7e7f45f7b
6
+ metadata.gz: 16e03232e4453b528812c925c4186360e1157b10aab0d663d1dc3d4a80a7d4bdf1da8f06d31c6ace1456fa4f6f5e20b2c62637ce0a23da6cae705b56baa6882b
7
+ data.tar.gz: 1a4c70a381783cc3f96372e28efc6b702b3b75a28c31a1a88eacace55c3a3cbd2aee3d3ff81236526366149a612754c22d9ec0861bc0a3dfb8669108f9bb0aba
@@ -11,9 +11,15 @@ app = Spring::Application.new(
11
11
 
12
12
  Signal.trap("TERM") { app.terminate }
13
13
 
14
- Spring::ProcessTitleUpdater.run { |distance|
15
- "spring app | #{app.app_name} | started #{distance} ago | #{app.app_env} mode"
16
- }
14
+ Spring::ProcessTitleUpdater.run do |distance|
15
+ attributes = [
16
+ app.app_name,
17
+ "started #{distance} ago",
18
+ "#{app.app_env} mode",
19
+ app.spawn_env,
20
+ ].compact
21
+ "spring app | #{attributes.join(" | ")}"
22
+ end
17
23
 
18
24
  app.eager_preload if ENV.delete("SPRING_PRELOAD") == "1"
19
25
  app.run
@@ -28,6 +28,11 @@ module Spring
28
28
  @interrupt.last.write "."
29
29
  end
30
30
 
31
+ def spawn_env
32
+ env = JSON.load(ENV["SPRING_SPAWN_ENV"].dup).map { |key, value| "#{key}=#{value}" }
33
+ env.join(", ") if env.any?
34
+ end
35
+
31
36
  def app_env
32
37
  ENV['RAILS_ENV']
33
38
  end
@@ -119,6 +124,11 @@ module Spring
119
124
 
120
125
  if defined?(Rails) && Rails.application
121
126
  watcher.add Rails.application.paths["config/initializers"]
127
+ Rails::Engine.descendants.each do |engine|
128
+ if engine.root.to_s.start_with?(Rails.root.to_s)
129
+ watcher.add engine.paths["config/initializers"].expanded
130
+ end
131
+ end
122
132
  watcher.add Rails.application.paths["config/database"]
123
133
  if secrets_path = Rails.application.paths["config/secrets"]
124
134
  watcher.add secrets_path
@@ -1,9 +1,10 @@
1
1
  module Spring
2
2
  class ApplicationManager
3
- attr_reader :pid, :child, :app_env, :spring_env, :status
3
+ attr_reader :pid, :child, :app_env, :spawn_env, :spring_env, :status
4
4
 
5
- def initialize(app_env, spring_env)
5
+ def initialize(app_env, spawn_env, spring_env)
6
6
  @app_env = app_env
7
+ @spawn_env = spawn_env
7
8
  @spring_env = spring_env
8
9
  @mutex = Mutex.new
9
10
  @state = :running
@@ -100,7 +101,9 @@ module Spring
100
101
  "RAILS_ENV" => app_env,
101
102
  "RACK_ENV" => app_env,
102
103
  "SPRING_ORIGINAL_ENV" => JSON.dump(Spring::ORIGINAL_ENV),
103
- "SPRING_PRELOAD" => preload ? "1" : "0"
104
+ "SPRING_PRELOAD" => preload ? "1" : "0",
105
+ "SPRING_SPAWN_ENV" => JSON.dump(spawn_env),
106
+ **spawn_env,
104
107
  },
105
108
  "ruby",
106
109
  *(bundler_dir != RbConfig::CONFIG["rubylibdir"] ? ["-I", bundler_dir] : []),
@@ -123,7 +126,8 @@ module Spring
123
126
  # as if it does we're no longer interested in the child
124
127
  loop do
125
128
  IO.select([child])
126
- break if child.recv(1, Socket::MSG_PEEK).empty?
129
+ peek = child.recv(1, Socket::MSG_PEEK)
130
+ break if peek.nil? || peek.empty?
127
131
  sleep 0.01
128
132
  end
129
133
 
@@ -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
 
@@ -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,7 +120,16 @@ 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
134
  $stderr.puts "There is a version mismatch between the Spring client " \
120
135
  "(#{env.version}) and the server (#{server_version})."
@@ -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"
@@ -232,6 +247,10 @@ module Spring
232
247
  def default_rails_env
233
248
  ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
234
249
  end
250
+
251
+ def spawn_env
252
+ ENV.slice(*Spring.spawn_on_env)
253
+ end
235
254
  end
236
255
  end
237
256
  end
@@ -1,8 +1,11 @@
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
8
+ attr_accessor :application_root, :connect_timeout, :boot_timeout
6
9
  attr_writer :quiet
7
10
 
8
11
  def gemfile
@@ -32,6 +35,14 @@ module Spring
32
35
  after_fork_callbacks << block
33
36
  end
34
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
+
35
46
  def verify_environment
36
47
  application_root_path
37
48
  end
data/lib/spring/json.rb CHANGED
@@ -1,4 +1,4 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # ### WHY SPRING VENDORS A JSON LIBRARY ###
4
4
  #
@@ -13,7 +13,6 @@
13
13
  module Spring
14
14
  module JSON
15
15
  def self.load(string)
16
- string.force_encoding("utf-8")
17
16
  OkJson.decode(string)
18
17
  end
19
18
 
@@ -364,7 +363,7 @@ private
364
363
  end
365
364
  end
366
365
  if rubydoesenc?
367
- a[w] = '' << uchar
366
+ a[w] = +'' << uchar
368
367
  w += 1
369
368
  else
370
369
  w += ucharenc(a, w, uchar)
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,8 +78,8 @@ 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.
@@ -136,6 +141,10 @@ module Spring
136
141
 
137
142
  private
138
143
 
144
+ def reset_if_env_changed(application, reset_env)
145
+ application.stop if ENV.slice(*reset_env.keys) != reset_env
146
+ end
147
+
139
148
  def default_env
140
149
  Env.new(log_file: default_log_file)
141
150
  end
@@ -1,3 +1,3 @@
1
1
  module Spring
2
- VERSION = "4.1.3"
2
+ VERSION = "4.3.0"
3
3
  end
metadata CHANGED
@@ -1,57 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spring
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.3
4
+ version: 4.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Leighton
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-11-22 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rake
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: bump
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: activesupport
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
10
+ date: 2025-03-12 00:00:00.000000000 Z
11
+ dependencies: []
55
12
  description: Preloads your application so things like console, rake and tests run
56
13
  faster
57
14
  email:
@@ -99,7 +56,6 @@ licenses:
99
56
  - MIT
100
57
  metadata:
101
58
  rubygems_mfa_required: 'true'
102
- post_install_message:
103
59
  rdoc_options: []
104
60
  require_paths:
105
61
  - lib
@@ -114,8 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
70
  - !ruby/object:Gem::Version
115
71
  version: '0'
116
72
  requirements: []
117
- rubygems_version: 3.3.7
118
- signing_key:
73
+ rubygems_version: 3.6.2
119
74
  specification_version: 4
120
75
  summary: Rails application preloader
121
76
  test_files: []