Compare commits
1 Commits
jarmo/mast
...
master
Author | SHA1 | Date |
---|---|---|
John Bintz | 36d24c0c14 |
|
@ -1,4 +1,4 @@
|
||||||
_I'm currently looking for a new maintainer for this project._
|
_This fork is no longer maintained. Visit [https://github.com/ranmocy/guard-rails](https://github.com/ranmocy/guard-rails) for the current official fork._
|
||||||
|
|
||||||
[![Build Status](http://travis-ci.org/johnbintz/guard-rails.png)](http://travis-ci.org/johnbintz/guard-rails)
|
[![Build Status](http://travis-ci.org/johnbintz/guard-rails.png)](http://travis-ci.org/johnbintz/guard-rails)
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,6 @@ Gem::Specification.new do |s|
|
||||||
s.require_paths = ["lib"]
|
s.require_paths = ["lib"]
|
||||||
|
|
||||||
s.add_dependency 'guard', '>= 0.2.2'
|
s.add_dependency 'guard', '>= 0.2.2'
|
||||||
s.add_dependency 'childprocess'
|
|
||||||
s.add_dependency 'sys-proctable'
|
|
||||||
|
|
||||||
s.add_development_dependency 'rspec', '~> 2.6.0'
|
s.add_development_dependency 'rspec', '~> 2.6.0'
|
||||||
s.add_development_dependency 'mocha'
|
s.add_development_dependency 'mocha'
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
require 'timeout'
|
|
||||||
require 'childprocess'
|
|
||||||
require 'sys/proctable'
|
|
||||||
|
|
||||||
module Guard
|
module Guard
|
||||||
class RailsRunner
|
class RailsRunner
|
||||||
|
MAX_WAIT_COUNT = 10
|
||||||
|
|
||||||
attr_reader :options
|
attr_reader :options
|
||||||
|
|
||||||
def initialize(options)
|
def initialize(options)
|
||||||
|
@ -13,19 +12,14 @@ module Guard
|
||||||
|
|
||||||
def start
|
def start
|
||||||
kill_unmanaged_pid! if options[:force_run]
|
kill_unmanaged_pid! if options[:force_run]
|
||||||
process = run_rails_command!
|
run_rails_command!
|
||||||
rails_started = wait_for_rails
|
wait_for_pid
|
||||||
File.open(pid_file, "w") {|file| file.write process.pid} if rails_started
|
|
||||||
rails_started
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def stop
|
def stop
|
||||||
if has_pid?
|
if File.file?(pid_file)
|
||||||
unless windows?
|
system %{kill -SIGINT #{File.read(pid_file).strip}}
|
||||||
Process.kill Signal.list["INT"], pid rescue nil
|
wait_for_no_pid if $?.exitstatus == 0
|
||||||
else
|
|
||||||
kill_all_child_processes
|
|
||||||
end
|
|
||||||
FileUtils.rm pid_file, :force => true
|
FileUtils.rm pid_file, :force => true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -42,15 +36,11 @@ module Guard
|
||||||
'--pid', pid_file
|
'--pid', pid_file
|
||||||
]
|
]
|
||||||
|
|
||||||
rails_options << '-d' if options[:daemon] && !windows?
|
rails_options << '-d' if options[:daemon]
|
||||||
rails_options << '-u' if options[:debugger]
|
rails_options << '-u' if options[:debugger]
|
||||||
rails_options << options[:server] if options[:server]
|
rails_options << options[:server] if options[:server]
|
||||||
|
|
||||||
cmd = []
|
%{sh -c 'cd #{Dir.pwd} && RAILS_ENV=#{options[:environment]} rails s #{rails_options.join(' ')} &'}
|
||||||
if windows?
|
|
||||||
cmd << 'cmd' << '/C'
|
|
||||||
end
|
|
||||||
cmd << "rails server #{rails_options.join(' ')}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def pid_file
|
def pid_file
|
||||||
|
@ -61,78 +51,56 @@ module Guard
|
||||||
File.file?(pid_file) ? File.read(pid_file).to_i : nil
|
File.file?(pid_file) ? File.read(pid_file).to_i : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def sleep_time
|
||||||
|
options[:timeout].to_f / MAX_WAIT_COUNT.to_f
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
def run_rails_command!
|
def run_rails_command!
|
||||||
process = ChildProcess.build *build_rails_command
|
system build_rails_command
|
||||||
process.environment["RAILS_ENV"] = options[:environment]
|
|
||||||
process.io.inherit!
|
|
||||||
process.start
|
|
||||||
process
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_pid?
|
def has_pid?
|
||||||
File.file?(pid_file)
|
File.file?(pid_file)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def wait_for_pid_action
|
||||||
|
sleep sleep_time
|
||||||
|
end
|
||||||
|
|
||||||
def kill_unmanaged_pid!
|
def kill_unmanaged_pid!
|
||||||
if pid = unmanaged_pid
|
if pid = unmanaged_pid
|
||||||
Process.kill Signal.list["KILL"], pid
|
system %{kill -KILL #{pid}}
|
||||||
FileUtils.rm pid_file if has_pid?
|
FileUtils.rm pid_file
|
||||||
|
wait_for_no_pid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def unmanaged_pid
|
def unmanaged_pid
|
||||||
unless windows?
|
|
||||||
%x{lsof -n -i TCP:#{options[:port]}}.each_line { |line|
|
%x{lsof -n -i TCP:#{options[:port]}}.each_line { |line|
|
||||||
if line["*:#{options[:port]} "]
|
if line["*:#{options[:port]} "]
|
||||||
return line.split("\s")[1]
|
return line.split("\s")[1]
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
else
|
|
||||||
%x{netstat -ano}.each_line { |line|
|
|
||||||
protocol, local_address, _, state, pid = line.strip.split(/\s+/)
|
|
||||||
return pid.to_i if protocol == "TCP" &&
|
|
||||||
state == "LISTENING" &&
|
|
||||||
local_address =~ /:#{options[:port]}$/
|
|
||||||
}
|
|
||||||
end
|
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
def wait_for_pid
|
||||||
def wait_for_rails
|
wait_for_pid_loop
|
||||||
Timeout.timeout(options[:timeout]) {sleep 1 until rails_running?}
|
|
||||||
true
|
|
||||||
rescue Timeout::Error
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def rails_running?
|
def wait_for_no_pid
|
||||||
return false unless has_pid?
|
wait_for_pid_loop(false)
|
||||||
TCPSocket.new('127.0.0.1', options[:port]).close
|
|
||||||
true
|
|
||||||
rescue Errno::ECONNREFUSED
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def windows?
|
def wait_for_pid_loop(check_for_existince = true)
|
||||||
RUBY_PLATFORM =~ /mswin|msys|mingw/
|
count = 0
|
||||||
|
while !(check_for_existince ? has_pid? : !has_pid?) && count < MAX_WAIT_COUNT
|
||||||
|
wait_for_pid_action
|
||||||
|
count += 1
|
||||||
end
|
end
|
||||||
|
!(count == MAX_WAIT_COUNT)
|
||||||
def kill_all_child_processes
|
|
||||||
all_pids_for(pid).each do |pid|
|
|
||||||
Process.kill Signal.list["KILL"], pid rescue nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def all_pids_for(parent_pid)
|
|
||||||
pids = [parent_pid]
|
|
||||||
Sys::ProcTable.ps do |process|
|
|
||||||
pids += all_pids_for(process.pid) if process.ppid == parent_pid
|
|
||||||
end
|
|
||||||
pids
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,15 +36,15 @@ describe Guard::RailsRunner do
|
||||||
describe '#build_rails_command' do
|
describe '#build_rails_command' do
|
||||||
context 'no daemon' do
|
context 'no daemon' do
|
||||||
it "should not have a daemon switch" do
|
it "should not have a daemon switch" do
|
||||||
runner.build_rails_command.last.should_not match(%r{ -d})
|
runner.build_rails_command.should_not match(%r{ -d})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'daemon', :unless => RUBY_PLATFORM =~ /mswin|msys|mingw/ do
|
context 'daemon' do
|
||||||
let(:options) { default_options.merge(:daemon => true) }
|
let(:options) { default_options.merge(:daemon => true) }
|
||||||
|
|
||||||
it "should have a daemon switch" do
|
it "should have a daemon switch" do
|
||||||
runner.build_rails_command.last.should match(%r{ -d})
|
runner.build_rails_command.should match(%r{ -d})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ describe Guard::RailsRunner do
|
||||||
let(:options) { default_options.merge(:debugger => true) }
|
let(:options) { default_options.merge(:debugger => true) }
|
||||||
|
|
||||||
it "should have a debugger switch" do
|
it "should have a debugger switch" do
|
||||||
runner.build_rails_command.last.should match(%r{ -u})
|
runner.build_rails_command.should match(%r{ -u})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -60,29 +60,24 @@ describe Guard::RailsRunner do
|
||||||
let(:options) { default_options.merge(:server => 'thin') }
|
let(:options) { default_options.merge(:server => 'thin') }
|
||||||
|
|
||||||
it "should have the server name" do
|
it "should have the server name" do
|
||||||
runner.build_rails_command.last.should match(%r{thin})
|
runner.build_rails_command.should match(%r{thin})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#start' do
|
describe '#start' do
|
||||||
include FakeFS::SpecHelpers
|
|
||||||
|
|
||||||
let(:kill_expectation) { runner.expects(:kill_unmanaged_pid!) }
|
let(:kill_expectation) { runner.expects(:kill_unmanaged_pid!) }
|
||||||
let(:pid_stub) { runner.stubs(:has_pid?) }
|
let(:pid_stub) { runner.stubs(:has_pid?) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
FileUtils.mkdir_p File.split(runner.pid_file).first
|
runner.expects(:run_rails_command!).once
|
||||||
process = mock('process')
|
|
||||||
process.stubs(:pid).returns(123)
|
|
||||||
runner.expects(:run_rails_command!).once.returns(process)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'do not force run' do
|
context 'do not force run' do
|
||||||
before do
|
before do
|
||||||
pid_stub.returns(true)
|
pid_stub.returns(true)
|
||||||
kill_expectation.never
|
kill_expectation.never
|
||||||
runner.stubs(:rails_running?).once.returns(true)
|
runner.expects(:wait_for_pid_action).never
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should act properly" do
|
it "should act properly" do
|
||||||
|
@ -96,7 +91,7 @@ describe Guard::RailsRunner do
|
||||||
before do
|
before do
|
||||||
pid_stub.returns(true)
|
pid_stub.returns(true)
|
||||||
kill_expectation.once
|
kill_expectation.once
|
||||||
runner.stubs(:rails_running?).once.returns(true)
|
runner.expects(:wait_for_pid_action).never
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should act properly" do
|
it "should act properly" do
|
||||||
|
@ -105,12 +100,10 @@ describe Guard::RailsRunner do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "don't write the pid" do
|
context "don't write the pid" do
|
||||||
let(:options) { default_options.merge(:timeout => 0.1) }
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
pid_stub.returns(false)
|
pid_stub.returns(false)
|
||||||
kill_expectation.never
|
kill_expectation.never
|
||||||
runner.stubs(:rails_running?).once.returns(false)
|
runner.expects(:wait_for_pid_action).times(Guard::RailsRunner::MAX_WAIT_COUNT)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should act properly" do
|
it "should act properly" do
|
||||||
|
@ -119,4 +112,12 @@ describe Guard::RailsRunner do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#sleep_time' do
|
||||||
|
let(:timeout) { 30 }
|
||||||
|
let(:options) { default_options.merge(:timeout => timeout) }
|
||||||
|
|
||||||
|
it "should adjust the sleep time as necessary" do
|
||||||
|
runner.sleep_time.should == (timeout.to_f / Guard::RailsRunner::MAX_WAIT_COUNT.to_f)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require 'mocha_standalone'
|
require 'mocha'
|
||||||
|
|
||||||
RSpec.configure do |c|
|
RSpec.configure do |c|
|
||||||
c.mock_with :mocha
|
c.mock_with :mocha
|
||||||
|
|
Loading…
Reference in New Issue