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.
- checksums.yaml +5 -5
- data/LICENSE.txt +1 -0
- data/README.md +66 -39
- data/lib/spring/application/boot.rb +9 -3
- data/lib/spring/application.rb +80 -42
- data/lib/spring/application_manager.rb +10 -5
- data/lib/spring/binstub.rb +0 -20
- data/lib/spring/client/binstub.rb +32 -40
- data/lib/spring/client/help.rb +1 -1
- data/lib/spring/client/rails.rb +4 -4
- data/lib/spring/client/run.rb +50 -12
- data/lib/spring/client/stop.rb +1 -1
- data/lib/spring/commands.rb +11 -4
- data/lib/spring/configuration.rb +33 -2
- data/lib/spring/env.rb +3 -4
- data/lib/spring/errors.rb +1 -1
- data/lib/spring/json.rb +27 -30
- data/lib/spring/process_title_updater.rb +1 -1
- data/lib/spring/server.rb +16 -6
- data/lib/spring/version.rb +1 -1
- data/lib/spring/watcher/abstract.rb +12 -12
- data/lib/spring/watcher/polling.rb +2 -2
- metadata +10 -59
- data/lib/spring/sid.rb +0 -42
- data/lib/spring/test/acceptance_test.rb +0 -558
- data/lib/spring/test/application.rb +0 -229
- data/lib/spring/test/application_generator.rb +0 -144
- data/lib/spring/test/rails_version.rb +0 -23
- data/lib/spring/test/watcher_test.rb +0 -194
- data/lib/spring/test.rb +0 -18
@@ -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
|
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
|
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 =
|
15
|
-
|
16
|
-
|
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 =
|
27
|
-
#!/usr/bin/env ruby
|
28
|
-
|
29
|
-
# This file loads
|
30
|
-
# It gets overwritten when you run the `spring binstub` command.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
%{
|
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 "
|
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 "
|
89
|
+
status "Spring inserted"
|
98
90
|
else
|
99
|
-
status "doesn't appear to be ruby, so cannot use
|
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
|
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 "
|
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
|
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
|
-
.
|
142
|
+
.flatten.uniq
|
151
143
|
.map { |command| Item.new(command) }
|
152
144
|
end
|
153
145
|
|
data/lib/spring/client/help.rb
CHANGED
@@ -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("
|
35
|
+
*command_help("Spring itself", spring_commands),
|
36
36
|
'',
|
37
37
|
*command_help("your application", application_commands)].join("\n")
|
38
38
|
end
|
data/lib/spring/client/rails.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
|
-
require "set"
|
2
|
-
|
3
1
|
module Spring
|
4
2
|
module Client
|
5
3
|
class Rails < Command
|
6
|
-
COMMANDS =
|
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
|
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
|
data/lib/spring/client/run.rb
CHANGED
@@ -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
|
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(
|
77
|
-
timeout = Time.now +
|
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 #{
|
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
|
-
|
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
|
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], [], [],
|
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
|
data/lib/spring/client/stop.rb
CHANGED
data/lib/spring/commands.rb
CHANGED
@@ -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
|
-
#
|
32
|
-
|
33
|
-
|
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
|
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
|
data/lib/spring/configuration.rb
CHANGED
@@ -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, :
|
8
|
+
attr_accessor :application_root, :connect_timeout, :boot_timeout
|
9
|
+
attr_writer :quiet
|
6
10
|
|
7
11
|
def gemfile
|
8
|
-
|
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
|
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
|
-
#
|
53
|
-
#
|
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 =
|
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
|
478
|
-
when ?\\ then t
|
479
|
-
when ?\b then t
|
480
|
-
when ?\f then t
|
481
|
-
when ?\n then t
|
482
|
-
when ?\r then t
|
483
|
-
when ?\t then 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
|
490
|
+
t << c
|
494
491
|
rescue
|
495
|
-
t
|
492
|
+
t << Ustrerr
|
496
493
|
end
|
497
494
|
elsif c < Spc
|
498
|
-
t
|
495
|
+
t << "\\u%04x" % c
|
499
496
|
elsif Spc <= c && c <= ?~
|
500
|
-
t
|
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
|
509
|
-
t
|
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
|
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
|
548
|
-
t
|
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
|
563
|
-
t
|
564
|
-
t
|
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
|
578
|
-
t
|
579
|
-
t
|
580
|
-
t
|
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
|
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
|
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
|
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
|
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.
|
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
|
data/lib/spring/version.rb
CHANGED