Froze rails gems
[depot.git] / vendor / rails / railties / lib / rails / vendor_gem_source_index.rb
1 require 'rubygems'
2 require 'yaml'
3
4 module Rails
5
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
10 # each gem directory.
11 include Enumerable
12
13 attr_reader :installed_source_index
14 attr_reader :vendor_source_index
15
16 @@silence_spec_warnings = false
17
18 def self.silence_spec_warnings
19 @@silence_spec_warnings
20 end
21
22 def self.silence_spec_warnings=(v)
23 @@silence_spec_warnings = v
24 end
25
26 def initialize(installed_index, vendor_dir=Rails::GemDependency.unpacked_path)
27 @installed_source_index = installed_index
28 @vendor_dir = vendor_dir
29 refresh!
30 end
31
32 def refresh!
33 # reload the installed gems
34 @installed_source_index.refresh!
35 vendor_gems = {}
36
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
42 end
43
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)
49 if spec
50 if spec.full_name != dir_name
51 # mismatched directory name and gem spec - produced by 2.1.0-era unpack code
52 if dir_version
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
59 else
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
63 end
64 end
65 else
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
70 if dir_version
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]
77 files = ['lib']
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
81 spec.files = files
82 else
83 $stderr.puts("config.gem: Unpacked gem #{dir_name} in vendor/gems not in a versioned directory."+
84 " Giving up.") unless @@silence_spec_warnings
85 next
86 end
87 end
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
91 class << spec
92 def full_gem_path
93 path = File.join installation_path, full_name
94 return path if File.directory? path
95 File.join installation_path, original_name
96 end
97 end
98 vendor_gems[File.basename(d)] = spec
99 end
100 @vendor_source_index = Gem::SourceIndex.new(vendor_gems)
101 end
102
103 def version_for_dir(d)
104 matches = /-([^-]+)$/.match(d)
105 Gem::Version.new(matches[1]) if matches
106 end
107
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)
111 end
112
113 def find_name(*args)
114 @installed_source_index.find_name(*args) + @vendor_source_index.find_name(*args)
115 end
116
117 def search(*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)
120 end
121
122 def each(&block)
123 @vendor_source_index.each(&block)
124 @installed_source_index.each(&block)
125 end
126
127 def add_spec(spec)
128 @vendor_source_index.add_spec spec
129 end
130
131 def remove_spec(spec)
132 @vendor_source_index.remove_spec spec
133 end
134
135 def size
136 @vendor_source_index.size + @installed_source_index.size
137 end
138
139 end
140 end