Adding merb app for integration testing
This commit is contained in:
parent
add38820e5
commit
2562942b6d
5
Rakefile
5
Rakefile
|
@ -110,6 +110,11 @@ namespace :spec do
|
||||||
result = system "rake test:integration"
|
result = system "rake test:integration"
|
||||||
raise "Tests failed" unless result
|
raise "Tests failed" unless result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Dir.chdir "spec/integration/merb" do
|
||||||
|
result = system "rake spec"
|
||||||
|
raise "Tests failed" unless result
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
.DS_Store
|
||||||
|
log/*
|
||||||
|
tmp/*
|
||||||
|
TAGS
|
||||||
|
*~
|
||||||
|
.#*
|
||||||
|
schema/schema.rb
|
||||||
|
schema/*_structure.sql
|
||||||
|
schema/*.sqlite3
|
||||||
|
schema/*.sqlite
|
||||||
|
schema/*.db
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite3
|
||||||
|
*.db
|
||||||
|
src/*
|
||||||
|
.hgignore
|
||||||
|
.hg/*
|
||||||
|
.svn/*
|
||||||
|
gems/gems/*
|
||||||
|
gems/specifications/*
|
||||||
|
merb_profile_results
|
|
@ -0,0 +1,35 @@
|
||||||
|
require 'rubygems'
|
||||||
|
require 'rake/rdoctask'
|
||||||
|
|
||||||
|
require 'merb-core'
|
||||||
|
require 'merb-core/tasks/merb'
|
||||||
|
|
||||||
|
include FileUtils
|
||||||
|
|
||||||
|
# Load the basic runtime dependencies; this will include
|
||||||
|
# any plugins and therefore plugin rake tasks.
|
||||||
|
init_env = ENV['MERB_ENV'] || 'rake'
|
||||||
|
Merb.load_dependencies(:environment => init_env)
|
||||||
|
|
||||||
|
# Get Merb plugins and dependencies
|
||||||
|
Merb::Plugins.rakefiles.each { |r| require r }
|
||||||
|
|
||||||
|
# Load any app level custom rakefile extensions from lib/tasks
|
||||||
|
tasks_path = File.join(File.dirname(__FILE__), "lib", "tasks")
|
||||||
|
rake_files = Dir["#{tasks_path}/*.rake"]
|
||||||
|
rake_files.each{|rake_file| load rake_file }
|
||||||
|
|
||||||
|
desc "Start runner environment"
|
||||||
|
task :merb_env do
|
||||||
|
Merb.start_environment(:environment => init_env, :adapter => 'runner')
|
||||||
|
end
|
||||||
|
|
||||||
|
require 'spec/rake/spectask'
|
||||||
|
require 'merb-core/test/tasks/spectasks'
|
||||||
|
desc 'Default: run spec examples'
|
||||||
|
task :default => 'spec'
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# ADD YOUR CUSTOM TASKS IN /lib/tasks
|
||||||
|
# NAME YOUR RAKE FILES file_name.rake
|
||||||
|
##############################################################################
|
|
@ -0,0 +1,2 @@
|
||||||
|
class Application < Merb::Controller
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
class Exceptions < Merb::Controller
|
||||||
|
|
||||||
|
# handle NotFound exceptions (404)
|
||||||
|
def not_found
|
||||||
|
render :format => :html
|
||||||
|
end
|
||||||
|
|
||||||
|
# handle NotAcceptable exceptions (406)
|
||||||
|
def not_acceptable
|
||||||
|
render :format => :html
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,10 @@
|
||||||
|
class Testing < Application
|
||||||
|
|
||||||
|
def show_form
|
||||||
|
render
|
||||||
|
end
|
||||||
|
|
||||||
|
def submit_form
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,63 @@
|
||||||
|
<div id="container">
|
||||||
|
<div id="header-container">
|
||||||
|
<img src="/images/merb.jpg" />
|
||||||
|
<!-- <h1>Mongrel + Erb</h1> -->
|
||||||
|
<h2>pocket rocket web framework</h2>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="left-container">
|
||||||
|
<h3>Exception:</h3>
|
||||||
|
<p><%= request.exceptions.first.message %></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="main-container">
|
||||||
|
<h3>Why am I seeing this page?</h3>
|
||||||
|
<p>Merb couldn't find an appropriate content_type to return,
|
||||||
|
based on what you said was available via provides() and
|
||||||
|
what the client requested.</p>
|
||||||
|
|
||||||
|
<h3>How to add a mime-type</h3>
|
||||||
|
<pre><code>
|
||||||
|
Merb.add_mime_type :pdf, :to_pdf, %w[application/pdf], "Content-Encoding" => "gzip"
|
||||||
|
</code></pre>
|
||||||
|
<h3>What this means is:</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Add a mime-type for :pdf</li>
|
||||||
|
<li>Register the method for converting objects to PDF as <code>#to_pdf</code>.</li>
|
||||||
|
<li>Register the incoming mime-type "Accept" header as <code>application/pdf</code>.</li>
|
||||||
|
<li>Specify a new header for PDF types so it will set <code>Content-Encoding</code> to gzip.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>You can then do:</h3>
|
||||||
|
<pre><code>
|
||||||
|
class Foo < Application
|
||||||
|
provides :pdf
|
||||||
|
end
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h3>Where can I find help?</h3>
|
||||||
|
<p>If you have any questions or if you can't figure something out, please take a
|
||||||
|
look at our <a href="http://merbivore.com/"> project page</a>,
|
||||||
|
feel free to come chat at irc.freenode.net, channel #merb,
|
||||||
|
or post to <a href="http://groups.google.com/group/merb">merb mailing list</a>
|
||||||
|
on Google Groups.</p>
|
||||||
|
|
||||||
|
<h3>What if I've found a bug?</h3>
|
||||||
|
<p>If you want to file a bug or make your own contribution to Merb,
|
||||||
|
feel free to register and create a ticket at our
|
||||||
|
<a href="http://merb.lighthouseapp.com/">project development page</a>
|
||||||
|
on Lighthouse.</p>
|
||||||
|
|
||||||
|
<h3>How do I edit this page?</h3>
|
||||||
|
<p>You can change what people see when this happens by editing <tt>app/views/exceptions/not_acceptable.html.erb</tt>.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="footer-container">
|
||||||
|
<hr />
|
||||||
|
<div class="left"></div>
|
||||||
|
<div class="right">© 2008 the merb dev team</div>
|
||||||
|
<p> </p>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,47 @@
|
||||||
|
<div id="container">
|
||||||
|
<div id="header-container">
|
||||||
|
<img src="/images/merb.jpg" />
|
||||||
|
<!-- <h1>Mongrel + Erb</h1> -->
|
||||||
|
<h2>pocket rocket web framework</h2>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="left-container">
|
||||||
|
<h3>Exception:</h3>
|
||||||
|
<p><%= request.exceptions.first.message %></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="main-container">
|
||||||
|
<h3>Welcome to Merb!</h3>
|
||||||
|
<p>Merb is a light-weight MVC framework written in Ruby. We hope you enjoy it.</p>
|
||||||
|
|
||||||
|
<h3>Where can I find help?</h3>
|
||||||
|
<p>If you have any questions or if you can't figure something out, please take a
|
||||||
|
look at our <a href="http://merbivore.com/"> project page</a>,
|
||||||
|
feel free to come chat at irc.freenode.net, channel #merb,
|
||||||
|
or post to <a href="http://groups.google.com/group/merb">merb mailing list</a>
|
||||||
|
on Google Groups.</p>
|
||||||
|
|
||||||
|
<h3>What if I've found a bug?</h3>
|
||||||
|
<p>If you want to file a bug or make your own contribution to Merb,
|
||||||
|
feel free to register and create a ticket at our
|
||||||
|
<a href="http://merb.lighthouseapp.com/">project development page</a>
|
||||||
|
on Lighthouse.</p>
|
||||||
|
|
||||||
|
<h3>How do I edit this page?</h3>
|
||||||
|
<p>You're seeing this page because you need to edit the following files:
|
||||||
|
<ul>
|
||||||
|
<li>config/router.rb <strong><em>(recommended)</em></strong></li>
|
||||||
|
<li>app/views/exceptions/not_found.html.erb <strong><em>(recommended)</em></strong></li>
|
||||||
|
<li>app/views/layout/application.html.erb <strong><em>(change this layout)</em></strong></li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="footer-container">
|
||||||
|
<hr />
|
||||||
|
<div class="left"></div>
|
||||||
|
<div class="right">© 2008 the merb dev team</div>
|
||||||
|
<p> </p>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
|
||||||
|
<head>
|
||||||
|
<title>Fresh Merb App</title>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||||
|
<link rel="stylesheet" href="/stylesheets/master.css" type="text/css" media="screen" charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%#= message[:notice] %>
|
||||||
|
<%= catch_content :for_layout %>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<h1>Webrat Form</h1>
|
||||||
|
|
||||||
|
<form action="/testing/submit_form" method="post">
|
||||||
|
<label>
|
||||||
|
Text field
|
||||||
|
<input type="text" name="text_field" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
TOS <input type="checkbox" name="tos" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
Month
|
||||||
|
<select name="month">
|
||||||
|
<option>None</option>
|
||||||
|
<option>January</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<input type="submit" value="Test">
|
||||||
|
</form>
|
|
@ -0,0 +1,15 @@
|
||||||
|
Merb.logger.info("Loaded DEVELOPMENT Environment...")
|
||||||
|
Merb::Config.use { |c|
|
||||||
|
c[:exception_details] = true
|
||||||
|
c[:reload_templates] = true
|
||||||
|
c[:reload_classes] = true
|
||||||
|
c[:reload_time] = 0.5
|
||||||
|
c[:ignore_tampered_cookies] = true
|
||||||
|
c[:log_auto_flush ] = true
|
||||||
|
c[:log_level] = :debug
|
||||||
|
|
||||||
|
c[:log_stream] = STDOUT
|
||||||
|
c[:log_file] = nil
|
||||||
|
# Or redirect logging into a file:
|
||||||
|
# c[:log_file] = Merb.root / "log" / "development.log"
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
Merb.logger.info("Loaded RAKE Environment...")
|
||||||
|
Merb::Config.use { |c|
|
||||||
|
c[:exception_details] = true
|
||||||
|
c[:reload_classes] = false
|
||||||
|
c[:log_auto_flush ] = true
|
||||||
|
|
||||||
|
c[:log_stream] = STDOUT
|
||||||
|
c[:log_file] = nil
|
||||||
|
# Or redirect logging into a file:
|
||||||
|
# c[:log_file] = Merb.root / "log" / "development.log"
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
Merb.logger.info("Loaded TEST Environment...")
|
||||||
|
Merb::Config.use { |c|
|
||||||
|
c[:testing] = true
|
||||||
|
c[:exception_details] = true
|
||||||
|
c[:log_auto_flush ] = true
|
||||||
|
# log less in testing environment
|
||||||
|
c[:log_level] = :error
|
||||||
|
|
||||||
|
#c[:log_file] = Merb.root / "log" / "test.log"
|
||||||
|
# or redirect logger using IO handle
|
||||||
|
c[:log_stream] = STDOUT
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Go to http://wiki.merbivore.com/pages/init-rb
|
||||||
|
|
||||||
|
# Specify a specific version of a dependency
|
||||||
|
# dependency "RedCloth", "> 3.0"
|
||||||
|
|
||||||
|
# use_orm :none
|
||||||
|
use_test :rspec
|
||||||
|
use_template_engine :erb
|
||||||
|
|
||||||
|
Merb::Config.use do |c|
|
||||||
|
c[:use_mutex] = false
|
||||||
|
c[:session_store] = 'cookie' # can also be 'memory', 'memcache', 'container', 'datamapper
|
||||||
|
|
||||||
|
# cookie session store configuration
|
||||||
|
c[:session_secret_key] = 'adb9ea7a0e94b5513503f58623a393c5efe18851' # required for cookie session store
|
||||||
|
c[:session_id_key] = '_merb_session_id' # cookie session id key, defaults to "_session_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
Merb::BootLoader.before_app_loads do
|
||||||
|
# This will get executed after dependencies have been loaded but before your app's classes have loaded.
|
||||||
|
end
|
||||||
|
|
||||||
|
Merb::BootLoader.after_app_loads do
|
||||||
|
# This will get executed after your app's classes have been loaded.
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
# use PathPrefix Middleware if :path_prefix is set in Merb::Config
|
||||||
|
if prefix = ::Merb::Config[:path_prefix]
|
||||||
|
use Merb::Rack::PathPrefix, prefix
|
||||||
|
end
|
||||||
|
|
||||||
|
# comment this out if you are running merb behind a load balancer
|
||||||
|
# that serves static files
|
||||||
|
use Merb::Rack::Static, Merb.dir_for(:public)
|
||||||
|
|
||||||
|
# this is our main merb application
|
||||||
|
run Merb::Rack::Application.new
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Merb::Router is the request routing mapper for the merb framework.
|
||||||
|
#
|
||||||
|
# You can route a specific URL to a controller / action pair:
|
||||||
|
#
|
||||||
|
# match("/contact").
|
||||||
|
# to(:controller => "info", :action => "contact")
|
||||||
|
#
|
||||||
|
# You can define placeholder parts of the url with the :symbol notation. These
|
||||||
|
# placeholders will be available in the params hash of your controllers. For example:
|
||||||
|
#
|
||||||
|
# match("/books/:book_id/:action").
|
||||||
|
# to(:controller => "books")
|
||||||
|
#
|
||||||
|
# Or, use placeholders in the "to" results for more complicated routing, e.g.:
|
||||||
|
#
|
||||||
|
# match("/admin/:module/:controller/:action/:id").
|
||||||
|
# to(:controller => ":module/:controller")
|
||||||
|
#
|
||||||
|
# You can specify conditions on the placeholder by passing a hash as the second
|
||||||
|
# argument of "match"
|
||||||
|
#
|
||||||
|
# match("/registration/:course_name", :course_name => /^[a-z]{3,5}-\d{5}$/).
|
||||||
|
# to(:controller => "registration")
|
||||||
|
#
|
||||||
|
# You can also use regular expressions, deferred routes, and many other options.
|
||||||
|
# See merb/specs/merb/router.rb for a fairly complete usage sample.
|
||||||
|
|
||||||
|
Merb.logger.info("Compiling routes...")
|
||||||
|
Merb::Router.prepare do
|
||||||
|
match("/").to(:controller => "testing", :action => "show_form")
|
||||||
|
end
|
|
@ -0,0 +1 @@
|
||||||
|
--color
|
|
@ -0,0 +1,20 @@
|
||||||
|
require "rubygems"
|
||||||
|
|
||||||
|
# Add the local gems dir if found within the app root; any dependencies loaded
|
||||||
|
# hereafter will try to load from the local gems before loading system gems.
|
||||||
|
if (local_gem_dir = File.join(File.dirname(__FILE__), '..', 'gems')) && $BUNDLE.nil?
|
||||||
|
$BUNDLE = true; Gem.clear_paths; Gem.path.unshift(local_gem_dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
require "merb-core"
|
||||||
|
require "spec" # Satisfies Autotest and anyone else not using the Rake tasks
|
||||||
|
|
||||||
|
# this loads all plugins required in your init file so don't add them
|
||||||
|
# here again, Merb will do it for you
|
||||||
|
Merb.start_environment(:testing => true, :adapter => 'runner', :environment => ENV['MERB_ENV'] || 'test')
|
||||||
|
|
||||||
|
Spec::Runner.configure do |config|
|
||||||
|
config.include(Merb::Test::ViewHelper)
|
||||||
|
config.include(Merb::Test::RouteHelper)
|
||||||
|
config.include(Merb::Test::ControllerHelper)
|
||||||
|
end
|
|
@ -0,0 +1,17 @@
|
||||||
|
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
|
||||||
|
|
||||||
|
describe "Webrat" do
|
||||||
|
it "should visit pages" do
|
||||||
|
response = visit "/"
|
||||||
|
response.should contain("Webrat Form")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should submit forms" do
|
||||||
|
visit "/"
|
||||||
|
fill_in "Text field", :with => "Hello"
|
||||||
|
check "TOS"
|
||||||
|
select "January"
|
||||||
|
click_button "Test"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
# This was added by Merb's bundler
|
||||||
|
|
||||||
|
require "rubygems"
|
||||||
|
require File.join(File.dirname(__FILE__), "common")
|
||||||
|
|
||||||
|
gems_dir = File.join(File.dirname(__FILE__), '..', 'gems')
|
||||||
|
|
||||||
|
if File.directory?(gems_dir)
|
||||||
|
$BUNDLE = true
|
||||||
|
Gem.clear_paths
|
||||||
|
Gem.path.replace([File.expand_path(gems_dir)])
|
||||||
|
ENV["PATH"] = "#{File.dirname(__FILE__)}:#{ENV["PATH"]}"
|
||||||
|
|
||||||
|
gem_file = File.join(gems_dir, "specifications", "<%= spec.name %>-*.gemspec")
|
||||||
|
|
||||||
|
if local_gem = Dir[gem_file].last
|
||||||
|
version = File.basename(local_gem)[/-([\.\d]+)\.gemspec$/, 1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
version ||= "<%= Gem::Requirement.default %>"
|
||||||
|
|
||||||
|
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
|
||||||
|
version = $1
|
||||||
|
ARGV.shift
|
||||||
|
end
|
||||||
|
|
||||||
|
gem '<%= @spec.name %>', version
|
||||||
|
load '<%= bin_file_name %>'
|
|
@ -0,0 +1,64 @@
|
||||||
|
# This was added via Merb's bundler
|
||||||
|
|
||||||
|
require "rubygems"
|
||||||
|
require "rubygems/source_index"
|
||||||
|
|
||||||
|
module Gem
|
||||||
|
BUNDLED_SPECS = File.join(Dir.pwd, "gems", "specifications")
|
||||||
|
MAIN_INDEX = Gem::SourceIndex.from_gems_in(BUNDLED_SPECS)
|
||||||
|
FALLBACK_INDEX = Gem::SourceIndex.from_installed_gems
|
||||||
|
|
||||||
|
def self.source_index
|
||||||
|
MultiSourceIndex.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.searcher
|
||||||
|
MultiPathSearcher.new
|
||||||
|
end
|
||||||
|
|
||||||
|
class ArbitrarySearcher < GemPathSearcher
|
||||||
|
def initialize(source_index)
|
||||||
|
@source_index = source_index
|
||||||
|
super()
|
||||||
|
end
|
||||||
|
|
||||||
|
def init_gemspecs
|
||||||
|
@source_index.map { |_, spec| spec }.sort { |a,b|
|
||||||
|
(a.name <=> b.name).nonzero? || (b.version <=> a.version)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MultiPathSearcher
|
||||||
|
def initialize
|
||||||
|
@main_searcher = ArbitrarySearcher.new(MAIN_INDEX)
|
||||||
|
@fallback_searcher = ArbitrarySearcher.new(FALLBACK_INDEX)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find(path)
|
||||||
|
try = @main_searcher.find(path)
|
||||||
|
return try if try
|
||||||
|
@fallback_searcher.find(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_all(path)
|
||||||
|
try = @main_searcher.find_all(path)
|
||||||
|
return try unless try.empty?
|
||||||
|
@fallback_searcher.find_all(path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MultiSourceIndex
|
||||||
|
def search(*args)
|
||||||
|
try = MAIN_INDEX.search(*args)
|
||||||
|
return try unless try.empty?
|
||||||
|
FALLBACK_INDEX.search(*args)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_name(*args)
|
||||||
|
try = MAIN_INDEX.find_name(*args)
|
||||||
|
return try unless try.empty?
|
||||||
|
FALLBACK_INDEX.find_name(*args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,124 @@
|
||||||
|
require "erb"
|
||||||
|
|
||||||
|
Gem.pre_install_hooks.push(proc do |installer|
|
||||||
|
$INSTALLING << installer.spec
|
||||||
|
|
||||||
|
unless File.file?(installer.bin_dir / "common.rb")
|
||||||
|
FileUtils.mkdir_p(installer.bin_dir)
|
||||||
|
FileUtils.cp(File.dirname(__FILE__) / "common.rb", installer.bin_dir / "common.rb")
|
||||||
|
end
|
||||||
|
|
||||||
|
include ColorfulMessages
|
||||||
|
name = installer.spec.name
|
||||||
|
if $GEMS && versions = ($GEMS.assoc(name) || [])[1]
|
||||||
|
dep = Gem::Dependency.new(name, versions)
|
||||||
|
unless dep.version_requirements.satisfied_by?(installer.spec.version)
|
||||||
|
error "Cannot install #{installer.spec.full_name} " \
|
||||||
|
"for #{$INSTALLING.map {|x| x.full_name}.join(", ")}; " \
|
||||||
|
"you required #{dep}"
|
||||||
|
::Thor::Tasks::Merb::Gem.rollback_trans
|
||||||
|
exit!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
success "Installing #{installer.spec.full_name}"
|
||||||
|
end)
|
||||||
|
|
||||||
|
class ::Gem::Uninstaller
|
||||||
|
def self._with_silent_ui
|
||||||
|
|
||||||
|
ui = Gem::DefaultUserInteraction.ui
|
||||||
|
def ui.say(str)
|
||||||
|
puts "- #{str}"
|
||||||
|
end
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
class << Gem::DefaultUserInteraction.ui
|
||||||
|
remove_method :say
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self._uninstall(source_index, name, op, version)
|
||||||
|
unless source_index.find_name(name, "#{op} #{version}").empty?
|
||||||
|
uninstaller = Gem::Uninstaller.new(
|
||||||
|
name,
|
||||||
|
:version => "#{op} #{version}",
|
||||||
|
:install_dir => Dir.pwd / "gems",
|
||||||
|
:all => true,
|
||||||
|
:ignore => true
|
||||||
|
)
|
||||||
|
_with_silent_ui { uninstaller.uninstall }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self._uninstall_others(source_index, name, version)
|
||||||
|
_uninstall(source_index, name, "<", version)
|
||||||
|
_uninstall(source_index, name, ">", version)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Gem.post_install_hooks.push(proc do |installer|
|
||||||
|
$INSTALLING.pop
|
||||||
|
source_index = installer.instance_variable_get("@source_index")
|
||||||
|
::Gem::Uninstaller._uninstall_others(
|
||||||
|
source_index, installer.spec.name, installer.spec.version
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
class ::Gem::DependencyInstaller
|
||||||
|
alias old_fg find_gems_with_sources
|
||||||
|
|
||||||
|
def find_gems_with_sources(dep)
|
||||||
|
if @source_index.any? { |_, installed_spec|
|
||||||
|
installed_spec.satisfies_requirement?(dep)
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
end
|
||||||
|
|
||||||
|
old_fg(dep)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ::Gem::SpecFetcher
|
||||||
|
alias old_fetch fetch
|
||||||
|
def fetch(dependency, all = false, matching_platform = true)
|
||||||
|
idx = Gem::SourceIndex.from_installed_gems
|
||||||
|
|
||||||
|
dep = idx.search(dependency).sort.last
|
||||||
|
|
||||||
|
if dep
|
||||||
|
file = dep.loaded_from.dup
|
||||||
|
file.gsub!(/specifications/, "cache")
|
||||||
|
file.gsub!(/gemspec$/, "gem")
|
||||||
|
spec = ::Gem::Format.from_file_by_path(file).spec
|
||||||
|
[[spec, file]]
|
||||||
|
else
|
||||||
|
old_fetch(dependency, all, matching_platform)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ::Gem::Installer
|
||||||
|
def app_script_text(bin_file_name)
|
||||||
|
template = File.read(File.dirname(__FILE__) / "app_script.rb")
|
||||||
|
erb = ERB.new(template)
|
||||||
|
erb.result(binding)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ::Gem::Specification
|
||||||
|
def recursive_dependencies(from, index = Gem.source_index)
|
||||||
|
specs = self.runtime_dependencies.map do |dep|
|
||||||
|
spec = index.search(dep).last
|
||||||
|
unless spec
|
||||||
|
from_name = from.is_a?(::Gem::Specification) ? from.full_name : from.to_s
|
||||||
|
wider_net = index.find_name(dep.name).last
|
||||||
|
ThorUI.error "Needed #{dep} for #{from_name}, but could not find it"
|
||||||
|
ThorUI.error "Found #{wider_net.full_name}" if wider_net
|
||||||
|
::Thor::Tasks::Merb::Gem.rollback_trans
|
||||||
|
end
|
||||||
|
spec
|
||||||
|
end
|
||||||
|
specs + specs.map {|s| s.recursive_dependencies(self, index)}.flatten.uniq
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,150 @@
|
||||||
|
require "rubygems"
|
||||||
|
require "rubygems/source_index"
|
||||||
|
require "rubygems/dependency_installer"
|
||||||
|
require "rubygems/uninstaller"
|
||||||
|
require "fileutils"
|
||||||
|
require File.join(File.dirname(__FILE__), "utils")
|
||||||
|
require File.join(File.dirname(__FILE__), "gem_ext")
|
||||||
|
require File.join(File.dirname(__FILE__), "ops")
|
||||||
|
|
||||||
|
$INSTALLING = []
|
||||||
|
|
||||||
|
module Merb
|
||||||
|
|
||||||
|
class Gem < Thor
|
||||||
|
extend ColorfulMessages
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
dirs = [Dir.pwd, File.dirname(__FILE__) / ".."]
|
||||||
|
root = dirs.find {|d| File.file?(d / "config" / "dependencies.rb")}
|
||||||
|
|
||||||
|
if root
|
||||||
|
@depsrb = root / "config" / "dependencies.rb"
|
||||||
|
else
|
||||||
|
self.class.error "dependencies.rb was not found"
|
||||||
|
exit!
|
||||||
|
end
|
||||||
|
|
||||||
|
FileUtils.mkdir_p(Dir.pwd / "gems")
|
||||||
|
|
||||||
|
@list = Collector.collect(File.read(@depsrb))
|
||||||
|
@idx = ::Gem::SourceIndex.new.load_gems_in("gems/specifications")
|
||||||
|
end
|
||||||
|
|
||||||
|
def list
|
||||||
|
require "pp"
|
||||||
|
pp @list
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "redeploy", "Syncs up gems/cache with gems/gems. All gems in the cache " \
|
||||||
|
"that are not already installed will be installed from the " \
|
||||||
|
"cache. All installed gems that are not in the cache will " \
|
||||||
|
"be uninstalled."
|
||||||
|
def redeploy
|
||||||
|
gem_dir = Dir.pwd / "gems" / "gems"
|
||||||
|
cache_dir = Dir.pwd / "gems" / "cache"
|
||||||
|
|
||||||
|
gems = Dir[gem_dir / "*"].map! {|n| File.basename(n)}
|
||||||
|
cache = Dir[cache_dir / "*.gem"].map! {|n| File.basename(n, ".gem")}
|
||||||
|
new_gems = cache - gems
|
||||||
|
outdated = gems - cache
|
||||||
|
idx = ::Gem::SourceIndex.new
|
||||||
|
idx.load_gems_in(Dir.pwd / "gems" / "specifications")
|
||||||
|
|
||||||
|
new_gems.each do |g|
|
||||||
|
installer = ::Gem::Installer.new(cache_dir / "#{g}.gem",
|
||||||
|
:bin_dir => Dir.pwd / "bin",
|
||||||
|
:install_dir => Dir.pwd / "gems",
|
||||||
|
:ignore_dependencies => true,
|
||||||
|
:user_install => false,
|
||||||
|
:wrappers => true,
|
||||||
|
:source_index => idx)
|
||||||
|
|
||||||
|
installer.install
|
||||||
|
end
|
||||||
|
|
||||||
|
outdated.each do |g|
|
||||||
|
/(.*)\-(.*)/ =~ g
|
||||||
|
name, version = $1, $2
|
||||||
|
uninstaller = ::Gem::Uninstaller.new(name,
|
||||||
|
:version => version,
|
||||||
|
:bin_dir => Dir.pwd / "bin",
|
||||||
|
:install_dir => Dir.pwd / "gems",
|
||||||
|
:ignore => true,
|
||||||
|
:executables => true
|
||||||
|
)
|
||||||
|
uninstaller.uninstall
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "confirm", "Confirm the current setup. merb:gem:install will " \
|
||||||
|
"automatically run this task before committing the " \
|
||||||
|
"changes it makes."
|
||||||
|
def confirm(gems = @list)
|
||||||
|
::Gem.path.replace([Dir.pwd / "gems"])
|
||||||
|
::Gem.source_index.load_gems_in(Dir.pwd / "gems" / "specifications")
|
||||||
|
|
||||||
|
self.class.info "Confirming configuration..."
|
||||||
|
|
||||||
|
::Gem.loaded_specs.clear
|
||||||
|
|
||||||
|
begin
|
||||||
|
gems.each do |name, versions|
|
||||||
|
versions ||= []
|
||||||
|
::Gem.activate name, *versions
|
||||||
|
end
|
||||||
|
rescue ::Gem::LoadError => e
|
||||||
|
self.class.error "Configuration could not be confirmed: #{e.message}"
|
||||||
|
self.class.rollback_trans
|
||||||
|
end
|
||||||
|
self.class.info "Confirmed"
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'install', 'Sync up your bundled gems with the list in config/dependencies.rb'
|
||||||
|
def install(*gems)
|
||||||
|
if gems.empty?
|
||||||
|
gems = @list
|
||||||
|
else
|
||||||
|
gems = gems.map {|desc| name, *versions = desc.split(" ") }
|
||||||
|
end
|
||||||
|
|
||||||
|
$GEMS = gems
|
||||||
|
|
||||||
|
self.class.begin_trans
|
||||||
|
|
||||||
|
gems.each do |name, versions|
|
||||||
|
dep = ::Gem::Dependency.new(name, versions || [])
|
||||||
|
unless @idx.search(dep).empty?
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue_failures do
|
||||||
|
$INSTALLING = []
|
||||||
|
_install(dep)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
gem_dir = Dir.pwd / "gems" / "gems"
|
||||||
|
installed_gems = Dir[gem_dir / "*"].map! {|n| File.basename(n)}
|
||||||
|
|
||||||
|
list = full_list.map {|x| x.full_name}.compact
|
||||||
|
|
||||||
|
(installed_gems - list).each do |g|
|
||||||
|
/^(.*)\-(.*)$/ =~ g
|
||||||
|
name, version = $1, $2
|
||||||
|
uninstaller = ::Gem::Uninstaller.new(name,
|
||||||
|
:version => version,
|
||||||
|
:bin_dir => (Dir.pwd / "bin").to_s,
|
||||||
|
:install_dir => (Dir.pwd / "gems").to_s,
|
||||||
|
:ignore => true,
|
||||||
|
:executables => true
|
||||||
|
)
|
||||||
|
uninstaller.uninstall
|
||||||
|
end
|
||||||
|
|
||||||
|
confirm(gems)
|
||||||
|
|
||||||
|
self.class.commit_trans
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,93 @@
|
||||||
|
module Thor::Tasks
|
||||||
|
module Merb
|
||||||
|
class Collector
|
||||||
|
attr_reader :dependencies
|
||||||
|
|
||||||
|
def self.collect(str)
|
||||||
|
collector = new
|
||||||
|
collector.instance_eval(str)
|
||||||
|
collector.dependencies
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@dependencies = []
|
||||||
|
end
|
||||||
|
|
||||||
|
def dependency(name, *versions)
|
||||||
|
versions.pop if versions.last.is_a?(Hash)
|
||||||
|
@dependencies << [name, versions]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Gem < Thor
|
||||||
|
def full_list
|
||||||
|
@idx.load_gems_in("gems/specifications")
|
||||||
|
|
||||||
|
@list.map do |name, versions|
|
||||||
|
dep = ::Gem::Dependency.new(name, versions)
|
||||||
|
spec = @idx.search(dep).last
|
||||||
|
unless spec
|
||||||
|
self.class.error "A required dependency #{dep} was not found"
|
||||||
|
self.class.rollback_trans
|
||||||
|
end
|
||||||
|
deps = spec.recursive_dependencies(dep, @idx)
|
||||||
|
[spec] + deps
|
||||||
|
end.flatten.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def rescue_failures(error = StandardError, prc = nil)
|
||||||
|
begin
|
||||||
|
yield
|
||||||
|
rescue error => e
|
||||||
|
if prc
|
||||||
|
prc.call(e)
|
||||||
|
else
|
||||||
|
puts e.message
|
||||||
|
puts e.backtrace
|
||||||
|
end
|
||||||
|
self.class.rollback_trans
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.begin_trans
|
||||||
|
note "Beginning transaction"
|
||||||
|
FileUtils.cp_r(Dir.pwd / "gems", Dir.pwd / ".original_gems")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.commit_trans
|
||||||
|
note "Committing transaction"
|
||||||
|
FileUtils.rm_rf(Dir.pwd / ".original_gems")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.rollback_trans
|
||||||
|
if File.exist?(Dir.pwd / ".original_gems")
|
||||||
|
note "Rolling back transaction"
|
||||||
|
FileUtils.rm_rf(Dir.pwd / "gems")
|
||||||
|
FileUtils.mv(Dir.pwd / ".original_gems", Dir.pwd / "gems")
|
||||||
|
end
|
||||||
|
exit!
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def _install(dep)
|
||||||
|
@idx.load_gems_in("gems/specifications")
|
||||||
|
return if @idx.search(dep).last
|
||||||
|
|
||||||
|
installer = ::Gem::DependencyInstaller.new(
|
||||||
|
:bin_dir => Dir.pwd / "bin",
|
||||||
|
:install_dir => Dir.pwd / "gems",
|
||||||
|
:user_install => false)
|
||||||
|
|
||||||
|
begin
|
||||||
|
installer.install dep.name, dep.version_requirements
|
||||||
|
rescue ::Gem::GemNotFoundException => e
|
||||||
|
puts "Cannot find #{dep}"
|
||||||
|
rescue ::Gem::RemoteFetcher::FetchError => e
|
||||||
|
puts e.message
|
||||||
|
puts "Retrying..."
|
||||||
|
retry
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,40 @@
|
||||||
|
class String
|
||||||
|
def /(other)
|
||||||
|
(Pathname.new(self) + other).to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ColorfulMessages
|
||||||
|
|
||||||
|
# red
|
||||||
|
def error(*messages)
|
||||||
|
puts messages.map { |msg| "\033[1;31m#{msg}\033[0m" }
|
||||||
|
end
|
||||||
|
|
||||||
|
# yellow
|
||||||
|
def warning(*messages)
|
||||||
|
puts messages.map { |msg| "\033[1;33m#{msg}\033[0m" }
|
||||||
|
end
|
||||||
|
|
||||||
|
# green
|
||||||
|
def success(*messages)
|
||||||
|
puts messages.map { |msg| "\033[1;32m#{msg}\033[0m" }
|
||||||
|
end
|
||||||
|
|
||||||
|
alias_method :message, :success
|
||||||
|
|
||||||
|
# magenta
|
||||||
|
def note(*messages)
|
||||||
|
puts messages.map { |msg| "\033[1;35m#{msg}\033[0m" }
|
||||||
|
end
|
||||||
|
|
||||||
|
# blue
|
||||||
|
def info(*messages)
|
||||||
|
puts messages.map { |msg| "\033[1;34m#{msg}\033[0m" }
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module ThorUI
|
||||||
|
extend ColorfulMessages
|
||||||
|
end
|
Loading…
Reference in New Issue