1 require 'rails/vendor_gem_source_index'
4 def self.source_index
=(index
)
11 attr_accessor
:lib, :source
13 def self.unpacked_path
14 @unpacked_path ||= File
.join(RAILS_ROOT
, 'vendor', 'gems')
19 def self.add_frozen_gem_path
20 @
@paths_loaded ||= begin
21 source_index
= Rails
::VendorGemSourceIndex.new(Gem
.source_index
)
23 Gem
.source_index
= source_index
24 # loaded before us - we can't change them, so mark them
25 Gem
.loaded_specs
.each
do |name
, spec
|
26 @
@framework_gems[name
] = spec
33 @
@framework_gems.has_key
?(name
)
37 Gem
.loaded_specs
.has_key
?(name
) && Gem
.loaded_specs
[name
].loaded_from
.empty
?
41 Gem
.loaded_specs
.has_key
?(name
) && Gem
.loaded_specs
[name
].loaded_from
.include?(self.class.unpacked_path
)
44 def initialize(name
, options
= {})
45 require 'rubygems' unless Object
.const_defined
?(:Gem)
47 if options
[:requirement]
48 req
= options
[:requirement]
49 elsif options
[:version]
50 req
= Gem
::Requirement.create(options
[:version])
52 req
= Gem
::Requirement.default
55 @dep = Gem
::Dependency.new(name
, req
)
57 @source = options
[:source]
58 @loaded = @frozen = @load_paths_added = false
62 self.class.add_frozen_gem_path
63 return if @loaded || @load_paths_added
65 @load_paths_added = @loaded = @frozen = true
69 @spec = Gem
.loaded_specs
[name
]
70 @frozen = @spec.loaded_from
.include?(self.class.unpacked_path
) if @spec
71 @load_paths_added = true
76 return [] if framework_gem
?
77 all_dependencies
= specification
.dependencies
.map
do |dependency
|
78 GemDependency
.new(dependency
.name
, :requirement => dependency
.version_requirements
)
80 all_dependencies
+= all_dependencies
.map(&:dependencies).flatten
84 def gem_dir(base_directory
)
85 File
.join(base_directory
, specification
.full_name
)
88 def spec_filename(base_directory
)
89 File
.join(gem_dir(base_directory
), '.specification')
93 return if @loaded || @load_paths_added == false
94 require(@lib || name
) unless @lib == false
98 $
!.backtrace
.each
{ |b
| puts b
}
106 r
= @dep.version_requirements
107 (r
== Gem
::Requirement.default
) ? nil : r
111 @frozen ||= vendor_rails
? || vendor_gem
?
118 elsif specification
.nil?
121 # check if the gem is loaded by inspecting $"
122 # specification.files lists all the files contained in the gem
123 gem_files
= specification
.files
124 # select only the files contained in require_paths - typically in bin and lib
125 require_paths_regexp
= Regexp
.new("^(#{specification.require_paths*'|'})/")
126 gem_lib_files
= gem_files
.select
{ |f
| require_paths_regexp
.match(f
) }
127 # chop the leading directory off - a typical file might be in
128 # lib/gem_name/file_name.rb, but it will be 'require'd as gem_name/file_name.rb
129 gem_lib_files
.map
! { |f
| f
.split('/', 2)[1] }
130 # if any of the files from the above list appear in $", the gem is assumed to
132 !(gem_lib_files
& $
").empty?
137 def load_paths_added?
138 # always try to add load paths - even if a gem is loaded, it may not
139 # be a compatible version (ie random_gem 0.4 is loaded and a later spec
140 # needs >= 0.5 - gem 'random_gem' will catch this and error out)
145 cmd = "#{gem_command} #{install_command.join(' ')}"
150 def unpack_to(directory)
151 FileUtils.mkdir_p directory
152 Dir.chdir directory do
153 Gem::GemRunner.new.run(unpack_command)
156 # Gem.activate changes the spec - get the original
157 real_spec = Gem::Specification.load(specification.loaded_from)
158 write_spec(directory, real_spec)
162 def write_spec(directory, spec)
163 # copy the gem's specification into GEMDIR/.specification so that
164 # we can access information about the gem on deployment systems
165 # without having the gem installed
166 File.open(spec_filename(directory), 'w') do |file|
167 file.puts spec.to_yaml
171 def refresh_spec(directory)
172 real_gems = Gem.source_index.installed_source_index
173 exact_dep = Gem::Dependency.new(name, "= #{specification.version}")
174 matches = real_gems.search(exact_dep)
175 installed_spec = matches.first
176 if File.exist?(File.dirname(spec_filename(directory)))
178 # we have a real copy
179 # get a fresh spec - matches should only have one element
180 # note that there is no reliable method to check that the loaded
181 # spec is the same as the copy from real_gems - Gem.activate changes
183 real_spec = Gem::Specification.load(matches.first.loaded_from)
184 write_spec(directory, real_spec)
185 puts "Reloaded specification for #{name} from installed gems."
187 # the gem isn't installed locally - write out our current specs
188 write_spec(directory, specification)
189 puts "Gem #{name} not loaded locally - writing out current spec."
193 puts "Gem directory for #{name} not found - check if it's loading before rails."
195 puts "Something bad is going on - gem directory not found for #{name}."
201 self.name == other.name && self.requirement == other.requirement
203 alias_method :"eql?", :"=="
210 # code repeated from Gem.activate. Find a matching spec, or the currently loaded version.
211 # error out if loaded version and requested version are incompatible.
213 matches = Gem.source_index.search(@dep)
214 matches << @@framework_gems[name] if framework_gem?
215 if Gem.loaded_specs[name] then
216 # This gem is already loaded. If the currently loaded gem is not in the
217 # list of candidate gems, then we have a version conflict.
218 existing_spec = Gem.loaded_specs[name]
219 unless matches.any? { |spec| spec.version == existing_spec.version } then
220 raise Gem::Exception,
221 "can't activate #{@dep}, already activated #{existing_spec.full_name}"
223 # we're stuck with it, so change to match
224 @dep.version_requirements = Gem::Requirement.create("=#{existing_spec.version}")
235 RUBY_PLATFORM =~ /win32/ ? 'gem.bat' : 'gem'
239 cmd = %w(install) << name
240 cmd << "--version" << %("#{requirement.to_s}") if requirement
241 cmd << "--source" << @source if @source
246 cmd = %w(unpack) << name
247 cmd << "--version" << "= "+specification.version.to_s if requirement