6
class VendorGemSourceIndex
7
# VendorGemSourceIndex acts as a proxy for the Gem source index, allowing
8
# gems to be loaded from vendor/gems. Rather than the standard gem repository format,
9
# vendor/gems contains unpacked gems, with YAML specifications in .specification in
13
attr_reader :installed_source_index
14
attr_reader :vendor_source_index
16
@@silence_spec_warnings = false
18
def self.silence_spec_warnings
19
@@silence_spec_warnings
22
def self.silence_spec_warnings=(v)
23
@@silence_spec_warnings = v
26
def initialize(installed_index, vendor_dir=Rails::GemDependency.unpacked_path)
27
@installed_source_index = installed_index
28
@vendor_dir = vendor_dir
33
# reload the installed gems
34
@installed_source_index.refresh!
37
# handle vendor Rails gems - they are identified by having loaded_from set to ""
38
# we add them manually to the list, so that other gems can find them via dependencies
39
Gem.loaded_specs.each do |n, s|
40
next unless s.loaded_from.empty?
41
vendor_gems[s.full_name] = s
44
# load specifications from vendor/gems
45
Dir[File.join(Rails::GemDependency.unpacked_path, '*')].each do |d|
46
dir_name = File.basename(d)
47
dir_version = version_for_dir(dir_name)
48
spec = load_specification(d)
50
if spec.full_name != dir_name
51
# mismatched directory name and gem spec - produced by 2.1.0-era unpack code
53
# fix the spec version - this is not optimal (spec.files may be wrong)
54
# but it's better than breaking apps. Complain to remind users to get correct specs.
55
# use ActiveSupport::Deprecation.warn, as the logger is not set yet
56
$stderr.puts("config.gem: Unpacked gem #{dir_name} in vendor/gems has a mismatched specification file."+
57
" Run 'rake gems:refresh_specs' to fix this.") unless @@silence_spec_warnings
58
spec.version = dir_version
60
$stderr.puts("config.gem: Unpacked gem #{dir_name} in vendor/gems is not in a versioned directory"+
61
"(should be #{spec.full_name}).") unless @@silence_spec_warnings
62
# continue, assume everything is OK
66
# no spec - produced by early-2008 unpack code
67
# emulate old behavior, and complain.
68
$stderr.puts("config.gem: Unpacked gem #{dir_name} in vendor/gems has no specification file."+
69
" Run 'rake gems:refresh_specs' to fix this.") unless @@silence_spec_warnings
71
spec = Gem::Specification.new
72
spec.version = dir_version
73
spec.require_paths = ['lib']
74
ext_path = File.join(d, 'ext')
75
spec.require_paths << 'ext' if File.exist?(ext_path)
76
spec.name = /^(.*)-[^-]+$/.match(dir_name)[1]
78
# set files to everything in lib/
79
files += Dir[File.join(d, 'lib', '*')].map { |v| v.gsub(/^#{d}\//, '') }
80
files += Dir[File.join(d, 'ext', '*')].map { |v| v.gsub(/^#{d}\//, '') } if ext_path
83
$stderr.puts("config.gem: Unpacked gem #{dir_name} in vendor/gems not in a versioned directory."+
84
" Giving up.") unless @@silence_spec_warnings
88
spec.loaded_from = File.join(d, '.specification')
89
# finally, swap out full_gem_path
90
# it would be better to use a Gem::Specification subclass, but the YAML loads an explicit class
93
path = File.join installation_path, full_name
94
return path if File.directory? path
95
File.join installation_path, original_name
98
vendor_gems[File.basename(d)] = spec
100
@vendor_source_index = Gem::SourceIndex.new(vendor_gems)
103
def version_for_dir(d)
104
matches = /-([^-]+)$/.match(d)
105
Gem::Version.new(matches[1]) if matches
108
def load_specification(gem_dir)
109
spec_file = File.join(gem_dir, '.specification')
110
YAML.load_file(spec_file) if File.exist?(spec_file)
114
@installed_source_index.find_name(*args) + @vendor_source_index.find_name(*args)
118
# look for vendor gems, and then installed gems - later elements take priority
119
@installed_source_index.search(*args) + @vendor_source_index.search(*args)
123
@vendor_source_index.each(&block)
124
@installed_source_index.each(&block)
128
@vendor_source_index.add_spec spec
131
def remove_spec(spec)
132
@vendor_source_index.remove_spec spec
136
@vendor_source_index.size + @installed_source_index.size