| Class | Gem::SpecFetcher |
| In: |
lib/rubygems/spec_fetcher.rb
|
| Parent: | Object |
SpecFetcher handles metadata updates from remote gem repositories.
# File lib/rubygems/spec_fetcher.rb, line 39
39: def initialize
40: @dir = File.join Gem.user_home, '.gem', 'specs'
41: @update_cache = File.stat(Gem.user_home).uid == Process.uid
42:
43: @specs = {}
44: @latest_specs = {}
45:
46: @fetcher = Gem::RemoteFetcher.fetcher
47: end
Retuns the local directory to write uri to.
# File lib/rubygems/spec_fetcher.rb, line 52
52: def cache_dir(uri)
53: File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path)
54: end
Fetch specs matching dependency. If all is true, all matching versions are returned. If matching_platform is false, all platforms are returned.
# File lib/rubygems/spec_fetcher.rb, line 61
61: def fetch(dependency, all = false, matching_platform = true)
62: specs_and_sources = find_matching dependency, all, matching_platform
63:
64: specs_and_sources.map do |spec_tuple, source_uri|
65: [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
66: end
67:
68: rescue Gem::RemoteFetcher::FetchError => e
69: raise unless warn_legacy e do
70: require 'rubygems/source_info_cache'
71:
72: return Gem::SourceInfoCache.search_with_source(dependency,
73: matching_platform, all)
74: end
75: end
# File lib/rubygems/spec_fetcher.rb, line 77
77: def fetch_spec(spec, source_uri)
78: spec = spec - [nil, 'ruby', '']
79: spec_file_name = "#{spec.join '-'}.gemspec"
80:
81: uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}"
82:
83: cache_dir = cache_dir uri
84:
85: local_spec = File.join cache_dir, spec_file_name
86:
87: if File.exist? local_spec then
88: spec = Gem.read_binary local_spec
89: else
90: uri.path << '.rz'
91:
92: spec = @fetcher.fetch_path uri
93: spec = Gem.inflate spec
94:
95: if @update_cache then
96: FileUtils.mkdir_p cache_dir
97:
98: open local_spec, 'wb' do |io|
99: io.write spec
100: end
101: end
102: end
103:
104: # TODO: Investigate setting Gem::Specification#loaded_from to a URI
105: Marshal.load spec
106: end
Find spec names that match dependency. If all is true, all matching versions are returned. If matching_platform is false, gems for all platforms are returned.
# File lib/rubygems/spec_fetcher.rb, line 113
113: def find_matching(dependency, all = false, matching_platform = true)
114: found = {}
115:
116: list(all).each do |source_uri, specs|
117: found[source_uri] = specs.select do |spec_name, version, spec_platform|
118: dependency =~ Gem::Dependency.new(spec_name, version) and
119: (not matching_platform or Gem::Platform.match(spec_platform))
120: end
121: end
122:
123: specs_and_sources = []
124:
125: found.each do |source_uri, specs|
126: uri_str = source_uri.to_s
127: specs_and_sources.push(*specs.map { |spec| [spec, uri_str] })
128: end
129:
130: specs_and_sources
131: end
Returns Array of gem repositories that were generated with RubyGems less than 1.2.
# File lib/rubygems/spec_fetcher.rb, line 137
137: def legacy_repos
138: Gem.sources.reject do |source_uri|
139: source_uri = URI.parse source_uri
140: spec_path = source_uri + "specs.#{Gem.marshal_version}.gz"
141:
142: begin
143: @fetcher.fetch_size spec_path
144: rescue Gem::RemoteFetcher::FetchError
145: begin
146: @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo
147: rescue Gem::RemoteFetcher::FetchError
148: alert_error "#{source_uri} does not appear to be a repository"
149: raise
150: end
151: false
152: end
153: end
154: end
Returns a list of gems available for each source in Gem::sources. If all is true, all versions are returned instead of only latest versions.
# File lib/rubygems/spec_fetcher.rb, line 160
160: def list(all = false)
161: list = {}
162:
163: file = all ? 'specs' : 'latest_specs'
164:
165: Gem.sources.each do |source_uri|
166: source_uri = URI.parse source_uri
167:
168: if all and @specs.include? source_uri then
169: list[source_uri] = @specs[source_uri]
170: elsif @latest_specs.include? source_uri then
171: list[source_uri] = @latest_specs[source_uri]
172: else
173: specs = load_specs source_uri, file
174:
175: cache = all ? @specs : @latest_specs
176:
177: cache[source_uri] = specs
178: list[source_uri] = specs
179: end
180: end
181:
182: list
183: end
# File lib/rubygems/spec_fetcher.rb, line 185
185: def load_specs(source_uri, file)
186: file_name = "#{file}.#{Gem.marshal_version}.gz"
187:
188: spec_path = source_uri + file_name
189:
190: cache_dir = cache_dir spec_path
191:
192: local_file = File.join(cache_dir, file_name).chomp '.gz'
193:
194: if File.exist? local_file then
195: local_size = File.stat(local_file).size
196:
197: remote_file = spec_path.dup
198: remote_file.path = remote_file.path.chomp '.gz'
199: remote_size = @fetcher.fetch_size remote_file
200:
201: spec_dump = Gem.read_binary local_file if remote_size == local_size
202: end
203:
204: unless spec_dump then
205: loaded = true
206:
207: spec_dump_gz = @fetcher.fetch_path spec_path
208: spec_dump = Gem.gunzip spec_dump_gz
209: end
210:
211: specs = Marshal.load spec_dump
212:
213: if loaded and @update_cache then
214: begin
215: FileUtils.mkdir_p cache_dir
216:
217: open local_file, 'wb' do |io|
218: Marshal.dump specs, io
219: end
220: rescue
221: end
222: end
223:
224: specs
225: end
Warn about legacy repositories if exception indicates only legacy repositories are available, and yield to the block. Returns false if the exception indicates some other FetchError.
# File lib/rubygems/spec_fetcher.rb, line 232
232: def warn_legacy(exception)
233: uri = exception.uri.to_s
234: if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then
235: alert_warning "RubyGems 1.2+ index not found for:\n\\t\#{legacy_repos.join \"\\n\\t\"}\n\nRubyGems will revert to legacy indexes degrading performance.\n"
236:
237: yield
238:
239: return true
240: end
241:
242: false
243: end