| 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 45
45: def initialize
46: @dir = File.join Gem.user_home, '.gem', 'specs'
47: @update_cache = File.stat(Gem.user_home).uid == Process.uid
48:
49: @specs = {}
50: @latest_specs = {}
51: @prerelease_specs = {}
52:
53: @fetcher = Gem::RemoteFetcher.fetcher
54: end
Returns the local directory to write uri to.
# File lib/rubygems/spec_fetcher.rb, line 59
59: def cache_dir(uri)
60: File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path)
61: end
# File lib/rubygems/spec_fetcher.rb, line 87
87: def fetch(*args)
88: fetch_with_errors(*args).first
89: end
# File lib/rubygems/spec_fetcher.rb, line 91
91: def fetch_spec(spec, source_uri)
92: spec = spec - [nil, 'ruby', '']
93: spec_file_name = "#{spec.join '-'}.gemspec"
94:
95: uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}"
96:
97: cache_dir = cache_dir uri
98:
99: local_spec = File.join cache_dir, spec_file_name
100:
101: if File.exist? local_spec then
102: spec = Gem.read_binary local_spec
103: else
104: uri.path << '.rz'
105:
106: spec = @fetcher.fetch_path uri
107: spec = Gem.inflate spec
108:
109: if @update_cache then
110: FileUtils.mkdir_p cache_dir
111:
112: open local_spec, 'wb' do |io|
113: io.write spec
114: end
115: end
116: end
117:
118: # TODO: Investigate setting Gem::Specification#loaded_from to a URI
119: Marshal.load spec
120: end
Fetch specs matching dependency. If all is true, all matching (released) versions are returned. If matching_platform is false, all platforms are returned. If prerelease is true, prerelease versions are included.
# File lib/rubygems/spec_fetcher.rb, line 69
69: def fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false)
70: specs_and_sources, errors = find_matching_with_errors dependency, all, matching_platform, prerelease
71:
72: ss = specs_and_sources.map do |spec_tuple, source_uri|
73: [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
74: end
75:
76: return [ss, errors]
77:
78: rescue Gem::RemoteFetcher::FetchError => e
79: raise unless warn_legacy e do
80: require 'rubygems/source_info_cache'
81:
82: return [Gem::SourceInfoCache.search_with_source(dependency,
83: matching_platform, all), nil]
84: end
85: end
# File lib/rubygems/spec_fetcher.rb, line 158
158: def find_matching(*args)
159: find_matching_with_errors(*args).first
160: end
Find spec names that match dependency. If all is true, all matching released versions are returned. If matching_platform is false, gems for all platforms are returned.
# File lib/rubygems/spec_fetcher.rb, line 127
127: def find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false)
128: found = {}
129:
130: rejected_specs = {}
131:
132: list(all, prerelease).each do |source_uri, specs|
133: found[source_uri] = specs.select do |spec_name, version, spec_platform|
134: if dependency.match?(spec_name, version)
135: if matching_platform and !Gem::Platform.match(spec_platform)
136: pm = (rejected_specs[dependency] ||= Gem::PlatformMismatch.new(spec_name, version))
137: pm.add_platform spec_platform
138: false
139: else
140: true
141: end
142: end
143: end
144: end
145:
146: errors = rejected_specs.values
147:
148: specs_and_sources = []
149:
150: found.each do |source_uri, specs|
151: uri_str = source_uri.to_s
152: specs_and_sources.push(*specs.map { |spec| [spec, uri_str] })
153: end
154:
155: [specs_and_sources, errors]
156: end
Returns Array of gem repositories that were generated with RubyGems less than 1.2.
# File lib/rubygems/spec_fetcher.rb, line 166
166: def legacy_repos
167: Gem.sources.reject do |source_uri|
168: source_uri = URI.parse source_uri
169: spec_path = source_uri + "specs.#{Gem.marshal_version}.gz"
170:
171: begin
172: @fetcher.fetch_size spec_path
173: rescue Gem::RemoteFetcher::FetchError
174: begin
175: @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo
176: rescue Gem::RemoteFetcher::FetchError
177: alert_error "#{source_uri} does not appear to be a repository"
178: raise
179: end
180: false
181: end
182: end
183: end
Returns a list of gems available for each source in Gem::sources. If all is true, all released versions are returned instead of only latest versions. If prerelease is true, include prerelease versions.
# File lib/rubygems/spec_fetcher.rb, line 190
190: def list(all = false, prerelease = false)
191: # TODO: make type the only argument
192: type = if all
193: :all
194: elsif prerelease
195: :prerelease
196: else
197: :latest
198: end
199:
200: list = {}
201:
202: file = { :latest => 'latest_specs',
203: :prerelease => 'prerelease_specs',
204: :all => 'specs' }[type]
205:
206: cache = { :latest => @latest_specs,
207: :prerelease => @prerelease_specs,
208: :all => @specs }[type]
209:
210: Gem.sources.each do |source_uri|
211: source_uri = URI.parse source_uri
212:
213: unless cache.include? source_uri
214: cache[source_uri] = load_specs source_uri, file
215: end
216:
217: list[source_uri] = cache[source_uri]
218: end
219:
220: if type == :all
221: list.values.map do |gems|
222: gems.reject! { |g| !g[1] || g[1].prerelease? }
223: end
224: end
225:
226: list
227: end
Loads specs in file, fetching from source_uri if the on-disk cache is out of date.
# File lib/rubygems/spec_fetcher.rb, line 233
233: def load_specs(source_uri, file)
234: file_name = "#{file}.#{Gem.marshal_version}"
235: spec_path = source_uri + "#{file_name}.gz"
236: cache_dir = cache_dir spec_path
237: local_file = File.join(cache_dir, file_name)
238: loaded = false
239:
240: if File.exist? local_file then
241: spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file)
242:
243: if spec_dump.nil? then
244: spec_dump = Gem.read_binary local_file
245: else
246: loaded = true
247: end
248: else
249: spec_dump = @fetcher.fetch_path spec_path
250: loaded = true
251: end
252:
253: specs = begin
254: Marshal.load spec_dump
255: rescue ArgumentError
256: spec_dump = @fetcher.fetch_path spec_path
257: loaded = true
258:
259: Marshal.load spec_dump
260: end
261:
262: if loaded and @update_cache then
263: begin
264: FileUtils.mkdir_p cache_dir
265:
266: open local_file, 'wb' do |io|
267: io << spec_dump
268: end
269: rescue
270: end
271: end
272:
273: specs
274: 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 281
281: def warn_legacy(exception)
282: uri = exception.uri.to_s
283: if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then
284: 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"
285:
286: yield
287:
288: return true
289: end
290:
291: false
292: end