spring 2.0.0 → 3.0.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 +5 -5
- data/LICENSE.txt +1 -1
- data/README.md +37 -24
- data/lib/spring/application.rb +39 -30
- data/lib/spring/application_manager.rb +4 -2
- data/lib/spring/binstub.rb +0 -20
- data/lib/spring/client/binstub.rb +13 -13
- data/lib/spring/client/help.rb +1 -1
- data/lib/spring/client/rails.rb +1 -1
- data/lib/spring/client/run.rb +16 -2
- data/lib/spring/client/stop.rb +1 -1
- data/lib/spring/commands.rb +1 -1
- data/lib/spring/configuration.rb +5 -1
- data/lib/spring/env.rb +2 -2
- data/lib/spring/errors.rb +1 -1
- data/lib/spring/process_title_updater.rb +1 -1
- data/lib/spring/version.rb +1 -1
- data/lib/spring/watcher/abstract.rb +33 -2
- data/lib/spring/watcher/polling.rb +46 -9
- metadata +13 -20
- data/lib/spring/test/acceptance_test.rb +0 -550
- data/lib/spring/test/application.rb +0 -229
- data/lib/spring/test/application_generator.rb +0 -139
- data/lib/spring/test/rails_version.rb +0 -23
- data/lib/spring/test/watcher_test.rb +0 -167
- data/lib/spring/test.rb +0 -18
@@ -1,229 +0,0 @@
|
|
1
|
-
require "spring/env"
|
2
|
-
|
3
|
-
module Spring
|
4
|
-
module Test
|
5
|
-
class Application
|
6
|
-
DEFAULT_TIMEOUT = ENV['CI'] ? 30 : 10
|
7
|
-
|
8
|
-
attr_reader :root, :spring_env
|
9
|
-
|
10
|
-
def initialize(root)
|
11
|
-
@root = Pathname.new(root)
|
12
|
-
@spring_env = Spring::Env.new(root: root)
|
13
|
-
@times = nil
|
14
|
-
end
|
15
|
-
|
16
|
-
def exists?
|
17
|
-
root.exist?
|
18
|
-
end
|
19
|
-
|
20
|
-
def stdout
|
21
|
-
@stdout ||= IO.pipe
|
22
|
-
end
|
23
|
-
|
24
|
-
def stderr
|
25
|
-
@stderr ||= IO.pipe
|
26
|
-
end
|
27
|
-
|
28
|
-
def log_file
|
29
|
-
@log_file ||= path("tmp/spring.log").open("w+")
|
30
|
-
end
|
31
|
-
|
32
|
-
def env
|
33
|
-
@env ||= {
|
34
|
-
"GEM_HOME" => gem_home.to_s,
|
35
|
-
"GEM_PATH" => gem_home.to_s,
|
36
|
-
"HOME" => user_home.to_s,
|
37
|
-
"RAILS_ENV" => nil,
|
38
|
-
"RACK_ENV" => nil,
|
39
|
-
"SPRING_LOG" => log_file.path
|
40
|
-
}
|
41
|
-
end
|
42
|
-
|
43
|
-
def path(addition)
|
44
|
-
root.join addition
|
45
|
-
end
|
46
|
-
|
47
|
-
def gemfile
|
48
|
-
path "Gemfile"
|
49
|
-
end
|
50
|
-
|
51
|
-
def gem_home
|
52
|
-
path "../gems/#{RUBY_VERSION}"
|
53
|
-
end
|
54
|
-
|
55
|
-
def user_home
|
56
|
-
path "user_home"
|
57
|
-
end
|
58
|
-
|
59
|
-
def spring
|
60
|
-
gem_home.join "bin/spring"
|
61
|
-
end
|
62
|
-
|
63
|
-
def rails_version
|
64
|
-
@rails_version ||= RailsVersion.new(gemfile.read.match(/gem 'rails', '(.*)'/)[1])
|
65
|
-
end
|
66
|
-
|
67
|
-
def spring_test_command
|
68
|
-
"bin/rake test #{test}"
|
69
|
-
end
|
70
|
-
|
71
|
-
def stop_spring
|
72
|
-
run "#{spring} stop"
|
73
|
-
rescue Errno::ENOENT
|
74
|
-
end
|
75
|
-
|
76
|
-
def test
|
77
|
-
path "test/controllers/posts_controller_test.rb"
|
78
|
-
end
|
79
|
-
|
80
|
-
def controller
|
81
|
-
path "app/controllers/posts_controller.rb"
|
82
|
-
end
|
83
|
-
|
84
|
-
def application_config
|
85
|
-
path "config/application.rb"
|
86
|
-
end
|
87
|
-
|
88
|
-
def spring_config
|
89
|
-
path "config/spring.rb"
|
90
|
-
end
|
91
|
-
|
92
|
-
def spring_client_config
|
93
|
-
path "config/spring_client.rb"
|
94
|
-
end
|
95
|
-
|
96
|
-
def run(command, opts = {})
|
97
|
-
start_time = Time.now
|
98
|
-
|
99
|
-
Bundler.with_clean_env do
|
100
|
-
Process.spawn(
|
101
|
-
env,
|
102
|
-
command.to_s,
|
103
|
-
out: stdout.last,
|
104
|
-
err: stderr.last,
|
105
|
-
in: :close,
|
106
|
-
chdir: root.to_s,
|
107
|
-
)
|
108
|
-
end
|
109
|
-
|
110
|
-
_, status = Timeout.timeout(opts.fetch(:timeout, DEFAULT_TIMEOUT)) { Process.wait2 }
|
111
|
-
|
112
|
-
if pid = spring_env.pid
|
113
|
-
@server_pid = pid
|
114
|
-
lines = `ps -A -o ppid= -o pid= | egrep '^\\s*#{@server_pid}'`.lines
|
115
|
-
@application_pids = lines.map { |l| l.split.last.to_i }
|
116
|
-
end
|
117
|
-
|
118
|
-
output = read_streams
|
119
|
-
puts dump_streams(command, output) if ENV["SPRING_DEBUG"]
|
120
|
-
|
121
|
-
@times << (Time.now - start_time) if @times
|
122
|
-
|
123
|
-
output.merge(status: status, command: command)
|
124
|
-
rescue Timeout::Error
|
125
|
-
raise Timeout::Error, "While running command:\n\n#{dump_streams(command, read_streams)}"
|
126
|
-
end
|
127
|
-
|
128
|
-
def with_timing
|
129
|
-
@times = []
|
130
|
-
yield
|
131
|
-
ensure
|
132
|
-
@times = nil
|
133
|
-
end
|
134
|
-
|
135
|
-
def last_time
|
136
|
-
@times.last
|
137
|
-
end
|
138
|
-
|
139
|
-
def first_time
|
140
|
-
@times.first
|
141
|
-
end
|
142
|
-
|
143
|
-
def timing_ratio
|
144
|
-
last_time / first_time
|
145
|
-
end
|
146
|
-
|
147
|
-
def read_streams
|
148
|
-
{
|
149
|
-
stdout: read_stream(stdout.first),
|
150
|
-
stderr: read_stream(stderr.first),
|
151
|
-
log: read_stream(log_file)
|
152
|
-
}
|
153
|
-
end
|
154
|
-
|
155
|
-
def read_stream(stream)
|
156
|
-
output = ""
|
157
|
-
while IO.select([stream], [], [], 0.5) && !stream.eof?
|
158
|
-
output << stream.readpartial(10240)
|
159
|
-
end
|
160
|
-
output
|
161
|
-
end
|
162
|
-
|
163
|
-
def dump_streams(command, streams)
|
164
|
-
output = "$ #{command}\n"
|
165
|
-
|
166
|
-
streams.each do |name, stream|
|
167
|
-
unless stream.chomp.empty?
|
168
|
-
output << "--- #{name} ---\n"
|
169
|
-
output << "#{stream.chomp}\n"
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
output << "\n"
|
174
|
-
output
|
175
|
-
end
|
176
|
-
|
177
|
-
def debug(artifacts)
|
178
|
-
artifacts = artifacts.dup
|
179
|
-
artifacts.delete :status
|
180
|
-
dump_streams(artifacts.delete(:command), artifacts)
|
181
|
-
end
|
182
|
-
|
183
|
-
def await_reload
|
184
|
-
raise "no pid" if @application_pids.nil? || @application_pids.empty?
|
185
|
-
|
186
|
-
Timeout.timeout(DEFAULT_TIMEOUT) do
|
187
|
-
sleep 0.1 while @application_pids.any? { |p| process_alive?(p) }
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def run!(command, options = {})
|
192
|
-
attempts = (options.delete(:retry) || 0) + 1
|
193
|
-
artifacts = nil
|
194
|
-
|
195
|
-
until attempts == 0 || artifacts && artifacts[:status].success?
|
196
|
-
artifacts = run(command, options)
|
197
|
-
attempts -= 1
|
198
|
-
end
|
199
|
-
|
200
|
-
if artifacts[:status].success?
|
201
|
-
artifacts
|
202
|
-
else
|
203
|
-
raise "command failed\n\n#{debug(artifacts)}"
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
def bundle
|
208
|
-
# Version restriction is a workaround for https://github.com/bundler/bundler/pull/4981
|
209
|
-
# The problem breaks our tests on Ruby 2.2
|
210
|
-
# We can remove once it's fixed
|
211
|
-
run! "(gem list bundler | grep bundler) || gem install bundler --version '~> 1.12.0'", timeout: nil, retry: 2
|
212
|
-
run! "bundle check || bundle update --retry=2", timeout: nil
|
213
|
-
end
|
214
|
-
|
215
|
-
def insert_into_test(code)
|
216
|
-
File.write(test, test.read.sub(/^\s*get .+$/, code))
|
217
|
-
end
|
218
|
-
|
219
|
-
private
|
220
|
-
|
221
|
-
def process_alive?(pid)
|
222
|
-
Process.kill 0, pid
|
223
|
-
true
|
224
|
-
rescue Errno::ESRCH
|
225
|
-
false
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
@@ -1,139 +0,0 @@
|
|
1
|
-
module Spring
|
2
|
-
module Test
|
3
|
-
class ApplicationGenerator
|
4
|
-
attr_reader :version_constraint, :version, :application
|
5
|
-
|
6
|
-
def initialize(version_constraint)
|
7
|
-
@version_constraint = version_constraint
|
8
|
-
@version = RailsVersion.new(version_constraint.split(' ').last)
|
9
|
-
@application = Application.new(root)
|
10
|
-
@bundled = false
|
11
|
-
@installed = false
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_root
|
15
|
-
Pathname.new Spring::Test.root
|
16
|
-
end
|
17
|
-
|
18
|
-
def root
|
19
|
-
test_root.join("apps/rails-#{version.major}-#{version.minor}-spring-#{Spring::VERSION}")
|
20
|
-
end
|
21
|
-
|
22
|
-
def system(command)
|
23
|
-
if ENV["SPRING_DEBUG"]
|
24
|
-
puts "$ #{command}\n"
|
25
|
-
else
|
26
|
-
command = "(#{command}) > /dev/null"
|
27
|
-
end
|
28
|
-
|
29
|
-
Kernel.system(command) or raise "command failed: #{command}"
|
30
|
-
puts if ENV["SPRING_DEBUG"]
|
31
|
-
end
|
32
|
-
|
33
|
-
def generate
|
34
|
-
Bundler.with_clean_env { generate_files }
|
35
|
-
install_spring
|
36
|
-
generate_scaffold
|
37
|
-
end
|
38
|
-
|
39
|
-
# Sporadic SSL errors keep causing test failures so there are anti-SSL workarounds here
|
40
|
-
def generate_files
|
41
|
-
if RUBY_VERSION == "1.9.3"
|
42
|
-
system("gem list '^mime-types$' --installed --version '~> 2' || " \
|
43
|
-
"gem install mime-types --clear-sources --source http://rubygems.org --version '~> 2'")
|
44
|
-
end
|
45
|
-
|
46
|
-
system("gem list '^rails$' --installed --version '#{version_constraint}' || " \
|
47
|
-
"gem install rails --clear-sources --source http://rubygems.org --version '#{version_constraint}'")
|
48
|
-
|
49
|
-
@version = RailsVersion.new(`ruby -e 'puts Gem::Specification.find_by_name("rails", "#{version_constraint}").version'`.chomp)
|
50
|
-
|
51
|
-
skips = %w(--skip-bundle --skip-javascript --skip-sprockets --skip-spring)
|
52
|
-
|
53
|
-
system("rails _#{version}_ new #{application.root} #{skips.join(' ')}")
|
54
|
-
raise "application generation failed" unless application.exists?
|
55
|
-
|
56
|
-
FileUtils.mkdir_p(application.gem_home)
|
57
|
-
FileUtils.mkdir_p(application.user_home)
|
58
|
-
FileUtils.rm_rf(application.path("test/performance"))
|
59
|
-
|
60
|
-
append_to_file(application.gemfile, "gem 'spring', '#{Spring::VERSION}'")
|
61
|
-
|
62
|
-
rewrite_file(application.gemfile) do |c|
|
63
|
-
c.sub!("https://rubygems.org", "http://rubygems.org")
|
64
|
-
c.gsub!(/(gem '(byebug|web-console|sdoc|jbuilder)')/, "# \\1")
|
65
|
-
c
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
|
-
if application.path("bin").exist?
|
70
|
-
FileUtils.cp_r(application.path("bin"), application.path("bin_original"))
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def rewrite_file(file)
|
75
|
-
File.write(file, yield(file.read))
|
76
|
-
end
|
77
|
-
|
78
|
-
def append_to_file(file, add)
|
79
|
-
rewrite_file(file) { |c| c << "#{add}\n" }
|
80
|
-
end
|
81
|
-
|
82
|
-
def generate_if_missing
|
83
|
-
generate unless application.exists?
|
84
|
-
end
|
85
|
-
|
86
|
-
def install_spring
|
87
|
-
return if @installed
|
88
|
-
|
89
|
-
if RUBY_VERSION < "2.2.2"
|
90
|
-
application.run! "gem install activesupport --version '#{version}'"
|
91
|
-
end
|
92
|
-
|
93
|
-
build_and_install_gems
|
94
|
-
|
95
|
-
application.bundle
|
96
|
-
|
97
|
-
FileUtils.rm_rf application.path("bin")
|
98
|
-
|
99
|
-
if application.path("bin_original").exist?
|
100
|
-
FileUtils.cp_r application.path("bin_original"), application.path("bin")
|
101
|
-
end
|
102
|
-
|
103
|
-
application.run! "#{application.spring} binstub --all"
|
104
|
-
@installed = true
|
105
|
-
end
|
106
|
-
|
107
|
-
def manually_built_gems
|
108
|
-
%w(spring)
|
109
|
-
end
|
110
|
-
|
111
|
-
def build_and_install_gems
|
112
|
-
manually_built_gems.each do |name|
|
113
|
-
spec = Gem::Specification.find_by_name(name)
|
114
|
-
|
115
|
-
FileUtils.cd(spec.gem_dir) do
|
116
|
-
FileUtils.rm(Dir.glob("#{name}-*.gem"))
|
117
|
-
system("gem build #{name}.gemspec 2>&1")
|
118
|
-
end
|
119
|
-
|
120
|
-
application.run! "gem install #{spec.gem_dir}/#{name}-*.gem --no-ri --no-rdoc", timeout: nil
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def copy_to(path)
|
125
|
-
system("rm -rf #{path}")
|
126
|
-
system("cp -r #{application.root} #{path}")
|
127
|
-
end
|
128
|
-
|
129
|
-
def generate_scaffold
|
130
|
-
application.run! "bundle exec rails g scaffold post title:string"
|
131
|
-
application.run! "bundle exec rake db:migrate db:test:clone"
|
132
|
-
end
|
133
|
-
|
134
|
-
def gemspec(name)
|
135
|
-
"#{Gem::Specification.find_by_name(name).gem_dir}/#{name}.gemspec"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Spring
|
2
|
-
module Test
|
3
|
-
class RailsVersion
|
4
|
-
attr_reader :version
|
5
|
-
|
6
|
-
def initialize(string)
|
7
|
-
@version = Gem::Version.new(string)
|
8
|
-
end
|
9
|
-
|
10
|
-
def major
|
11
|
-
version.segments[0]
|
12
|
-
end
|
13
|
-
|
14
|
-
def minor
|
15
|
-
version.segments[1]
|
16
|
-
end
|
17
|
-
|
18
|
-
def to_s
|
19
|
-
version.to_s
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,167 +0,0 @@
|
|
1
|
-
require "tmpdir"
|
2
|
-
require "fileutils"
|
3
|
-
require "timeout"
|
4
|
-
require "active_support/core_ext/numeric/time"
|
5
|
-
|
6
|
-
module Spring
|
7
|
-
module Test
|
8
|
-
class WatcherTest < ActiveSupport::TestCase
|
9
|
-
runnables.delete self # prevent Minitest running this class
|
10
|
-
|
11
|
-
LATENCY = 0.001
|
12
|
-
TIMEOUT = 1
|
13
|
-
|
14
|
-
attr_accessor :dir
|
15
|
-
|
16
|
-
def watcher_class
|
17
|
-
raise NotImplementedError
|
18
|
-
end
|
19
|
-
|
20
|
-
def watcher
|
21
|
-
@watcher ||= watcher_class.new(dir, LATENCY)
|
22
|
-
end
|
23
|
-
|
24
|
-
def setup
|
25
|
-
@dir = File.realpath(Dir.mktmpdir)
|
26
|
-
end
|
27
|
-
|
28
|
-
def teardown
|
29
|
-
FileUtils.remove_entry_secure @dir
|
30
|
-
watcher.stop
|
31
|
-
end
|
32
|
-
|
33
|
-
def touch(file, mtime = nil)
|
34
|
-
options = {}
|
35
|
-
options[:mtime] = mtime if mtime
|
36
|
-
FileUtils.touch(file, options)
|
37
|
-
end
|
38
|
-
|
39
|
-
def assert_stale
|
40
|
-
timeout = Time.now + TIMEOUT
|
41
|
-
sleep LATENCY until watcher.stale? || Time.now > timeout
|
42
|
-
assert watcher.stale?
|
43
|
-
end
|
44
|
-
|
45
|
-
def assert_not_stale
|
46
|
-
sleep LATENCY * 10
|
47
|
-
assert !watcher.stale?
|
48
|
-
end
|
49
|
-
|
50
|
-
test "starting with no file" do
|
51
|
-
file = "#{@dir}/omg"
|
52
|
-
touch file, Time.now - 2.seconds
|
53
|
-
|
54
|
-
watcher.start
|
55
|
-
watcher.add file
|
56
|
-
|
57
|
-
assert_not_stale
|
58
|
-
touch file, Time.now
|
59
|
-
assert_stale
|
60
|
-
end
|
61
|
-
|
62
|
-
test "is stale when a watched file is updated" do
|
63
|
-
file = "#{@dir}/omg"
|
64
|
-
touch file, Time.now - 2.seconds
|
65
|
-
|
66
|
-
watcher.add file
|
67
|
-
watcher.start
|
68
|
-
|
69
|
-
assert_not_stale
|
70
|
-
touch file, Time.now
|
71
|
-
assert_stale
|
72
|
-
end
|
73
|
-
|
74
|
-
test "is stale when removing files" do
|
75
|
-
file = "#{@dir}/omg"
|
76
|
-
touch file, Time.now
|
77
|
-
|
78
|
-
watcher.add file
|
79
|
-
watcher.start
|
80
|
-
|
81
|
-
assert_not_stale
|
82
|
-
FileUtils.rm(file)
|
83
|
-
assert_stale
|
84
|
-
end
|
85
|
-
|
86
|
-
test "is stale when files are added to a watched directory" do
|
87
|
-
subdir = "#{@dir}/subdir"
|
88
|
-
FileUtils.mkdir(subdir)
|
89
|
-
|
90
|
-
watcher.add subdir
|
91
|
-
watcher.start
|
92
|
-
|
93
|
-
assert_not_stale
|
94
|
-
touch "#{subdir}/foo", Time.now - 1.minute
|
95
|
-
assert_stale
|
96
|
-
end
|
97
|
-
|
98
|
-
test "is stale when a file is changed in a watched directory" do
|
99
|
-
subdir = "#{@dir}/subdir"
|
100
|
-
FileUtils.mkdir(subdir)
|
101
|
-
touch "#{subdir}/foo", Time.now - 1.minute
|
102
|
-
|
103
|
-
watcher.add subdir
|
104
|
-
watcher.start
|
105
|
-
|
106
|
-
assert_not_stale
|
107
|
-
touch "#{subdir}/foo", Time.now
|
108
|
-
assert_stale
|
109
|
-
end
|
110
|
-
|
111
|
-
test "adding doesn't wipe stale state" do
|
112
|
-
file = "#{@dir}/omg"
|
113
|
-
file2 = "#{@dir}/foo"
|
114
|
-
touch file, Time.now - 2.seconds
|
115
|
-
touch file2, Time.now - 2.seconds
|
116
|
-
|
117
|
-
watcher.add file
|
118
|
-
watcher.start
|
119
|
-
|
120
|
-
assert_not_stale
|
121
|
-
|
122
|
-
touch file, Time.now
|
123
|
-
watcher.add file2
|
124
|
-
|
125
|
-
assert_stale
|
126
|
-
end
|
127
|
-
|
128
|
-
test "on stale" do
|
129
|
-
file = "#{@dir}/omg"
|
130
|
-
touch file, Time.now - 2.seconds
|
131
|
-
|
132
|
-
stale = false
|
133
|
-
watcher.on_stale { stale = true }
|
134
|
-
|
135
|
-
watcher.add file
|
136
|
-
watcher.start
|
137
|
-
|
138
|
-
touch file, Time.now
|
139
|
-
|
140
|
-
Timeout.timeout(1) { sleep 0.01 until stale }
|
141
|
-
assert stale
|
142
|
-
|
143
|
-
# Check that we only get notified once
|
144
|
-
stale = false
|
145
|
-
sleep LATENCY * 3
|
146
|
-
assert !stale
|
147
|
-
end
|
148
|
-
|
149
|
-
test "add relative path" do
|
150
|
-
File.write("#{dir}/foo", "foo")
|
151
|
-
watcher.add "foo"
|
152
|
-
assert_equal ["#{dir}/foo"], watcher.files.to_a
|
153
|
-
end
|
154
|
-
|
155
|
-
test "add dot relative path" do
|
156
|
-
File.write("#{dir}/foo", "foo")
|
157
|
-
watcher.add "./foo"
|
158
|
-
assert_equal ["#{dir}/foo"], watcher.files.to_a
|
159
|
-
end
|
160
|
-
|
161
|
-
test "add non existent file" do
|
162
|
-
watcher.add './foobar'
|
163
|
-
assert watcher.files.empty?
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
data/lib/spring/test.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require "active_support"
|
2
|
-
require "active_support/test_case"
|
3
|
-
|
4
|
-
ActiveSupport.test_order = :random
|
5
|
-
|
6
|
-
module Spring
|
7
|
-
module Test
|
8
|
-
class << self
|
9
|
-
attr_accessor :root
|
10
|
-
end
|
11
|
-
|
12
|
-
require "spring/test/application"
|
13
|
-
require "spring/test/application_generator"
|
14
|
-
require "spring/test/rails_version"
|
15
|
-
require "spring/test/watcher_test"
|
16
|
-
require "spring/test/acceptance_test"
|
17
|
-
end
|
18
|
-
end
|