diff --git a/lib/autospec/base_runner.rb b/lib/autospec/base_runner.rb new file mode 100644 index 00000000000..b3e884c0c4d --- /dev/null +++ b/lib/autospec/base_runner.rb @@ -0,0 +1,22 @@ +module Autospec + class BaseRunner + def run(args, specs) + end + + def abort + end + + def reload + end + + def running? + true + end + + def start + end + + def stop + end + end +end diff --git a/lib/autospec/runner.rb b/lib/autospec/runner.rb index b5d0d44f92c..5d8121b36db 100644 --- a/lib/autospec/runner.rb +++ b/lib/autospec/runner.rb @@ -2,6 +2,9 @@ require "drb/drb" require "thread" require "fileutils" require "autospec/reload_css" +require "autospec/base_runner" +require "autospec/simple_runner" +require "autospec/spork_runner" module Autospec; end @@ -48,19 +51,19 @@ class Autospec::Runner end def run(opts = {}) - if already_running?(pid_file) - puts "autospec appears to be running, it is possible the pid file is old" - puts "if you are sure it is not running, delete #{pid_file}" - return - end - write_pid_file(pid_file, Process.pid) - - start_spork - Signal.trap("HUP") {stop_spork; exit } - Signal.trap("SIGINT") {stop_spork; exit } puts "Forced polling (slower) - inotify does not work on network filesystems, use local filesystem to avoid" if opts[:force_polling] + if ENV["SPORK"] == 0 + @runner = Autospec::SimpleRunner.new + else + @runner = Autospec::SporkRunner.new + end + @runner.start + + Signal.trap("HUP") {@runner.stop; exit } + Signal.trap("SIGINT") {@runner.stop; exit } + options = {filter: /^app|^spec|^lib/, relative_paths: true} if opts[:force_polling] @@ -79,22 +82,14 @@ class Autospec::Runner @signal.signal end - spork_running = true - Thread.new do - Process.wait(@spork_pid) - spork_running = false - end - - while spork_running + while @runner.running? process_queue end - puts "Spork has been terminated, exiting" - rescue => e puts e puts e.backtrace - stop_spork + @runner.stop end def process_queue @@ -168,15 +163,13 @@ class Autospec::Runner def process_change(files) return unless files.length > 0 + specs = [] hit = false files.each do |file| RELOAD_MATCHERS.each do |k| if k.match(file) - spork_service.abort - stop_spork - sleep 1 - start_spork + @runner.reload return end end @@ -213,7 +206,7 @@ class Autospec::Runner end return else - spork_service.abort + @runner.abort end @mutex.synchronize do @@ -305,72 +298,9 @@ class Autospec::Runner "-r", "#{File.dirname(__FILE__)}/formatter.rb", "-f", "Autospec::Formatter"].flatten - spork_service.run(args,$stderr,$stdout) - end - - - def spork_pid_file - Rails.root + "tmp/pids/spork.pid" - end - - def pid_file - Rails.root + "tmp/pids/autospec.pid" - end - - def already_running?(pid_file) - if File.exists? pid_file - pid = File.read(pid_file).to_i - Process.getpgid(pid) rescue nil - end - end - - def write_pid_file(file,pid) - FileUtils.mkdir_p(Rails.root + "tmp/pids") - File.open(file,'w') do |f| - f.write(pid) - end - end - - def spork_running? - spork_service.port rescue nil - end - - def spork_service - - unless @drb_listener_running - begin - DRb.start_service("druby://127.0.0.1:0") - rescue SocketError, Errno::EADDRNOTAVAIL - DRb.start_service("druby://:0") - end - - @drb_listener_running = true - end - - @spork_service ||= DRbObject.new_with_uri("druby://127.0.0.1:8989") - end - - def stop_spork - pid = File.read(spork_pid_file).to_i - Process.kill("SIGTERM",pid) - end - - def start_spork - - if already_running?(spork_pid_file) - puts "Killing old orphan spork instance" - stop_spork - sleep 1 - end - - @spork_pid = Process.spawn({'RAILS_ENV' => 'test'}, "bundle exec spork") - write_pid_file(spork_pid_file, @spork_pid) - - running = false - while !running - running = spork_running? - sleep 0.1 - end + @runner.run(args, specs) end + + end diff --git a/lib/autospec/simple_runner.rb b/lib/autospec/simple_runner.rb new file mode 100644 index 00000000000..d43cb32abb8 --- /dev/null +++ b/lib/autospec/simple_runner.rb @@ -0,0 +1,26 @@ +module Autospec + class SimpleRunner < BaseRunner + + def abort + if @pid + Process.kill("SIGINT", @pid) rescue nil + while(Process.getpgid(@pid) rescue nil) + sleep 0.001 + end + @pid = nil + end + end + + def run(args, spec) + self.abort + puts "Running: " << spec + @pid = Process.spawn({"RAILS_ENV" => "test"}, "bundle exec rspec " << args.join(" ")) + pid, status = Process.wait2(@pid) + status + end + + def stop + self.abort + end + end +end diff --git a/lib/autospec/spork_runner.rb b/lib/autospec/spork_runner.rb new file mode 100644 index 00000000000..95b3525418f --- /dev/null +++ b/lib/autospec/spork_runner.rb @@ -0,0 +1,107 @@ +module Autospec + class SporkRunner < BaseRunner + + def start + if already_running?(pid_file) + puts "autospec appears to be running, it is possible the pid file is old" + puts "if you are sure it is not running, delete #{pid_file}" + return + end + write_pid_file(pid_file, Process.pid) + start_spork + @spork_running = true + end + + def running? + @monitor_thread ||= + Thread.new do + Process.wait(@spork_pid) + @spork_running = false + end + @spork_running + end + + def stop + stop_spork + end + + def run(args,specs) + spork_service.run(args,$stderr,$stdout) + end + + def abort + spork_service.abort + end + + def reload + stop_spork + sleep 1 + start_spork + end + + private + def spork_pid_file + Rails.root + "tmp/pids/spork.pid" + end + + def pid_file + Rails.root + "tmp/pids/autospec.pid" + end + + def already_running?(pid_file) + if File.exists? pid_file + pid = File.read(pid_file).to_i + Process.getpgid(pid) rescue nil + end + end + + def write_pid_file(file,pid) + FileUtils.mkdir_p(Rails.root + "tmp/pids") + File.open(file,'w') do |f| + f.write(pid) + end + end + + def spork_running? + spork_service.port rescue nil + end + + def spork_service + + unless @drb_listener_running + begin + DRb.start_service("druby://127.0.0.1:0") + rescue SocketError, Errno::EADDRNOTAVAIL + DRb.start_service("druby://:0") + end + + @drb_listener_running = true + end + + @spork_service ||= DRbObject.new_with_uri("druby://127.0.0.1:8989") + end + + def stop_spork + pid = File.read(spork_pid_file).to_i + Process.kill("SIGTERM",pid) + end + + def start_spork + if already_running?(spork_pid_file) + puts "Killing old orphan spork instance" + stop_spork + sleep 1 + end + + @spork_pid = Process.spawn({'RAILS_ENV' => 'test'}, "bundle exec spork") + write_pid_file(spork_pid_file, @spork_pid) + + running = false + while !running + running = spork_running? + sleep 0.01 + end + + end + end +end