mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
a7fa4d5d9a
Compatibly renamed Gem::DependencyResolver to Gem::Resolver. Added support for git gems in gem.deps.rb and Gemfile. Fixed resolver bugs. * test/rubygems: ditto. * lib/rubygems/LICENSE.txt: Updated to license from RubyGems trunk. [ruby-trunk - Bug #9086] * lib/rubygems/commands/which_command.rb: RubyGems now indicates failure when any file is missing. [ruby-trunk - Bug #9004] * lib/rubygems/ext/builder: Extensions are now installed into the extension install directory and the first directory in the require path from the gem. This allows backwards compatibility with msgpack and other gems that calculate full require paths. [ruby-trunk - Bug #9106] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43714 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
191 lines
4.1 KiB
Ruby
191 lines
4.1 KiB
Ruby
require 'uri'
|
|
require 'fileutils'
|
|
|
|
class Gem::Source
|
|
FILES = {
|
|
:released => 'specs',
|
|
:latest => 'latest_specs',
|
|
:prerelease => 'prerelease_specs',
|
|
}
|
|
|
|
def initialize(uri)
|
|
unless uri.kind_of? URI
|
|
uri = URI.parse(uri.to_s)
|
|
end
|
|
|
|
@uri = uri
|
|
@api_uri = nil
|
|
end
|
|
|
|
attr_reader :uri
|
|
|
|
def api_uri
|
|
require 'rubygems/remote_fetcher'
|
|
@api_uri ||= Gem::RemoteFetcher.fetcher.api_endpoint uri
|
|
end
|
|
|
|
def <=>(other)
|
|
case other
|
|
when Gem::Source::Installed,
|
|
Gem::Source::Local,
|
|
Gem::Source::SpecificFile,
|
|
Gem::Source::Git,
|
|
Gem::Source::Vendor then
|
|
-1
|
|
when Gem::Source then
|
|
if !@uri
|
|
return 0 unless other.uri
|
|
return 1
|
|
end
|
|
|
|
return -1 if !other.uri
|
|
|
|
@uri.to_s <=> other.uri.to_s
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
|
|
include Comparable
|
|
|
|
def ==(other)
|
|
self.class === other and @uri == other.uri
|
|
end
|
|
|
|
alias_method :eql?, :==
|
|
|
|
##
|
|
# Returns a Set that can fetch specifications from this source.
|
|
|
|
def dependency_resolver_set # :nodoc:
|
|
bundler_api_uri = api_uri + './api/v1/dependencies'
|
|
|
|
begin
|
|
fetcher = Gem::RemoteFetcher.fetcher
|
|
fetcher.fetch_path bundler_api_uri, nil, true
|
|
rescue Gem::RemoteFetcher::FetchError
|
|
Gem::Resolver::IndexSet.new self
|
|
else
|
|
Gem::Resolver::APISet.new bundler_api_uri
|
|
end
|
|
end
|
|
|
|
def hash
|
|
@uri.hash
|
|
end
|
|
|
|
##
|
|
# Returns the local directory to write +uri+ to.
|
|
|
|
def cache_dir(uri)
|
|
# Correct for windows paths
|
|
escaped_path = uri.path.sub(/^\/([a-z]):\//i, '/\\1-/')
|
|
File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path)
|
|
end
|
|
|
|
def update_cache?
|
|
@update_cache ||=
|
|
begin
|
|
File.stat(Gem.user_home).uid == Process.uid
|
|
rescue Errno::ENOENT
|
|
false
|
|
end
|
|
end
|
|
|
|
##
|
|
# Fetches a specification for the given +name_tuple+.
|
|
|
|
def fetch_spec name_tuple
|
|
fetcher = Gem::RemoteFetcher.fetcher
|
|
|
|
spec_file_name = name_tuple.spec_name
|
|
|
|
uri = api_uri + "#{Gem::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 = Gem.read_binary local_spec
|
|
spec = Marshal.load(spec) rescue nil
|
|
return spec if spec
|
|
end
|
|
|
|
uri.path << '.rz'
|
|
|
|
spec = fetcher.fetch_path uri
|
|
spec = Gem.inflate spec
|
|
|
|
if update_cache? then
|
|
FileUtils.mkdir_p cache_dir
|
|
|
|
open local_spec, 'wb' do |io|
|
|
io.write spec
|
|
end
|
|
end
|
|
|
|
# TODO: Investigate setting Gem::Specification#loaded_from to a URI
|
|
Marshal.load spec
|
|
end
|
|
|
|
##
|
|
# 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
|
|
#
|
|
|
|
def load_specs(type)
|
|
file = FILES[type]
|
|
fetcher = Gem::RemoteFetcher.fetcher
|
|
file_name = "#{file}.#{Gem.marshal_version}"
|
|
spec_path = api_uri + "#{file_name}.gz"
|
|
cache_dir = cache_dir spec_path
|
|
local_file = File.join(cache_dir, file_name)
|
|
retried = false
|
|
|
|
FileUtils.mkdir_p cache_dir if update_cache?
|
|
|
|
spec_dump = fetcher.cache_update_path spec_path, local_file, update_cache?
|
|
|
|
begin
|
|
Gem::NameTuple.from_list Marshal.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
|
|
|
|
def download(spec, dir=Dir.pwd)
|
|
fetcher = Gem::RemoteFetcher.fetcher
|
|
fetcher.download spec, api_uri.to_s, dir
|
|
end
|
|
|
|
def pretty_print q # :nodoc:
|
|
q.group 2, '[Remote:', ']' do
|
|
q.breakable
|
|
q.text @uri.to_s
|
|
if api = api_uri
|
|
g.text api
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
require 'rubygems/source/git'
|
|
require 'rubygems/source/installed'
|
|
require 'rubygems/source/specific_file'
|
|
require 'rubygems/source/local'
|
|
require 'rubygems/source/vendor'
|
|
|