Permalink
Browse files

Initial import of nginx_thin spike

  • Loading branch information...
0 parents commit 51a81d2778266eb072f96846f28a2327336887bf @raggi committed Aug 20, 2011
Showing with 658 additions and 0 deletions.
  1. +54 −0 .autotest
  2. +1 −0 .gemtest
  3. +18 −0 .gitignore
  4. +5 −0 CHANGELOG.rdoc
  5. +14 −0 Manifest.txt
  6. +62 −0 README.rdoc
  7. +22 −0 Rakefile
  8. +23 −0 bin/nginx_thin
  9. +1 −0 config.ru
  10. +101 −0 lib/nginx_thin.rb
  11. +125 −0 lib/nginx_thin/nginx_server.rb
  12. +79 −0 lib/nginx_thin/thin_server.rb
  13. +61 −0 nginx_thin.gemspec
  14. +11 −0 test/gemloader.rb
  15. +6 −0 test/helper.rb
  16. +75 −0 test/test_nginx_thin.rb
@@ -0,0 +1,54 @@
+# -*- ruby -*-
+
+require 'autotest/restart'
+
+module Glob2Rexp
+ GLOB2REXP = {
+ '.' => '\.',
+ /(?:^|[^\\])\*/ => '\1.*'
+ }
+
+ def self.call(pattern)
+ GLOB2REXP.each { |from, to| pattern.gsub!(from, to) }
+ Regexp.new(pattern)
+ end
+end
+
+Autotest.add_hook :initialize do |at|
+ at.testlib = 'minitest/autorun'
+
+ # Don't track extras, this just burns cpu.
+ ignores = %w[]
+ ignores.concat File.read('.gitignore').split
+ ignores.delete_if { |pattern| pattern.nil? || pattern.empty? }
+ ignores.map! { |pattern| Glob2Rexp.call pattern }
+ ignores.each do |ignore|
+ at.add_exception ignore
+ end
+
+ # Make sure that we run all tests if the helper changes:
+ at.add_mapping(%r%^test/helper\.rb$%) do |f, _|
+ at.files_matching %r%test_.*\.rb%
+ end
+
+ # If the gemspec changes, we need to run the tests
+ at.add_mapping(%r%^.*\.gemspec$%) do |f, _|
+ at.files_matching %r%test_.*\.rb%
+ end
+
+ # If bundle did something, run all tests again
+ at.add_mapping(%r%^Gemfile\.lock$%) do |f, _|
+ at.files_matching %r%test_.*\.rb%
+ end
+end
+
+if File.exists?('Gemfile')
+ require 'autotest/bundler'
+
+ # If the Gemfile gets updated, run bundle install
+ Autotest.add_hook :updated do |at, *args|
+ if args.flatten.grep(%r%^Gemfile$|^.*\.gemspec$%).any?
+ system 'bundle'
+ end
+ end
+end
@@ -0,0 +1 @@
+
@@ -0,0 +1,18 @@
+coverage
+rdoc
+doc
+pkg
+test/tmp
+test/version_tmp
+tmp
+pkg
+*.gem
+*.rbc
+lib/bundler/man
+spec/reports
+.config
+InstalledFiles
+.bundle
+.yardoc
+_yardoc
+doc/
@@ -0,0 +1,5 @@
+=== 1.0.0 / 2011-08-19
+
+* 1 major enhancement
+
+ * Birthday!
@@ -0,0 +1,14 @@
+.autotest
+.gemtest
+CHANGELOG.rdoc
+Manifest.txt
+README.rdoc
+Rakefile
+bin/nginx_thin
+config.ru
+lib/nginx_thin.rb
+lib/nginx_thin/nginx_server.rb
+lib/nginx_thin/thin_server.rb
+test/gemloader.rb
+test/helper.rb
+test/test_nginx_thin.rb
@@ -0,0 +1,62 @@
+= nginx_thin
+
+http://rubygems.org/gems/nginx_thin
+{Project}[http://rubygems.org/gems/nginx_thin]
+{Documentation}[http://libraggi.rubyforge.org/nginx_thin/README_rdoc.html]
+{Wiki}[http://wiki.github.com/raggi/nginx_thin/]
+{Source Code}[http://github.com/raggi/nginx_thin/]
+{Issues}[http://github.com/raggi/nginx_thin/issues]
+{Rubyforge}[http://rubyforge.org/projects/libraggi]
+
+== DESCRIPTION:
+
+A wrapper around Thin and Nginx to support easily booting them together. This
+is most useful for integration test suites when you want to test through your
+nginx configuration. In some cases it may also provide a performance boost for
+such integration tests.
+
+== FEATURES/PROBLEMS:
+
+* Capybara integration (just call NginxThin.capybara in your setup)
+
+== SYNOPSIS:
+
+For easy Capybara integration:
+
+ NginxThin.capybara
+
+For other uses, see the documentation on NginxThin.
+
+== REQUIREMENTS:
+
+* nginx
+* thin
+
+== INSTALL:
+
+* gem install nginx_thin
+
+== LICENSE:
+
+(The MIT License)
+
+Copyright (c) 2011 raggi
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
+#!/usr/bin/env rake
+
+require 'hoe'
+Hoe.plugin :doofus, :git, :minitest, :gemspec2, :rubyforge
+
+Hoe.spec 'nginx_thin' do
+ developer 'raggi', 'raggi@rubyforge.org'
+ extra_dev_deps << %w(hoe-doofus >=1.0)
+ extra_dev_deps << %w(hoe-seattlerb >=1.2)
+ extra_dev_deps << %w(hoe-git >=1.3)
+ extra_dev_deps << %w(hoe-gemspec >=1.0.0)
+
+ extra_deps << %w(thin)
+
+ extra_dev_deps << %w(capybara)
+
+ self.extra_rdoc_files = FileList["**/*.rdoc"]
+ self.history_file = "CHANGELOG.rdoc"
+ self.readme_file = "README.rdoc"
+ self.rubyforge_name = 'libraggi'
+ self.testlib = :minitest
+end
@@ -0,0 +1,23 @@
+#!/usr/bin/env ruby
+
+config = ARGV.shift || ('config.ru' if File.exists?('config.ru'))
+port = ARGV.shift || 0
+root = ARGV.shift || Dir.pwd
+
+unless config && File.exists?(config) && File.directory?(root)
+ abort "Usage: nginx_thin config.ru [port] [root_path]"
+end
+
+require 'nginx_thin'
+
+app, opts = Rack::Builder.parse_file(config)
+
+server = NginxThin.new app, port, root
+server.start
+puts server.url
+puts "kill -INT #{$$} or CTRL+C to quit"
+puts "kill -HUP #{$$} to restart"
+trap(:INT) { server.stop }
+trap(:HUP) { server.stop; server.start }
+system "open #{server.url}"
+sleep
@@ -0,0 +1 @@
+run proc { |env| [200, {'Content-Type' => 'text/plain'}, ['Nginx + Thin']] }
@@ -0,0 +1,101 @@
+# = TODO
+# * Document more
+# * Support custom configs + urls
+# * Support multiple rack apps
+
+require 'thin'
+require 'tmpdir'
+require 'tempfile'
+require 'fileutils'
+require 'uri'
+
+class NginxThin
+ autoload :NginxServer, 'nginx_thin/nginx_server'
+ autoload :ThinServer, 'nginx_thin/thin_server'
+
+ VERSION = '1.0.0'
+
+ attr_reader :app_root, :rack_app, :url, :nginx_server, :rack_server, :port
+ attr_reader :forking
+
+ def initialize(rack_app, port = nil, app_root = nil, forking = true)
+ @rack_app = rack_app
+ @app_root = app_root || Dir.pwd + '/public'
+ @port = port == 0 ? nil : port
+ @uri = nil
+ @forking = forking
+ end
+
+ def forking?
+ @forking
+ end
+
+ def start
+ @rack_server = ThinServer.new(rack_app, socket, forking)
+ @rack_server.start
+
+ @nginx_server = NginxServer.new(app_root, socket, port)
+ @nginx_server.start
+
+ times = 0
+ until responsive?
+ times += 1
+ sleep 0.01
+ if times > 100
+ stop
+ states = "thin:#{thin_responsive?} nginx:#{nginx_responsive?}"
+ raise "Timed out booting NginxThin (#{states})"
+ end
+ end
+ end
+
+ def nginx_responsive?
+ TCPSocket.open('127.0.0.1', port) { |s| s.close; true }
+ rescue
+ nil
+ end
+
+ def thin_responsive?
+ File.exists?(socket)
+ end
+
+ def responsive?
+ thin_responsive? && nginx_responsive?
+ end
+
+ def stop
+ @nginx_server.stop if @nginx_server
+ # TODO improve handling if both error out
+ ensure
+ @rack_server.stop if @rack_server
+ end
+
+ def url
+ nginx_server.url
+ end
+
+ def port
+ @port || nginx_server && nginx_server.port
+ end
+
+ def socket
+ @socket ||= Dir.tmpdir + "/nginx.thin.#{@rack_app.object_id}.sock"
+ end
+
+ class <<self
+ attr_accessor :forking
+ end
+ @forking = true
+
+ def self.capybara(root = nil)
+ root ||= (Rails.root.to_s rescue Dir.pwd) + '/public'
+ root = File.expand_path(root)
+
+ Capybara.server do |app, port|
+ server = new(app, port, root, forking)
+ server.start
+ at_exit { server.stop }
+ end
+ end
+
+end
Oops, something went wrong.

0 comments on commit 51a81d2

Please sign in to comment.