Skip to content

Commit

Permalink
Added config.gem for specifying which gems are required by the applic…
Browse files Browse the repository at this point in the history
…ation, as well as rake tasks for installing and freezing gems. [rick]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@9140 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
technoweenie committed Mar 30, 2008
1 parent 81286f8 commit 088ef18
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 2 deletions.
17 changes: 17 additions & 0 deletions railties/CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
*SVN*

* Added config.gem for specifying which gems are required by the application, as well as rake tasks for installing and freezing gems. [rick]

Rails::Initializer.run do |config|
config.gems "bj"
config.gems "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
config.gems "aws-s3", :lib => "aws/s3"
end

# List required gems.
rake gems

# Install all required gems:
rake gems:install

# Unpack specified gem to vendor/gems/gem_name-x.x.x
rake gems:unpack GEM=bj

* Removed the default .htaccess configuration as there are so many good deployment options now (kept it as an example in README) [DHH]

* config.time_zone accepts TZInfo::Timezone identifiers as well as Rails TimeZone identifiers [Geoff Buesing]
Expand Down
45 changes: 43 additions & 2 deletions railties/lib/initializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
require 'rails/version'
require 'rails/plugin/locator'
require 'rails/plugin/loader'
require 'rails/gem_dependency'


RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
Expand Down Expand Up @@ -77,6 +78,7 @@ def process

require_frameworks
set_autoload_paths
add_gem_load_paths
add_plugin_load_paths
load_environment

Expand All @@ -98,8 +100,8 @@ def process

add_support_load_paths

load_gems
load_plugins

load_application_initializers

# the framework is now fully initialized
Expand Down Expand Up @@ -185,6 +187,17 @@ def add_plugin_load_paths
plugin_loader.add_plugin_load_paths
end

def add_gem_load_paths
unless @configuration.gems.empty?
require "rubygems"
@configuration.gems.each &:add_load_paths
end
end

def load_gems
@configuration.gems.each &:load
end

# Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt>
# defaults to <tt>vendor/plugins</tt> but may also be set to a list of
# paths, such as
Expand Down Expand Up @@ -229,7 +242,11 @@ def load_environment

def load_observers
if configuration.frameworks.include?(:active_record)
ActiveRecord::Base.instantiate_observers
if @configuration.gems.any? { |g| !g.loaded? }
puts "Unable to instantiate observers, some gems that this application depends on are missing. Run 'rake gems:install'"
else
ActiveRecord::Base.instantiate_observers
end
end
end

Expand Down Expand Up @@ -494,6 +511,25 @@ def plugins=(plugins)
# a sub class would have access to fine grained modification of the loading behavior. See
# the implementation of Rails::Plugin::Loader for more details.
attr_accessor :plugin_loader

# An array of gems that this rails application depends on. Rails will automatically load
# these gems during installation, and allow you to install any missing gems with:
#
# rake gems:install
#
# You can add with the #gem method.
attr_accessor :gems

# Adds a single Gem dependency to the rails application.
#
# # gem 'aws-s3', '>= 0.4.0'
# # require 'aws/s3'
# config.gem 'aws-s3', :lib => 'aws/s3', :version => '>= 0.4.0', \
# :source => "http://code.whytheluckystiff.net"
#
def gem(name, options = {})
@gems << Rails::GemDependency.new(name, options)
end

# Deprecated options:
def breakpoint_server(_ = nil)
Expand Down Expand Up @@ -529,6 +565,7 @@ def initialize
self.plugin_locators = default_plugin_locators
self.plugin_loader = default_plugin_loader
self.database_configuration_file = default_database_configuration_file
self.gems = default_gems

for framework in default_frameworks
self.send("#{framework}=", Rails::OrderedOptions.new)
Expand Down Expand Up @@ -712,6 +749,10 @@ def default_cache_store
:memory_store
end
end

def default_gems
[]
end
end
end

Expand Down
78 changes: 78 additions & 0 deletions railties/lib/rails/gem_dependency.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
module Rails
class GemDependency
attr_accessor :name, :requirement, :version, :lib, :source

def self.unpacked_path
@unpacked_path ||= File.join(RAILS_ROOT, 'vendor', 'gems')
end

def initialize(name, options = {})
@name = name.to_s
if options[:version]
@requirement = Gem::Requirement.create(options[:version])
@version = @requirement.requirements.first.last
end
@lib = options[:lib]
@source = options[:source]
@loaded = false
@load_paths_added = false
@unpack_directory = nil
end

def add_load_paths
return if @loaded || @load_paths_added
unpacked_paths = Dir[File.join(self.class.unpacked_path, "#{@name}-#{@version || "*"}")]
if unpacked_paths.empty?
args = [@name]
args << @requirement.to_s if @requirement
gem *args
else
$LOAD_PATH << File.join(unpacked_paths.first, 'lib')
end
@load_paths_added = true
rescue Gem::LoadError
puts $!.to_s
end

def load
return if @load_paths_added == false
require(@lib || @name)
@loaded = true
rescue LoadError
puts $!.to_s
$!.backtrace.each { |b| puts b }
end

def loaded?
@loaded
end

def load_paths_added?
@load_paths_added
end

def install
Gem::GemRunner.new.run(install_command)
end

def unpack_to(directory)
FileUtils.mkdir_p directory
Dir.chdir directory do
Gem::GemRunner.new.run(unpack_command)
end
end

def install_command
cmd = %w(install) << @name
cmd << "--version" << "#{@requirement.to_s}" if @requirement
cmd << "--source" << @source if @source
cmd
end

def unpack_command
cmd = %w(unpack) << @name
cmd << "--version" << "#{@requirement.to_s}" if @requirement
cmd
end
end
end
31 changes: 31 additions & 0 deletions railties/lib/tasks/gems.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
desc "List the gems that this rails application depends on"
task :gems => :environment do
Rails.configuration.gems.each do |gem|
puts "[#{gem.loaded? ? '*' : ' '}] #{gem.name} #{gem.requirement.to_s}"
end
end

namespace :gems do
desc "Installs all required gems for this application."
task :install => :environment do
require 'rubygems'
require 'rubygems/gem_runner'
Rails.configuration.gems.each { |gem| gem.install unless gem.loaded? }
end

desc "Unpacks the specified gem into vendor/gems."
task :unpack do
raise "Specify name of gem in the config.gems array with GEM=" if ENV['GEM'].blank?
Rake::Task["environment"].invoke
require 'rubygems'
require 'rubygems/gem_runner'
unless Rails.configuration.gems.select do |gem|
if gem.loaded? && gem.name == ENV['GEM']
gem.unpack_to(File.join(RAILS_ROOT, 'vendor', 'gems'))
true
end
end.any?
puts "No gem named #{ENV['GEM'].inspect} found."
end
end
end
62 changes: 62 additions & 0 deletions railties/test/gem_dependency_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
require 'plugin_test_helper'

uses_mocha "Plugin Tests" do
class GemDependencyTest < Test::Unit::TestCase
def setup
@gem = Rails::GemDependency.new "hpricot"
@gem_with_source = Rails::GemDependency.new "hpricot", :source => "http://code.whytheluckystiff.net"
@gem_with_version = Rails::GemDependency.new "hpricot", :version => "= 0.6"
@gem_with_lib = Rails::GemDependency.new "aws-s3", :lib => "aws/s3"
end

def test_configuration_adds_gem_dependency
config = Rails::Configuration.new
config.gem "aws-s3", :lib => "aws/s3", :version => "0.4.0"
assert_equal [["install", "aws-s3", "--version", "= 0.4.0"]], config.gems.collect(&:install_command)
end

def test_gem_creates_install_command
assert_equal %w(install hpricot), @gem.install_command
end

def test_gem_with_source_creates_install_command
assert_equal %w(install hpricot --source http://code.whytheluckystiff.net), @gem_with_source.install_command
end

def test_gem_with_version_creates_install_command
assert_equal ["install", "hpricot", "--version", "= 0.6"], @gem_with_version.install_command
end

def test_gem_creates_unpack_command
assert_equal %w(unpack hpricot), @gem.unpack_command
end

def test_gem_with_version_unpack_install_command
assert_equal ["unpack", "hpricot", "--version", "= 0.6"], @gem_with_version.unpack_command
end

def test_gem_adds_load_paths
@gem.expects(:gem).with(@gem.name)
@gem.add_load_paths
end

def test_gem_with_version_adds_load_paths
@gem_with_version.expects(:gem).with(@gem_with_version.name, @gem_with_version.requirement.to_s)
@gem_with_version.add_load_paths
end

def test_gem_loading
@gem.expects(:gem).with(@gem.name)
@gem.expects(:require).with(@gem.name)
@gem.add_load_paths
@gem.load
end

def test_gem_with_lib_loading
@gem_with_lib.expects(:gem).with(@gem_with_lib.name)
@gem_with_lib.expects(:require).with(@gem_with_lib.lib)
@gem_with_lib.add_load_paths
@gem_with_lib.load
end
end
end

0 comments on commit 088ef18

Please sign in to comment.