Class: Gem::Source
- Inherits:
-
Object
- Object
- Gem::Source
- Includes:
- Comparable, Text
- Defined in:
- lib/rubygems/source.rb
Overview
A Source knows how to list and fetch gems from a RubyGems marshal index.
There are other Source subclasses for installed gems, local gems, the Compact Index API and so-forth.
Direct Known Subclasses
Defined Under Namespace
Classes: Git, Installed, Local, Lock, SpecificFile, Vendor
Constant Summary collapse
- FILES =
:nodoc:
{ # :nodoc: released: "specs", latest: "latest_specs", prerelease: "prerelease_specs", }.freeze
Instance Attribute Summary collapse
-
#uri ⇒ Object
readonly
The URI this source will fetch gems from.
Instance Method Summary collapse
-
#<=>(other) ⇒ Object
Sources are ordered by installation preference.
-
#==(other) ⇒ Object
(also: #eql?)
:nodoc:.
-
#cache_dir(uri) ⇒ Object
Returns the local directory to write
urito. -
#dependency_resolver_set(prerelease = false) ⇒ Object
Returns a Set that can fetch specifications from this source.
-
#download(spec, dir = Dir.pwd) ⇒ Object
Downloads
specand writes it todir. -
#fetch_spec(name_tuple) ⇒ Object
Fetches a specification for the given Gem::NameTuple.
-
#hash ⇒ Object
:nodoc:.
-
#initialize(uri) ⇒ Source
constructor
Creates a new Source which will use the index located at
uri. -
#load_specs(type) ⇒ Object
Loads
typekind of specs fetching from@uriif the on-disk cache is out of date. -
#pretty_print(q) ⇒ Object
:nodoc:.
- #typo_squatting?(host, distance_threshold = 4) ⇒ Boolean
-
#update_cache? ⇒ Boolean
Returns true when it is possible and safe to update the cache directory.
Methods included from Text
#clean_text, #format_text, #levenshtein_distance, #min3, #truncate_text
Constructor Details
Instance Attribute Details
#uri ⇒ Object (readonly)
The URI this source will fetch gems from.
23 24 25 |
# File 'lib/rubygems/source.rb', line 23 def uri @uri end |
Instance Method Details
#<=>(other) ⇒ Object
Sources are ordered by installation preference.
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/rubygems/source.rb', line 37 def <=>(other) case other when Gem::Source::Installed, Gem::Source::Local, Gem::Source::Lock, Gem::Source::SpecificFile, Gem::Source::Git, Gem::Source::Vendor then -1 when Gem::Source then unless @uri return 0 unless other.uri return 1 end return -1 unless other.uri # Returning 1 here ensures that when sorting a list of sources, the # original ordering of sources supplied by the user is preserved. return 1 unless @uri.to_s == other.uri.to_s 0 end end |
#==(other) ⇒ Object Also known as: eql?
:nodoc:
62 63 64 |
# File 'lib/rubygems/source.rb', line 62 def ==(other) # :nodoc: self.class === other && @uri == other.uri end |
#cache_dir(uri) ⇒ Object
Returns the local directory to write uri to.
84 85 86 87 88 89 |
# File 'lib/rubygems/source.rb', line 84 def cache_dir(uri) # Correct for windows paths escaped_path = uri.path.sub(%r{^/([a-z]):/}i, '/\\1-/') File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path) end |
#dependency_resolver_set(prerelease = false) ⇒ Object
Returns a Set that can fetch specifications from this source.
The set will optionally fetch prereleases if requested.
73 74 75 |
# File 'lib/rubygems/source.rb', line 73 def dependency_resolver_set(prerelease = false) new_dependency_resolver_set.tap {|set| set.prerelease = prerelease } end |
#download(spec, dir = Dir.pwd) ⇒ Object
Downloads spec and writes it to dir. See also
Gem::RemoteFetcher#download.
200 201 202 203 |
# File 'lib/rubygems/source.rb', line 200 def download(spec, dir = Dir.pwd) fetcher = Gem::RemoteFetcher.fetcher fetcher.download spec, uri.to_s, dir end |
#fetch_spec(name_tuple) ⇒ Object
Fetches a specification for the given Gem::NameTuple.
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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/rubygems/source.rb', line 107 def fetch_spec(name_tuple) fetcher = Gem::RemoteFetcher.fetcher spec_file_name = name_tuple.spec_name # The name tuple comes from a remote index and is not otherwise # validated, so refuse anything that would escape the spec cache # directory when used as a path component. if File.basename(spec_file_name) != spec_file_name raise Gem::Exception, "malformed spec name: #{spec_file_name.inspect}" end source_uri = enforce_trailing_slash(uri) + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}" cache_dir = cache_dir source_uri local_spec = File.join cache_dir, spec_file_name if File.exist? local_spec spec = Gem.read_binary local_spec Gem.load_safe_marshal spec = begin Gem::SafeMarshal.safe_load(spec) rescue StandardError nil end return spec if spec end source_uri.path << ".rz" spec = fetcher.fetch_path source_uri spec = Gem::Util.inflate spec if update_cache? require "fileutils" FileUtils.mkdir_p cache_dir File.open local_spec, "wb" do |io| io.write spec end end Gem.load_safe_marshal # TODO: Investigate setting Gem::Specification#loaded_from to a URI Gem::SafeMarshal.safe_load spec end |
#hash ⇒ Object
:nodoc:
77 78 79 |
# File 'lib/rubygems/source.rb', line 77 def hash # :nodoc: @uri.hash end |
#load_specs(type) ⇒ Object
Loads type kind of specs fetching from @uri if the on-disk cache is
out of date.
type is one of the following:
:released => Return the list of all released specs :latest => Return the list of only the highest version of each gem :prerelease => Return the list of all prerelease only specs
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/rubygems/source.rb', line 166 def load_specs(type) file = FILES[type] fetcher = Gem::RemoteFetcher.fetcher file_name = "#{file}.#{Gem.marshal_version}" spec_path = enforce_trailing_slash(uri) + "#{file_name}.gz" cache_dir = cache_dir spec_path local_file = File.join(cache_dir, file_name) retried = false if update_cache? require "fileutils" FileUtils.mkdir_p cache_dir end spec_dump = fetcher.cache_update_path spec_path, local_file, update_cache? Gem.load_safe_marshal begin Gem::NameTuple.from_list Gem::SafeMarshal.safe_load(spec_dump) rescue ArgumentError if update_cache? && !retried FileUtils.rm local_file retried = true retry else raise Gem::Exception.new("Invalid spec cache file in #{local_file}") end end end |
#pretty_print(q) ⇒ Object
:nodoc:
205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/rubygems/source.rb', line 205 def pretty_print(q) # :nodoc: q.object_group(self) do q.group 2, "[Remote:", "]" do q.breakable q.text @uri.to_s if api = uri q.breakable q.text "API URI: " q.text api.to_s end end end end |
#typo_squatting?(host, distance_threshold = 4) ⇒ Boolean
220 221 222 223 |
# File 'lib/rubygems/source.rb', line 220 def typo_squatting?(host, distance_threshold = 4) return if @uri.host.nil? levenshtein_distance(@uri.host, host).between? 1, distance_threshold end |
#update_cache? ⇒ Boolean
Returns true when it is possible and safe to update the cache directory.
94 95 96 97 98 99 100 101 102 |
# File 'lib/rubygems/source.rb', line 94 def update_cache? return @update_cache unless @update_cache.nil? @update_cache = begin File.stat(Gem.user_home).uid == Process.uid rescue Errno::ENOENT false end end |