Class Gem::SpecFetcher
In: lib/rubygems/spec_fetcher.rb
Parent: Object

SpecFetcher handles metadata updates from remote gem repositories.

Methods

Included Modules

Gem::UserInteraction

Public Class methods

[Source]

    # File lib/rubygems/spec_fetcher.rb, line 37
37:   def self.fetcher
38:     @fetcher ||= new
39:   end

[Source]

    # 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

Public Instance methods

Returns the local directory to write uri to.

[Source]

    # 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

[Source]

    # File lib/rubygems/spec_fetcher.rb, line 87
87:   def fetch(*args)
88:     fetch_with_errors(*args).first
89:   end

[Source]

     # 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.

[Source]

    # 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

[Source]

     # 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.

[Source]

     # 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.

[Source]

     # 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.

[Source]

     # 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.

[Source]

     # 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.

[Source]

     # 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

[Validate]