OSDN Git Service

5b7721f303f8440db9c8dfdbf69c3f4f0368b021
[redminele/redminele.git] / ruby / lib / ruby / gems / 1.8 / gems / rails-2.3.5 / 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