| 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 44
44: def initialize
45: @dir = File.join Gem.user_home, '.gem', 'specs'
46: @update_cache = File.stat(Gem.user_home).uid == Process.uid
47:
48: @specs = {}
49: @latest_specs = {}
50: @prerelease_specs = {}
51:
52: @fetcher = Gem::RemoteFetcher.fetcher
53: end
Retuns the local directory to write uri to.
# File lib/rubygems/spec_fetcher.rb, line 58
58: def cache_dir(uri)
59: File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path)
60: 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 68
68: def fetch(dependency, all = false, matching_platform = true, prerelease = false)
69: specs_and_sources = find_matching dependency, all, matching_platform, prerelease
70:
71: specs_and_sources.map do |spec_tuple, source_uri|
72: [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
73: end
74:
75: rescue Gem::RemoteFetcher::FetchError => e
76: raise unless warn_legacy e do
77: require 'rubygems/source_info_cache'
78:
79: return Gem::SourceInfoCache.search_with_source(dependency,
80: matching_platform, all)
81: end
82: end
# File lib/rubygems/spec_fetcher.rb, line 84
84: def fetch_spec(spec, source_uri)
85: spec = spec - [nil, 'ruby', '']
86: spec_file_name = "#{spec.join '-'}.gemspec"
87:
88: uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}"
89:
90: cache_dir = cache_dir uri
91:
92: local_spec = File.join cache_dir, spec_file_name
93:
94: if File.exist? local_spec then
95: spec = Gem.read_binary local_spec
96: else
97: uri.path << '.rz'
98:
99: spec = @fetcher.fetch_path uri
100: spec = Gem.inflate spec
101:
102: if @update_cache then
103: FileUtils.mkdir_p cache_dir
104:
105: open local_spec, 'wb' do |io|
106: io.write spec
107: end
108: end
109: end
110:
111: # TODO: Investigate setting Gem::Specification#loaded_from to a URI
112: Marshal.load spec
113: 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 120
120: def find_matching(dependency, all = false, matching_platform = true, prerelease = false)
121: found = {}
122:
123: list(all, prerelease).each do |source_uri, specs|
124: found[source_uri] = specs.select do |spec_name, version, spec_platform|
125: dependency =~ Gem::Dependency.new(spec_name, version) and
126: (not matching_platform or Gem::Platform.match(spec_platform))
127: end
128: end
129:
130: specs_and_sources = []
131:
132: found.each do |source_uri, specs|
133: uri_str = source_uri.to_s
134: specs_and_sources.push(*specs.map { |spec| [spec, uri_str] })
135: end
136:
137: specs_and_sources
138: end
Returns Array of gem repositories that were generated with RubyGems less than 1.2.
# File lib/rubygems/spec_fetcher.rb, line 144
144: def legacy_repos
145: Gem.sources.reject do |source_uri|
146: source_uri = URI.parse source_uri
147: spec_path = source_uri + "specs.#{Gem.marshal_version}.gz"
148:
149: begin
150: @fetcher.fetch_size spec_path
151: rescue Gem::RemoteFetcher::FetchError
152: begin
153: @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo
154: rescue Gem::RemoteFetcher::FetchError
155: alert_error "#{source_uri} does not appear to be a repository"
156: raise
157: end
158: false
159: end
160: end
161: 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 168
168: def list(all = false, prerelease = false)
169: # TODO: make type the only argument
170: type = if all
171: :all
172: elsif prerelease
173: :prerelease
174: else
175: :latest
176: end
177:
178: list = {}
179:
180: file = { :latest => 'latest_specs',
181: :prerelease => 'prerelease_specs',
182: :all => 'specs' }[type]
183:
184: cache = { :latest => @latest_specs,
185: :prerelease => @prerelease_specs,
186: :all => @specs }[type]
187:
188: Gem.sources.each do |source_uri|
189: source_uri = URI.parse source_uri
190:
191: unless cache.include? source_uri
192: cache[source_uri] = load_specs source_uri, file
193: end
194:
195: list[source_uri] = cache[source_uri]
196: end
197:
198: if type == :all
199: list.values.map do |gems|
200: gems.reject! { |g| g[1].prerelease? }
201: end
202: end
203:
204: list
205: 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 211
211: def load_specs(source_uri, file)
212: file_name = "#{file}.#{Gem.marshal_version}"
213: spec_path = source_uri + "#{file_name}.gz"
214: cache_dir = cache_dir spec_path
215: local_file = File.join(cache_dir, file_name)
216: loaded = false
217:
218: if File.exist? local_file then
219: spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file)
220:
221: if spec_dump.nil? then
222: spec_dump = Gem.read_binary local_file
223: else
224: loaded = true
225: end
226: else
227: spec_dump = @fetcher.fetch_path spec_path
228: loaded = true
229: end
230:
231: specs = begin
232: Marshal.load spec_dump
233: rescue ArgumentError
234: spec_dump = @fetcher.fetch_path spec_path
235: loaded = true
236:
237: Marshal.load spec_dump
238: end
239:
240: if loaded and @update_cache then
241: begin
242: FileUtils.mkdir_p cache_dir
243:
244: open local_file, 'wb' do |io|
245: Marshal.dump specs, io
246: end
247: rescue
248: end
249: end
250:
251: specs
252: 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 259
259: def warn_legacy(exception)
260: uri = exception.uri.to_s
261: if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then
262: 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"
263:
264: yield
265:
266: return true
267: end
268:
269: false
270: end