diff --git a/Rakefile b/Rakefile index 889e1f8..e80cd8e 100644 --- a/Rakefile +++ b/Rakefile @@ -110,6 +110,11 @@ namespace :spec do result = system "rake test:integration" raise "Tests failed" unless result end + + Dir.chdir "spec/integration/merb" do + result = system "rake spec" + raise "Tests failed" unless result + end end end diff --git a/spec/integration/merb/.gitignore b/spec/integration/merb/.gitignore new file mode 100644 index 0000000..753409b --- /dev/null +++ b/spec/integration/merb/.gitignore @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/Rakefile b/spec/integration/merb/Rakefile new file mode 100644 index 0000000..a760c99 --- /dev/null +++ b/spec/integration/merb/Rakefile @@ -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 +############################################################################## diff --git a/spec/integration/merb/app/controllers/application.rb b/spec/integration/merb/app/controllers/application.rb new file mode 100644 index 0000000..5ce39a0 --- /dev/null +++ b/spec/integration/merb/app/controllers/application.rb @@ -0,0 +1,2 @@ +class Application < Merb::Controller +end \ No newline at end of file diff --git a/spec/integration/merb/app/controllers/exceptions.rb b/spec/integration/merb/app/controllers/exceptions.rb new file mode 100644 index 0000000..4fdb566 --- /dev/null +++ b/spec/integration/merb/app/controllers/exceptions.rb @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/app/controllers/testing.rb b/spec/integration/merb/app/controllers/testing.rb new file mode 100644 index 0000000..40a56da --- /dev/null +++ b/spec/integration/merb/app/controllers/testing.rb @@ -0,0 +1,10 @@ +class Testing < Application + + def show_form + render + end + + def submit_form + end + +end \ No newline at end of file diff --git a/spec/integration/merb/app/views/exceptions/not_acceptable.html.erb b/spec/integration/merb/app/views/exceptions/not_acceptable.html.erb new file mode 100644 index 0000000..a7b7752 --- /dev/null +++ b/spec/integration/merb/app/views/exceptions/not_acceptable.html.erb @@ -0,0 +1,63 @@ +
+
+ + +

pocket rocket web framework

+
+
+ +
+

Exception:

+

<%= request.exceptions.first.message %>

+
+ +
+

Why am I seeing this page?

+

Merb couldn't find an appropriate content_type to return, + based on what you said was available via provides() and + what the client requested.

+ +

How to add a mime-type

+

+      Merb.add_mime_type :pdf, :to_pdf, %w[application/pdf], "Content-Encoding" => "gzip"
+    
+

What this means is:

+ + +

You can then do:

+

+      class Foo < Application
+        provides :pdf
+      end
+    
+ +

Where can I find help?

+

If you have any questions or if you can't figure something out, please take a + look at our project page, + feel free to come chat at irc.freenode.net, channel #merb, + or post to merb mailing list + on Google Groups.

+ +

What if I've found a bug?

+

If you want to file a bug or make your own contribution to Merb, + feel free to register and create a ticket at our + project development page + on Lighthouse.

+ +

How do I edit this page?

+

You can change what people see when this happens by editing app/views/exceptions/not_acceptable.html.erb.

+ +
+ + +
diff --git a/spec/integration/merb/app/views/exceptions/not_found.html.erb b/spec/integration/merb/app/views/exceptions/not_found.html.erb new file mode 100644 index 0000000..42b41a8 --- /dev/null +++ b/spec/integration/merb/app/views/exceptions/not_found.html.erb @@ -0,0 +1,47 @@ +
+
+ + +

pocket rocket web framework

+
+
+ +
+

Exception:

+

<%= request.exceptions.first.message %>

+
+ +
+

Welcome to Merb!

+

Merb is a light-weight MVC framework written in Ruby. We hope you enjoy it.

+ +

Where can I find help?

+

If you have any questions or if you can't figure something out, please take a + look at our project page, + feel free to come chat at irc.freenode.net, channel #merb, + or post to merb mailing list + on Google Groups.

+ +

What if I've found a bug?

+

If you want to file a bug or make your own contribution to Merb, + feel free to register and create a ticket at our + project development page + on Lighthouse.

+ +

How do I edit this page?

+

You're seeing this page because you need to edit the following files: +

+

+
+ + +
diff --git a/spec/integration/merb/app/views/layout/application.html.erb b/spec/integration/merb/app/views/layout/application.html.erb new file mode 100644 index 0000000..4637ef2 --- /dev/null +++ b/spec/integration/merb/app/views/layout/application.html.erb @@ -0,0 +1,12 @@ + + + + Fresh Merb App + + + + + <%#= message[:notice] %> + <%= catch_content :for_layout %> + + \ No newline at end of file diff --git a/spec/integration/merb/app/views/testing/show_form.html.erb b/spec/integration/merb/app/views/testing/show_form.html.erb new file mode 100644 index 0000000..cee070b --- /dev/null +++ b/spec/integration/merb/app/views/testing/show_form.html.erb @@ -0,0 +1,22 @@ +

Webrat Form

+ +
+ + + + + + + +
\ No newline at end of file diff --git a/spec/integration/merb/config/environments/development.rb b/spec/integration/merb/config/environments/development.rb new file mode 100644 index 0000000..d6d4ab3 --- /dev/null +++ b/spec/integration/merb/config/environments/development.rb @@ -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" +} diff --git a/spec/integration/merb/config/environments/rake.rb b/spec/integration/merb/config/environments/rake.rb new file mode 100644 index 0000000..5e4b9a7 --- /dev/null +++ b/spec/integration/merb/config/environments/rake.rb @@ -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" +} diff --git a/spec/integration/merb/config/environments/test.rb b/spec/integration/merb/config/environments/test.rb new file mode 100644 index 0000000..671ec76 --- /dev/null +++ b/spec/integration/merb/config/environments/test.rb @@ -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 +} diff --git a/spec/integration/merb/config/init.rb b/spec/integration/merb/config/init.rb new file mode 100644 index 0000000..e7268e9 --- /dev/null +++ b/spec/integration/merb/config/init.rb @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/config/rack.rb b/spec/integration/merb/config/rack.rb new file mode 100644 index 0000000..494c687 --- /dev/null +++ b/spec/integration/merb/config/rack.rb @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/config/router.rb b/spec/integration/merb/config/router.rb new file mode 100644 index 0000000..6df8fb2 --- /dev/null +++ b/spec/integration/merb/config/router.rb @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/spec/spec.opts b/spec/integration/merb/spec/spec.opts new file mode 100644 index 0000000..4e1e0d2 --- /dev/null +++ b/spec/integration/merb/spec/spec.opts @@ -0,0 +1 @@ +--color diff --git a/spec/integration/merb/spec/spec_helper.rb b/spec/integration/merb/spec/spec_helper.rb new file mode 100644 index 0000000..ae04668 --- /dev/null +++ b/spec/integration/merb/spec/spec_helper.rb @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/spec/webrat_spec.rb b/spec/integration/merb/spec/webrat_spec.rb new file mode 100644 index 0000000..cc9fc1b --- /dev/null +++ b/spec/integration/merb/spec/webrat_spec.rb @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/tasks/merb.thor/app_script.rb b/spec/integration/merb/tasks/merb.thor/app_script.rb new file mode 100644 index 0000000..fb0e116 --- /dev/null +++ b/spec/integration/merb/tasks/merb.thor/app_script.rb @@ -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 %>' \ No newline at end of file diff --git a/spec/integration/merb/tasks/merb.thor/common.rb b/spec/integration/merb/tasks/merb.thor/common.rb new file mode 100644 index 0000000..0258520 --- /dev/null +++ b/spec/integration/merb/tasks/merb.thor/common.rb @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/tasks/merb.thor/gem_ext.rb b/spec/integration/merb/tasks/merb.thor/gem_ext.rb new file mode 100644 index 0000000..61bd474 --- /dev/null +++ b/spec/integration/merb/tasks/merb.thor/gem_ext.rb @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/tasks/merb.thor/main.thor b/spec/integration/merb/tasks/merb.thor/main.thor new file mode 100644 index 0000000..ea6438b --- /dev/null +++ b/spec/integration/merb/tasks/merb.thor/main.thor @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/tasks/merb.thor/ops.rb b/spec/integration/merb/tasks/merb.thor/ops.rb new file mode 100644 index 0000000..c758af2 --- /dev/null +++ b/spec/integration/merb/tasks/merb.thor/ops.rb @@ -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 \ No newline at end of file diff --git a/spec/integration/merb/tasks/merb.thor/utils.rb b/spec/integration/merb/tasks/merb.thor/utils.rb new file mode 100644 index 0000000..1b1caa6 --- /dev/null +++ b/spec/integration/merb/tasks/merb.thor/utils.rb @@ -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