9e909d5be3
Update Bundler to 1.0.15. Update Rails to 2.3.12. Update rails_xss plugin. The latter two were the source of a considerable amount of grief, as rails_xss is now MUCH stricter about what string methods can be used. Also made it possible to use rake 0.9.x with Instiki. But you probably REALLY want to use ruby bundle exec rake ... instead of just saying rake ....
317 lines
9.9 KiB
Ruby
317 lines
9.9 KiB
Ruby
require 'rails/vendor_gem_source_index'
|
|
|
|
module Gem
|
|
def self.source_index=(index)
|
|
@@source_index = index
|
|
end
|
|
end
|
|
|
|
module Rails
|
|
class GemDependency < Gem::Dependency
|
|
attr_accessor :lib, :source, :dep
|
|
|
|
def self.unpacked_path
|
|
@unpacked_path ||= File.join(RAILS_ROOT, 'vendor', 'gems')
|
|
end
|
|
|
|
@@framework_gems = {}
|
|
|
|
def self.add_frozen_gem_path
|
|
@@paths_loaded ||= begin
|
|
source_index = Rails::VendorGemSourceIndex.new(Gem.source_index)
|
|
Gem.clear_paths
|
|
Gem.source_index = source_index
|
|
# loaded before us - we can't change them, so mark them
|
|
Gem.loaded_specs.each do |name, spec|
|
|
@@framework_gems[name] = spec
|
|
end
|
|
true
|
|
end
|
|
end
|
|
|
|
def self.from_directory_name(directory_name, load_spec=true)
|
|
directory_name_parts = File.basename(directory_name).split('-')
|
|
|
|
version = directory_name_parts.find { |s| s.match(/^\d(\.\d|\.\w+)*$/) }
|
|
name = directory_name_parts[0..directory_name_parts.index(version)-1].join('-') if version
|
|
|
|
result = self.new(name, :version => version)
|
|
spec_filename = File.join(directory_name, '.specification')
|
|
if load_spec
|
|
raise "Missing specification file in #{File.dirname(spec_filename)}. Perhaps you need to do a 'rake gems:refresh_specs'\?" unless File.exists?(spec_filename)
|
|
spec = YAML::load_file(spec_filename)
|
|
result.specification = spec
|
|
end
|
|
result
|
|
rescue ArgumentError => e
|
|
raise "Unable to determine gem name and version from '#{directory_name}'"
|
|
end
|
|
|
|
def initialize(name, options = {})
|
|
require 'rubygems' unless Object.const_defined?(:Gem)
|
|
|
|
if options[:requirement]
|
|
req = options[:requirement]
|
|
elsif options[:version]
|
|
req = Gem::Requirement.create(options[:version])
|
|
else
|
|
req = Gem::Requirement.default
|
|
end
|
|
|
|
@lib = options[:lib]
|
|
@source = options[:source]
|
|
@loaded = @frozen = @load_paths_added = false
|
|
|
|
super(name, req)
|
|
end
|
|
|
|
def add_load_paths
|
|
self.class.add_frozen_gem_path
|
|
return if @loaded || @load_paths_added
|
|
if framework_gem?
|
|
@load_paths_added = @loaded = @frozen = true
|
|
return
|
|
end
|
|
|
|
begin
|
|
dep = Gem::Dependency.new(name, requirement)
|
|
spec = Gem.source_index.find { |_,s| s.satisfies_requirement?(dep) }.last
|
|
spec.activate # a way that exists
|
|
rescue
|
|
gem self.name, self.requirement # < 1.8 unhappy way
|
|
end
|
|
|
|
@spec = Gem.loaded_specs[name]
|
|
@frozen = @spec.loaded_from.include?(self.class.unpacked_path) if @spec
|
|
@load_paths_added = true
|
|
rescue Gem::LoadError
|
|
end
|
|
|
|
def dependencies
|
|
return [] if framework_gem?
|
|
return [] unless installed?
|
|
specification.dependencies.reject do |dependency|
|
|
dependency.type == :development
|
|
end.map do |dependency|
|
|
GemDependency.new(dependency.name, :requirement => (dependency.respond_to?(:requirement) ? dependency.requirement : dependency.version_requirements))
|
|
end
|
|
end
|
|
|
|
def specification
|
|
# code repeated from Gem.activate. Find a matching spec, or the currently loaded version.
|
|
# error out if loaded version and requested version are incompatible.
|
|
@spec ||= begin
|
|
matches = Gem.source_index.search(self)
|
|
matches << @@framework_gems[name] if framework_gem?
|
|
if Gem.loaded_specs[name] then
|
|
# This gem is already loaded. If the currently loaded gem is not in the
|
|
# list of candidate gems, then we have a version conflict.
|
|
existing_spec = Gem.loaded_specs[name]
|
|
unless matches.any? { |spec| spec.version == existing_spec.version } then
|
|
raise Gem::Exception,
|
|
"can't activate #{@dep}, already activated #{existing_spec.full_name}"
|
|
end
|
|
# we're stuck with it, so change to match
|
|
version_requirements = Gem::Requirement.create("=#{existing_spec.version}")
|
|
existing_spec
|
|
else
|
|
# new load
|
|
matches.last
|
|
end
|
|
end
|
|
end
|
|
|
|
def specification=(s)
|
|
@spec = s
|
|
end
|
|
|
|
def built?
|
|
return false unless frozen?
|
|
|
|
if vendor_gem?
|
|
specification.extensions.each do |ext|
|
|
makefile = File.join(unpacked_gem_directory, File.dirname(ext), 'Makefile')
|
|
return false unless File.exists?(makefile)
|
|
end
|
|
end
|
|
|
|
true
|
|
end
|
|
|
|
def framework_gem?
|
|
@@framework_gems.has_key?(name)
|
|
end
|
|
|
|
def frozen?
|
|
@frozen ||= vendor_rails? || vendor_gem?
|
|
end
|
|
|
|
def installed?
|
|
Gem.loaded_specs.keys.include?(name)
|
|
end
|
|
|
|
def load_paths_added?
|
|
# always try to add load paths - even if a gem is loaded, it may not
|
|
# be a compatible version (ie random_gem 0.4 is loaded and a later spec
|
|
# needs >= 0.5 - gem 'random_gem' will catch this and error out)
|
|
@load_paths_added
|
|
end
|
|
|
|
def loaded?
|
|
@loaded ||= begin
|
|
if vendor_rails?
|
|
true
|
|
elsif specification.nil?
|
|
false
|
|
else
|
|
# check if the gem is loaded by inspecting $"
|
|
# specification.files lists all the files contained in the gem
|
|
gem_files = specification.files
|
|
# select only the files contained in require_paths - typically in bin and lib
|
|
require_paths_regexp = Regexp.new("^(#{specification.require_paths*'|'})/")
|
|
gem_lib_files = gem_files.select { |f| require_paths_regexp.match(f) }
|
|
# chop the leading directory off - a typical file might be in
|
|
# lib/gem_name/file_name.rb, but it will be 'require'd as gem_name/file_name.rb
|
|
gem_lib_files.map! { |f| f.split('/', 2)[1] }
|
|
# if any of the files from the above list appear in $", the gem is assumed to
|
|
# have been loaded
|
|
!(gem_lib_files & $").empty?
|
|
end
|
|
end
|
|
end
|
|
|
|
def vendor_rails?
|
|
Gem.loaded_specs.has_key?(name) && Gem.loaded_specs[name].loaded_from.empty?
|
|
end
|
|
|
|
def vendor_gem?
|
|
specification && File.exists?(unpacked_gem_directory)
|
|
end
|
|
|
|
def build(options={})
|
|
require 'rails/gem_builder'
|
|
return if specification.nil?
|
|
if options[:force] || !built?
|
|
return unless File.exists?(unpacked_specification_filename)
|
|
spec = YAML::load_file(unpacked_specification_filename)
|
|
Rails::GemBuilder.new(spec, unpacked_gem_directory).build_extensions
|
|
puts "Built gem: '#{unpacked_gem_directory}'"
|
|
end
|
|
dependencies.each { |dep| dep.build(options) }
|
|
end
|
|
|
|
def install
|
|
unless installed?
|
|
cmd = "#{gem_command} #{install_command.join(' ')}"
|
|
puts cmd
|
|
puts %x(#{cmd})
|
|
end
|
|
end
|
|
|
|
def load
|
|
return if @loaded || @load_paths_added == false
|
|
require(@lib || name) unless @lib == false
|
|
@loaded = true
|
|
rescue LoadError
|
|
puts $!.to_s
|
|
$!.backtrace.each { |b| puts b }
|
|
end
|
|
|
|
def refresh
|
|
Rails::VendorGemSourceIndex.silence_spec_warnings = true
|
|
real_gems = Gem.source_index.installed_source_index
|
|
exact_dep = Gem::Dependency.new(name, "= #{specification.version}")
|
|
matches = real_gems.search(exact_dep)
|
|
installed_spec = matches.first
|
|
if frozen?
|
|
if installed_spec
|
|
# we have a real copy
|
|
# get a fresh spec - matches should only have one element
|
|
# note that there is no reliable method to check that the loaded
|
|
# spec is the same as the copy from real_gems - Gem.activate changes
|
|
# some of the fields
|
|
real_spec = Gem::Specification.load(matches.first.loaded_from)
|
|
write_specification(real_spec)
|
|
puts "Reloaded specification for #{name} from installed gems."
|
|
else
|
|
# the gem isn't installed locally - write out our current specs
|
|
write_specification(specification)
|
|
puts "Gem #{name} not loaded locally - writing out current spec."
|
|
end
|
|
else
|
|
if framework_gem?
|
|
puts "Gem directory for #{name} not found - check if it's loading before rails."
|
|
else
|
|
puts "Something bad is going on - gem directory not found for #{name}."
|
|
end
|
|
end
|
|
end
|
|
|
|
def unpack(options={})
|
|
unless frozen? || framework_gem?
|
|
FileUtils.mkdir_p unpack_base
|
|
Dir.chdir unpack_base do
|
|
Gem::GemRunner.new.run(unpack_command)
|
|
end
|
|
# Gem.activate changes the spec - get the original
|
|
real_spec = Gem::Specification.load(specification.loaded_from)
|
|
write_specification(real_spec)
|
|
end
|
|
dependencies.each { |dep| dep.unpack(options) } if options[:recursive]
|
|
end
|
|
|
|
def write_specification(spec)
|
|
# copy the gem's specification into GEMDIR/.specification so that
|
|
# we can access information about the gem on deployment systems
|
|
# without having the gem installed
|
|
File.open(unpacked_specification_filename, 'w') do |file|
|
|
file.puts spec.to_yaml
|
|
end
|
|
end
|
|
|
|
def ==(other)
|
|
Gem::Dependency === other.class &&
|
|
self.name == other.name && self.requirement == other.requirement
|
|
end
|
|
alias_method :eql?, :"=="
|
|
|
|
private
|
|
|
|
def gem_command
|
|
case RUBY_PLATFORM
|
|
when /win32/
|
|
'gem.bat'
|
|
when /java/
|
|
'jruby -S gem'
|
|
else
|
|
'gem'
|
|
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" << "= "+specification.version.to_s if requirement
|
|
cmd
|
|
end
|
|
|
|
def unpack_base
|
|
Rails::GemDependency.unpacked_path
|
|
end
|
|
|
|
def unpacked_gem_directory
|
|
File.join(unpack_base, specification.full_name)
|
|
end
|
|
|
|
def unpacked_specification_filename
|
|
File.join(unpacked_gem_directory, '.specification')
|
|
end
|
|
|
|
end
|
|
end
|