spring 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@ require "socket"
3
3
  require "spring/env"
4
4
  require "spring/application_manager"
5
5
 
6
- class Spring
6
+ module Spring
7
7
  class Server
8
8
  def self.boot
9
9
  new.boot
@@ -25,15 +25,20 @@ class Spring
25
25
  set_exit_hook
26
26
  write_pidfile
27
27
 
28
+ $0 = "spring server | #{env.app_name} | started #{Time.now}"
29
+
28
30
  server = UNIXServer.open(env.socket_name)
29
31
  loop { serve server.accept }
30
32
  end
31
33
 
32
34
  def serve(client)
35
+ client.puts env.version
33
36
  app_client = client.recv_io
34
37
  rails_env = client.gets.chomp
35
38
 
36
39
  client.puts @applications[rails_env].run(app_client)
40
+ rescue SocketError => e
41
+ raise e unless client.eof?
37
42
  end
38
43
 
39
44
  def set_exit_hook
@@ -45,6 +50,8 @@ class Spring
45
50
  [env.socket_path, env.pidfile_path].each do |path|
46
51
  path.unlink if path.exist?
47
52
  end
53
+
54
+ @applications.values.each(&:stop)
48
55
  end
49
56
  end
50
57
  end
@@ -56,7 +63,7 @@ class Spring
56
63
  @pidfile.fsync
57
64
  else
58
65
  STDERR.puts "#{file.path} is locked; it looks like a server is already running"
59
- exit(1)
66
+ exit 1
60
67
  end
61
68
  end
62
69
  end
@@ -1,6 +1,6 @@
1
1
  require 'fiddle'
2
2
 
3
- class Spring
3
+ module Spring
4
4
  module SID
5
5
  FUNC = Fiddle::Function.new(
6
6
  DL::Handle::DEFAULT['getsid'],
@@ -1,3 +1,3 @@
1
- class Spring
2
- VERSION = "0.0.5"
1
+ module Spring
2
+ VERSION = "0.0.6"
3
3
  end
@@ -1,20 +1,28 @@
1
1
  require 'helper'
2
2
  require 'io/wait'
3
3
  require "timeout"
4
+ require "spring/sid"
5
+ require "spring/env"
4
6
 
5
7
  class AppTest < ActiveSupport::TestCase
6
- BINFILE = File.expand_path('../bin/spring', TEST_ROOT)
7
-
8
8
  def app_root
9
- "#{TEST_ROOT}/apps/rails-3-2"
9
+ Pathname.new("#{TEST_ROOT}/apps/rails-3-2")
10
10
  end
11
11
 
12
12
  def server_pidfile
13
13
  "#{app_root}/tmp/spring/#{Spring::SID.sid}.pid"
14
14
  end
15
15
 
16
+ def spring_env
17
+ @spring_env ||= Spring::Env.new(app_root)
18
+ end
19
+
16
20
  def server_pid
17
- File.exist?(server_pidfile) ? File.read(server_pidfile).to_i : nil
21
+ spring_env.pid
22
+ end
23
+
24
+ def server_running?
25
+ spring_env.server_running?
18
26
  end
19
27
 
20
28
  def stdout
@@ -30,10 +38,15 @@ class AppTest < ActiveSupport::TestCase
30
38
 
31
39
  Bundler.with_clean_env do
32
40
  Process.spawn(
41
+ {
42
+ "GEM_HOME" => "#{app_root}/vendor/gems",
43
+ "GEM_PATH" => "",
44
+ "PATH" => "#{app_root}/vendor/gems/bin:#{ENV["PATH"]}"
45
+ },
33
46
  command,
34
47
  out: stdout.last,
35
48
  err: stderr.last,
36
- chdir: app_root,
49
+ chdir: app_root.to_s,
37
50
  )
38
51
  end
39
52
 
@@ -41,7 +54,9 @@ class AppTest < ActiveSupport::TestCase
41
54
 
42
55
  out, err = read_streams
43
56
 
44
- @times << (Time.now - start_time) if opts.fetch(:timer, true)
57
+ @times << (Time.now - start_time) if @times
58
+
59
+ print_streams(out, err) if ENV["SPRING_DEBUG"]
45
60
 
46
61
  [status, out, err]
47
62
  rescue Timeout::Error
@@ -62,17 +77,17 @@ class AppTest < ActiveSupport::TestCase
62
77
  end
63
78
 
64
79
  def await_reload
65
- sleep 0.2
80
+ sleep 0.4
66
81
  end
67
82
 
68
83
  def assert_successful_run(*args)
69
84
  status, _, _ = app_run(*args)
70
- assert status.success?, 'The run should be successful but it was '
85
+ assert status.success?, "The run should be successful but it wasn't"
71
86
  end
72
87
 
73
88
  def assert_unsuccessful_run(*args)
74
89
  status, _, _ = app_run(*args)
75
- assert !status.success?, 'The run should not be successful but it was'
90
+ assert !status.success?, "The run should not be successful but it was"
76
91
  end
77
92
 
78
93
  def assert_stdout(command, expected)
@@ -80,6 +95,11 @@ class AppTest < ActiveSupport::TestCase
80
95
  assert stdout.include?(expected), "expected '#{expected}' to be printed to stdout. But it wasn't, the stdout is:\n#{stdout}"
81
96
  end
82
97
 
98
+ def assert_stderr(command, expected)
99
+ _, _, stderr = app_run(command)
100
+ assert stderr.include?(expected), "expected '#{expected}' to be printed to stderr. But it wasn't, the stderr is:\n#{stderr}"
101
+ end
102
+
83
103
  def assert_speedup(opts = {})
84
104
  ratio = opts.fetch(:ratio, 0.5)
85
105
  from = opts.fetch(:from, 0)
@@ -89,20 +109,40 @@ class AppTest < ActiveSupport::TestCase
89
109
  assert (second / first) < ratio, "#{second} was not less than #{ratio} of #{first}"
90
110
  end
91
111
 
112
+ def assert_server_running(*args)
113
+ assert server_running?, "The server should be running but it isn't"
114
+ end
115
+
116
+ def assert_server_not_running(*args)
117
+ assert !server_running?, "The server should not be running but it is"
118
+ end
119
+
92
120
  def test_command
93
- "#{BINFILE} test #{@test}"
121
+ "spring test #{@test}"
94
122
  end
95
123
 
124
+ @@installed_spring = false
125
+
96
126
  setup do
97
127
  @test = "#{app_root}/test/functional/posts_controller_test.rb"
98
128
  @test_contents = File.read(@test)
99
129
  @controller = "#{app_root}/app/controllers/posts_controller.rb"
100
130
  @controller_contents = File.read(@controller)
101
131
 
102
- @times = []
132
+ @spring_env = Spring::Env.new(app_root)
133
+
134
+ unless @@installed_spring
135
+ system "gem build spring.gemspec 2>/dev/null 1>/dev/null"
136
+ app_run "gem install ../../../spring-*.gem"
137
+ @@installed_spring = true
138
+ end
139
+
140
+ FileUtils.rm_rf "#{app_root}/bin"
141
+ app_run "(gem list bundler | grep bundler) || gem install bundler", timeout: nil
142
+ app_run "bundle check || bundle update", timeout: nil
143
+ app_run "bundle exec rake db:migrate"
103
144
 
104
- app_run "bundle check || bundle update", timer: false, timeout: nil
105
- app_run "bundle exec rake db:migrate", timer: false
145
+ @times = []
106
146
  end
107
147
 
108
148
  teardown do
@@ -123,7 +163,7 @@ class AppTest < ActiveSupport::TestCase
123
163
  end
124
164
 
125
165
  test "help message when called without arguments" do
126
- assert_stdout BINFILE, 'Usage: spring COMMAND [ARGS]'
166
+ assert_stdout "spring", 'Usage: spring COMMAND [ARGS]'
127
167
  end
128
168
 
129
169
  test "test changes are picked up" do
@@ -176,8 +216,7 @@ class AppTest < ActiveSupport::TestCase
176
216
  CODE
177
217
  File.write(@test, @test_contents.sub("get :index", "Foo.omg"))
178
218
 
179
- # Wait twice to give plenty of time for the wait thread to kick in
180
- 2.times { await_reload }
219
+ await_reload
181
220
 
182
221
  assert_stdout test_command, "RuntimeError: omg"
183
222
  assert_stdout test_command, "RuntimeError: omg"
@@ -209,11 +248,34 @@ class AppTest < ActiveSupport::TestCase
209
248
  end
210
249
  end
211
250
 
251
+ test "stop command kills server" do
252
+ assert_successful_run test_command
253
+ assert_server_running
254
+
255
+ assert_successful_run 'spring stop'
256
+ assert_server_not_running
257
+ end
258
+
212
259
  test "custom commands" do
213
- assert_stdout "#{BINFILE} custom", "omg"
260
+ assert_stdout "spring custom", "omg"
214
261
  end
215
262
 
216
263
  test "runner alias" do
217
- assert_stdout "#{BINFILE} r 'puts 1'", "1"
264
+ assert_stdout "spring r 'puts 1'", "1"
265
+ end
266
+
267
+ test "binstubs" do
268
+ app_run "spring binstub rake"
269
+ assert_successful_run "bin/spring help"
270
+ assert_stdout "bin/rake -T", "rake db:migrate"
271
+ end
272
+
273
+ test "missing config/application.rb" do
274
+ begin
275
+ FileUtils.mv app_root.join("config/application.rb"), app_root.join("config/application.rb.bak")
276
+ assert_stderr "spring rake -T", "unable to find your config/application.rb"
277
+ ensure
278
+ FileUtils.mv app_root.join("config/application.rb.bak"), app_root.join("config/application.rb")
279
+ end
218
280
  end
219
281
  end
@@ -13,3 +13,6 @@
13
13
  # Ignore all logfiles and tempfiles.
14
14
  /log/*.log
15
15
  /tmp
16
+
17
+ /bin
18
+ /vendor/gems/*
@@ -1,5 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'rails', '~> 3.2.8'
3
+ gem 'rails', '~> 3.2.0'
4
4
  gem 'sqlite3'
5
- gem 'spring', path: '../../..'
@@ -1,7 +1,6 @@
1
1
  $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
2
2
 
3
3
  require "bundler/setup"
4
- require "spring"
5
4
  require "active_support/test_case"
6
5
  require "minitest/autorun"
7
6
 
@@ -3,7 +3,7 @@ require "fileutils"
3
3
  require "active_support/core_ext/numeric/time"
4
4
  require "spring/application_watcher"
5
5
 
6
- class ApplicationWatcherTest < Test::Unit::TestCase
6
+ class ApplicationWatcherTest < ActiveSupport::TestCase
7
7
  def setup
8
8
  @dir = "/tmp/spring"
9
9
  FileUtils.mkdir(@dir)
@@ -19,7 +19,7 @@ class ApplicationWatcherTest < Test::Unit::TestCase
19
19
  FileUtils.touch(file, options)
20
20
  end
21
21
 
22
- def test_file_mtime
22
+ test "file mtime" do
23
23
  file = "#{@dir}/omg"
24
24
  touch file, Time.now - 2.seconds
25
25
 
@@ -31,7 +31,19 @@ class ApplicationWatcherTest < Test::Unit::TestCase
31
31
  assert watcher.stale?
32
32
  end
33
33
 
34
- def test_glob
34
+ test "tolerates enoent" do
35
+ file = "#{@dir}/omg"
36
+ touch file
37
+
38
+ watcher = Spring::ApplicationWatcher.new
39
+ watcher.add_files [file]
40
+
41
+ assert !watcher.stale?
42
+ FileUtils.rm(file)
43
+ assert watcher.stale?
44
+ end
45
+
46
+ test "accepts glob patterns" do
35
47
  FileUtils.mkdir("#{@dir}/1")
36
48
  FileUtils.mkdir("#{@dir}/2")
37
49
 
@@ -0,0 +1,34 @@
1
+ require "helper"
2
+ require "spring/commands"
3
+
4
+ class CommandsTest < ActiveSupport::TestCase
5
+
6
+ test "test command needs a test name" do
7
+ begin
8
+ real_stderr = $stderr
9
+ $stderr = StringIO.new('')
10
+
11
+ command = Spring::Commands::Test.new
12
+ command.call([])
13
+
14
+ assert_equal "you need to specify what test to run: spring test TEST_NAME\n", $stderr.string
15
+ ensure
16
+ $stderr = real_stderr
17
+ end
18
+ end
19
+
20
+ test "prints error message when preloaded file does not exist" do
21
+ begin
22
+ original_stderr = $stderr
23
+ $stderr = StringIO.new('')
24
+ my_command_class = Class.new(Spring::Commands::Command)
25
+ my_command_class.preloads = %w(i_do_not_exist)
26
+
27
+ my_command_class.new.setup
28
+ assert_match /The #<Class:0x[0-9a-f]+> command tried to preload i_do_not_exist but could not find it./, $stderr.string
29
+ ensure
30
+ $stderr = original_stderr
31
+ end
32
+ end
33
+
34
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spring
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-26 00:00:00.000000000 Z
12
+ date: 2013-02-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -58,12 +58,19 @@ files:
58
58
  - README.md
59
59
  - Rakefile
60
60
  - bin/spring
61
- - lib/spring.rb
62
61
  - lib/spring/application.rb
63
62
  - lib/spring/application_manager.rb
64
63
  - lib/spring/application_watcher.rb
64
+ - lib/spring/client.rb
65
+ - lib/spring/client/binstub.rb
66
+ - lib/spring/client/command.rb
67
+ - lib/spring/client/help.rb
68
+ - lib/spring/client/run.rb
69
+ - lib/spring/client/stop.rb
65
70
  - lib/spring/commands.rb
71
+ - lib/spring/configuration.rb
66
72
  - lib/spring/env.rb
73
+ - lib/spring/errors.rb
67
74
  - lib/spring/server.rb
68
75
  - lib/spring/sid.rb
69
76
  - lib/spring/version.rb
@@ -134,9 +141,11 @@ files:
134
141
  - test/apps/rails-3-2/test/unit/post_test.rb
135
142
  - test/apps/rails-3-2/vendor/assets/javascripts/.gitkeep
136
143
  - test/apps/rails-3-2/vendor/assets/stylesheets/.gitkeep
144
+ - test/apps/rails-3-2/vendor/gems/.gitkeep
137
145
  - test/apps/rails-3-2/vendor/plugins/.gitkeep
138
146
  - test/helper.rb
139
147
  - test/unit/application_watcher_test.rb
148
+ - test/unit/commands_test.rb
140
149
  homepage: http://github.com/jonleighton/spring
141
150
  licenses: []
142
151
  post_install_message:
@@ -228,6 +237,8 @@ test_files:
228
237
  - test/apps/rails-3-2/test/unit/post_test.rb
229
238
  - test/apps/rails-3-2/vendor/assets/javascripts/.gitkeep
230
239
  - test/apps/rails-3-2/vendor/assets/stylesheets/.gitkeep
240
+ - test/apps/rails-3-2/vendor/gems/.gitkeep
231
241
  - test/apps/rails-3-2/vendor/plugins/.gitkeep
232
242
  - test/helper.rb
233
243
  - test/unit/application_watcher_test.rb
244
+ - test/unit/commands_test.rb
@@ -1,151 +0,0 @@
1
- require "rbconfig"
2
- require "socket"
3
- require "pty"
4
-
5
- require "spring/version"
6
- require "spring/sid"
7
- require "spring/env"
8
- require "spring/commands"
9
-
10
- class Spring
11
- SERVER_COMMAND = [
12
- File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')),
13
- "-I", File.expand_path("../", __FILE__),
14
- "-r", "spring/server",
15
- "-r", "bundler/setup",
16
- "-e", "Spring::Server.boot"
17
- ]
18
-
19
- FORWARDED_SIGNALS = %w(INT QUIT USR1 USR2 INFO)
20
-
21
- def self.run(args)
22
- exit new.run(args)
23
- end
24
-
25
- attr_reader :env
26
-
27
- def initialize
28
- @env = Env.new
29
- end
30
-
31
- def server_running?
32
- if env.pidfile_path.exist?
33
- pidfile = env.pidfile_path.open('r')
34
- !pidfile.flock(File::LOCK_EX | File::LOCK_NB)
35
- else
36
- false
37
- end
38
- ensure
39
- if pidfile
40
- pidfile.flock(File::LOCK_UN)
41
- pidfile.close
42
- end
43
- end
44
-
45
- # Boot the server into the process group of the current session.
46
- # This will cause it to be automatically killed once the session
47
- # ends (i.e. when the user closes their terminal).
48
- def boot_server
49
- env.socket_path.unlink if env.socket_path.exist?
50
- Process.spawn(*SERVER_COMMAND, pgroup: SID.pgid)
51
- sleep 0.1 until env.socket_path.exist?
52
- end
53
-
54
- def run(args)
55
- if self.class.command_registered?(args.first)
56
- run_command(args)
57
- else
58
- print_help
59
- end
60
- end
61
-
62
- private
63
-
64
- def print_help
65
- puts <<-EOT
66
- Usage: spring COMMAND [ARGS]
67
-
68
- The most common spring commands are:
69
- rake Run a rake task
70
- console Start the Rails console
71
- runner Execute a command with the Rails runner
72
- generate Trigger a Rails generator
73
-
74
- test Execute a Test::Unit test
75
- rspec Execute an RSpec spec
76
- EOT
77
- false
78
- end
79
-
80
- def run_command(args)
81
- boot_server unless server_running?
82
-
83
- application, client = UNIXSocket.pair
84
-
85
- server = UNIXSocket.open(env.socket_name)
86
- server.send_io client
87
- server.puts rails_env_for(args.first)
88
-
89
- application.send_io STDOUT
90
- application.send_io STDERR
91
- application.send_io stdin_slave
92
-
93
- application.puts args.length
94
-
95
- args.each do |arg|
96
- application.puts arg.length
97
- application.write arg
98
- end
99
-
100
- pid = server.gets.chomp
101
-
102
- # We must not close the client socket until we are sure that the application has
103
- # received the FD. Otherwise the FD can end up getting closed while it's in the server
104
- # socket buffer on OS X. This doesn't happen on Linux.
105
- client.close
106
-
107
- if pid.empty?
108
- false
109
- else
110
- forward_signals(pid.to_i)
111
- application.read # FIXME: receive exit status from server
112
- true
113
- end
114
- rescue Errno::ECONNRESET
115
- false
116
- ensure
117
- application.close if application
118
- server.close if server
119
- end
120
-
121
- def rails_env_for(command_name)
122
- command = Spring.command(command_name)
123
-
124
- if command.respond_to?(:env)
125
- command.env
126
- else
127
- ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
128
- end
129
- end
130
-
131
- def stdin_slave
132
- master, slave = PTY.open
133
-
134
- # Sadly I cannot find a way to achieve this without shelling out to stty, or
135
- # using a C extension library. [Ruby does not have direct support for calling
136
- # tcsetattr().] We don't want to use a C extension library so
137
- # that spring can be used by Rails in the future.
138
- system "stty -icanon -echo"
139
- at_exit { system "stty sane" }
140
-
141
- Thread.new { master.write STDIN.read(1) until STDIN.closed? }
142
-
143
- slave
144
- end
145
-
146
- def forward_signals(pid)
147
- (FORWARDED_SIGNALS & Signal.list.keys).each do |sig|
148
- trap(sig) { Process.kill(sig, pid) }
149
- end
150
- end
151
- end