Class: LibGems::SpecFetcher
- Inherits:
-
Object
- Object
- LibGems::SpecFetcher
- Includes:
- Text, UserInteraction
- Defined in:
- lib/libgems/spec_fetcher.rb
Overview
SpecFetcher handles metadata updates from remote gem repositories.
Constant Summary collapse
- FILES =
{ :all => 'specs', :latest => 'latest_specs', :prerelease => 'prerelease_specs', }
Instance Attribute Summary collapse
-
#dir ⇒ Object
readonly
The SpecFetcher cache dir.
-
#latest_specs ⇒ Object
readonly
Cache of latest specs.
-
#prerelease_specs ⇒ Object
readonly
Cache of prerelease specs.
-
#specs ⇒ Object
readonly
Cache of all released specs.
Class Method Summary collapse
Instance Method Summary collapse
-
#cache_dir(uri) ⇒ Object
Returns the local directory to write
uri
to. - #fetch(*args) ⇒ Object
- #fetch_spec(spec, source_uri) ⇒ Object
-
#fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false) ⇒ Object
Fetch specs matching
dependency
. - #find_matching(*args) ⇒ Object
-
#find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false) ⇒ Object
Find spec names that match
dependency
. -
#initialize ⇒ SpecFetcher
constructor
A new instance of SpecFetcher.
-
#legacy_repos ⇒ Object
Returns Array of gem repositories that were generated with SlimGems less than 1.2.
-
#list(all = false, prerelease = false) ⇒ Object
Returns a list of gems available for each source in LibGems::sources.
-
#load_specs(source_uri, file) ⇒ Object
Loads specs in
file
, fetching fromsource_uri
if the on-disk cache is out of date. -
#suggest_gems_from_name(gem_name) ⇒ Object
Suggests a gem based on the supplied
gem_name
. -
#warn_legacy(exception) ⇒ Object
Warn about legacy repositories if
exception
indicates only legacy repositories are available, and yield to the block.
Methods included from Text
#format_text, #levenshtein_distance
Methods included from UserInteraction
Methods included from DefaultUserInteraction
ui, #ui, ui=, #ui=, use_ui, #use_ui
Constructor Details
#initialize ⇒ SpecFetcher
Returns a new instance of SpecFetcher.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/libgems/spec_fetcher.rb', line 53 def initialize @dir = File.join LibGems.user_home, '.gem', 'specs' @update_cache = File.stat(LibGems.user_home).uid == Process.uid @specs = {} @latest_specs = {} @prerelease_specs = {} @caches = { :latest => @latest_specs, :prerelease => @prerelease_specs, :all => @specs } @fetcher = LibGems::RemoteFetcher.fetcher end |
Instance Attribute Details
#dir ⇒ Object (readonly)
The SpecFetcher cache dir.
26 27 28 |
# File 'lib/libgems/spec_fetcher.rb', line 26 def dir @dir end |
#latest_specs ⇒ Object (readonly)
Cache of latest specs
31 32 33 |
# File 'lib/libgems/spec_fetcher.rb', line 31 def latest_specs @latest_specs end |
#prerelease_specs ⇒ Object (readonly)
Cache of prerelease specs
41 42 43 |
# File 'lib/libgems/spec_fetcher.rb', line 41 def prerelease_specs @prerelease_specs end |
#specs ⇒ Object (readonly)
Cache of all released specs
36 37 38 |
# File 'lib/libgems/spec_fetcher.rb', line 36 def specs @specs end |
Class Method Details
.fetcher ⇒ Object
45 46 47 |
# File 'lib/libgems/spec_fetcher.rb', line 45 def self.fetcher @fetcher ||= new end |
.fetcher=(fetcher) ⇒ Object
:nodoc:
49 50 51 |
# File 'lib/libgems/spec_fetcher.rb', line 49 def self.fetcher=(fetcher) # :nodoc: @fetcher = fetcher end |
Instance Method Details
#cache_dir(uri) ⇒ Object
Returns the local directory to write uri
to.
73 74 75 |
# File 'lib/libgems/spec_fetcher.rb', line 73 def cache_dir(uri) File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path) end |
#fetch(*args) ⇒ Object
101 102 103 |
# File 'lib/libgems/spec_fetcher.rb', line 101 def fetch(*args) fetch_with_errors(*args).first end |
#fetch_spec(spec, source_uri) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/libgems/spec_fetcher.rb', line 105 def fetch_spec(spec, source_uri) spec = spec - [nil, 'ruby', ''] spec_file_name = "#{spec.join '-'}.gemspec" uri = source_uri + "#{LibGems::MARSHAL_SPEC_DIR}#{spec_file_name}" cache_dir = cache_dir uri local_spec = File.join cache_dir, spec_file_name if File.exist? local_spec then spec = LibGems.read_binary local_spec else uri.path << '.rz' spec = @fetcher.fetch_path uri spec = LibGems.inflate spec if @update_cache then FileUtils.mkdir_p cache_dir open local_spec, 'wb' do |io| io.write spec end end end # TODO: Investigate setting LibGems::Specification#loaded_from to a URI Marshal.load spec end |
#fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false) ⇒ Object
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.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/libgems/spec_fetcher.rb', line 83 def fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false) specs_and_sources, errors = find_matching_with_errors dependency, all, matching_platform, prerelease ss = specs_and_sources.map do |spec_tuple, source_uri| [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri] end return [ss, errors] rescue LibGems::RemoteFetcher::FetchError => e raise unless warn_legacy e do require 'libgems/source_info_cache' return [LibGems::SourceInfoCache.search_with_source(dependency, matching_platform, all), nil] end end |
#find_matching(*args) ⇒ Object
172 173 174 |
# File 'lib/libgems/spec_fetcher.rb', line 172 def find_matching(*args) find_matching_with_errors(*args).first end |
#find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false) ⇒ Object
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.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/libgems/spec_fetcher.rb', line 141 def find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false) found = {} rejected_specs = {} list(all, prerelease).each do |source_uri, specs| found[source_uri] = specs.select do |spec_name, version, spec_platform| if dependency.match?(spec_name, version) if matching_platform and !LibGems::Platform.match(spec_platform) pm = (rejected_specs[dependency] ||= LibGems::PlatformMismatch.new(spec_name, version)) pm.add_platform spec_platform false else true end end end end errors = rejected_specs.values specs_and_sources = [] found.each do |source_uri, specs| uri_str = source_uri.to_s specs_and_sources.push(*specs.map { |spec| [spec, uri_str] }) end [specs_and_sources, errors] end |
#legacy_repos ⇒ Object
Returns Array of gem repositories that were generated with SlimGems less than 1.2.
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/libgems/spec_fetcher.rb', line 180 def legacy_repos LibGems.sources.reject do |source_uri| source_uri = URI.parse source_uri spec_path = source_uri + "specs.#{LibGems.marshal_version}.gz" begin @fetcher.fetch_size spec_path rescue LibGems::RemoteFetcher::FetchError begin @fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo rescue LibGems::RemoteFetcher::FetchError alert_error "#{source_uri} does not appear to be a repository" raise end false end end end |
#list(all = false, prerelease = false) ⇒ Object
Returns a list of gems available for each source in LibGems::sources. If all
is true, all released versions are returned instead of only latest versions. If prerelease
is true, include prerelease versions.
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/libgems/spec_fetcher.rb', line 233 def list(all = false, prerelease = false) # TODO: make type the only argument type = if all :all elsif prerelease :prerelease else :latest end list = {} file = FILES[type] cache = @caches[type] LibGems.sources.each do |source_uri| source_uri = URI.parse source_uri unless cache.include? source_uri cache[source_uri] = load_specs source_uri, file end list[source_uri] = cache[source_uri] end if type == :all list.values.map do |gems| gems.reject! { |g| !g[1] || g[1].prerelease? } end end list end |
#load_specs(source_uri, file) ⇒ Object
Loads specs in file
, fetching from source_uri
if the on-disk cache is out of date.
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/libgems/spec_fetcher.rb', line 270 def load_specs(source_uri, file) file_name = "#{file}.#{LibGems.marshal_version}" spec_path = source_uri + "#{file_name}.gz" cache_dir = cache_dir spec_path local_file = File.join(cache_dir, file_name) loaded = false if File.exist? local_file then spec_dump = @fetcher.fetch_path spec_path, File.mtime(local_file) if spec_dump.nil? then spec_dump = LibGems.read_binary local_file else loaded = true end else spec_dump = @fetcher.fetch_path spec_path loaded = true end specs = LibGems.with_rubygems_compat do begin Marshal.load spec_dump rescue ArgumentError spec_dump = @fetcher.fetch_path spec_path loaded = true Marshal.load spec_dump end end if loaded and @update_cache then begin FileUtils.mkdir_p cache_dir open local_file, 'wb' do |io| io << spec_dump end rescue end end specs end |
#suggest_gems_from_name(gem_name) ⇒ Object
Suggests a gem based on the supplied gem_name
. Returns a string of the gem name if an approximate match can be found or nil otherwise. NOTE: for performance reasons only gems which exactly match the first character of gem_name
are considered.
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/libgems/spec_fetcher.rb', line 205 def suggest_gems_from_name gem_name gem_name = gem_name.downcase gem_starts_with = gem_name[0,1] max = gem_name.size / 2 specs = list.values.flatten(1) # flatten(1) is 1.8.7 and up matches = specs.map { |name, version, platform| next unless LibGems::Platform.match platform distance = levenshtein_distance gem_name, name.downcase next if distance >= max return [name] if distance == 0 [name, distance] }.compact matches = matches.uniq.sort_by { |name, dist| dist } matches.first(5).map { |name, dist| name } end |
#warn_legacy(exception) ⇒ Object
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.
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/libgems/spec_fetcher.rb', line 320 def warn_legacy(exception) uri = exception.uri.to_s if uri =~ /specs\.#{Regexp.escape LibGems.marshal_version}\.gz$/ then alert_warning <<-EOF #{LibGems::NAME} 1.2+ index not found for: \t#{legacy_repos.join "\n\t"} #{LibGems::NAME} will revert to legacy indexes degrading performance. EOF yield return true end false end |