1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Update RubyGems to 1.1.1 r1778 (almost 1.2)

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17392 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
drbrain 2008-06-17 22:04:18 +00:00
parent f98e6b91de
commit 9d4f37f51f
71 changed files with 3765 additions and 1127 deletions

View file

@ -1,3 +1,7 @@
Wed Jun 18 07:03:30 2008 Eric Hodel <drbrain@egment7.net>
* lib/rubygems/*: Update to RubyGems r1778 (pre 1.2).
Wed Jun 18 04:27:58 2008 Koichi Sasada <ko1@atdot.net>
* KNOWNBUGS.rb, bootstraptest/pending.rb: move pending bug.

View file

@ -67,11 +67,14 @@ module Gem
:RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
:arch => RbConfig::CONFIG["arch"],
:bindir => RbConfig::CONFIG["bindir"],
:datadir => RbConfig::CONFIG["datadir"],
:libdir => RbConfig::CONFIG["libdir"],
:ruby_install_name => RbConfig::CONFIG["ruby_install_name"],
:ruby_version => RbConfig::CONFIG["ruby_version"],
:sitedir => RbConfig::CONFIG["sitedir"],
:sitelibdir => RbConfig::CONFIG["sitelibdir"]
:sitelibdir => RbConfig::CONFIG["sitelibdir"],
:vendordir => RbConfig::CONFIG["vendordir"] ,
:vendorlibdir => RbConfig::CONFIG["vendorlibdir"]
)
DIRECTORIES = %w[cache doc gems specifications] unless defined?(DIRECTORIES)
@ -137,7 +140,7 @@ module Gem
unless matches.any? { |spec| spec.version == existing_spec.version } then
raise Gem::Exception,
"can't activate #{gem}, already activated #{existing_spec.full_name}]"
"can't activate #{gem}, already activated #{existing_spec.full_name}"
end
return false
@ -151,7 +154,7 @@ module Gem
@loaded_specs[spec.name] = spec
# Load dependent gems first
spec.dependencies.each do |dep_gem|
spec.runtime_dependencies.each do |dep_gem|
activate dep_gem
end
@ -203,6 +206,19 @@ module Gem
private_class_method :all_partials
##
# See if a given gem is available.
def self.available?(gem, *requirements)
requirements = Gem::Requirement.default if requirements.empty?
unless gem.respond_to?(:name) && gem.respond_to?(:version_requirements)
gem = Gem::Dependency.new(gem, requirements)
end
!Gem.source_index.search(gem).empty?
end
##
# The mode needed to read a file as straight binary.
@ -267,6 +283,13 @@ module Gem
File.join(spec.full_gem_path, 'data', gem_name)
end
##
# A Zlib::Deflate.deflate wrapper
def self.deflate(data)
Zlib::Deflate.deflate data
end
##
# The path where gems are to be installed.
@ -345,6 +368,33 @@ module Gem
private_class_method :find_home
##
# Zlib::GzipReader wrapper that unzips +data+.
def self.gunzip(data)
data = StringIO.new data
Zlib::GzipReader.new(data).read
end
##
# Zlib::GzipWriter wrapper that zips +data+.
def self.gzip(data)
zipped = StringIO.new
Zlib::GzipWriter.wrap zipped do |io| io.write data end
zipped.string
end
##
# A Zlib::Inflate#inflate wrapper
def self.inflate(data)
Zlib::Inflate.inflate data
end
##
# Return a list of all possible load paths for the latest version for all
# gems in the Gem installation.
@ -438,7 +488,11 @@ module Gem
@gem_path ||= nil
unless @gem_path then
paths = [ENV['GEM_PATH']] || [default_path]
paths = if ENV['GEM_PATH'] then
[ENV['GEM_PATH']]
else
[default_path]
end
if defined?(APPLE_GEM_HOME) and not ENV['GEM_PATH'] then
paths << APPLE_GEM_HOME
@ -459,7 +513,7 @@ module Gem
##
# Array of platforms this RubyGems supports.
def self.platforms
@platforms ||= []
if @platforms.empty?
@ -586,13 +640,13 @@ module Gem
def self.set_paths(gpaths)
if gpaths
@gem_path = gpaths.split(File::PATH_SEPARATOR)
if File::ALT_SEPARATOR then
@gem_path.map! do |path|
path.gsub File::ALT_SEPARATOR, File::SEPARATOR
end
end
@gem_path << Gem.dir
else
@gem_path = [Gem.dir]
@ -683,24 +737,25 @@ module Gem
end
MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/"
YAML_SPEC_DIR = 'quick/'
end
# Modify the non-gem version of datadir to handle gem package names.
require 'rbconfig/datadir'
module Config # :nodoc:
module Config
# :stopdoc:
class << self
alias gem_original_datadir datadir
# Return the path to the data directory associated with the named
# package. If the package is loaded as a gem, return the gem
# specific data directory. Otherwise return a path to the share
# area as define by "#{ConfigMap[:datadir]}/#{package_name}".
def datadir(package_name)
Gem.datadir(package_name) || Config.gem_original_datadir(package_name)
Gem.datadir(package_name) ||
File.join(Gem::ConfigMap[:datadir], package_name)
end
end
# :startdoc:
end
require 'rubygems/exceptions'
@ -712,6 +767,18 @@ require 'rubygems/source_index' # Needed for Kernel#gem
require 'rubygems/platform'
require 'rubygems/builder' # HACK: Needed for rake's package task.
begin
require 'rubygems/defaults/operating_system'
rescue LoadError
end
if defined?(RUBY_ENGINE) then
begin
require "rubygems/defaults/#{RUBY_ENGINE}"
rescue LoadError
end
end
if RUBY_VERSION < '1.9' then
require 'rubygems/custom_require'
end

View file

@ -46,6 +46,7 @@ module Gem
register_command :server
register_command :sources
register_command :specification
register_command :stale
register_command :uninstall
register_command :unpack
register_command :update

View file

@ -46,37 +46,67 @@ class Gem::Commands::DependencyCommand < Gem::Command
options[:args] << '.' if options[:args].empty?
specs = {}
source_indexes = []
source_indexes = Hash.new do |h, source_uri|
h[source_uri] = Gem::SourceIndex.new
end
pattern = /\A#{Regexp.union(*options[:args])}/
dependency = Gem::Dependency.new pattern, options[:version]
if options[:reverse_dependencies] and remote? and not local? then
alert_error 'Only reverse dependencies for local gems are supported.'
terminate_interaction 1
end
if local? then
source_indexes << Gem::SourceIndex.from_installed_gems
end
if remote? then
Gem::SourceInfoCache.cache_data.map do |_, sice|
source_indexes << sice.source_index
Gem.source_index.search(dependency).each do |spec|
source_indexes[:local].add_spec spec
end
end
options[:args].each do |name|
new_specs = nil
source_indexes.each do |source_index|
new_specs = find_gems(name, source_index)
if remote? and not options[:reverse_dependencies] then
fetcher = Gem::SpecFetcher.fetcher
begin
fetcher.find_matching(dependency).each do |spec_tuple, source_uri|
spec = fetcher.fetch_spec spec_tuple, URI.parse(source_uri)
source_indexes[source_uri].add_spec spec
end
rescue Gem::RemoteFetcher::FetchError => e
raise unless fetcher.warn_legacy e do
require 'rubygems/source_info_cache'
specs = Gem::SourceInfoCache.search_with_source dependency, false
specs.each do |spec, source_uri|
source_indexes[source_uri].add_spec spec
end
end
end
say "No match found for #{name} (#{options[:version]})" if
new_specs.empty?
specs = specs.merge new_specs
end
terminate_interaction 1 if specs.empty?
if source_indexes.empty? then
patterns = options[:args].join ','
say "No gems found matching #{patterns} (#{options[:version]})" if
Gem.configuration.verbose
terminate_interaction 1
end
specs = {}
source_indexes.values.each do |source_index|
source_index.gems.each do |name, spec|
specs[spec.full_name] = [source_index, spec]
end
end
reverse = Hash.new { |h, k| h[k] = [] }
if options[:reverse_dependencies] then
specs.values.each do |source_index, spec|
reverse[spec.full_name] = find_reverse_dependencies spec, source_index
specs.values.each do |_, spec|
reverse[spec.full_name] = find_reverse_dependencies spec
end
end
@ -118,10 +148,10 @@ class Gem::Commands::DependencyCommand < Gem::Command
end
# Retuns list of [specification, dep] that are satisfied by spec.
def find_reverse_dependencies(spec, source_index)
def find_reverse_dependencies(spec)
result = []
source_index.each do |name, sp|
Gem.source_index.each do |name, sp|
sp.dependencies.each do |dep|
dep = Gem::Dependency.new(*dep) unless Gem::Dependency === dep
@ -146,5 +176,6 @@ class Gem::Commands::DependencyCommand < Gem::Command
specs
end
end

View file

@ -51,6 +51,8 @@ class Gem::Commands::EnvironmentCommand < Gem::Command
out << " - RUBY EXECUTABLE: #{Gem.ruby}\n"
out << " - EXECUTABLE DIRECTORY: #{Gem.bindir}\n"
out << " - RUBYGEMS PLATFORMS:\n"
Gem.platforms.each do |platform|
out << " - #{platform}\n"

View file

@ -33,12 +33,14 @@ class Gem::Commands::FetchCommand < Gem::Command
def execute
version = options[:version] || Gem::Requirement.default
all = Gem::Requirement.default
gem_names = get_all_gem_names
gem_names.each do |gem_name|
dep = Gem::Dependency.new gem_name, version
specs_and_sources = Gem::SourceInfoCache.search_with_source dep, true
specs_and_sources = Gem::SpecFetcher.fetcher.fetch dep, all
specs_and_sources.sort_by { |spec,| spec.version }

View file

@ -16,7 +16,6 @@ class Gem::Commands::InstallCommand < Gem::Command
defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
:generate_rdoc => true,
:generate_ri => true,
:install_dir => Gem.dir,
:format_executable => false,
:test => false,
:version => Gem::Requirement.default,
@ -62,7 +61,8 @@ class Gem::Commands::InstallCommand < Gem::Command
:install_dir => options[:install_dir],
:security_policy => options[:security_policy],
:wrappers => options[:wrappers],
:bin_dir => options[:bin_dir]
:bin_dir => options[:bin_dir],
:development => options[:development],
}
exit_code = 0

View file

@ -1,33 +1,35 @@
require 'rubygems/command'
require 'rubygems/commands/query_command'
module Gem
module Commands
class ListCommand < QueryCommand
##
# An alternate to Gem::Commands::QueryCommand that searches for gems starting
# with the the supplied argument.
def initialize
super 'list', 'Display gems whose name starts with STRING'
class Gem::Commands::ListCommand < Gem::Commands::QueryCommand
remove_option('--name-matches')
end
def initialize
super 'list', 'Display gems whose name starts with STRING'
def arguments # :nodoc:
"STRING start of gem name to look for"
end
def defaults_str # :nodoc:
"--local --no-details"
end
def usage # :nodoc:
"#{program_name} [STRING]"
end
def execute
string = get_one_optional_argument || ''
options[:name] = /^#{string}/i
super
end
end
remove_option('--name-matches')
end
def arguments # :nodoc:
"STRING start of gem name to look for"
end
def defaults_str # :nodoc:
"--local --no-details"
end
def usage # :nodoc:
"#{program_name} [STRING]"
end
def execute
string = get_one_optional_argument || ''
options[:name] = /^#{string}/i
super
end
end

View file

@ -80,7 +80,7 @@ lock it down to the exact version.
say "gem '#{spec.name}', '= #{spec.version}'" unless locked[spec.name]
locked[spec.name] = true
spec.dependencies.each do |dep|
spec.runtime_dependencies.each do |dep|
next if locked[dep.name]
candidates = Gem.source_index.search dep.name, dep.requirement_list

View file

@ -1,6 +1,6 @@
require 'rubygems/command'
require 'rubygems/local_remote_options'
require 'rubygems/source_info_cache'
require 'rubygems/spec_fetcher'
require 'rubygems/version_option'
class Gem::Commands::OutdatedCommand < Gem::Command
@ -20,8 +20,11 @@ class Gem::Commands::OutdatedCommand < Gem::Command
locals.outdated.sort.each do |name|
local = locals.search(/^#{name}$/).last
remotes = Gem::SourceInfoCache.search_with_source(/^#{name}$/, true)
dep = Gem::Dependency.new local.name, ">= #{local.version}"
remotes = Gem::SpecFetcher.fetcher.fetch dep
remote = remotes.last.first
say "#{local.name} (#{local.version} < #{remote.version})"
end
end

View file

@ -82,51 +82,10 @@ revert the gem.
end
# TODO use installer options
installer = Gem::Installer.new gem, :wrappers => true
installer = Gem::Installer.new gem, :wrappers => true, :force => true
installer.install
gem_file = File.join install_dir, "cache", "#{spec.full_name}.gem"
security_policy = nil # TODO use installer option
format = Gem::Format.from_file_by_path gem_file, security_policy
target_directory = File.join(install_dir, "gems", format.spec.full_name)
target_directory.untaint
pristine_files = format.file_entries.collect { |data| data[0]["path"] }
file_map = {}
format.file_entries.each do |entry, file_data|
file_map[entry["path"]] = file_data
end
Dir.chdir target_directory do
deployed_files = Dir.glob(File.join("**", "*")) +
Dir.glob(File.join("**", ".*"))
pristine_files = pristine_files.map { |f| File.expand_path f }
deployed_files = deployed_files.map { |f| File.expand_path f }
to_redeploy = (pristine_files - deployed_files)
to_redeploy = to_redeploy.map { |path| path.untaint}
if to_redeploy.length > 0 then
say "Restoring #{to_redeploy.length} file#{to_redeploy.length == 1 ? "" : "s"} to #{spec.full_name}..."
to_redeploy.each do |path|
say " #{path}"
FileUtils.mkdir_p File.dirname(path)
File.open(path, "wb") do |out|
out.write file_map[path]
end
end
else
say "#{spec.full_name} is in pristine condition"
end
end
installer.generate_bin
installer.build_extensions
say "Restored #{spec.full_name}"
end
end

View file

@ -1,6 +1,6 @@
require 'rubygems/command'
require 'rubygems/local_remote_options'
require 'rubygems/source_info_cache'
require 'rubygems/spec_fetcher'
require 'rubygems/version_option'
class Gem::Commands::QueryCommand < Gem::Command
@ -74,7 +74,13 @@ class Gem::Commands::QueryCommand < Gem::Command
say "*** LOCAL GEMS ***"
say
output_query_results Gem.source_index.search(name)
specs = Gem.source_index.search name
spec_tuples = specs.map do |spec|
[[spec.name, spec.version, spec.original_platform, spec], :local]
end
output_query_results spec_tuples
end
if remote? then
@ -84,13 +90,26 @@ class Gem::Commands::QueryCommand < Gem::Command
all = options[:all]
dep = Gem::Dependency.new name, Gem::Requirement.default
begin
Gem::SourceInfoCache.cache all
rescue Gem::RemoteFetcher::FetchError
# no network
fetcher = Gem::SpecFetcher.fetcher
spec_tuples = fetcher.find_matching dep, all, false
rescue Gem::RemoteFetcher::FetchError => e
raise unless fetcher.warn_legacy e do
require 'rubygems/source_info_cache'
dep.name = '' if dep.name == //
specs = Gem::SourceInfoCache.search_with_source dep, false, all
spec_tuples = specs.map do |spec, source_uri|
[[spec.name, spec.version, spec.original_platform, spec],
source_uri]
end
end
end
output_query_results Gem::SourceInfoCache.search(name, false, all)
output_query_results spec_tuples
end
end
@ -104,28 +123,30 @@ class Gem::Commands::QueryCommand < Gem::Command
!Gem.source_index.search(dep).empty?
end
def output_query_results(gemspecs)
def output_query_results(spec_tuples)
output = []
gem_list_with_version = {}
versions = Hash.new { |h,name| h[name] = [] }
gemspecs.flatten.each do |gemspec|
gem_list_with_version[gemspec.name] ||= []
gem_list_with_version[gemspec.name] << gemspec
spec_tuples.each do |spec_tuple, source_uri|
versions[spec_tuple.first] << [spec_tuple, source_uri]
end
gem_list_with_version = gem_list_with_version.sort_by do |name, spec|
versions = versions.sort_by do |(name,),|
name.downcase
end
gem_list_with_version.each do |gem_name, list_of_matching|
list_of_matching = list_of_matching.sort_by { |x| x.version.to_ints }.reverse
seen_versions = {}
versions.each do |gem_name, matching_tuples|
matching_tuples = matching_tuples.sort_by do |(name, version,),|
version
end.reverse
list_of_matching.delete_if do |item|
if seen_versions[item.version] then
seen = {}
matching_tuples.delete_if do |(name, version,),|
if seen[version] then
true
else
seen_versions[item.version] = true
seen[version] = true
false
end
end
@ -133,12 +154,50 @@ class Gem::Commands::QueryCommand < Gem::Command
entry = gem_name.dup
if options[:versions] then
versions = list_of_matching.map { |s| s.version }.uniq
versions = matching_tuples.map { |(name, version,),| version }.uniq
entry << " (#{versions.join ', '})"
end
entry << "\n" << format_text(list_of_matching[0].summary, 68, 4) if
options[:details]
if options[:details] then
detail_tuple = matching_tuples.first
spec = if detail_tuple.first.length == 4 then
detail_tuple.first.last
else
uri = URI.parse detail_tuple.last
Gem::SpecFetcher.fetcher.fetch_spec detail_tuple.first, uri
end
entry << "\n"
authors = "Author#{spec.authors.length > 1 ? 's' : ''}: "
authors << spec.authors.join(', ')
entry << format_text(authors, 68, 4)
if spec.rubyforge_project and not spec.rubyforge_project.empty? then
rubyforge = "Rubyforge: http://rubyforge.org/projects/#{spec.rubyforge_project}"
entry << "\n" << format_text(rubyforge, 68, 4)
end
if spec.homepage and not spec.homepage.empty? then
entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4)
end
if spec.loaded_from then
if matching_tuples.length == 1 then
loaded_from = File.dirname File.dirname(spec.loaded_from)
entry << "\n" << " Installed at: #{loaded_from}"
else
label = 'Installed at'
matching_tuples.each do |(_,version,_,s),|
loaded_from = File.dirname File.dirname(s.loaded_from)
entry << "\n" << " #{label} (#{version}): #{loaded_from}"
label = ' ' * label.length
end
end
end
entry << "\n\n" << format_text(spec.summary, 68, 4)
end
output << entry
end

View file

@ -1,7 +1,8 @@
require 'fileutils'
require 'rubygems/command'
require 'rubygems/remote_fetcher'
require 'rubygems/source_info_cache'
require 'rubygems/source_info_cache_entry'
require 'rubygems/spec_fetcher'
class Gem::Commands::SourcesCommand < Gem::Command
@ -21,14 +22,14 @@ class Gem::Commands::SourcesCommand < Gem::Command
options[:remove] = value
end
add_option '-u', '--update', 'Update source cache' do |value, options|
options[:update] = value
end
add_option '-c', '--clear-all',
'Remove all sources (clear the cache)' do |value, options|
options[:clear_all] = value
end
add_option '-u', '--update', 'Update source cache' do |value, options|
options[:update] = value
end
end
def defaults_str
@ -36,9 +37,23 @@ class Gem::Commands::SourcesCommand < Gem::Command
end
def execute
options[:list] = !(options[:add] || options[:remove] || options[:clear_all] || options[:update])
options[:list] = !(options[:add] ||
options[:clear_all] ||
options[:remove] ||
options[:update])
if options[:clear_all] then
path = Gem::SpecFetcher.fetcher.dir
FileUtils.rm_rf path
if not File.exist?(path) then
say "*** Removed specs cache ***"
elsif not File.writable?(path) then
say "*** Unable to remove source cache (write protected) ***"
else
say "*** Unable to remove source cache ***"
end
sic = Gem::SourceInfoCache
remove_cache_file 'user', sic.user_cache_file
remove_cache_file 'latest user', sic.latest_user_cache_file
@ -48,15 +63,10 @@ class Gem::Commands::SourcesCommand < Gem::Command
if options[:add] then
source_uri = options[:add]
uri = URI.parse source_uri
sice = Gem::SourceInfoCacheEntry.new nil, nil
begin
sice.refresh source_uri, true
Gem::SourceInfoCache.cache_data[source_uri] = sice
Gem::SourceInfoCache.cache.update
Gem::SourceInfoCache.cache.flush
Gem::SpecFetcher.fetcher.load_specs uri, 'specs'
Gem.sources << source_uri
Gem.configuration.write
@ -64,31 +74,32 @@ class Gem::Commands::SourcesCommand < Gem::Command
rescue URI::Error, ArgumentError
say "#{source_uri} is not a URI"
rescue Gem::RemoteFetcher::FetchError => e
say "Error fetching #{source_uri}:\n\t#{e.message}"
yaml_uri = uri + 'yaml'
gem_repo = Gem::RemoteFetcher.fetcher.fetch_size yaml_uri rescue false
if e.uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ and
gem_repo then
alert_warning <<-EOF
RubyGems 1.2+ index not found for:
\t#{source_uri}
Will cause RubyGems to revert to legacy indexes, degrading performance.
EOF
say "#{source_uri} added to sources"
else
say "Error fetching #{source_uri}:\n\t#{e.message}"
end
end
end
if options[:update] then
Gem::SourceInfoCache.cache true
Gem::SourceInfoCache.cache.flush
say "source cache successfully updated"
end
if options[:remove] then
source_uri = options[:remove]
unless Gem.sources.include? source_uri then
say "source #{source_uri} not present in cache"
else
begin # HACK figure out how to get the cache w/o update
Gem::SourceInfoCache.cache
rescue Gem::RemoteFetcher::FetchError
end
Gem::SourceInfoCache.cache_data.delete source_uri
Gem::SourceInfoCache.cache.update
Gem::SourceInfoCache.cache.flush
Gem.sources.delete source_uri
Gem.configuration.write
@ -96,6 +107,23 @@ class Gem::Commands::SourcesCommand < Gem::Command
end
end
if options[:update] then
fetcher = Gem::SpecFetcher.fetcher
if fetcher.legacy_repos.empty? then
Gem.sources.each do |source_uri|
source_uri = URI.parse source_uri
fetcher.load_specs source_uri, 'specs'
fetcher.load_specs source_uri, 'latest_specs'
end
else
Gem::SourceInfoCache.cache true
Gem::SourceInfoCache.cache.flush
end
say "source cache successfully updated"
end
if options[:list] then
say "*** CURRENT SOURCES ***"
say

View file

@ -52,9 +52,10 @@ class Gem::Commands::SpecificationCommand < Gem::Command
end
if remote? then
Gem::SourceInfoCache.cache_data.each do |_,sice|
specs.push(*sice.source_index.search(gem, options[:version]))
end
dep = Gem::Dependency.new gem, options[:version]
found = Gem::SpecFetcher.fetcher.fetch dep
specs.push(*found.map { |spec,| spec })
end
if specs.empty? then

View file

@ -0,0 +1,27 @@
require 'rubygems/command'
class Gem::Commands::StaleCommand < Gem::Command
def initialize
super('stale', 'List gems along with access times')
end
def usage # :nodoc:
"#{program_name}"
end
def execute
gem_to_atime = {}
Gem.source_index.each do |name, spec|
Dir["#{spec.full_gem_path}/**/*.*"].each do |file|
next if File.directory?(file)
stat = File.stat(file)
gem_to_atime[name] ||= stat.atime
gem_to_atime[name] = stat.atime if gem_to_atime[name] < stat.atime
end
end
gem_to_atime.sort_by { |_, atime| atime }.each do |name, atime|
say "#{name} at #{atime.strftime '%c'}"
end
end
end

View file

@ -2,7 +2,7 @@ require 'rubygems/command'
require 'rubygems/command_manager'
require 'rubygems/install_update_options'
require 'rubygems/local_remote_options'
require 'rubygems/source_info_cache'
require 'rubygems/spec_fetcher'
require 'rubygems/version_option'
require 'rubygems/commands/install_command'
@ -15,11 +15,10 @@ class Gem::Commands::UpdateCommand < Gem::Command
def initialize
super 'update',
'Update the named gems (or all installed gems) in the local repository',
:generate_rdoc => true,
:generate_ri => true,
:force => false,
:test => false,
:install_dir => Gem.dir
:generate_rdoc => true,
:generate_ri => true,
:force => false,
:test => false
add_install_update_options
@ -60,21 +59,13 @@ class Gem::Commands::UpdateCommand < Gem::Command
hig = {} # highest installed gems
Gem::SourceIndex.from_installed_gems.each do |name, spec|
Gem.source_index.each do |name, spec|
if hig[spec.name].nil? or hig[spec.name].version < spec.version then
hig[spec.name] = spec
end
end
pattern = if options[:args].empty? then
//
else
Regexp.union(*options[:args])
end
remote_gemspecs = Gem::SourceInfoCache.search pattern
gems_to_update = which_to_update hig, remote_gemspecs
gems_to_update = which_to_update hig, options[:args]
updated = []
@ -135,20 +126,42 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
end
def which_to_update(highest_installed_gems, remote_gemspecs)
def which_to_update(highest_installed_gems, gem_names)
result = []
highest_installed_gems.each do |l_name, l_spec|
matching_gems = remote_gemspecs.select do |spec|
spec.name == l_name and Gem.platforms.any? do |platform|
platform == spec.platform
next if not gem_names.empty? and
gem_names.all? { |name| /#{name}/ !~ l_spec.name }
dependency = Gem::Dependency.new l_spec.name, "> #{l_spec.version}"
begin
fetcher = Gem::SpecFetcher.fetcher
spec_tuples = fetcher.find_matching dependency
rescue Gem::RemoteFetcher::FetchError => e
raise unless fetcher.warn_legacy e do
require 'rubygems/source_info_cache'
dependency.name = '' if dependency.name == //
specs = Gem::SourceInfoCache.search_with_source dependency
spec_tuples = specs.map do |spec, source_uri|
[[spec.name, spec.version, spec.original_platform], source_uri]
end
end
end
highest_remote_gem = matching_gems.sort_by { |spec| spec.version }.last
matching_gems = spec_tuples.select do |(name, version, platform),|
name == l_name and Gem::Platform.match platform
end
highest_remote_gem = matching_gems.sort_by do |(name, version),|
version
end.last
if highest_remote_gem and
l_spec.version < highest_remote_gem.version then
l_spec.version < highest_remote_gem.first[1] then
result << l_name
end
end

View file

@ -18,6 +18,22 @@ class Gem::ConfigFile
DEFAULT_VERBOSITY = true
DEFAULT_UPDATE_SOURCES = true
system_config_path =
begin
require 'Win32API'
CSIDL_COMMON_APPDATA = 0x0023
path = 0.chr * 260
SHGetFolderPath = Win32API.new 'shell32', 'SHGetFolderPath', 'LLLLP', 'L'
SHGetFolderPath.call 0, CSIDL_COMMON_APPDATA, 0, 1, path
path.strip
rescue LoadError
'/etc'
end
SYSTEM_WIDE_CONFIG_FILE = File.join system_config_path, 'gemrc'
# List of arguments supplied to the config file object.
attr_reader :args
@ -81,18 +97,8 @@ class Gem::ConfigFile
@verbose = DEFAULT_VERBOSITY
@update_sources = DEFAULT_UPDATE_SOURCES
begin
# HACK $SAFE ok?
@hash = open(config_file_name.dup.untaint) {|f| YAML.load(f) }
rescue ArgumentError
warn "Failed to load #{config_file_name}"
rescue Errno::ENOENT
# Ignore missing config file error.
rescue Errno::EACCES
warn "Failed to load #{config_file_name} due to permissions problem."
end
@hash ||= {}
@hash = load_file(SYSTEM_WIDE_CONFIG_FILE)
@hash.merge!(load_file(config_file_name.dup.untaint))
# HACK these override command-line args, which is bad
@backtrace = @hash[:backtrace] if @hash.key? :backtrace
@ -105,6 +111,16 @@ class Gem::ConfigFile
handle_arguments arg_list
end
def load_file(filename)
begin
YAML.load(File.read(filename)) if filename and File.exist?(filename)
rescue ArgumentError
warn "Failed to load #{config_file_name}"
rescue Errno::EACCES
warn "Failed to load #{config_file_name} due to permissions problem."
end or {}
end
# True if the backtrace option has been specified, or debug is on.
def backtrace
@backtrace or $DEBUG

View file

@ -26,7 +26,7 @@ module Kernel
def require(path) # :nodoc:
gem_original_require path
rescue LoadError => load_error
if load_error.message =~ /\A[Nn]o such file to load -- #{Regexp.escape path}\z/ and
if load_error.message =~ /#{Regexp.escape path}\z/ and
spec = Gem.searcher.find(path) then
Gem.activate(spec.name, "= #{spec.version}")
gem_original_require path

View file

@ -2,7 +2,7 @@ module Gem
# An Array of the default sources that come with RubyGems.
def self.default_sources
%w[http://gems.rubyforge.org]
%w[http://gems.rubyforge.org/]
end
# Default home directory path to be used if an alternate value is not

View file

@ -8,24 +8,54 @@ require 'rubygems'
##
# The Dependency class holds a Gem name and a Gem::Requirement
class Gem::Dependency
##
# Valid dependency types.
#--
# When this list is updated, be sure to change
# Gem::Specification::CURRENT_SPECIFICATION_VERSION as well.
TYPES = [
:development,
:runtime,
]
##
# Dependency name or regular expression.
attr_accessor :name
##
# Dependency type.
attr_reader :type
##
# Dependent versions.
attr_writer :version_requirements
##
# Orders dependencies by name only.
def <=>(other)
[@name] <=> [other.name]
end
##
# Constructs the dependency
#
# name:: [String] name of the Gem
# version_requirements:: [String Array] version requirement (e.g. ["> 1.2"])
#
def initialize(name, version_requirements)
# Constructs a dependency with +name+ and +requirements+.
def initialize(name, version_requirements, type=:runtime)
@name = name
unless TYPES.include? type
raise ArgumentError, "Valid types are #{TYPES.inspect}, not #{@type.inspect}"
end
@type = type
@version_requirements = Gem::Requirement.create version_requirements
@version_requirement = nil # Avoid warnings.
end
@ -48,17 +78,41 @@ class Gem::Dependency
end
def to_s # :nodoc:
"#{name} (#{version_requirements})"
"#{name} (#{version_requirements}, #{@type || :runtime})"
end
def ==(other) # :nodoc:
self.class === other &&
self.name == other.name &&
self.type == other.type &&
self.version_requirements == other.version_requirements
end
def hash
name.hash + version_requirements.hash
##
# Uses this dependency as a pattern to compare to the dependency +other+.
# This dependency will match if the name matches the other's name, and other
# has only an equal version requirement that satisfies this dependency.
def =~(other)
return false unless self.class === other
pattern = @name
pattern = /\A#{@name}\Z/ unless Regexp === pattern
return false unless pattern =~ other.name
reqs = other.version_requirements.requirements
return false unless reqs.length == 1
return false unless reqs.first.first == '='
version = reqs.first.last
version_requirements.satisfied_by? version
end
def hash # :nodoc:
name.hash + type.hash + version_requirements.hash
end
end

View file

@ -1,9 +1,12 @@
require 'rubygems'
require 'rubygems/dependency_list'
require 'rubygems/installer'
require 'rubygems/source_info_cache'
require 'rubygems/spec_fetcher'
require 'rubygems/user_interaction'
##
# Installs a gem along with all its dependencies from local and remote gems.
class Gem::DependencyInstaller
include Gem::UserInteraction
@ -25,36 +28,50 @@ class Gem::DependencyInstaller
# Creates a new installer instance.
#
# Options are:
# :env_shebang:: See Gem::Installer::new.
# :cache_dir:: Alternate repository path to store .gem files in.
# :domain:: :local, :remote, or :both. :local only searches gems in the
# current directory. :remote searches only gems in Gem::sources.
# :both searches both.
# :env_shebang:: See Gem::Installer::new.
# :force:: See Gem::Installer#install.
# :format_executable:: See Gem::Installer#initialize.
# :ignore_dependencies: Don't install any dependencies.
# :install_dir: See Gem::Installer#install.
# :security_policy: See Gem::Installer::new and Gem::Security.
# :wrappers: See Gem::Installer::new
# :ignore_dependencies:: Don't install any dependencies.
# :install_dir:: See Gem::Installer#install.
# :security_policy:: See Gem::Installer::new and Gem::Security.
# :wrappers:: See Gem::Installer::new
def initialize(options = {})
options = DEFAULT_OPTIONS.merge options
@env_shebang = options[:env_shebang]
@bin_dir = options[:bin_dir]
@development = options[:development]
@domain = options[:domain]
@env_shebang = options[:env_shebang]
@force = options[:force]
@format_executable = options[:format_executable]
@ignore_dependencies = options[:ignore_dependencies]
@install_dir = options[:install_dir] || Gem.dir
@security_policy = options[:security_policy]
@wrappers = options[:wrappers]
@bin_dir = options[:bin_dir]
@installed_gems = []
@install_dir = options[:install_dir] || Gem.dir
@cache_dir = options[:cache_dir] || @install_dir
if options[:install_dir] then
spec_dir = File.join @install_dir, 'specifications'
@source_index = Gem::SourceIndex.from_gems_in spec_dir
else
@source_index = Gem.source_index
end
end
##
# Returns a list of pairs of gemspecs and source_uris that match
# Gem::Dependency +dep+ from both local (Dir.pwd) and remote (Gem.sources)
# sources. Gems are sorted with newer gems preferred over older gems, and
# sources. Gems are sorted with newer gems prefered over older gems, and
# local gems preferred over remote gems.
def find_gems_with_sources(dep)
gems_and_sources = []
@ -74,8 +91,7 @@ class Gem::DependencyInstaller
all = requirements.length > 1 ||
(requirements.first != ">=" and requirements.first != ">")
found = Gem::SourceInfoCache.search_with_source dep, true, all
found = Gem::SpecFetcher.fetcher.fetch dep, all
gems_and_sources.push(*found)
rescue Gem::RemoteFetcher::FetchError => e
@ -95,6 +111,7 @@ class Gem::DependencyInstaller
##
# Gathers all dependencies necessary for the installation from local and
# remote sources unless the ignore_dependencies was given.
def gather_dependencies
specs = @specs_and_sources.map { |spec,_| spec }
@ -110,8 +127,18 @@ class Gem::DependencyInstaller
next if spec.nil? or seen[spec.name]
seen[spec.name] = true
spec.dependencies.each do |dep|
results = find_gems_with_sources(dep).reverse # local gems first
deps = spec.runtime_dependencies
deps |= spec.development_dependencies if @development
deps.each do |dep|
results = find_gems_with_sources(dep).reverse
results.reject! do |spec,|
@source_index.any? do |_, installed_spec|
dep.name == installed_spec.name and
dep.version_requirements.satisfied_by? installed_spec.version
end
end
results.each do |dep_spec, source_uri|
next if seen[dep_spec.name]
@ -126,6 +153,11 @@ class Gem::DependencyInstaller
@gems_to_install = dependency_list.dependency_order.reverse
end
##
# Finds a spec and the source_uri it came from for gem +gem_name+ and
# +version+. Returns an Array of specs and sources required for
# installation of the gem.
def find_spec_by_name_and_version gem_name, version = Gem::Requirement.default
spec_and_source = nil
@ -160,14 +192,16 @@ class Gem::DependencyInstaller
if spec_and_source.nil? then
raise Gem::GemNotFoundException,
"could not find #{gem_name} locally or in a repository"
"could not find gem #{gem_name} locally or in a repository"
end
@specs_and_sources = [spec_and_source]
end
##
# Installs the gem and all its dependencies.
# Installs the gem and all its dependencies. Returns an Array of installed
# gems specifications.
def install dep_or_name, version = Gem::Requirement.default
if String === dep_or_name then
find_spec_by_name_and_version dep_or_name, version
@ -175,15 +209,14 @@ class Gem::DependencyInstaller
@specs_and_sources = [find_gems_with_sources(dep_or_name).last]
end
gather_dependencies
@installed_gems = []
spec_dir = File.join @install_dir, 'specifications'
source_index = Gem::SourceIndex.from_gems_in spec_dir
gather_dependencies
@gems_to_install.each do |spec|
last = spec == @gems_to_install.last
# HACK is this test for full_name acceptable?
next if source_index.any? { |n,_| n == spec.full_name } and not last
next if @source_index.any? { |n,_| n == spec.full_name } and not last
# TODO: make this sorta_verbose so other users can benefit from it
say "Installing gem #{spec.full_name}" if Gem.configuration.really_verbose
@ -191,7 +224,7 @@ class Gem::DependencyInstaller
_, source_uri = @specs_and_sources.assoc spec
begin
local_gem_path = Gem::RemoteFetcher.fetcher.download spec, source_uri,
@install_dir
@cache_dir
rescue Gem::RemoteFetcher::FetchError
next if @force
raise
@ -205,12 +238,15 @@ class Gem::DependencyInstaller
:install_dir => @install_dir,
:security_policy => @security_policy,
:wrappers => @wrappers,
:bin_dir => @bin_dir
:bin_dir => @bin_dir,
:development => @development
spec = inst.install
@installed_gems << spec
end
@installed_gems
end
end

View file

@ -69,7 +69,7 @@ class Gem::DependencyList
# Are all the dependencies in the list satisfied?
def ok?
@specs.all? do |spec|
spec.dependencies.all? do |dep|
spec.runtime_dependencies.all? do |dep|
@specs.find { |s| s.satisfies_requirement? dep }
end
end

View file

@ -9,9 +9,9 @@ require 'fileutils'
module Gem
class DocManager
include UserInteraction
# Create a document manager for the given gem spec.
#
# spec:: The Gem::Specification object representing the gem.
@ -22,12 +22,12 @@ module Gem
@doc_dir = File.join(spec.installation_path, "doc", spec.full_name)
@rdoc_args = rdoc_args.nil? ? [] : rdoc_args.split
end
# Is the RDoc documentation installed?
def rdoc_installed?
return File.exist?(File.join(@doc_dir, "rdoc"))
end
# Generate the RI documents for this gem spec.
#
# Note that if both RI and RDoc documents are generated from the
@ -102,7 +102,7 @@ module Gem
args << '--quiet'
args << @spec.require_paths.clone
args << @spec.extra_rdoc_files
args.flatten!
args = args.flatten.map do |arg| arg.to_s end
r = RDoc::RDoc.new

View file

@ -1,5 +1,6 @@
require 'fileutils'
require 'tmpdir'
require 'zlib'
require 'rubygems'
require 'rubygems/format'
@ -40,104 +41,43 @@ class Gem::Indexer
marshal_name = "Marshal.#{Gem.marshal_version}"
@master_index = Gem::Indexer::MasterIndexBuilder.new "yaml", @directory
@marshal_index = Gem::Indexer::MarshalIndexBuilder.new marshal_name, @directory
@quick_index = Gem::Indexer::QuickIndexBuilder.new 'index', @directory
@master_index = File.join @directory, 'yaml'
@marshal_index = File.join @directory, marshal_name
quick_dir = File.join @directory, 'quick'
@latest_index = Gem::Indexer::LatestIndexBuilder.new 'latest_index', quick_dir
@quick_dir = File.join @directory, 'quick'
@quick_marshal_dir = File.join @quick_dir, marshal_name
@quick_index = File.join @quick_dir, 'index'
@latest_index = File.join @quick_dir, 'latest_index'
@specs_index = File.join @directory, "specs.#{Gem.marshal_version}"
@latest_specs_index = File.join @directory,
"latest_specs.#{Gem.marshal_version}"
files = [
@specs_index,
"#{@specs_index}.gz",
@latest_specs_index,
"#{@latest_specs_index}.gz",
@quick_dir,
@master_index,
"#{@master_index}.Z",
@marshal_index,
"#{@marshal_index}.Z",
]
@files = files.map do |path|
path.sub @directory, ''
end
end
##
# Build the index.
# Abbreviate the spec for downloading. Abbreviated specs are only used for
# searching, downloading and related activities and do not need deployment
# specific information (e.g. list of files). So we abbreviate the spec,
# making it much smaller for quicker downloads.
def build_index
@master_index.build do
@quick_index.build do
@marshal_index.build do
@latest_index.build do
progress = ui.progress_reporter gem_file_list.size,
"Generating index for #{gem_file_list.size} gems in #{@dest_directory}",
"Loaded all gems"
gem_file_list.each do |gemfile|
if File.size(gemfile.to_s) == 0 then
alert_warning "Skipping zero-length gem: #{gemfile}"
next
end
begin
spec = Gem::Format.from_file_by_path(gemfile).spec
unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then
alert_warning "Skipping misnamed gem: #{gemfile} => #{spec.full_name} (#{spec.original_name})"
next
end
abbreviate spec
sanitize spec
@master_index.add spec
@quick_index.add spec
@marshal_index.add spec
@latest_index.add spec
progress.updated spec.original_name
rescue SignalException => e
alert_error "Received signal, exiting"
raise
rescue Exception => e
alert_error "Unable to process #{gemfile}\n#{e.message} (#{e.class})\n\t#{e.backtrace.join "\n\t"}"
end
end
progress.done
say "Generating master indexes (this may take a while)"
end
end
end
end
end
def install_index
verbose = Gem.configuration.really_verbose
say "Moving index into production dir #{@dest_directory}" if verbose
files = @master_index.files + @quick_index.files + @marshal_index.files +
@latest_index.files
files.each do |file|
src_name = File.join @directory, file
dst_name = File.join @dest_directory, file
FileUtils.rm_rf dst_name, :verbose => verbose
FileUtils.mv src_name, @dest_directory, :verbose => verbose
end
end
def generate_index
FileUtils.rm_rf @directory
FileUtils.mkdir_p @directory, :mode => 0700
build_index
install_index
rescue SignalException
ensure
FileUtils.rm_rf @directory
end
# List of gem file names to index.
def gem_file_list
Dir.glob(File.join(@dest_directory, "gems", "*.gem"))
end
# Abbreviate the spec for downloading. Abbreviated specs are only
# used for searching, downloading and related activities and do not
# need deployment specific information (e.g. list of files). So we
# abbreviate the spec, making it much smaller for quicker downloads.
def abbreviate(spec)
spec.files = []
spec.test_files = []
@ -147,9 +87,257 @@ class Gem::Indexer
spec
end
##
# Build various indicies
def build_indicies(index)
progress = ui.progress_reporter index.size,
"Generating quick index gemspecs for #{index.size} gems",
"Complete"
index.each do |original_name, spec|
spec_file_name = "#{original_name}.gemspec.rz"
yaml_name = File.join @quick_dir, spec_file_name
marshal_name = File.join @quick_marshal_dir, spec_file_name
yaml_zipped = Gem.deflate spec.to_yaml
open yaml_name, 'wb' do |io| io.write yaml_zipped end
marshal_zipped = Gem.deflate Marshal.dump(spec)
open marshal_name, 'wb' do |io| io.write marshal_zipped end
progress.updated original_name
end
progress.done
say "Generating specs index"
open @specs_index, 'wb' do |io|
specs = index.sort.map do |_, spec|
platform = spec.original_platform
platform = Gem::Platform::RUBY if platform.nil?
[spec.name, spec.version, platform]
end
specs = compact_specs specs
Marshal.dump specs, io
end
say "Generating latest specs index"
open @latest_specs_index, 'wb' do |io|
specs = index.latest_specs.sort.map do |spec|
[spec.name, spec.version, spec.original_platform]
end
specs = compact_specs specs
Marshal.dump specs, io
end
say "Generating quick index"
quick_index = File.join @quick_dir, 'index'
open quick_index, 'wb' do |io|
io.puts index.sort.map { |_, spec| spec.original_name }
end
say "Generating latest index"
latest_index = File.join @quick_dir, 'latest_index'
open latest_index, 'wb' do |io|
io.puts index.latest_specs.sort.map { |spec| spec.original_name }
end
say "Generating Marshal master index"
open @marshal_index, 'wb' do |io|
io.write index.dump
end
progress = ui.progress_reporter index.size,
"Generating YAML master index for #{index.size} gems (this may take a while)",
"Complete"
open @master_index, 'wb' do |io|
io.puts "--- !ruby/object:#{index.class}"
io.puts "gems:"
gems = index.sort_by { |name, gemspec| gemspec.sort_obj }
gems.each do |original_name, gemspec|
yaml = gemspec.to_yaml.gsub(/^/, ' ')
yaml = yaml.sub(/\A ---/, '') # there's a needed extra ' ' here
io.print " #{original_name}:"
io.puts yaml
progress.updated original_name
end
end
progress.done
say "Compressing indicies"
# use gzip for future files.
compress quick_index, 'rz'
paranoid quick_index, 'rz'
compress latest_index, 'rz'
paranoid latest_index, 'rz'
compress @marshal_index, 'Z'
paranoid @marshal_index, 'Z'
compress @master_index, 'Z'
paranoid @master_index, 'Z'
gzip @specs_index
gzip @latest_specs_index
end
##
# Collect specifications from .gem files from the gem directory.
def collect_specs
index = Gem::SourceIndex.new
progress = ui.progress_reporter gem_file_list.size,
"Loading #{gem_file_list.size} gems from #{@dest_directory}",
"Loaded all gems"
gem_file_list.each do |gemfile|
if File.size(gemfile.to_s) == 0 then
alert_warning "Skipping zero-length gem: #{gemfile}"
next
end
begin
spec = Gem::Format.from_file_by_path(gemfile).spec
unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then
alert_warning "Skipping misnamed gem: #{gemfile} => #{spec.full_name} (#{spec.original_name})"
next
end
abbreviate spec
sanitize spec
index.gems[spec.original_name] = spec
progress.updated spec.original_name
rescue SignalException => e
alert_error "Received signal, exiting"
raise
rescue Exception => e
alert_error "Unable to process #{gemfile}\n#{e.message} (#{e.class})\n\t#{e.backtrace.join "\n\t"}"
end
end
progress.done
index
end
##
# Compacts Marshal output for the specs index data source by using identical
# objects as much as possible.
def compact_specs(specs)
names = {}
versions = {}
platforms = {}
specs.map do |(name, version, platform)|
names[name] = name unless names.include? name
versions[version] = version unless versions.include? version
platforms[platform] = platform unless platforms.include? platform
[names[name], versions[version], platforms[platform]]
end
end
##
# Compress +filename+ with +extension+.
def compress(filename, extension)
data = Gem.read_binary filename
zipped = Gem.deflate data
open "#{filename}.#{extension}", 'wb' do |io|
io.write zipped
end
end
##
# List of gem file names to index.
def gem_file_list
Dir.glob(File.join(@dest_directory, "gems", "*.gem"))
end
##
# Builds and installs indexicies.
def generate_index
FileUtils.rm_rf @directory
FileUtils.mkdir_p @directory, :mode => 0700
FileUtils.mkdir_p @quick_marshal_dir
index = collect_specs
build_indicies index
install_indicies
rescue SignalException
ensure
FileUtils.rm_rf @directory
end
##
# Zlib::GzipWriter wrapper that gzips +filename+ on disk.
def gzip(filename)
Zlib::GzipWriter.open "#{filename}.gz" do |io|
io.write Gem.read_binary(filename)
end
end
##
# Install generated indicies into the destination directory.
def install_indicies
verbose = Gem.configuration.really_verbose
say "Moving index into production dir #{@dest_directory}" if verbose
@files.each do |file|
src_name = File.join @directory, file
dst_name = File.join @dest_directory, file
FileUtils.rm_rf dst_name, :verbose => verbose
FileUtils.mv src_name, @dest_directory, :verbose => verbose
end
end
##
# Ensure +path+ and path with +extension+ are identical.
def paranoid(path, extension)
data = Gem.read_binary path
compressed_data = Gem.read_binary "#{path}.#{extension}"
unless data == Gem.inflate(compressed_data) then
raise "Compressed file #{compressed_path} does not match uncompressed file #{path}"
end
end
##
# Sanitize the descriptive fields in the spec. Sometimes non-ASCII
# characters will garble the site index. Non-ASCII characters will
# be replaced by their XML entity equivalent.
def sanitize(spec)
spec.summary = sanitize_string(spec.summary)
spec.description = sanitize_string(spec.description)
@ -158,7 +346,9 @@ class Gem::Indexer
spec
end
##
# Sanitize a single string.
def sanitize_string(string)
# HACK the #to_s is in here because RSpec has an Array of Arrays of
# Strings for authors. Need a way to disallow bad values on gempsec
@ -168,9 +358,3 @@ class Gem::Indexer
end
require 'rubygems/indexer/abstract_index_builder'
require 'rubygems/indexer/master_index_builder'
require 'rubygems/indexer/quick_index_builder'
require 'rubygems/indexer/marshal_index_builder'
require 'rubygems/indexer/latest_index_builder'

View file

@ -89,6 +89,12 @@ module Gem::InstallUpdateOptions
'foo_exec18') do |value, options|
options[:format_executable] = value
end
add_option(:"Install/Update", "--development",
"Install any additional development",
"dependencies") do |value, options|
options[:development] = true
end
end
# Default options for the gem install command.

View file

@ -56,6 +56,7 @@ class Gem::Installer
# foo_exec18.
# :security_policy:: Use the specified security policy. See Gem::Security
# :wrappers:: Install wrappers if true, symlinks if false.
def initialize(gem, options={})
@gem = gem
@ -76,6 +77,7 @@ class Gem::Installer
@security_policy = options[:security_policy]
@wrappers = options[:wrappers]
@bin_dir = options[:bin_dir]
@development = options[:development]
begin
@format = Gem::Format.from_file_by_path @gem, @security_policy
@ -98,6 +100,7 @@ class Gem::Installer
# cache/<gem-version>.gem #=> a cached copy of the installed gem
# gems/<gem-version>/... #=> extracted files
# specifications/<gem-version>.gemspec #=> the Gem::Specification
def install
# If we're forcing the install then disable security unless the security
# policy says that we only install singed gems.
@ -119,7 +122,10 @@ class Gem::Installer
end
unless @ignore_dependencies then
@spec.dependencies.each do |dep_gem|
deps = @spec.runtime_dependencies
deps |= @spec.development_dependencies if @development
deps.each do |dep_gem|
ensure_dependency @spec, dep_gem
end
end
@ -150,6 +156,8 @@ class Gem::Installer
@spec.loaded_from = File.join(@gem_home, 'specifications',
"#{@spec.full_name}.gemspec")
Gem.source_index.add_spec @spec
return @spec
rescue Zlib::GzipFile::Error
raise Gem::InstallError, "gzip error installing #{@gem}"
@ -161,6 +169,7 @@ class Gem::Installer
#
# spec :: Gem::Specification
# dependency :: Gem::Dependency
def ensure_dependency(spec, dependency)
unless installation_satisfies_dependency? dependency then
raise Gem::InstallError, "#{spec.name} requires #{dependency}"
@ -170,17 +179,15 @@ class Gem::Installer
end
##
# True if the current installed gems satisfy the given dependency.
#
# dependency :: Gem::Dependency
# True if the gems in Gem.source_index satisfy +dependency+.
def installation_satisfies_dependency?(dependency)
current_index = Gem::SourceIndex.from_installed_gems
current_index.find_name(dependency.name, dependency.version_requirements).size > 0
Gem.source_index.find_name(dependency.name, dependency.version_requirements).size > 0
end
##
# Unpacks the gem into the given directory.
#
def unpack(directory)
@gem_dir = directory
@format = Gem::Format.from_file_by_path @gem, @security_policy
@ -193,7 +200,7 @@ class Gem::Installer
#
# spec:: [Gem::Specification] The Gem specification to output
# spec_path:: [String] The location (path) to write the gemspec to
#
def write_spec
rubycode = @spec.to_ruby
@ -208,7 +215,7 @@ class Gem::Installer
##
# Creates windows .bat files for easy running of commands
#
def generate_windows_script(bindir, filename)
if Gem.win_platform? then
script_name = filename + ".bat"
@ -227,7 +234,7 @@ class Gem::Installer
# If the user has asked for the gem to be installed in a directory that is
# the system gem directory, then use the system bin directory, else create
# (or use) a new bin dir under the gem_home.
bindir = @bin_dir ? @bin_dir : (Gem.bindir @gem_home)
bindir = @bin_dir ? @bin_dir : Gem.bindir(@gem_home)
Dir.mkdir bindir unless File.exist? bindir
raise Gem::FilePermissionError.new(bindir) unless File.writable? bindir
@ -252,7 +259,7 @@ class Gem::Installer
# The Windows script is generated in addition to the regular one due to a
# bug or misfeature in the Windows shell's pipe. See
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/193379
#
def generate_bin_script(filename, bindir)
bin_script_path = File.join bindir, formatted_program_filename(filename)
@ -260,6 +267,8 @@ class Gem::Installer
# HACK some gems don't have #! in their executables, restore 2008/06
#if File.read(exec_path, 2) == '#!' then
FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
File.open bin_script_path, 'w', 0755 do |file|
file.print app_script_text(filename)
end
@ -277,7 +286,7 @@ class Gem::Installer
##
# Creates the symlinks to run the applications in the gem. Moves
# the symlink if the gem being installed has a newer version.
#
def generate_bin_symlink(filename, bindir)
if Gem.win_platform? then
alert_warning "Unable to use symlinks on Windows, installing wrapper"
@ -303,6 +312,7 @@ class Gem::Installer
##
# Generates a #! line for +bin_file_name+'s wrapper copying arguments if
# necessary.
def shebang(bin_file_name)
if @env_shebang then
"#!/usr/bin/env " + Gem::ConfigMap[:ruby_install_name]
@ -324,7 +334,9 @@ class Gem::Installer
end
end
##
# Return the text for an application file.
def app_script_text(bin_file_name)
<<-TEXT
#{shebang bin_file_name}
@ -349,7 +361,9 @@ load '#{bin_file_name}'
TEXT
end
##
# return the stub script text used to launch the true ruby script
def windows_stub_script(bindir, bin_file_name)
<<-TEXT
@ECHO OFF
@ -361,8 +375,10 @@ GOTO :EOF
TEXT
end
##
# Builds extensions. Valid types of extensions are extconf.rb files,
# configure scripts and rakefiles or mkrf_conf files.
def build_extensions
return if @spec.extensions.empty?
say "Building native extensions. This could take a while..."
@ -418,6 +434,7 @@ Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
# Reads the file index and extracts each file into the gem directory.
#
# Ensures that files can't be installed outside the gem directory.
def extract_files
expand_and_validate_gem_dir
@ -445,11 +462,15 @@ Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
out.write file_data
end
FileUtils.chmod entry['mode'], path
say path if Gem.configuration.really_verbose
end
end
##
# Prefix and suffix the program filename the same as ruby.
def formatted_program_filename(filename)
if @format_executable then
self.class.exec_format % File.basename(filename)
@ -460,7 +481,9 @@ Results logged to #{File.join(Dir.pwd, 'gem_make.out')}
private
##
# HACK Pathname is broken on windows.
def absolute_path? pathname
pathname.absolute? or (Gem.win_platform? and pathname.to_s =~ /\A[a-z]:/i)
end

View file

@ -4,27 +4,34 @@
# See LICENSE.txt for permissions.
#++
require 'uri'
require 'rubygems'
##
# Mixin methods for local and remote Gem::Command options.
module Gem::LocalRemoteOptions
##
# Allows OptionParser to handle HTTP URIs.
def accept_uri_http
OptionParser.accept URI::HTTP do |value|
begin
value = URI.parse value
uri = URI.parse value
rescue URI::InvalidURIError
raise OptionParser::InvalidArgument, value
end
raise OptionParser::InvalidArgument, value unless value.scheme == 'http'
raise OptionParser::InvalidArgument, value unless uri.scheme == 'http'
value
end
end
##
# Add local/remote options to the command line parser.
def add_local_remote_options
add_option(:"Local/Remote", '-l', '--local',
'Restrict operations to the LOCAL domain') do |value, options|
@ -47,7 +54,9 @@ module Gem::LocalRemoteOptions
add_update_sources_option
end
##
# Add the --bulk-threshold option
def add_bulk_threshold_option
add_option(:"Local/Remote", '-B', '--bulk-threshold COUNT',
"Threshold for switching to bulk",
@ -57,7 +66,9 @@ module Gem::LocalRemoteOptions
end
end
##
# Add the --http-proxy option
def add_proxy_option
accept_uri_http
@ -68,22 +79,28 @@ module Gem::LocalRemoteOptions
end
end
##
# Add the --source option
def add_source_option
accept_uri_http
add_option(:"Local/Remote", '--source URL', URI::HTTP,
'Use URL as the remote source for gems') do |value, options|
'Use URL as the remote source for gems') do |source, options|
source << '/' if source !~ /\/\z/
if options[:added_source] then
Gem.sources << value
Gem.sources << source
else
options[:added_source] = true
Gem.sources.replace [value]
Gem.sources.replace [source]
end
end
end
##
# Add the --source option
def add_update_sources_option
add_option(:"Local/Remote", '-u', '--[no-]update-sources',
@ -92,12 +109,16 @@ module Gem::LocalRemoteOptions
end
end
##
# Is local fetching enabled?
def local?
options[:domain] == :local || options[:domain] == :both
end
##
# Is remote fetching enabled?
def remote?
options[:domain] == :remote || options[:domain] == :both
end

View file

@ -1,7 +1,8 @@
require 'rubygems'
##
# Available list of platforms for targeting Gem installations.
#
class Gem::Platform
@local = nil
@ -122,11 +123,20 @@ class Gem::Platform
to_a.compact.join '-'
end
##
# Is +other+ equal to this platform? Two platforms are equal if they have
# the same CPU, OS and version.
def ==(other)
self.class === other and
@cpu == other.cpu and @os == other.os and @version == other.version
end
##
# Does +other+ match this platform? Two platforms match if they have the
# same CPU, or either has a CPU of 'universal', they have the same OS, and
# they have the same version, or either has no version.
def ===(other)
return nil unless Gem::Platform === other
@ -140,6 +150,10 @@ class Gem::Platform
(@version.nil? or other.version.nil? or @version == other.version)
end
##
# Does +other+ match this platform? If +other+ is a String it will be
# converted to a Gem::Platform first. See #=== for matching rules.
def =~(other)
case other
when Gem::Platform then # nop

View file

@ -1,4 +1,5 @@
require 'net/http'
require 'stringio'
require 'uri'
require 'rubygems'
@ -11,15 +12,38 @@ class Gem::RemoteFetcher
include Gem::UserInteraction
class FetchError < Gem::Exception; end
##
# A FetchError exception wraps up the various possible IO and HTTP failures
# that could happen while downloading from the internet.
class FetchError < Gem::Exception
##
# The URI which was being accessed when the exception happened.
attr_accessor :uri
def initialize(message, uri)
super message
@uri = uri
end
def to_s # :nodoc:
"#{super} (#{uri})"
end
end
@fetcher = nil
##
# Cached RemoteFetcher instance.
def self.fetcher
@fetcher ||= self.new Gem.configuration[:http_proxy]
end
##
# Initialize a remote fetcher using the source URI and possible proxy
# information.
#
@ -29,6 +53,7 @@ class Gem::RemoteFetcher
# * nil: respect environment variables (HTTP_PROXY, HTTP_PROXY_USER,
# HTTP_PROXY_PASS)
# * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
def initialize(proxy)
Socket.do_not_reverse_lookup = true
@ -47,11 +72,13 @@ class Gem::RemoteFetcher
# Moves the gem +spec+ from +source_uri+ to the cache dir unless it is
# already there. If the source_uri is local the gem cache dir copy is
# always replaced.
def download(spec, source_uri, install_dir = Gem.dir)
gem_file_name = "#{spec.full_name}.gem"
local_gem_path = File.join install_dir, 'cache', gem_file_name
Gem.ensure_gem_subdirectories install_dir
def download(spec, source_uri, install_dir = Gem.dir)
cache_dir = File.join install_dir, 'cache'
gem_file_name = "#{spec.full_name}.gem"
local_gem_path = File.join cache_dir, gem_file_name
FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir
source_uri = URI.parse source_uri unless URI::Generic === source_uri
scheme = source_uri.scheme
@ -102,21 +129,26 @@ class Gem::RemoteFetcher
local_gem_path
end
# Downloads +uri+.
##
# Downloads +uri+ and returns it as a String.
def fetch_path(uri)
open_uri_or_path(uri) do |input|
input.read
end
rescue FetchError
raise
rescue Timeout::Error
raise FetchError, "timed out fetching #{uri}"
raise FetchError.new('timed out', uri)
rescue IOError, SocketError, SystemCallError => e
raise FetchError, "#{e.class}: #{e} reading #{uri}"
raise FetchError.new("#{e.class}: #{e}", uri)
rescue => e
message = "#{e.class}: #{e} reading #{uri}"
raise FetchError, message
raise FetchError.new("#{e.class}: #{e}", uri)
end
##
# Returns the size of +uri+ in bytes.
def fetch_size(uri)
return File.size(get_file_uri_path(uri)) if file_uri? uri
@ -124,30 +156,21 @@ class Gem::RemoteFetcher
raise ArgumentError, 'uri is not an HTTP URI' unless URI::HTTP === uri
http = connect_to uri.host, uri.port
response = request uri, Net::HTTP::Head
request = Net::HTTP::Head.new uri.request_uri
request.basic_auth unescape(uri.user), unescape(uri.password) unless
uri.user.nil? or uri.user.empty?
resp = http.request request
if resp.code !~ /^2/ then
raise Gem::RemoteSourceException,
"HTTP Response #{resp.code} fetching #{uri}"
if response.code !~ /^2/ then
raise FetchError.new("bad response #{response.message} #{response.code}", uri)
end
if resp['content-length'] then
return resp['content-length'].to_i
if response['content-length'] then
return response['content-length'].to_i
else
resp = http.get uri.request_uri
return resp.body.size
response = http.get uri.request_uri
return response.body.size
end
rescue SocketError, SystemCallError, Timeout::Error => e
raise Gem::RemoteFetcher::FetchError,
"#{e.message} (#{e.class})\n\tgetting size of #{uri}"
raise FetchError.new("#{e.message} (#{e.class})\n\tfetching size", uri)
end
private
@ -162,7 +185,9 @@ class Gem::RemoteFetcher
URI.unescape(str)
end
##
# Returns an HTTP proxy URI if one is set in the environment variables.
def get_proxy_from_env
env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
@ -179,104 +204,129 @@ class Gem::RemoteFetcher
uri
end
##
# Normalize the URI by adding "http://" if it is missing.
def normalize_uri(uri)
(uri =~ /^(https?|ftp|file):/) ? uri : "http://#{uri}"
end
# Connect to the source host/port, using a proxy if needed.
def connect_to(host, port)
if @proxy_uri
Net::HTTP::Proxy(@proxy_uri.host, @proxy_uri.port, unescape(@proxy_uri.user), unescape(@proxy_uri.password)).new(host, port)
else
Net::HTTP.new(host, port)
##
# Creates or an HTTP connection based on +uri+, or retrieves an existing
# connection, using a proxy if needed.
def connection_for(uri)
net_http_args = [uri.host, uri.port]
if @proxy_uri then
net_http_args += [
@proxy_uri.host,
@proxy_uri.port,
@proxy_uri.user,
@proxy_uri.password
]
end
connection_id = net_http_args.join ':'
@connections[connection_id] ||= Net::HTTP.new(*net_http_args)
connection = @connections[connection_id]
if uri.scheme == 'https' and not connection.started? then
http_obj.use_ssl = true
http_obj.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
connection.start unless connection.started?
connection
end
##
# Read the data from the (source based) URI, but if it is a file:// URI,
# read from the filesystem instead.
def open_uri_or_path(uri, depth = 0, &block)
if file_uri?(uri)
open(get_file_uri_path(uri), &block)
else
uri = URI.parse uri unless URI::Generic === uri
net_http_args = [uri.host, uri.port]
if @proxy_uri then
net_http_args += [ @proxy_uri.host,
@proxy_uri.port,
@proxy_uri.user,
@proxy_uri.password
]
end
connection_id = net_http_args.join ':'
@connections[connection_id] ||= Net::HTTP.new(*net_http_args)
connection = @connections[connection_id]
if uri.scheme == 'https' && ! connection.started?
http_obj.use_ssl = true
http_obj.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
connection.start unless connection.started?
request = Net::HTTP::Get.new(uri.request_uri)
unless uri.nil? || uri.user.nil? || uri.user.empty? then
request.basic_auth(uri.user, uri.password)
end
ua = "RubyGems/#{Gem::RubyGemsVersion} #{Gem::Platform.local}"
ua << " Ruby/#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
ua << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
ua << ")"
request.add_field 'User-Agent', ua
request.add_field 'Connection', 'keep-alive'
request.add_field 'Keep-Alive', '30'
# HACK work around EOFError bug in Net::HTTP
# NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
# to install gems.
retried = false
begin
@requests[connection_id] += 1
response = connection.request(request)
rescue EOFError, Errno::ECONNABORTED
requests = @requests[connection_id]
say "connection reset after #{requests} requests, retrying" if
Gem.configuration.really_verbose
raise Gem::RemoteFetcher::FetchError, 'too many connection resets' if
retried
@requests[connection_id] = 0
connection.finish
connection.start
retried = true
retry
end
response = request uri
case response
when Net::HTTPOK then
block.call(StringIO.new(response.body)) if block
when Net::HTTPRedirection then
raise Gem::RemoteFetcher::FetchError, "too many redirects" if depth > 10
raise FetchError.new('too many redirects', uri) if depth > 10
open_uri_or_path(response['Location'], depth + 1, &block)
else
raise Gem::RemoteFetcher::FetchError,
"bad response #{response.message} #{response.code}"
raise FetchError.new("bad response #{response.message} #{response.code}", uri)
end
end
end
##
# Performs a Net::HTTP request of type +request_class+ on +uri+ returning
# a Net::HTTP response object. request maintains a table of persistent
# connections to reduce connect overhead.
def request(uri, request_class = Net::HTTP::Get)
request = request_class.new uri.request_uri
unless uri.nil? || uri.user.nil? || uri.user.empty? then
request.basic_auth uri.user, uri.password
end
ua = "RubyGems/#{Gem::RubyGemsVersion} #{Gem::Platform.local}"
ua << " Ruby/#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
ua << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
ua << ")"
request.add_field 'User-Agent', ua
request.add_field 'Connection', 'keep-alive'
request.add_field 'Keep-Alive', '30'
connection = connection_for uri
retried = false
# HACK work around EOFError bug in Net::HTTP
# NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
# to install gems.
begin
@requests[connection.object_id] += 1
response = connection.request request
say "#{request.method} #{response.code} #{response.message}: #{uri}" if
Gem.configuration.really_verbose
rescue EOFError, Errno::ECONNABORTED, Errno::ECONNRESET
requests = @requests[connection.object_id]
say "connection reset after #{requests} requests, retrying" if
Gem.configuration.really_verbose
raise FetchError.new('too many connection resets', uri) if retried
@requests.delete connection.object_id
connection.finish
connection.start
retried = true
retry
end
response
end
##
# Checks if the provided string is a file:// URI.
def file_uri?(uri)
uri =~ %r{\Afile://}
end
##
# Given a file:// URI, returns its local path.
def get_file_uri_path(uri)
uri.sub(%r{\Afile://}, '')
end

View file

@ -12,6 +12,7 @@ require 'rubygems/version'
#
# A Requirement object can actually contain multiple, er,
# requirements, as in (> 1.2, < 2.0).
class Gem::Requirement
include Comparable
@ -35,7 +36,7 @@ class Gem::Requirement
# Version, a String, or nil. Intended to simplify client code.
#
# If the input is "weird", the default version requirement is returned.
#
def self.create(input)
case input
when Gem::Requirement then
@ -57,6 +58,7 @@ class Gem::Requirement
# This comment once said:
#
# "A default "version requirement" can surely _only_ be '> 0'."
def self.default
self.new ['>= 0']
end
@ -65,6 +67,7 @@ class Gem::Requirement
# Constructs a Requirement from +requirements+ which can be a String, a
# Gem::Version, or an Array of those. See parse for details on the
# formatting of requirement strings.
def initialize(requirements)
@requirements = case requirements
when Array then
@ -77,13 +80,17 @@ class Gem::Requirement
@version = nil # Avoid warnings.
end
##
# Marshal raw requirements, rather than the full object
def marshal_dump
def marshal_dump # :nodoc:
[@requirements]
end
##
# Load custom marshal format
def marshal_load(array)
def marshal_load(array) # :nodoc:
@requirements = array[0]
@version = nil
end
@ -108,20 +115,16 @@ class Gem::Requirement
end
##
# Is the requirement satisfied by +version+.
#
# version:: [Gem::Version] the version to compare against
# return:: [Boolean] true if this requirement is satisfied by
# the version, otherwise false
#
# True if this requirement satisfied by the Gem::Version +version+.
def satisfied_by?(version)
normalize
@requirements.all? { |op, rv| satisfy?(op, version, rv) }
end
##
# Is "version op required_version" satisfied?
#
# Is "+version+ +op+ +required_version+" satisfied?
def satisfy?(op, version, required_version)
OPS[op].call(version, required_version)
end
@ -132,6 +135,7 @@ class Gem::Requirement
# The requirement can be a String or a Gem::Version. A String can be an
# operator (<, <=, =, =>, >, !=, ~>), a version number, or both, operator
# first.
def parse(obj)
case obj
when /^\s*(#{OP_RE})\s*([0-9.]+)\s*$/o then
@ -147,7 +151,7 @@ class Gem::Requirement
end
end
def <=>(other)
def <=>(other) # :nodoc:
to_s <=> other.to_s
end

View file

@ -2,5 +2,5 @@
# This file is auto-generated by build scripts.
# See: rake update_version
module Gem
RubyGemsVersion = '1.1.1'
RubyGemsVersion = '1.1.1.1778'
end

View file

@ -4,6 +4,7 @@ require 'zlib'
require 'erb'
require 'rubygems'
require 'rubygems/doc_manager'
##
# Gem::Server and allows users to serve gems for consumption by
@ -11,18 +12,24 @@ require 'rubygems'
#
# gem_server starts an HTTP server on the given port and serves the following:
# * "/" - Browsing of gem spec files for installed gems
# * "/Marshal" - Full SourceIndex dump of metadata for installed gems
# * "/yaml" - YAML dump of metadata for installed gems - deprecated
# * "/specs.#{Gem.marshal_version}.gz" - specs name/version/platform index
# * "/latest_specs.#{Gem.marshal_version}.gz" - latest specs
# name/version/platform index
# * "/quick/" - Individual gemspecs
# * "/gems" - Direct access to download the installable gems
# * legacy indexes:
# * "/Marshal.#{Gem.marshal_version}" - Full SourceIndex dump of metadata
# for installed gems
# * "/yaml" - YAML dump of metadata for installed gems - deprecated
#
# == Usage
#
# gem server [-p portnum] [-d gem_path]
# gem_server = Gem::Server.new Gem.dir, 8089, false
# gem_server.run
#
# port_num:: The TCP port the HTTP server will bind to
# gem_path::
# Root gem directory containing both "cache" and "specifications"
# subdirectories.
#--
# TODO Refactor into a real WEBrick servlet to remove code duplication.
class Gem::Server
include Gem::UserInteraction
@ -36,7 +43,6 @@ class Gem::Server
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>RubyGems Documentation Index</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
</head>
<body>
@ -325,32 +331,99 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
new(options[:gemdir], options[:port], options[:daemon]).run
end
def initialize(gemdir, port, daemon)
def initialize(gem_dir, port, daemon)
Socket.do_not_reverse_lookup = true
@gemdir = gemdir
@gem_dir = gem_dir
@port = port
@daemon = daemon
logger = WEBrick::Log.new nil, WEBrick::BasicLog::FATAL
@server = WEBrick::HTTPServer.new :DoNotListen => true, :Logger => logger
@spec_dir = File.join @gemdir, "specifications"
@spec_dir = File.join @gem_dir, 'specifications'
unless File.directory? @spec_dir then
raise ArgumentError, "#{@gem_dir} does not appear to be a gem repository"
end
@source_index = Gem::SourceIndex.from_gems_in @spec_dir
end
def Marshal(req, res)
@source_index.refresh!
res['date'] = File.stat(@spec_dir).mtime
index = Marshal.dump @source_index
if req.request_method == 'HEAD' then
res['content-length'] = index.length
return
end
if req.path =~ /Z$/ then
res['content-type'] = 'application/x-deflate'
index = Gem.deflate index
else
res['content-type'] = 'application/octet-stream'
end
res.body << index
end
def latest_specs(req, res)
@source_index.refresh!
res['content-type'] = 'application/x-gzip'
res['date'] = File.stat(@spec_dir).mtime
specs = @source_index.latest_specs.sort.map do |spec|
platform = spec.original_platform
platform = Gem::Platform::RUBY if platform.nil?
[spec.name, spec.version, platform]
end
specs = Marshal.dump specs
if req.path =~ /\.gz$/ then
specs = Gem.gzip specs
res['content-type'] = 'application/x-gzip'
else
res['content-type'] = 'application/octet-stream'
end
if req.request_method == 'HEAD' then
res['content-length'] = specs.length
else
res.body << specs
end
end
def quick(req, res)
@source_index.refresh!
res['content-type'] = 'text/plain'
res['date'] = File.stat(@spec_dir).mtime
case req.request_uri.request_uri
case req.request_uri.path
when '/quick/index' then
res.body << @source_index.map { |name,_| name }.join("\n")
res.body << @source_index.map { |name,| name }.sort.join("\n")
when '/quick/index.rz' then
index = @source_index.map { |name,_| name }.join("\n")
res.body << Zlib::Deflate.deflate(index)
index = @source_index.map { |name,| name }.sort.join("\n")
res['content-type'] = 'application/x-deflate'
res.body << Gem.deflate(index)
when '/quick/latest_index' then
index = @source_index.latest_specs.map { |spec| spec.full_name }
res.body << index.sort.join("\n")
when '/quick/latest_index.rz' then
index = @source_index.latest_specs.map { |spec| spec.full_name }
res['content-type'] = 'application/x-deflate'
res.body << Gem.deflate(index.sort.join("\n"))
when %r|^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)-([0-9.]+)(-.*?)?\.gemspec\.rz$| then
dep = Gem::Dependency.new $2, $3
specs = @source_index.search dep
marshal_format = $1
selector = [$2, $3, $4].map { |s| s.inspect }.join ' '
@ -368,17 +441,98 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
elsif specs.length > 1 then
res.status = 500
res.body = "Multiple gems found matching #{selector}"
elsif $1 then # marshal quickindex instead of YAML
res.body << Zlib::Deflate.deflate(Marshal.dump(specs.first))
elsif marshal_format then
res['content-type'] = 'application/x-deflate'
res.body << Gem.deflate(Marshal.dump(specs.first))
else # deprecated YAML format
res.body << Zlib::Deflate.deflate(specs.first.to_yaml)
res['content-type'] = 'application/x-deflate'
res.body << Gem.deflate(specs.first.to_yaml)
end
else
res.status = 404
res.body = "#{req.request_uri} not found"
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
end
end
def root(req, res)
@source_index.refresh!
res['date'] = File.stat(@spec_dir).mtime
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." unless
req.path == '/'
specs = []
total_file_count = 0
@source_index.each do |path, spec|
total_file_count += spec.files.size
deps = spec.dependencies.map do |dep|
{ "name" => dep.name,
"type" => dep.type,
"version" => dep.version_requirements.to_s, }
end
deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] }
deps.last["is_last"] = true unless deps.empty?
# executables
executables = spec.executables.sort.collect { |exec| {"executable" => exec} }
executables = nil if executables.empty?
executables.last["is_last"] = true if executables
specs << {
"authors" => spec.authors.sort.join(", "),
"date" => spec.date.to_s,
"dependencies" => deps,
"doc_path" => "/doc_root/#{spec.full_name}/rdoc/index.html",
"executables" => executables,
"only_one_executable" => (executables && executables.size == 1),
"full_name" => spec.full_name,
"has_deps" => !deps.empty?,
"homepage" => spec.homepage,
"name" => spec.name,
"rdoc_installed" => Gem::DocManager.new(spec).rdoc_installed?,
"summary" => spec.summary,
"version" => spec.version.to_s,
}
end
specs << {
"authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others",
"dependencies" => [],
"doc_path" => "/doc_root/rubygems-#{Gem::RubyGemsVersion}/rdoc/index.html",
"executables" => [{"executable" => 'gem', "is_last" => true}],
"only_one_executable" => true,
"full_name" => "rubygems-#{Gem::RubyGemsVersion}",
"has_deps" => false,
"homepage" => "http://rubygems.org/",
"name" => 'rubygems',
"rdoc_installed" => true,
"summary" => "RubyGems itself",
"version" => Gem::RubyGemsVersion,
}
specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] }
specs.last["is_last"] = true
# tag all specs with first_name_entry
last_spec = nil
specs.each do |spec|
is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase)
spec["first_name_entry"] = is_first
last_spec = spec
end
# create page from template
template = ERB.new(DOC_TEMPLATE)
res['content-type'] = 'text/html'
values = { "gem_count" => specs.size.to_s, "specs" => specs,
"total_file_count" => total_file_count.to_s }
result = template.result binding
res.body = result
end
def run
@server.listen nil, @port
@ -386,27 +540,21 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
WEBrick::Daemon.start if @daemon
@server.mount_proc("/yaml") do |req, res|
res['content-type'] = 'text/plain'
res['date'] = File.stat(@spec_dir).mtime
if req.request_method == 'HEAD' then
res['content-length'] = @source_index.to_yaml.length
else
res.body << @source_index.to_yaml
end
end
@server.mount_proc "/yaml", method(:yaml)
@server.mount_proc "/yaml.Z", method(:yaml)
@server.mount_proc("/Marshal") do |req, res|
res['content-type'] = 'text/plain'
res['date'] = File.stat(@spec_dir).mtime
if req.request_method == 'HEAD' then
res['content-length'] = Marshal.dump(@source_index).length
else
res.body << Marshal.dump(@source_index)
end
end
@server.mount_proc "/Marshal.#{Gem.marshal_version}", method(:Marshal)
@server.mount_proc "/Marshal.#{Gem.marshal_version}.Z", method(:Marshal)
@server.mount_proc("/quick/", &method(:quick))
@server.mount_proc "/specs.#{Gem.marshal_version}", method(:specs)
@server.mount_proc "/specs.#{Gem.marshal_version}.gz", method(:specs)
@server.mount_proc "/latest_specs.#{Gem.marshal_version}",
method(:latest_specs)
@server.mount_proc "/latest_specs.#{Gem.marshal_version}.gz",
method(:latest_specs)
@server.mount_proc "/quick/", method(:quick)
@server.mount_proc("/gem-server-rdoc-style.css") do |req, res|
res['content-type'] = 'text/css'
@ -414,80 +562,12 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
res.body << RDOC_CSS
end
@server.mount_proc("/") do |req, res|
specs = []
total_file_count = 0
@source_index.each do |path, spec|
total_file_count += spec.files.size
deps = spec.dependencies.collect { |dep|
{ "name" => dep.name,
"version" => dep.version_requirements.to_s, }
}
deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] }
deps.last["is_last"] = true unless deps.empty?
# executables
executables = spec.executables.sort.collect { |exec| {"executable" => exec} }
executables = nil if executables.empty?
executables.last["is_last"] = true if executables
specs << {
"authors" => spec.authors.sort.join(", "),
"date" => spec.date.to_s,
"dependencies" => deps,
"doc_path" => ('/doc_root/' + spec.full_name + '/rdoc/index.html'),
"executables" => executables,
"only_one_executable" => (executables && executables.size==1),
"full_name" => spec.full_name,
"has_deps" => !deps.empty?,
"homepage" => spec.homepage,
"name" => spec.name,
"rdoc_installed" => Gem::DocManager.new(spec).rdoc_installed?,
"summary" => spec.summary,
"version" => spec.version.to_s,
}
end
specs << {
"authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others",
"dependencies" => [],
"doc_path" => "/doc_root/rubygems-#{Gem::RubyGemsVersion}/rdoc/index.html",
"executables" => [{"executable" => 'gem', "is_last" => true}],
"only_one_executable" => true,
"full_name" => "rubygems-#{Gem::RubyGemsVersion}",
"has_deps" => false,
"homepage" => "http://rubygems.org/",
"name" => 'rubygems',
"rdoc_installed" => true,
"summary" => "RubyGems itself",
"version" => Gem::RubyGemsVersion,
}
specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] }
specs.last["is_last"] = true
# tag all specs with first_name_entry
last_spec = nil
specs.each do |spec|
is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase)
spec["first_name_entry"] = is_first
last_spec = spec
end
# create page from template
template = ERB.new(DOC_TEMPLATE)
res['content-type'] = 'text/html'
values = { "gem_count" => specs.size.to_s, "specs" => specs,
"total_file_count" => total_file_count.to_s }
result = template.result binding
res.body = result
end
@server.mount_proc "/", method(:root)
paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }
paths.each do |mount_point, mount_dir|
@server.mount(mount_point, WEBrick::HTTPServlet::FileHandler,
File.join(@gemdir, mount_dir), true)
File.join(@gem_dir, mount_dir), true)
end
trap("INT") { @server.shutdown; exit! }
@ -496,5 +576,54 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
@server.start
end
def specs(req, res)
@source_index.refresh!
res['date'] = File.stat(@spec_dir).mtime
specs = @source_index.sort.map do |_, spec|
platform = spec.original_platform
platform = Gem::Platform::RUBY if platform.nil?
[spec.name, spec.version, platform]
end
specs = Marshal.dump specs
if req.path =~ /\.gz$/ then
specs = Gem.gzip specs
res['content-type'] = 'application/x-gzip'
else
res['content-type'] = 'application/octet-stream'
end
if req.request_method == 'HEAD' then
res['content-length'] = specs.length
else
res.body << specs
end
end
def yaml(req, res)
@source_index.refresh!
res['date'] = File.stat(@spec_dir).mtime
index = @source_index.to_yaml
if req.path =~ /Z$/ then
res['content-type'] = 'application/x-deflate'
index = Gem.deflate index
else
res['content-type'] = 'text/plain'
end
if req.request_method == 'HEAD' then
res['content-length'] = index.length
return
end
res.body << index
end
end

View file

@ -7,6 +7,7 @@
require 'rubygems'
require 'rubygems/user_interaction'
require 'rubygems/specification'
require 'rubygems/spec_fetcher'
##
# The SourceIndex object indexes all the gems available from a
@ -27,6 +28,11 @@ class Gem::SourceIndex
attr_reader :gems # :nodoc:
##
# Directories to use to refresh this SourceIndex when calling refresh!
attr_accessor :spec_dirs
class << self
include Gem::UserInteraction
@ -39,7 +45,7 @@ class Gem::SourceIndex
# +from_gems_in+. This argument is deprecated and is provided
# just for backwards compatibility, and should not generally
# be used.
#
#
# return::
# SourceIndex instance
@ -63,7 +69,9 @@ class Gem::SourceIndex
# +spec_dirs+.
def from_gems_in(*spec_dirs)
self.new.load_gems_in(*spec_dirs)
source_index = new
source_index.spec_dirs = spec_dirs
source_index.refresh!
end
##
@ -79,6 +87,8 @@ class Gem::SourceIndex
return gemspec
end
alert_warning "File '#{file_name}' does not evaluate to a gem specification"
rescue SignalException, SystemExit
raise
rescue SyntaxError => e
alert_warning e
alert_warning spec_code
@ -100,6 +110,7 @@ class Gem::SourceIndex
def initialize(specifications={})
@gems = specifications
@spec_dirs = nil
end
##
@ -121,8 +132,8 @@ class Gem::SourceIndex
end
##
# Returns a Hash of name => Specification of the latest versions of each
# gem in this index.
# Returns an Array specifications for the latest versions of each gem in
# this index.
def latest_specs
result = Hash.new { |h,k| h[k] = [] }
@ -241,7 +252,9 @@ class Gem::SourceIndex
when Gem::Dependency then
only_platform = platform_only
version_requirement = gem_pattern.version_requirements
gem_pattern = if gem_pattern.name.empty? then
gem_pattern = if Regexp === gem_pattern.name then
gem_pattern.name
elsif gem_pattern.name.empty? then
//
else
/^#{Regexp.escape gem_pattern.name}$/
@ -271,29 +284,43 @@ class Gem::SourceIndex
##
# Replaces the gems in the source index from specifications in the
# installed_spec_directories,
# directories this source index was created from. Raises an exception if
# this source index wasn't created from a directory (via from_gems_in or
# from_installed_gems, or having spec_dirs set).
def refresh!
load_gems_in(*self.class.installed_spec_directories)
raise 'source index not created from disk' if @spec_dirs.nil?
load_gems_in(*@spec_dirs)
end
##
# Returns an Array of Gem::Specifications that are not up to date.
def outdated
dep = Gem::Dependency.new '', Gem::Requirement.default
remotes = Gem::SourceInfoCache.search dep, true
outdateds = []
latest_specs.each do |local|
name = local.name
remote = remotes.select { |spec| spec.name == name }.
sort_by { |spec| spec.version.to_ints }.
last
outdateds << name if remote and local.version < remote.version
dependency = Gem::Dependency.new name, ">= #{local.version}"
begin
fetcher = Gem::SpecFetcher.fetcher
remotes = fetcher.find_matching dependency
remotes = remotes.map { |(name, version,),| version }
rescue Gem::RemoteFetcher::FetchError => e
raise unless fetcher.warn_legacy e do
require 'rubygems/source_info_cache'
specs = Gem::SourceInfoCache.search_with_source dependency, true
remotes = specs.map { |spec,| spec.version }
end
end
latest = remotes.sort.last
outdateds << name if latest and local.version < latest
end
outdateds
@ -387,7 +414,8 @@ class Gem::SourceIndex
end
def fetch_bulk_index(source_uri)
say "Bulk updating Gem source index for: #{source_uri}"
say "Bulk updating Gem source index for: #{source_uri}" if
Gem.configuration.verbose
index = fetch_index_from(source_uri)
if index.nil? then
@ -447,7 +475,7 @@ class Gem::SourceIndex
def unzip(string)
require 'zlib'
Zlib::Inflate.inflate(string)
Gem.inflate string
end
##

View file

@ -0,0 +1,251 @@
require 'zlib'
require 'rubygems'
require 'rubygems/remote_fetcher'
require 'rubygems/user_interaction'
##
# SpecFetcher handles metadata updates from remote gem repositories.
class Gem::SpecFetcher
include Gem::UserInteraction
##
# The SpecFetcher cache dir.
attr_reader :dir # :nodoc:
##
# Cache of latest specs
attr_reader :latest_specs # :nodoc:
##
# Cache of all spces
attr_reader :specs # :nodoc:
@fetcher = nil
def self.fetcher
@fetcher ||= new
end
def self.fetcher=(fetcher) # :nodoc:
@fetcher = fetcher
end
def initialize
@dir = File.join Gem.user_home, '.gem', 'specs'
@update_cache = File.stat(Gem.user_home).uid == Process.uid
@specs = {}
@latest_specs = {}
@fetcher = Gem::RemoteFetcher.fetcher
end
##
# Retuns the local directory to write +uri+ to.
def cache_dir(uri)
File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(uri.path)
end
##
# Fetch specs matching +dependency+. If +all+ is true, all matching
# versions are returned. If +matching_platform+ is false, all platforms are
# returned.
def fetch(dependency, all = false, matching_platform = true)
specs_and_sources = find_matching dependency, all, matching_platform
specs_and_sources.map do |spec_tuple, source_uri|
[fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
end
rescue Gem::RemoteFetcher::FetchError => e
raise unless warn_legacy e do
require 'rubygems/source_info_cache'
return Gem::SourceInfoCache.search_with_source(dependency,
matching_platform, all)
end
end
def fetch_spec(spec, source_uri)
spec = spec - [nil, 'ruby', '']
spec_file_name = "#{spec.join '-'}.gemspec"
uri = source_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
else
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
end
# TODO: Investigate setting Gem::Specification#loaded_from to a URI
Marshal.load spec
end
##
# Find spec names that match +dependency+. If +all+ is true, all matching
# versions are returned. If +matching_platform+ is false, gems for all
# platforms are returned.
def find_matching(dependency, all = false, matching_platform = true)
found = {}
list(all).each do |source_uri, specs|
found[source_uri] = specs.select do |spec_name, version, spec_platform|
dependency =~ Gem::Dependency.new(spec_name, version) and
(not matching_platform or Gem::Platform.match(spec_platform))
end
end
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
end
##
# Returns Array of gem repositories that were generated with RubyGems less
# than 1.2.
def legacy_repos
Gem.sources.reject do |source_uri|
source_uri = URI.parse source_uri
spec_path = source_uri + "specs.#{Gem.marshal_version}.gz"
begin
@fetcher.fetch_size spec_path
rescue Gem::RemoteFetcher::FetchError
begin
@fetcher.fetch_size(source_uri + 'yaml') # re-raise if non-repo
rescue Gem::RemoteFetcher::FetchError
alert_error "#{source_uri} does not appear to be a repository"
raise
end
false
end
end
end
##
# Returns a list of gems available for each source in Gem::sources. If
# +all+ is true, all versions are returned instead of only latest versions.
def list(all = false)
list = {}
file = all ? 'specs' : 'latest_specs'
Gem.sources.each do |source_uri|
source_uri = URI.parse source_uri
if all and @specs.include? source_uri then
list[source_uri] = @specs[source_uri]
elsif @latest_specs.include? source_uri then
list[source_uri] = @latest_specs[source_uri]
else
specs = load_specs source_uri, file
cache = all ? @specs : @latest_specs
cache[source_uri] = specs
list[source_uri] = specs
end
end
list
end
def load_specs(source_uri, file)
file_name = "#{file}.#{Gem.marshal_version}.gz"
spec_path = source_uri + file_name
cache_dir = cache_dir spec_path
local_file = File.join(cache_dir, file_name).chomp '.gz'
if File.exist? local_file then
local_size = File.stat(local_file).size
remote_file = spec_path.dup
remote_file.path = remote_file.path.chomp '.gz'
remote_size = @fetcher.fetch_size remote_file
spec_dump = Gem.read_binary local_file if remote_size == local_size
end
unless spec_dump then
loaded = true
spec_dump_gz = @fetcher.fetch_path spec_path
spec_dump = Gem.gunzip spec_dump_gz
end
specs = Marshal.load spec_dump
if loaded and @update_cache then
begin
FileUtils.mkdir_p cache_dir
open local_file, 'wb' do |io|
Marshal.dump specs, io
end
rescue
end
end
specs
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.
def warn_legacy(exception)
uri = exception.uri.to_s
if uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ then
alert_warning <<-EOF
RubyGems 1.2+ index not found for:
\t#{legacy_repos.join "\n\t"}
RubyGems will revert to legacy indexes degrading performance.
EOF
yield
return true
end
false
end
end

View file

@ -6,6 +6,7 @@
require 'rubygems'
require 'rubygems/version'
require 'rubygems/requirement'
require 'rubygems/platform'
# :stopdoc:
@ -16,6 +17,9 @@ if RUBY_VERSION < '1.9' then
t - ((t.to_f + t.gmt_offset) % 86400)
end unless defined? Time.today
end
class Date; end # for ruby_code if date.rb wasn't required
# :startdoc:
module Gem
@ -37,22 +41,32 @@ module Gem
#
class Specification
##
# Allows deinstallation of gems with legacy platforms.
attr_accessor :original_platform # :nodoc:
# ------------------------- Specification version constants.
##
# The the version number of a specification that does not specify one
# (i.e. RubyGems 0.7 or earlier).
NONEXISTENT_SPECIFICATION_VERSION = -1
##
# The specification version applied to any new Specification instances
# created. This should be bumped whenever something in the spec format
# changes.
CURRENT_SPECIFICATION_VERSION = 2
#--
# When updating this number, be sure to also update #to_ruby.
CURRENT_SPECIFICATION_VERSION = 3
##
# An informal list of changes to the specification. The highest-valued
# key should be equal to the CURRENT_SPECIFICATION_VERSION.
SPECIFICATION_VERSION_HISTORY = {
-1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'],
1 => [
@ -63,10 +77,13 @@ module Gem
'Added "required_rubygems_version"',
'Now forward-compatible with future versions',
],
3 => [
'Added dependency types',
],
}
# :stopdoc:
MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16 }
MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16, 3 => 16 }
now = Time.at(Time.now.to_i)
TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
@ -335,6 +352,14 @@ module Gem
read_only :dependencies
def runtime_dependencies
dependencies.select { |d| d.type == :runtime || d.type == nil }
end
def development_dependencies
dependencies.select { |d| d.type == :development }
end
# ALIASED gemspec attributes -------------------------------------
attribute_alias_singular :executable, :executables
@ -629,27 +654,31 @@ module Gem
end
end
# Adds a dependency to this Gem. For example,
# Adds a development dependency to this Gem. For example,
#
# spec.add_dependency('jabber4r', '> 0.1', '<= 0.5')
# spec.add_development_dependency('jabber4r', '> 0.1', '<= 0.5')
#
# Development dependencies aren't installed by default, and
# aren't activated when a gem is required.
#
# gem:: [String or Gem::Dependency] The Gem name/dependency.
# requirements:: [default=">= 0"] The version requirements.
#
def add_dependency(gem, *requirements)
requirements = if requirements.empty? then
Gem::Requirement.default
else
requirements.flatten
end
unless gem.respond_to?(:name) && gem.respond_to?(:version_requirements)
gem = Dependency.new(gem, requirements)
end
dependencies << gem
def add_development_dependency(gem, *requirements)
add_dependency_with_type(gem, :development, *requirements)
end
# Adds a runtime dependency to this Gem. For example,
#
# spec.add_runtime_dependency('jabber4r', '> 0.1', '<= 0.5')
#
# gem:: [String or Gem::Dependency] The Gem name/dependency.
# requirements:: [default=">= 0"] The version requirements.
def add_runtime_dependency(gem, *requirements)
add_dependency_with_type(gem, :runtime, *requirements)
end
alias add_dependency add_runtime_dependency
# Returns the full name (name-version) of this Gem. Platform information
# is included (name-version-platform) if it is specified (and not the
# default Ruby platform).
@ -673,30 +702,31 @@ module Gem
end
end
##
# The full path to the gem (install path + full name).
#
# return:: [String] the full gem path
#
def full_gem_path
path = File.join installation_path, 'gems', full_name
return path if File.directory? path
File.join installation_path, 'gems', original_name
end
##
# The default (generated) file name of the gem.
def file_name
full_name + ".gem"
end
# The root directory that the gem was installed into.
#
# return:: [String] the installation path
#
##
# The directory that this gem was installed into.
def installation_path
(File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2]).
join(File::SEPARATOR)
path = File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2]
path = path.join File::SEPARATOR
File.expand_path path
end
# Checks if this Specification meets the requirement of the supplied
# dependency.
#
@ -778,9 +808,11 @@ module Gem
self.platform = Gem::Platform.new @platform
end
##
# Returns a Ruby code representation of this specification, such that it
# can be eval'ed and reconstruct the same specification later. Attributes
# that still have their default values are omitted.
def to_ruby
mark_version
result = []
@ -792,8 +824,6 @@ module Gem
result << " s.platform = #{ruby_code original_platform}"
end
result << ""
result << " s.specification_version = #{specification_version} if s.respond_to? :specification_version="
result << ""
result << " s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version="
handled = [
@ -816,15 +846,42 @@ module Gem
end
end
result << "" unless dependencies.empty?
result << nil
result << " if s.respond_to? :specification_version then"
result << " current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION"
result << " s.specification_version = #{specification_version}"
result << nil
dependencies.each do |dep|
version_reqs_param = dep.requirements_list.inspect
result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
result << " if current_version >= 3 then"
unless dependencies.empty? then
dependencies.each do |dep|
version_reqs_param = dep.requirements_list.inspect
dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{version_reqs_param})"
end
end
result << " else"
unless dependencies.empty? then
dependencies.each do |dep|
version_reqs_param = dep.requirements_list.inspect
result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
end
end
result << ' end'
result << " else"
dependencies.each do |dep|
version_reqs_param = dep.requirements_list.inspect
result << " s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
end
result << " end"
result << "end"
result << ""
result << nil
result.join "\n"
end
@ -940,6 +997,22 @@ module Gem
private
def add_dependency_with_type(dependency, type, *requirements)
requirements = if requirements.empty? then
Gem::Requirement.default
else
requirements.flatten
end
unless dependency.respond_to?(:name) &&
dependency.respond_to?(:version_requirements)
dependency = Dependency.new(dependency, requirements, type)
end
dependencies << dependency
end
def find_all_satisfiers(dep)
Gem.source_index.each do |name,gem|
if(gem.satisfies_requirement?(dep)) then

View file

@ -0,0 +1,120 @@
require 'tempfile'
require 'rubygems'
require 'rubygems/remote_fetcher'
##
# A fake Gem::RemoteFetcher for use in tests or to avoid real live HTTP
# requests when testing code that uses RubyGems.
#
# Example:
#
# @fetcher = Gem::FakeFetcher.new
# @fetcher.data['http://gems.example.com/yaml'] = source_index.to_yaml
# Gem::RemoteFetcher.fetcher = @fetcher
#
# # invoke RubyGems code
#
# paths = @fetcher.paths
# assert_equal 'http://gems.example.com/yaml', paths.shift
# assert paths.empty?, paths.join(', ')
#
# See RubyGems' tests for more examples of FakeFetcher.
class Gem::FakeFetcher
attr_reader :data
attr_accessor :paths
def initialize
@data = {}
@paths = []
end
def fetch_path(path)
path = path.to_s
@paths << path
raise ArgumentError, 'need full URI' unless path =~ %r'^http://'
data = @data[path]
if data.nil? then
raise Gem::RemoteFetcher::FetchError.new('no data', path)
end
data.respond_to?(:call) ? data.call : data
end
def fetch_size(path)
path = path.to_s
@paths << path
raise ArgumentError, 'need full URI' unless path =~ %r'^http://'
data = @data[path]
if data.nil? then
raise Gem::RemoteFetcher::FetchError.new("no data for #{path}", nil)
end
data.respond_to?(:call) ? data.call : data.length
end
def download spec, source_uri, install_dir = Gem.dir
name = "#{spec.full_name}.gem"
path = File.join(install_dir, 'cache', name)
Gem.ensure_gem_subdirectories install_dir
if source_uri =~ /^http/ then
File.open(path, "wb") do |f|
f.write fetch_path(File.join(source_uri, "gems", name))
end
else
FileUtils.cp source_uri, path
end
path
end
end
# :stopdoc:
class Gem::RemoteFetcher
def self.fetcher=(fetcher)
@fetcher = fetcher
end
end
# :startdoc:
##
# A StringIO duck-typed class that uses Tempfile instead of String as the
# backing store.
#--
# This class was added to flush out problems in Rubinius' IO implementation.
class TempIO
@@count = 0
def initialize(string = '')
@tempfile = Tempfile.new "TempIO-#{@@count += 1}"
@tempfile.binmode
@tempfile.write string
@tempfile.rewind
end
def method_missing(meth, *args, &block)
@tempfile.send(meth, *args, &block)
end
def respond_to?(meth)
@tempfile.respond_to? meth
end
def string
@tempfile.flush
Gem.read_binary @tempfile.path
end
end

View file

@ -176,9 +176,10 @@ class Gem::Uninstaller
end
def path_ok?(spec)
match_path = File.join @gem_home, 'gems', spec.full_name
full_path = File.join @gem_home, 'gems', spec.full_name
original_path = File.join @gem_home, 'gems', spec.original_name
match_path == spec.full_gem_path
full_path == spec.full_gem_path || original_path == spec.full_gem_path
end
def dependencies_ok?(spec)

View file

@ -6,54 +6,71 @@
module Gem
####################################################################
# Module that defines the default UserInteraction. Any class
# including this module will have access to the +ui+ method that
# returns the default UI.
##
# Module that defines the default UserInteraction. Any class including this
# module will have access to the +ui+ method that returns the default UI.
module DefaultUserInteraction
##
# The default UI is a class variable of the singleton class for this
# module.
@ui = nil
##
# Return the default UI.
def self.ui
@ui ||= Gem::ConsoleUI.new
end
##
# Set the default UI. If the default UI is never explicitly set, a simple
# console based UserInteraction will be used automatically.
def self.ui=(new_ui)
@ui = new_ui
end
##
# Use +new_ui+ for the duration of +block+.
def self.use_ui(new_ui)
old_ui = @ui
@ui = new_ui
yield
ensure
@ui = old_ui
end
##
# See DefaultUserInteraction::ui
def ui
DefaultUserInteraction.ui
end
# Set the default UI. If the default UI is never explicitly set, a
# simple console based UserInteraction will be used automatically.
##
# See DefaultUserInteraction::ui=
def ui=(new_ui)
DefaultUserInteraction.ui = new_ui
end
##
# See DefaultUserInteraction::use_ui
def use_ui(new_ui, &block)
DefaultUserInteraction.use_ui(new_ui, &block)
end
# The default UI is a class variable of the singleton class for
# this module.
@ui = nil
class << self
def ui
@ui ||= Gem::ConsoleUI.new
end
def ui=(new_ui)
@ui = new_ui
end
def use_ui(new_ui)
old_ui = @ui
@ui = new_ui
yield
ensure
@ui = old_ui
end
end
end
####################################################################
##
# Make the default UI accessable without the "ui." prefix. Classes
# including this module may use the interaction methods on the
# default UI directly. Classes may also reference the +ui+ and
# <tt>ui=</tt> methods.
# including this module may use the interaction methods on the default UI
# directly. Classes may also reference the ui and ui= methods.
#
# Example:
#
@ -64,22 +81,30 @@ module Gem
# n = ask("What is the meaning of life?")
# end
# end
module UserInteraction
include DefaultUserInteraction
[
:choose_from_list, :ask, :ask_yes_no, :say, :alert, :alert_warning,
:alert_error, :terminate_interaction
].each do |methname|
[:alert,
:alert_error,
:alert_warning,
:ask,
:ask_yes_no,
:choose_from_list,
:say,
:terminate_interaction ].each do |methname|
class_eval %{
def #{methname}(*args)
ui.#{methname}(*args)
end
}
}, __FILE__, __LINE__
end
end
####################################################################
##
# StreamUI implements a simple stream based user interface.
class StreamUI
attr_reader :ins, :outs, :errs
@ -89,15 +114,19 @@ module Gem
@outs = out_stream
@errs = err_stream
end
# Choose from a list of options. +question+ is a prompt displayed
# above the list. +list+ is a list of option strings. Returns
# the pair [option_name, option_index].
##
# Choose from a list of options. +question+ is a prompt displayed above
# the list. +list+ is a list of option strings. Returns the pair
# [option_name, option_index].
def choose_from_list(question, list)
@outs.puts question
list.each_with_index do |item, index|
@outs.puts " #{index+1}. #{item}"
end
@outs.print "> "
@outs.flush
@ -109,28 +138,32 @@ module Gem
return list[result], result
end
# Ask a question. Returns a true for yes, false for no. If not
# connected to a tty, raises an exception if default is nil,
# otherwise returns default.
##
# Ask a question. Returns a true for yes, false for no. If not connected
# to a tty, raises an exception if default is nil, otherwise returns
# default.
def ask_yes_no(question, default=nil)
if not @ins.tty? then
unless @ins.tty? then
if default.nil? then
raise(
Gem::OperationNotSupportedError,
"Not connected to a tty and no default specified")
raise Gem::OperationNotSupportedError,
"Not connected to a tty and no default specified"
else
return default
end
end
qstr = case default
when nil
'yn'
when true
'Yn'
else
'yN'
end
when nil
'yn'
when true
'Yn'
else
'yN'
end
result = nil
while result.nil?
result = ask("#{question} [#{qstr}]")
result = case result
@ -144,51 +177,68 @@ module Gem
nil
end
end
return result
end
# Ask a question. Returns an answer if connected to a tty, nil
# otherwise.
##
# Ask a question. Returns an answer if connected to a tty, nil otherwise.
def ask(question)
return nil if not @ins.tty?
@outs.print(question + " ")
@outs.flush
result = @ins.gets
result.chomp! if result
result
end
##
# Display a statement.
def say(statement="")
@outs.puts statement
end
# Display an informational alert.
##
# Display an informational alert. Will ask +question+ if it is not nil.
def alert(statement, question=nil)
@outs.puts "INFO: #{statement}"
return ask(question) if question
ask(question) if question
end
# Display a warning in a location expected to get error messages.
##
# Display a warning in a location expected to get error messages. Will
# ask +question+ if it is not nil.
def alert_warning(statement, question=nil)
@errs.puts "WARNING: #{statement}"
ask(question) if question
ask(question) if question
end
# Display an error message in a location expected to get error
# messages.
##
# Display an error message in a location expected to get error messages.
# Will ask +question+ if it is not nil.
def alert_error(statement, question=nil)
@errs.puts "ERROR: #{statement}"
ask(question) if question
end
# Terminate the application normally, running any exit handlers
# that might have been defined.
##
# Terminate the application with exit code +status+, running any exit
# handlers that might have been defined.
def terminate_interaction(status = 0)
raise Gem::SystemExitException, status
end
# Return a progress reporter object
##
# Return a progress reporter object chosen from the current verbosity.
def progress_reporter(*args)
case Gem.configuration.verbose
when nil, false
@ -200,6 +250,9 @@ module Gem
end
end
##
# An absolutely silent progress reporter.
class SilentProgressReporter
attr_reader :count
@ -213,6 +266,9 @@ module Gem
end
end
##
# A basic dotted progress reporter.
class SimpleProgressReporter
include DefaultUserInteraction
@ -228,17 +284,27 @@ module Gem
@out.puts initial_message
end
##
# Prints out a dot and ignores +message+.
def updated(message)
@count += 1
@out.print "."
@out.flush
end
##
# Prints out the terminal message.
def done
@out.puts "\n#{@terminal_message}"
end
end
##
# A progress reporter that prints out messages about the current progress.
class VerboseProgressReporter
include DefaultUserInteraction
@ -254,32 +320,41 @@ module Gem
@out.puts initial_message
end
##
# Prints out the position relative to the total and the +message+.
def updated(message)
@count += 1
@out.puts "#{@count}/#{@total}: #{message}"
end
##
# Prints out the terminal message.
def done
@out.puts @terminal_message
end
end
end
####################################################################
# Subclass of StreamUI that instantiates the user interaction using
# standard in, out and error.
##
# Subclass of StreamUI that instantiates the user interaction using STDIN,
# STDOUT, and STDERR.
class ConsoleUI < StreamUI
def initialize
super(STDIN, STDOUT, STDERR)
end
end
####################################################################
##
# SilentUI is a UI choice that is absolutely silent.
class SilentUI
def method_missing(sym, *args, &block)
self
end
end
end

View file

@ -8,6 +8,7 @@ require 'rubygems'
##
# The Version class processes string versions into comparable values
class Gem::Version
include Comparable
@ -17,11 +18,8 @@ class Gem::Version
attr_reader :version
##
# Checks if version string is valid format
#
# str:: [String] the version string
# return:: [Boolean] true if the string format is correct, otherwise false
#
# Returns true if +version+ is a valid version string.
def self.correct?(version)
case version
when Integer, /\A\s*(\d+(\.\d+)*)*\s*\z/ then true
@ -36,7 +34,7 @@ class Gem::Version
# ver1 = Version.create('1.3.17') # -> (Version object)
# ver2 = Version.create(ver1) # -> (ver1)
# ver3 = Version.create(nil) # -> nil
#
def self.create(input)
if input.respond_to? :version then
input
@ -48,10 +46,9 @@ class Gem::Version
end
##
# Constructs a version from the supplied string
#
# version:: [String] The version string. Format is digit.digit...
#
# Constructs a Version from the +version+ string. A version string is a
# series of digits separated by dots.
def initialize(version)
raise ArgumentError, "Malformed version number string #{version}" unless
self.class.correct?(version)
@ -73,7 +70,9 @@ class Gem::Version
self.version = array[0]
end
##
# Strip ignored trailing zeros.
def normalize
@ints = build_array_from_version_string
@ -94,10 +93,8 @@ class Gem::Version
end
##
# Convert version to integer array
#
# return:: [Array] list of integers
#
# Returns an integer array representation of this Version.
def to_ints
normalize unless @ints
@ints
@ -117,20 +114,25 @@ class Gem::Version
end
##
# Compares two versions
#
# other:: [Version or .ints] other version to compare to
# return:: [Fixnum] -1, 0, 1
#
# Compares this version with +other+ returning -1, 0, or 1 if the other
# version is larger, the same, or smaller than this one.
def <=>(other)
return nil unless self.class === other
return 1 unless other
@ints <=> other.ints
end
alias eql? == # :nodoc:
##
# A Version is only eql? to another version if it has the same version
# string. "1.0" is not the same version as "1".
def eql?(other)
self.class === other and @version == other.version
end
def hash # :nodoc:
to_ints.inject { |hash_code, n| hash_code + n }
@version.hash
end
# Return a new version object where the next to the last revision

View file

@ -10,10 +10,9 @@ at_exit { $SAFE = 1 }
require 'fileutils'
require 'test/unit'
require 'tmpdir'
require 'tempfile'
require 'uri'
require 'rubygems/source_info_cache'
require 'rubygems/package'
require 'rubygems/test_utilities'
require File.join(File.expand_path(File.dirname(__FILE__)), 'mockgemui')
@ -27,54 +26,6 @@ module Gem
end
end
class FakeFetcher
attr_reader :data
attr_accessor :uri
attr_accessor :paths
def initialize
@data = {}
@paths = []
@uri = nil
end
def fetch_path(path)
path = path.to_s
@paths << path
raise ArgumentError, 'need full URI' unless path =~ %r'^http://'
data = @data[path]
raise Gem::RemoteFetcher::FetchError, "no data for #{path}" if data.nil?
data.respond_to?(:call) ? data.call : data
end
def fetch_size(path)
path = path.to_s
@paths << path
raise ArgumentError, 'need full URI' unless path =~ %r'^http://'
data = @data[path]
raise Gem::RemoteFetcher::FetchError, "no data for #{path}" if data.nil?
data.respond_to?(:call) ? data.call : data.length
end
def download spec, source_uri, install_dir = Gem.dir
name = "#{spec.full_name}.gem"
path = File.join(install_dir, 'cache', name)
Gem.ensure_gem_subdirectories install_dir
if source_uri =~ /^http/ then
File.open(path, "wb") do |f|
f.write fetch_path(File.join(source_uri, "gems", name))
end
else
FileUtils.cp source_uri, path
end
path
end
end
class RubyGemTestCase < Test::Unit::TestCase
include Gem::DefaultUserInteraction
@ -94,8 +45,13 @@ class RubyGemTestCase < Test::Unit::TestCase
@gemcache = File.join(@gemhome, "source_cache")
@usrcache = File.join(@gemhome, ".gem", "user_cache")
@latest_usrcache = File.join(@gemhome, ".gem", "latest_user_cache")
@userhome = File.join @tempdir, 'userhome'
ENV['HOME'] = @userhome
Gem.instance_variable_set :@user_home, nil
FileUtils.mkdir_p @gemhome
FileUtils.mkdir_p @userhome
ENV['GEMCACHE'] = @usrcache
Gem.use_paths(@gemhome)
@ -104,9 +60,12 @@ class RubyGemTestCase < Test::Unit::TestCase
Gem.configuration.verbose = true
Gem.configuration.update_sources = true
@gem_repo = "http://gems.example.com"
@gem_repo = "http://gems.example.com/"
@uri = URI.parse @gem_repo
Gem.sources.replace [@gem_repo]
Gem::SpecFetcher.fetcher = nil
@orig_BASERUBY = Gem::ConfigMap[:BASERUBY]
Gem::ConfigMap[:BASERUBY] = Gem::ConfigMap[:RUBY_INSTALL_NAME]
@ -131,7 +90,7 @@ class RubyGemTestCase < Test::Unit::TestCase
Gem::ConfigMap[:arch] = @orig_arch
if defined? Gem::RemoteFetcher then
Gem::RemoteFetcher.instance_variable_set :@fetcher, nil
Gem::RemoteFetcher.fetcher = nil
end
FileUtils.rm_rf @tempdir
@ -141,7 +100,6 @@ class RubyGemTestCase < Test::Unit::TestCase
ENV.delete 'GEM_PATH'
Gem.clear_paths
Gem::SourceInfoCache.instance_variable_set :@cache, nil
end
def install_gem gem
@ -154,7 +112,7 @@ class RubyGemTestCase < Test::Unit::TestCase
end
gem = File.join(@tempdir, "#{gem.full_name}.gem").untaint
Gem::Installer.new(gem).install
Gem::Installer.new(gem, :wrappers => true).install
end
def prep_cache_files(lc)
@ -231,6 +189,8 @@ class RubyGemTestCase < Test::Unit::TestCase
spec.loaded_from = written_path
Gem.source_index.add_spec spec
return spec
end
@ -254,6 +214,12 @@ class RubyGemTestCase < Test::Unit::TestCase
end
end
def util_clear_gems
FileUtils.rm_r File.join(@gemhome, 'gems')
FileUtils.rm_r File.join(@gemhome, 'specifications')
Gem.source_index.refresh!
end
def util_gem(name, version, &block)
spec = quick_gem(name, version, &block)
@ -271,6 +237,16 @@ class RubyGemTestCase < Test::Unit::TestCase
[spec, cache_file]
end
def util_gzip(data)
out = StringIO.new
Zlib::GzipWriter.wrap out do |io|
io.write data
end
out.string
end
def util_make_gems
init = proc do |s|
s.files = %w[lib/code.rb]
@ -303,7 +279,7 @@ class RubyGemTestCase < Test::Unit::TestCase
end
##
# Set the platform to +cpu+ and +os+
# Set the platform to +arch+
def util_set_arch(arch)
Gem::ConfigMap[:arch] = arch
@ -320,9 +296,7 @@ class RubyGemTestCase < Test::Unit::TestCase
require 'socket'
require 'rubygems/remote_fetcher'
@uri = URI.parse @gem_repo
@fetcher = FakeFetcher.new
@fetcher.uri = @uri
@fetcher = Gem::FakeFetcher.new
util_make_gems
@ -338,10 +312,11 @@ class RubyGemTestCase < Test::Unit::TestCase
@source_index.add_spec @a_evil9
@source_index.add_spec @c1_2
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
Gem::RemoteFetcher.fetcher = @fetcher
end
def util_setup_source_info_cache(*specs)
require 'rubygems/source_info_cache'
require 'rubygems/source_info_cache_entry'
specs = Hash[*specs.map { |spec| [spec.full_name, spec] }.flatten]
@ -356,6 +331,35 @@ class RubyGemTestCase < Test::Unit::TestCase
sic.reset_cache_data
Gem::SourceInfoCache.instance_variable_set :@cache, sic
si
end
def util_setup_spec_fetcher(*specs)
specs = Hash[*specs.map { |spec| [spec.full_name, spec] }.flatten]
si = Gem::SourceIndex.new specs
spec_fetcher = Gem::SpecFetcher.fetcher
spec_fetcher.specs[@uri] = []
si.gems.sort_by { |_, spec| spec }.each do |_, spec|
spec_tuple = [spec.name, spec.version, spec.original_platform]
spec_fetcher.specs[@uri] << spec_tuple
end
spec_fetcher.latest_specs[@uri] = []
si.latest_specs.sort.each do |spec|
spec_tuple = [spec.name, spec.version, spec.original_platform]
spec_fetcher.latest_specs[@uri] << spec_tuple
end
si.gems.sort_by { |_,spec| spec }.each do |_, spec|
path = "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{spec.original_name}.gemspec.rz"
data = Marshal.dump spec
data_deflate = Zlib::Deflate.deflate data
@fetcher.data[path] = data_deflate
end
si
end
@ -384,30 +388,3 @@ class RubyGemTestCase < Test::Unit::TestCase
end
class TempIO
@@count = 0
def initialize(string = '')
@tempfile = Tempfile.new "TempIO-#{@@count ++ 1}"
@tempfile.binmode
@tempfile.write string
@tempfile.rewind
end
def method_missing(meth, *args, &block)
@tempfile.send(meth, *args, &block)
end
def respond_to?(meth)
@tempfile.respond_to? meth
end
def string
@tempfile.flush
Gem.read_binary @tempfile.path
end
end

View file

@ -12,11 +12,6 @@ require 'rubygems'
class TestConfig < RubyGemTestCase
def test_gem_original_datadir
datadir = Config::CONFIG['datadir']
assert_equal "#{datadir}/xyz", Config.gem_original_datadir('xyz')
end
def test_datadir
datadir = Config::CONFIG['datadir']
assert_equal "#{datadir}/xyz", Config.datadir('xyz')

View file

@ -27,6 +27,14 @@ class TestGem < RubyGemTestCase
assert_equal expected, Gem.all_load_paths.sort
end
def test_self_available?
util_make_gems
assert(Gem.available?("a"))
assert(Gem.available?("a", "1"))
assert(Gem.available?("a", ">1"))
assert(!Gem.available?("monkeys"))
end
def test_self_bindir
assert_equal File.join(@gemhome, 'bin'), Gem.bindir
@ -129,7 +137,7 @@ class TestGem < RubyGemTestCase
end
def test_self_default_sources
assert_equal %w[http://gems.rubyforge.org], Gem.default_sources
assert_equal %w[http://gems.rubyforge.org/], Gem.default_sources
end
def test_self_dir
@ -237,6 +245,18 @@ class TestGem < RubyGemTestCase
assert_equal [Gem.dir], Gem.path
end
def test_self_path_default
if defined? APPLE_GEM_HOME
orig_APPLE_GEM_HOME = APPLE_GEM_HOME
Object.send :remove_const, :APPLE_GEM_HOME
end
Gem.instance_variable_set :@gem_path, nil
assert_equal [Gem.default_path, Gem.dir], Gem.path
ensure
Object.const_set :APPLE_GEM_HOME, orig_APPLE_GEM_HOME
end
unless win_platform?
def test_self_path_APPLE_GEM_HOME
Gem.clear_paths
@ -382,7 +402,7 @@ class TestGem < RubyGemTestCase
end
def test_self_sources
assert_equal %w[http://gems.example.com], Gem.sources
assert_equal %w[http://gems.example.com/], Gem.sources
end
def test_ssl_available_eh

View file

@ -66,7 +66,7 @@ class TestGemCommandManager < RubyGemTestCase
assert_equal :both, check_options[:domain]
assert_equal true, check_options[:wrappers]
assert_equal Gem::Requirement.default, check_options[:version]
assert_equal Gem.dir, check_options[:install_dir]
assert_equal nil, check_options[:install_dir]
assert_equal nil, check_options[:bin_dir]
#check settings

View file

@ -9,6 +9,8 @@ class TestGemCommandsDependencyCommand < RubyGemTestCase
@cmd = Gem::Commands::DependencyCommand.new
@cmd.options[:domain] = :local
util_setup_fake_fetcher
end
def test_execute
@ -16,13 +18,15 @@ class TestGemCommandsDependencyCommand < RubyGemTestCase
gem.add_dependency 'bar', '> 1'
end
Gem.source_index = nil
@cmd.options[:args] = %w[foo]
use_ui @ui do
@cmd.execute
end
assert_equal "Gem foo-2\n bar (> 1)\n\n", @ui.output
assert_equal "Gem foo-2\n bar (> 1, runtime)\n\n", @ui.output
assert_equal '', @ui.error
end
@ -35,7 +39,7 @@ class TestGemCommandsDependencyCommand < RubyGemTestCase
end
end
assert_equal "No match found for foo (>= 0)\n", @ui.output
assert_equal "No gems found matching foo (>= 0)\n", @ui.output
assert_equal '', @ui.error
end
@ -64,6 +68,8 @@ class TestGemCommandsDependencyCommand < RubyGemTestCase
gem.add_dependency 'foo'
end
Gem.source_index = nil
@cmd.options[:args] = %w[foo]
@cmd.options[:reverse_dependencies] = true
@ -73,9 +79,9 @@ class TestGemCommandsDependencyCommand < RubyGemTestCase
expected = <<-EOF
Gem foo-2
bar (> 1)
bar (> 1, runtime)
Used by
baz-2 (foo (>= 0))
baz-2 (foo (>= 0, runtime))
EOF
@ -83,12 +89,34 @@ Gem foo-2
assert_equal '', @ui.error
end
def test_execute_reverse_remote
@cmd.options[:args] = %w[foo]
@cmd.options[:reverse_dependencies] = true
@cmd.options[:domain] = :remote
assert_raise MockGemUi::TermError do
use_ui @ui do
@cmd.execute
end
end
expected = <<-EOF
ERROR: Only reverse dependencies for local gems are supported.
EOF
assert_equal '', @ui.output
assert_equal expected, @ui.error
end
def test_execute_remote
foo = quick_gem 'foo' do |gem|
gem.add_dependency 'bar', '> 1'
end
util_setup_source_info_cache foo
@fetcher = Gem::FakeFetcher.new
Gem::RemoteFetcher.fetcher = @fetcher
util_setup_spec_fetcher foo
FileUtils.rm File.join(@gemhome, 'specifications',
"#{foo.full_name}.gemspec")
@ -100,9 +128,48 @@ Gem foo-2
@cmd.execute
end
assert_equal "Gem foo-2\n bar (> 1)\n\n", @ui.output
assert_equal "Gem foo-2\n bar (> 1, runtime)\n\n", @ui.output
assert_equal '', @ui.error
end
def test_execute_remote_legacy
foo = quick_gem 'foo' do |gem|
gem.add_dependency 'bar', '> 1'
end
@fetcher = Gem::FakeFetcher.new
Gem::RemoteFetcher.fetcher = @fetcher
Gem::SpecFetcher.fetcher = nil
si = util_setup_source_info_cache foo
@fetcher.data["#{@gem_repo}yaml"] = YAML.dump si
@fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] =
si.dump
@fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] = nil
FileUtils.rm File.join(@gemhome, 'specifications',
"#{foo.full_name}.gemspec")
@cmd.options[:args] = %w[foo]
@cmd.options[:domain] = :remote
use_ui @ui do
@cmd.execute
end
assert_equal "Gem foo-2\n bar (> 1, runtime)\n\n", @ui.output
expected = <<-EOF
WARNING: RubyGems 1.2+ index not found for:
\t#{@gem_repo}
RubyGems will revert to legacy indexes degrading performance.
EOF
assert_equal expected, @ui.error
end
end

View file

@ -27,6 +27,7 @@ class TestGemCommandsEnvironmentCommand < RubyGemTestCase
assert_match %r|RUBYGEMS PREFIX: |, @ui.output
assert_match %r|RUBY EXECUTABLE:.*#{Gem::ConfigMap[:RUBY_INSTALL_NAME]}|,
@ui.output
assert_match %r|EXECUTABLE DIRECTORY:|, @ui.output
assert_match %r|RUBYGEMS PLATFORMS:|, @ui.output
assert_match %r|- #{Gem::Platform.local}|, @ui.output
assert_match %r|GEM PATHS:|, @ui.output

View file

@ -14,10 +14,9 @@ class TestGemCommandsFetchCommand < RubyGemTestCase
def test_execute
util_setup_fake_fetcher
util_setup_spec_fetcher @a2
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
@source_index.dump
@fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] =
@fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] =
File.read(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
@cmd.options[:args] = [@a2.name]
@ -28,7 +27,28 @@ class TestGemCommandsFetchCommand < RubyGemTestCase
end
end
assert File.exist?(File.join(@tempdir, "#{@a2.full_name}.gem"))
assert File.exist?(File.join(@tempdir, "#{@a2.full_name}.gem")),
"#{@a2.full_name} fetched"
end
def test_execute_legacy
util_setup_fake_fetcher
util_setup_source_info_cache @a2
@fetcher.data["#{@gem_repo}yaml"] = ''
@fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] =
File.read(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
@cmd.options[:args] = [@a2.name]
use_ui @ui do
Dir.chdir @tempdir do
@cmd.execute
end
end
assert File.exist?(File.join(@tempdir, "#{@a2.full_name}.gem")),
"#{@a2.full_name} fetched"
end
end

View file

@ -72,7 +72,7 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
end
# HACK no repository was checked
assert_equal "ERROR: could not find no_such_gem locally or in a repository\n",
assert_equal "ERROR: could not find gem no_such_gem locally or in a repository\n",
@ui.error
end
@ -86,8 +86,7 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
def test_execute_nonexistent
util_setup_fake_fetcher
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
@source_index.dump
util_setup_spec_fetcher
@cmd.options[:args] = %w[nonexistent]
@ -98,18 +97,18 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
assert_equal 2, e.exit_code
end
assert_equal "ERROR: could not find nonexistent locally or in a repository\n",
assert_equal "ERROR: could not find gem nonexistent locally or in a repository\n",
@ui.error
end
def test_execute_remote
@cmd.options[:generate_rdoc] = true
@cmd.options[:generate_ri] = true
util_setup_fake_fetcher
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
@source_index.dump
@fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] =
util_setup_fake_fetcher
util_setup_spec_fetcher @a2
@fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] =
read_binary(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
@cmd.options[:args] = [@a2.name]
@ -122,7 +121,6 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
end
out = @ui.output.split "\n"
assert_match %r|Bulk updating|, out.shift
assert_equal "Successfully installed #{@a2.full_name}", out.shift
assert_equal "1 gem installed", out.shift
assert_equal "Installing ri documentation for #{@a2.full_name}...",

View file

@ -0,0 +1,43 @@
require 'test/unit'
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/commands/outdated_command'
class TestGemCommandsOutdatedCommand < RubyGemTestCase
def setup
super
@cmd = Gem::Commands::OutdatedCommand.new
end
def test_initialize
assert @cmd.handles?(%W[--platform #{Gem::Platform.local}])
end
def test_execute
local_01 = quick_gem 'foo', '0.1'
local_02 = quick_gem 'foo', '0.2'
remote_10 = quick_gem 'foo', '1.0'
remote_20 = quick_gem 'foo', '2.0'
remote_spec_file = File.join @gemhome, 'specifications',
remote_10.full_name + ".gemspec"
FileUtils.rm remote_spec_file
remote_spec_file = File.join @gemhome, 'specifications',
remote_20.full_name + ".gemspec"
FileUtils.rm remote_spec_file
@fetcher = Gem::FakeFetcher.new
Gem::RemoteFetcher.fetcher = @fetcher
util_setup_spec_fetcher remote_10, remote_20
use_ui @ui do @cmd.execute end
assert_equal "foo (0.2 < 2.0)\n", @ui.output
assert_equal "", @ui.error
end
end

View file

@ -18,16 +18,24 @@ class TestGemCommandsPristineCommand < RubyGemTestCase
install_gem a
foo_path = File.join @gemhome, 'gems', a.full_name, 'bin', 'foo'
File.open foo_path, 'w' do |io|
io.puts 'I changed it!'
end
@cmd.options[:args] = %w[a]
use_ui @ui do
@cmd.execute
end
assert_equal "#!/usr/bin/ruby\n", File.read(foo_path), foo_path
out = @ui.output.split "\n"
assert_equal "Restoring gem(s) to pristine condition...", out.shift
assert_equal "#{a.full_name} is in pristine condition", out.shift
assert_equal "Restored #{a.full_name}", out.shift
assert out.empty?, out.inspect
end
@ -40,7 +48,7 @@ class TestGemCommandsPristineCommand < RubyGemTestCase
install_gem a
gem_bin = File.join @gemhome, 'gems', "#{a.full_name}", 'bin', 'foo'
gem_bin = File.join @gemhome, 'gems', a.full_name, 'bin', 'foo'
FileUtils.rm gem_bin
@ -50,11 +58,12 @@ class TestGemCommandsPristineCommand < RubyGemTestCase
@cmd.execute
end
assert File.exist?(gem_bin)
out = @ui.output.split "\n"
assert_equal "Restoring gem(s) to pristine condition...", out.shift
assert_equal "Restoring 1 file to #{a.full_name}...", out.shift
assert_equal " #{gem_bin}", out.shift
assert_equal "Restored #{a.full_name}", out.shift
assert out.empty?, out.inspect
end

View file

@ -7,33 +7,18 @@ class TestGemCommandsQueryCommand < RubyGemTestCase
def setup
super
util_make_gems
@a2.summary = 'This is a lot of text. ' * 4
@cmd = Gem::Commands::QueryCommand.new
@si = util_setup_source_info_cache @a1, @a2, @pl1
util_setup_fake_fetcher
@fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] = proc do
@si = util_setup_spec_fetcher @a1, @a2, @pl1
@fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do
raise Gem::RemoteFetcher::FetchError
end
end
def test_execute
cache = Gem::SourceInfoCache.cache
cache.update
cache.write_cache
cache.reset_cache_data
Gem::SourceInfoCache.reset
a2_name = @a2.full_name
@fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = util_zip a2_name
@fetcher.data["#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{a2_name}.gemspec.rz"] = util_zip Marshal.dump(@a2)
@fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] =
Marshal.dump @si
@cmd.handle_options %w[-r]
use_ui @ui do
@ -44,10 +29,8 @@ class TestGemCommandsQueryCommand < RubyGemTestCase
*** REMOTE GEMS ***
Updating metadata for 1 gems from http://gems.example.com/
.
complete
a (2)
pl (1)
EOF
assert_equal expected, @ui.output
@ -55,21 +38,8 @@ a (2)
end
def test_execute_all
cache = Gem::SourceInfoCache.cache
cache.update
cache.write_cache
cache.reset_cache_data
Gem::SourceInfoCache.reset
a1_name = @a1.full_name
a2_name = @a2.full_name
@fetcher.data["#{@gem_repo}/quick/index.rz"] =
util_zip [a1_name, a2_name].join("\n")
@fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = util_zip a2_name
@fetcher.data["#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{a1_name}.gemspec.rz"] = util_zip Marshal.dump(@a1)
@fetcher.data["#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{a2_name}.gemspec.rz"] = util_zip Marshal.dump(@a2)
@fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] =
Marshal.dump @si
@cmd.handle_options %w[-r --all]
@ -81,10 +51,8 @@ a (2)
*** REMOTE GEMS ***
Updating metadata for 2 gems from http://gems.example.com/
..
complete
a (2, 1)
pl (1)
EOF
assert_equal expected, @ui.output
@ -92,6 +60,13 @@ a (2, 1)
end
def test_execute_details
@a2.summary = 'This is a lot of text. ' * 4
@a2.authors = ['Abraham Lincoln', 'Hirohito']
@a2.homepage = 'http://a.example.com/'
@a2.rubyforge_project = 'rubygems'
@si = util_setup_spec_fetcher @a1, @a2, @pl1
@cmd.handle_options %w[-r -d]
use_ui @ui do
@ -103,10 +78,17 @@ a (2, 1)
*** REMOTE GEMS ***
a (2)
Authors: Abraham Lincoln, Hirohito
Rubyforge: http://rubyforge.org/projects/rubygems
Homepage: http://a.example.com/
This is a lot of text. This is a lot of text. This is a lot of text.
This is a lot of text.
pl (1)
Author: A User
Homepage: http://example.com
this is a summary
EOF
@ -126,6 +108,7 @@ pl (1)
assert_equal 0, e.exit_code
assert_equal "true\n", @ui.output
assert_equal '', @ui.error
end
@ -189,6 +172,99 @@ pl (1)
assert_equal 1, e.exit_code
end
def test_execute_legacy
Gem::SpecFetcher.fetcher = nil
si = util_setup_source_info_cache @a1, @a2, @pl1
@fetcher.data["#{@gem_repo}yaml"] = YAML.dump si
@fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] =
si.dump
@fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] = nil
@cmd.handle_options %w[-r]
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
*** REMOTE GEMS ***
a (2)
pl (1)
EOF
assert_equal expected, @ui.output
expected = <<-EOF
WARNING: RubyGems 1.2+ index not found for:
\t#{@gem_repo}
RubyGems will revert to legacy indexes degrading performance.
EOF
assert_equal expected, @ui.error
end
def test_execute_local_details
@a2.summary = 'This is a lot of text. ' * 4
@a2.authors = ['Abraham Lincoln', 'Hirohito']
@a2.homepage = 'http://a.example.com/'
@a2.rubyforge_project = 'rubygems'
@cmd.handle_options %w[--local --details]
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
*** LOCAL GEMS ***
a (2, 1)
Author: A User
Homepage: http://example.com
Installed at (2): #{@gemhome}
(1): #{@gemhome}
this is a summary
a_evil (9)
Author: A User
Homepage: http://example.com
Installed at: #{@gemhome}
this is a summary
b (2)
Author: A User
Homepage: http://example.com
Installed at: #{@gemhome}
this is a summary
c (1.2)
Author: A User
Homepage: http://example.com
Installed at: #{@gemhome}
this is a summary
pl (1)
Author: A User
Homepage: http://example.com
Installed at: #{@gemhome}
this is a summary
EOF
assert_equal expected, @ui.output
assert_equal '', @ui.error
end
def test_execute_no_versions
@cmd.handle_options %w[-r --no-versions]

View file

@ -8,10 +8,12 @@ class TestGemCommandsSourcesCommand < RubyGemTestCase
super
@cmd = Gem::Commands::SourcesCommand.new
@new_repo = "http://beta-gems.example.com"
end
def test_execute
util_setup_source_info_cache
util_setup_spec_fetcher
@cmd.handle_options []
use_ui @ui do
@ -34,43 +36,49 @@ class TestGemCommandsSourcesCommand < RubyGemTestCase
si = Gem::SourceIndex.new
si.add_spec @a1
@fetcher.data["http://beta-gems.example.com/Marshal.#{@marshal_version}"] =
si.dump
specs = si.map do |_, spec|
[spec.name, spec.version, spec.original_platform]
end
@cmd.handle_options %w[--add http://beta-gems.example.com]
specs_dump_gz = StringIO.new
Zlib::GzipWriter.wrap specs_dump_gz do |io|
Marshal.dump specs, io
end
util_setup_source_info_cache
@fetcher.data["#{@new_repo}/specs.#{@marshal_version}.gz"] =
specs_dump_gz.string
@cmd.handle_options %W[--add #{@new_repo}]
util_setup_spec_fetcher
use_ui @ui do
@cmd.execute
end
assert_equal [@gem_repo, @new_repo], Gem.sources
expected = <<-EOF
Bulk updating Gem source index for: http://beta-gems.example.com/
http://beta-gems.example.com added to sources
#{@new_repo} added to sources
EOF
assert_equal expected, @ui.output
assert_equal '', @ui.error
Gem::SourceInfoCache.cache.flush
assert_equal %W[http://beta-gems.example.com #{@gem_repo}],
Gem::SourceInfoCache.cache_data.keys.sort
end
def test_execute_add_nonexistent_source
util_setup_fake_fetcher
@fetcher.data["http://beta-gems.example.com/Marshal.#{@marshal_version}"] =
proc do
raise Gem::RemoteFetcher::FetchError, 'it died'
end
uri = "http://beta-gems.example.com/specs.#{@marshal_version}.gz"
@fetcher.data[uri] = proc do
raise Gem::RemoteFetcher::FetchError.new('it died', uri)
end
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
Gem::RemoteFetcher.fetcher = @fetcher
@cmd.handle_options %w[--add http://beta-gems.example.com]
util_setup_source_info_cache
util_setup_spec_fetcher
use_ui @ui do
@cmd.execute
@ -78,7 +86,7 @@ http://beta-gems.example.com added to sources
expected = <<-EOF
Error fetching http://beta-gems.example.com:
\tit died
\tit died (#{uri})
EOF
assert_equal expected, @ui.output
@ -88,12 +96,14 @@ Error fetching http://beta-gems.example.com:
def test_execute_add_bad_uri
@cmd.handle_options %w[--add beta-gems.example.com]
util_setup_source_info_cache
util_setup_spec_fetcher
use_ui @ui do
@cmd.execute
end
assert_equal [@gem_repo], Gem.sources
expected = <<-EOF
beta-gems.example.com is not a URI
EOF
@ -102,6 +112,34 @@ beta-gems.example.com is not a URI
assert_equal '', @ui.error
end
def test_execute_add_legacy
util_setup_fake_fetcher
util_setup_source_info_cache
si = Gem::SourceIndex.new
si.add_spec @a1
@fetcher.data["#{@new_repo}/yaml"] = ''
@cmd.handle_options %W[--add #{@new_repo}]
use_ui @ui do
@cmd.execute
end
assert_equal [@gem_repo], Gem.sources
expected = <<-EOF
WARNING: RubyGems 1.2+ index not found for:
\t#{@new_repo}
Will cause RubyGems to revert to legacy indexes, degrading performance.
EOF
assert_equal "#{@new_repo} added to sources\n", @ui.output
assert_equal expected, @ui.error
end
def test_execute_clear_all
@cmd.handle_options %w[--clear-all]
@ -116,11 +154,19 @@ beta-gems.example.com is not a URI
assert File.exist?(cache.latest_system_cache_file),
'latest system cache file'
util_setup_spec_fetcher
fetcher = Gem::SpecFetcher.fetcher
# HACK figure out how to force directory creation via fetcher
#assert File.directory?(fetcher.dir), 'cache dir exists'
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
*** Removed specs cache ***
*** Removed user source cache ***
*** Removed latest user source cache ***
*** Removed system source cache ***
@ -135,12 +181,13 @@ beta-gems.example.com is not a URI
assert !File.exist?(cache.latest_system_cache_file),
'latest system cache file'
assert !File.exist?(fetcher.dir), 'cache dir removed'
end
def test_execute_remove
@cmd.handle_options %W[--remove #{@gem_repo}]
util_setup_source_info_cache
util_setup_spec_fetcher
use_ui @ui do
@cmd.execute
@ -150,9 +197,6 @@ beta-gems.example.com is not a URI
assert_equal expected, @ui.output
assert_equal '', @ui.error
Gem::SourceInfoCache.cache.flush
assert_equal [], Gem::SourceInfoCache.cache_data.keys
end
def test_execute_remove_no_network
@ -160,7 +204,7 @@ beta-gems.example.com is not a URI
util_setup_fake_fetcher
@fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] = proc do
@fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do
raise Gem::RemoteFetcher::FetchError
end
@ -172,34 +216,60 @@ beta-gems.example.com is not a URI
assert_equal expected, @ui.output
assert_equal '', @ui.error
Gem::SourceInfoCache.cache.flush
assert_equal [], Gem::SourceInfoCache.cache_data.keys
end
def test_execute_update
@cmd.handle_options %w[--update]
util_setup_fake_fetcher
source_index = util_setup_spec_fetcher @a1
specs = source_index.map do |name, spec|
[spec.name, spec.version, spec.original_platform]
end
@fetcher.data["#{@gem_repo}specs.#{Gem.marshal_version}.gz"] =
util_gzip Marshal.dump(specs)
latest_specs = source_index.latest_specs.map do |spec|
[spec.name, spec.version, spec.original_platform]
end
@fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] =
util_gzip Marshal.dump(latest_specs)
use_ui @ui do
@cmd.execute
end
assert_equal "source cache successfully updated\n", @ui.output
assert_equal '', @ui.error
end
def test_execute_update_legacy
@cmd.handle_options %w[--update]
util_setup_fake_fetcher
util_setup_source_info_cache
Gem::SourceInfoCache.reset
util_setup_fake_fetcher
si = Gem::SourceIndex.new
si.add_spec @a1
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
@fetcher.data["#{@gem_repo}yaml"] = YAML.dump si
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = si.dump
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
Bulk updating Gem source index for: #{@gem_repo}/
Bulk updating Gem source index for: #{@gem_repo}
source cache successfully updated
EOF
assert_equal expected, @ui.output
assert_equal '', @ui.error
end
end

View file

@ -74,7 +74,10 @@ class TestGemCommandsSpecificationCommand < RubyGemTestCase
def test_execute_remote
foo = quick_gem 'foo'
util_setup_source_info_cache foo
@fetcher = Gem::FakeFetcher.new
Gem::RemoteFetcher.fetcher = @fetcher
util_setup_spec_fetcher foo
FileUtils.rm File.join(@gemhome, 'specifications',
"#{foo.full_name}.gemspec")

View file

@ -0,0 +1,39 @@
require 'test/unit'
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/commands/stale_command'
class TestGemCommandsStaleCommand < RubyGemTestCase
def setup
super
@cmd = Gem::Commands::StaleCommand.new
end
def test_execute_sorts
files = %w[lib/foo_bar.rb Rakefile]
foo_bar = quick_gem 'foo_bar' do |gem|
gem.files = files
end
bar_baz = quick_gem 'bar_baz' do |gem|
gem.files = files
end
files.each do |file|
filename = bar_baz.full_gem_path + "/#{file}"
FileUtils.mkdir_p(File.dirname(filename))
FileUtils.touch(filename, :mtime => Time.now)
filename = foo_bar.full_gem_path + "/#{file}"
FileUtils.mkdir_p(File.dirname(filename))
FileUtils.touch(filename, :mtime => Time.now - 86400)
end
use_ui @ui do
@cmd.execute
end
lines = @ui.output.split("\n")
assert_equal("#{foo_bar.name}-#{foo_bar.version}", lines[0].split.first)
assert_equal("#{bar_baz.name}-#{bar_baz.version}", lines[1].split.first)
end
end

View file

@ -14,14 +14,16 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
@a1_path = File.join @gemhome, 'cache', "#{@a1.full_name}.gem"
@a2_path = File.join @gemhome, 'cache', "#{@a2.full_name}.gem"
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
@source_index.dump
@fetcher.data["#{@gem_repo}/gems/#{@a1.full_name}.gem"] = read_binary @a1_path
@fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] = read_binary @a2_path
util_setup_spec_fetcher @a1, @a2
@fetcher.data["#{@gem_repo}gems/#{@a1.full_name}.gem"] =
read_binary @a1_path
@fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] =
read_binary @a2_path
end
def test_execute
util_remove_gems
util_clear_gems
Gem::Installer.new(@a1_path).install
@ -33,7 +35,6 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
out = @ui.output.split "\n"
assert_equal "Updating installed gems", out.shift
assert_match %r|Bulk updating|, out.shift
assert_equal "Updating #{@a2.name}", out.shift
assert_equal "Successfully installed #{@a2.full_name}", out.shift
assert_equal "Gems updated: #{@a2.name}", out.shift
@ -73,16 +74,15 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
util_build_gem @a2
util_build_gem @c2
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
@source_index.dump
@fetcher.data["#{@gem_repo}/gems/#{@a1.full_name}.gem"] = read_binary @a1_path
@fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] = read_binary @a2_path
@fetcher.data["#{@gem_repo}/gems/#{@b2.full_name}.gem"] = read_binary @b2_path
@fetcher.data["#{@gem_repo}/gems/#{@c1_2.full_name}.gem"] =
@fetcher.data["#{@gem_repo}gems/#{@a1.full_name}.gem"] = read_binary @a1_path
@fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] = read_binary @a2_path
@fetcher.data["#{@gem_repo}gems/#{@b2.full_name}.gem"] = read_binary @b2_path
@fetcher.data["#{@gem_repo}gems/#{@c1_2.full_name}.gem"] =
read_binary @c1_2_path
@fetcher.data["#{@gem_repo}/gems/#{@c2.full_name}.gem"] = read_binary @c2_path
@fetcher.data["#{@gem_repo}gems/#{@c2.full_name}.gem"] = read_binary @c2_path
util_remove_gems
util_setup_spec_fetcher @a1, @a2, @b2, @c1_2, @c2
util_clear_gems
Gem::Installer.new(@c1_2_path).install
Gem::Installer.new(@a1_path).install
@ -95,9 +95,7 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
out = @ui.output.split "\n"
assert_equal "Updating installed gems", out.shift
assert_match %r|Bulk updating|, out.shift
assert_equal "Updating #{@a2.name}", out.shift
assert_match %r|Bulk updating|, out.shift
assert_equal "Successfully installed #{@c2.full_name}", out.shift
assert_equal "Successfully installed #{@b2.full_name}", out.shift
assert_equal "Successfully installed #{@a2.full_name}", out.shift
@ -108,7 +106,7 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
end
def test_execute_named
util_remove_gems
util_clear_gems
Gem::Installer.new(@a1_path).install
@ -120,7 +118,6 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
out = @ui.output.split "\n"
assert_equal "Updating installed gems", out.shift
assert_match %r|Bulk updating|, out.shift
assert_equal "Updating #{@a2.name}", out.shift
assert_equal "Successfully installed #{@a2.full_name}", out.shift
assert_equal "Gems updated: #{@a2.name}", out.shift
@ -129,7 +126,7 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
end
def test_execute_named_up_to_date
util_remove_gems
util_clear_gems
Gem::Installer.new(@a2_path).install
@ -141,14 +138,13 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
out = @ui.output.split "\n"
assert_equal "Updating installed gems", out.shift
assert_match %r|Bulk updating|, out.shift
assert_equal "Nothing to update", out.shift
assert out.empty?, out.inspect
end
def test_execute_up_to_date
util_remove_gems
util_clear_gems
Gem::Installer.new(@a2_path).install
@ -160,16 +156,10 @@ class TestGemCommandsUpdateCommand < RubyGemTestCase
out = @ui.output.split "\n"
assert_equal "Updating installed gems", out.shift
assert_match %r|Bulk updating|, out.shift
assert_equal "Nothing to update", out.shift
assert out.empty?, out.inspect
end
def util_remove_gems
FileUtils.rm_r File.join(@gemhome, 'gems')
FileUtils.rm_r File.join(@gemhome, 'specifications')
end
end

View file

@ -17,9 +17,23 @@ class TestGemConfigFile < RubyGemTestCase
@temp_conf = File.join @tempdir, '.gemrc'
@cfg_args = %W[--config-file #{@temp_conf}]
@orig_SYSTEM_WIDE_CONFIG_FILE = Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE
Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE
Gem::ConfigFile.send :const_set, :SYSTEM_WIDE_CONFIG_FILE,
File.join(@tempdir, 'system-gemrc')
util_config_file
end
def teardown
Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE
Gem::ConfigFile.send :const_set, :SYSTEM_WIDE_CONFIG_FILE,
@orig_SYSTEM_WIDE_CONFIG_FILE
super
end
def test_initialize
assert_equal @temp_conf, @cfg.config_file_name
@ -28,7 +42,7 @@ class TestGemConfigFile < RubyGemTestCase
assert_equal false, @cfg.benchmark
assert_equal Gem::ConfigFile::DEFAULT_BULK_THRESHOLD, @cfg.bulk_threshold
assert_equal true, @cfg.verbose
assert_equal %w[http://gems.example.com], Gem.sources
assert_equal [@gem_repo], Gem.sources
File.open @temp_conf, 'w' do |fp|
fp.puts ":backtrace: true"
@ -202,6 +216,23 @@ class TestGemConfigFile < RubyGemTestCase
assert_equal %w[http://even-more-gems.example.com], Gem.sources
end
def test_global_config_file
File.open(@temp_conf, 'w') do |fp|
fp.puts ":backtrace: true"
end
File.open(File.join(Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE),
'w') do |fp|
fp.puts ":backtrace: false"
fp.puts ":bulk_threshold: 2048"
end
util_config_file
assert_equal 2048, @cfg.bulk_threshold
assert @cfg.backtrace
end
def util_config_file(args = @cfg_args)
@cfg = Gem::ConfigFile.new args
end

View file

@ -60,6 +60,21 @@ class TestGemDependency < RubyGemTestCase
assert_equal Gem::Requirement.new('= 2'), dep.version_requirements
end
def test_initialize_with_type
dep = Gem::Dependency.new("pkg", [], :development)
assert_equal(:development, dep.type)
end
def test_type_is_runtime_by_default
assert_equal(:runtime, Gem::Dependency.new("pkg", []).type)
end
def test_type_is_restricted
assert_raise(ArgumentError) do
Gem::Dependency.new("pkg", [:sometimes])
end
end
def test_equals2
assert_equal @pkg1_0, @pkg1_0.dup
assert_equal @pkg1_0.dup, @pkg1_0
@ -74,6 +89,36 @@ class TestGemDependency < RubyGemTestCase
assert_not_equal Object.new, @pkg1_0
end
def test_equals2_type
runtime = Gem::Dependency.new("pkg", [])
development = Gem::Dependency.new("pkg", [], :development)
assert_not_equal(runtime, development)
end
def test_equals_tilde
def dep(name, version)
Gem::Dependency.new name, version
end
a0 = dep 'a', '0'
a1 = dep 'a', '1'
b0 = dep 'b', '0'
pa0 = dep 'a', '>= 0'
pa0r = dep(/a/, '>= 0')
pab0r = dep(/a|b/, '>= 0')
assert((a0 =~ a0), 'match self')
assert((pa0 =~ a0), 'match version exact')
assert((pa0 =~ a1), 'match version')
assert((pa0r =~ a0), 'match regex simple')
assert((pab0r =~ a0), 'match regex complex')
assert(!(pa0r =~ b0), 'fail match regex')
assert(!(pa0r =~ Object.new), 'fail match Object')
end
def test_hash
assert_equal @pkg1_0.hash, @pkg1_0.dup.hash
assert_equal @pkg1_0.dup.hash, @pkg1_0.hash
@ -85,5 +130,11 @@ class TestGemDependency < RubyGemTestCase
assert_not_equal @oth1_0.hash, @pkg1_0.hash, "names different"
end
def test_hash_type
runtime = Gem::Dependency.new("pkg", [])
development = Gem::Dependency.new("pkg", [], :development)
assert_not_equal(runtime.hash, development.hash)
end
end

View file

@ -15,8 +15,12 @@ class TestGemDependencyInstaller < RubyGemTestCase
fp.puts "#!/usr/bin/ruby"
end
@a1, @a1_gem = util_gem 'a', '1' do |s| s.executables << 'a_bin' end
@aa1, @aa1_gem = util_gem 'aa', '1'
@b1, @b1_gem = util_gem 'b', '1' do |s| s.add_dependency 'a' end
@b1, @b1_gem = util_gem 'b', '1' do |s|
s.add_dependency 'a'
s.add_development_dependency 'aa'
end
@d1, @d1_gem = util_gem 'd', '1'
@d2, @d2_gem = util_gem 'd', '2'
@ -38,15 +42,13 @@ class TestGemDependencyInstaller < RubyGemTestCase
@z1, @z1_gem = util_gem 'z', '1' do |s| s.add_dependency 'y' end
si = util_setup_source_info_cache @a1, @b1, @d1, @d2, @x1_m, @x1_o, @w1,
@y1, @y1_1_p, @z1
@fetcher = Gem::FakeFetcher.new
Gem::RemoteFetcher.fetcher = @fetcher
@fetcher = FakeFetcher.new
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
@fetcher.uri = URI.parse 'http://gems.example.com'
@fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
si = util_setup_spec_fetcher @a1, @b1, @d1, @d2, @x1_m, @x1_o, @w1, @y1,
@y1_1_p, @z1
FileUtils.rm_rf File.join(@gemhome, 'gems')
util_clear_gems
end
def test_install
@ -64,6 +66,52 @@ class TestGemDependencyInstaller < RubyGemTestCase
assert_equal [@a1], inst.installed_gems
end
def test_install_cache_dir
FileUtils.mv @a1_gem, @tempdir
FileUtils.mv @b1_gem, @tempdir
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new :cache_dir => @tempdir
inst.install 'b'
end
assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
assert File.exist?(File.join(@tempdir, 'cache', "#{@a1.full_name}.gem"))
assert File.exist?(File.join(@tempdir, 'cache', "#{@b1.full_name}.gem"))
end
def test_install_dependencies_satisfied
a2, a2_gem = util_gem 'a', '2'
FileUtils.rm_rf File.join(@gemhome, 'gems')
Gem.source_index.refresh!
FileUtils.mv @a1_gem, @tempdir
FileUtils.mv a2_gem, @tempdir # not in index
FileUtils.mv @b1_gem, @tempdir
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new
inst.install 'a-2'
end
FileUtils.rm File.join(@tempdir, "#{a2.full_name}.gem")
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new
inst.install 'b'
end
installed = Gem::SourceIndex.from_installed_gems.map { |n,s| s.full_name }
assert_equal %w[a-2 b-1], installed.sort
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_dependency
FileUtils.mv @a1_gem, @tempdir
FileUtils.mv @b1_gem, @tempdir
@ -77,6 +125,20 @@ class TestGemDependencyInstaller < RubyGemTestCase
assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_dependency_development
FileUtils.mv @a1_gem, @tempdir
FileUtils.mv @aa1_gem, @tempdir
FileUtils.mv @b1_gem, @tempdir
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new(:development => true)
inst.install 'b'
end
assert_equal %w[a-1 aa-1 b-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_dependency_existing
Gem::Installer.new(@a1_gem).install
FileUtils.mv @a1_gem, @tempdir
@ -177,7 +239,7 @@ class TestGemDependencyInstaller < RubyGemTestCase
def test_install_force
FileUtils.mv @b1_gem, @tempdir
si = util_setup_source_info_cache @b1
si = util_setup_spec_fetcher @b1
@fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
inst = nil
@ -249,8 +311,6 @@ class TestGemDependencyInstaller < RubyGemTestCase
end
def test_install_domain_both_no_network
Gem::SourceInfoCache.instance_variable_set :@cache, nil
@fetcher.data["http://gems.example.com/gems/Marshal.#{@marshal_version}"] =
proc do
raise Gem::RemoteFetcher::FetchError
@ -272,12 +332,14 @@ class TestGemDependencyInstaller < RubyGemTestCase
FileUtils.mv @b1_gem, @tempdir
inst = nil
Gem.source_index.gems.delete @a1.full_name
Dir.chdir @tempdir do
e = assert_raise Gem::InstallError do
inst = Gem::DependencyInstaller.new :domain => :local
inst.install 'b'
end
assert_equal 'b requires a (>= 0)', e.message
assert_equal 'b requires a (>= 0, runtime)', e.message
end
assert_equal [], inst.installed_gems.map { |s| s.full_name }
@ -297,6 +359,30 @@ class TestGemDependencyInstaller < RubyGemTestCase
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_dual_repository
FileUtils.mv @a1_gem, @tempdir
FileUtils.mv @b1_gem, @tempdir
inst = nil
gemhome2 = "#{@gemhome}2"
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new :install_dir => gemhome2
inst.install 'a'
end
ENV['GEM_HOME'] = @gemhome
ENV['GEM_PATH'] = [@gemhome, gemhome2].join ':'
Gem.clear_paths
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new
inst.install 'b'
end
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_remote
a1_data = nil
File.open @a1_gem, 'rb' do |fp|
@ -337,7 +423,9 @@ class TestGemDependencyInstaller < RubyGemTestCase
s.platform = Gem::Platform.new %w[cpu other_platform 1]
end
si = util_setup_source_info_cache @a1, a2_o
util_clear_gems
si = util_setup_spec_fetcher @a1, a2_o
@fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
@ -439,7 +527,7 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = Gem::DependencyInstaller.new
dep = Gem::Dependency.new 'b', '>= 0'
assert_equal [[@b1, 'http://gems.example.com']],
assert_equal [[@b1, @gem_repo]],
inst.find_gems_with_sources(dep)
end
@ -456,7 +544,7 @@ class TestGemDependencyInstaller < RubyGemTestCase
assert_equal 2, gems.length
remote = gems.first
assert_equal 'a-1', remote.first.full_name, 'remote spec'
assert_equal 'http://gems.example.com', remote.last, 'remote path'
assert_equal @gem_repo, remote.last, 'remote path'
local = gems.last
assert_equal 'a-1', local.first.full_name, 'local spec'
@ -476,12 +564,9 @@ class TestGemDependencyInstaller < RubyGemTestCase
b2, = util_gem 'b', '2'
c1, = util_gem 'c', '1' do |s| s.add_dependency 'b' end
si = util_setup_source_info_cache @a1, @b1, b2, c1
util_clear_gems
@fetcher = FakeFetcher.new
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
@fetcher.uri = URI.parse 'http://gems.example.com'
@fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
si = util_setup_spec_fetcher @a1, @b1, b2, c1
inst = Gem::DependencyInstaller.new
inst.find_spec_by_name_and_version 'c'
@ -512,12 +597,9 @@ class TestGemDependencyInstaller < RubyGemTestCase
def test_gather_dependencies_old_required
e1, = util_gem 'e', '1' do |s| s.add_dependency 'd', '= 1' end
si = util_setup_source_info_cache @d1, @d2, e1
util_clear_gems
@fetcher = FakeFetcher.new
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
@fetcher.uri = URI.parse 'http://gems.example.com'
@fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
si = util_setup_spec_fetcher @d1, @d2, e1
inst = Gem::DependencyInstaller.new
inst.find_spec_by_name_and_version 'e'
@ -525,5 +607,6 @@ class TestGemDependencyInstaller < RubyGemTestCase
assert_equal %w[d-1 e-1], inst.gems_to_install.map { |s| s.full_name }
end
end

View file

@ -28,7 +28,10 @@ class TestGemGemPathSearcher < RubyGemTestCase
@bar1 = quick_gem 'bar', '0.1'
@bar2 = quick_gem 'bar', '0.2'
Gem.source_index = util_setup_source_info_cache @foo1, @foo2, @bar1, @bar2
@fetcher = Gem::FakeFetcher.new
Gem::RemoteFetcher.fetcher = @fetcher
Gem.source_index = util_setup_spec_fetcher @foo1, @foo2, @bar1, @bar2
@gps = Gem::GemPathSearcher.new
end

View file

@ -20,6 +20,10 @@ class TestGemIndexer < RubyGemTestCase
util_make_gems
@d2_0 = quick_gem 'd', '2.0'
write_file File.join(*%W[gems #{@d2_0.original_name} lib code.rb]) do end
util_build_gem @d2_0
gems = File.join(@tempdir, 'gems')
FileUtils.mkdir_p gems
cache_gems = File.join @gemhome, 'cache', '*.gem'
@ -39,10 +43,10 @@ class TestGemIndexer < RubyGemTestCase
@indexer.generate_index
end
assert File.exist?(File.join(@tempdir, 'yaml'))
assert File.exist?(File.join(@tempdir, 'yaml.Z'))
assert File.exist?(File.join(@tempdir, "Marshal.#{@marshal_version}"))
assert File.exist?(File.join(@tempdir, "Marshal.#{@marshal_version}.Z"))
assert_indexed @tempdir, 'yaml'
assert_indexed @tempdir, 'yaml.Z'
assert_indexed @tempdir, "Marshal.#{@marshal_version}"
assert_indexed @tempdir, "Marshal.#{@marshal_version}.Z"
quickdir = File.join @tempdir, 'quick'
marshal_quickdir = File.join quickdir, "Marshal.#{@marshal_version}"
@ -53,10 +57,33 @@ class TestGemIndexer < RubyGemTestCase
assert_indexed quickdir, "index"
assert_indexed quickdir, "index.rz"
quick_index = File.read File.join(quickdir, 'index')
expected = <<-EOF
a-1
a-2
a_evil-9
b-2
c-1.2
d-2.0
pl-1-i386-linux
EOF
assert_equal expected, quick_index
assert_indexed quickdir, "latest_index"
assert_indexed quickdir, "latest_index.rz"
assert_no_match %r|a-1|, File.read(File.join(quickdir, 'latest_index'))
latest_quick_index = File.read File.join(quickdir, 'latest_index')
expected = <<-EOF
a-2
a_evil-9
b-2
c-1.2
d-2.0
pl-1-i386-linux
EOF
assert_equal expected, latest_quick_index
assert_indexed quickdir, "#{@a1.full_name}.gemspec.rz"
assert_indexed quickdir, "#{@a2.full_name}.gemspec.rz"
@ -64,13 +91,19 @@ class TestGemIndexer < RubyGemTestCase
assert_indexed quickdir, "#{@c1_2.full_name}.gemspec.rz"
assert_indexed quickdir, "#{@pl1.original_name}.gemspec.rz"
deny_indexed quickdir, "#{@pl1.full_name}.gemspec.rz"
refute_indexed quickdir, "#{@pl1.full_name}.gemspec.rz"
assert_indexed marshal_quickdir, "#{@a1.full_name}.gemspec.rz"
assert_indexed marshal_quickdir, "#{@a2.full_name}.gemspec.rz"
deny_indexed quickdir, "#{@c1_2.full_name}.gemspec"
deny_indexed marshal_quickdir, "#{@c1_2.full_name}.gemspec"
refute_indexed quickdir, "#{@c1_2.full_name}.gemspec"
refute_indexed marshal_quickdir, "#{@c1_2.full_name}.gemspec"
assert_indexed @tempdir, "specs.#{@marshal_version}"
assert_indexed @tempdir, "specs.#{@marshal_version}.gz"
assert_indexed @tempdir, "latest_specs.#{@marshal_version}"
assert_indexed @tempdir, "latest_specs.#{@marshal_version}.gz"
end
def test_generate_index_ui
@ -79,28 +112,37 @@ class TestGemIndexer < RubyGemTestCase
end
expected = <<-EOF
Generating index for 6 gems in #{@tempdir}
......
Loading 7 gems from #{@tempdir}
.......
Loaded all gems
Generating master indexes (this may take a while)
Generating quick index gemspecs for 7 gems
.......
Complete
Generating specs index
Generating latest specs index
Generating quick index
Generating latest index
Generating Marshal master index
Generating YAML master index for 7 gems (this may take a while)
.......
Complete
Compressing indicies
EOF
assert_equal expected, @ui.output
assert_equal '', @ui.error
end
def test_generate_index_contents
def test_generate_index_master
use_ui @ui do
@indexer.generate_index
end
yaml_path = File.join(@tempdir, 'yaml')
dump_path = File.join(@tempdir, "Marshal.#{@marshal_version}")
yaml_path = File.join @tempdir, 'yaml'
dump_path = File.join @tempdir, "Marshal.#{@marshal_version}"
yaml_index = YAML.load_file(yaml_path)
dump_str = nil
File.open dump_path, 'rb' do |fp| dump_str = fp.read end
dump_index = Marshal.load dump_str
yaml_index = YAML.load_file yaml_path
dump_index = Marshal.load Gem.read_binary(dump_path)
dump_index.each do |_,gem|
gem.send :remove_instance_variable, :@loaded
@ -110,12 +152,75 @@ Generating master indexes (this may take a while)
"expected YAML and Marshal to produce identical results"
end
def test_generate_index_specs
use_ui @ui do
@indexer.generate_index
end
specs_path = File.join @tempdir, "specs.#{@marshal_version}"
specs_dump = Gem.read_binary specs_path
specs = Marshal.load specs_dump
expected = [
['a', Gem::Version.new(1), 'ruby'],
['a', Gem::Version.new(2), 'ruby'],
['a_evil', Gem::Version.new(9), 'ruby'],
['b', Gem::Version.new(2), 'ruby'],
['c', Gem::Version.new('1.2'), 'ruby'],
['d', Gem::Version.new('2.0'), 'ruby'],
['pl', Gem::Version.new(1), 'i386-linux'],
]
assert_equal expected, specs
assert_same specs[0].first, specs[1].first,
'identical names not identical'
assert_same specs[0][1], specs[-1][1],
'identical versions not identical'
assert_same specs[0].last, specs[1].last,
'identical platforms not identical'
assert_not_same specs[1][1], specs[5][1],
'different versions not different'
end
def test_generate_index_latest_specs
use_ui @ui do
@indexer.generate_index
end
latest_specs_path = File.join @tempdir, "latest_specs.#{@marshal_version}"
latest_specs_dump = Gem.read_binary latest_specs_path
latest_specs = Marshal.load latest_specs_dump
expected = [
['a', Gem::Version.new(2), 'ruby'],
['a_evil', Gem::Version.new(9), 'ruby'],
['b', Gem::Version.new(2), 'ruby'],
['c', Gem::Version.new('1.2'), 'ruby'],
['d', Gem::Version.new('2.0'), 'ruby'],
['pl', Gem::Version.new(1), 'i386-linux'],
]
assert_equal expected, latest_specs
assert_same latest_specs[0][1], latest_specs[2][1],
'identical versions not identical'
assert_same latest_specs[0].last, latest_specs[1].last,
'identical platforms not identical'
end
def assert_indexed(dir, name)
file = File.join dir, name
assert File.exist?(file), "#{file} does not exist"
end
def deny_indexed(dir, name)
def refute_indexed(dir, name)
file = File.join dir, name
assert !File.exist?(file), "#{file} exists"
end

View file

@ -102,7 +102,7 @@ load 'my_exec'
@installer.ensure_dependency @spec, dep
end
assert_equal 'a requires b (> 2)', e.message
assert_equal 'a requires b (> 2, runtime)', e.message
end
def test_expand_and_validate_gem_dir
@ -128,7 +128,12 @@ load 'my_exec'
@installer.extract_files
assert_equal 'thefile', File.read(File.join(util_gem_dir, 'thefile'))
thefile_path = File.join(util_gem_dir, 'thefile')
assert_equal 'thefile', File.read(thefile_path)
unless Gem.win_platform? then
assert_equal 0400, File.stat(thefile_path).mode & 0777
end
end
def test_extract_files_bad_dest
@ -313,6 +318,29 @@ load 'my_exec'
#assert_no_match %r|generated by RubyGems|, wrapper
end
def test_generate_bin_script_wrappers
@installer.wrappers = true
util_make_exec
@installer.gem_dir = util_gem_dir
installed_exec = File.join(util_inst_bindir, "my_exec")
real_exec = File.join util_gem_dir, 'bin', 'my_exec'
# fake --no-wrappers for previous install
FileUtils.mkdir_p File.dirname(installed_exec)
FileUtils.ln_s real_exec, installed_exec
@installer.generate_bin
assert_equal true, File.directory?(util_inst_bindir)
assert_equal true, File.exist?(installed_exec)
assert_equal(0100755, File.stat(installed_exec).mode) unless win_platform?
assert_match %r|generated by RubyGems|, File.read(installed_exec)
assert_no_match %r|generated by RubyGems|, File.read(real_exec),
'real executable overwritten'
end
def test_generate_bin_symlink
return if win_platform? #Windows FS do not support symlinks

View file

@ -46,12 +46,13 @@ class TestGemLocalRemoteOptions < RubyGemTestCase
def test_source_option
@cmd.add_source_option
s1 = URI.parse 'http://more-gems.example.com'
s2 = URI.parse 'http://even-more-gems.example.com'
s1 = URI.parse 'http://more-gems.example.com/'
s2 = URI.parse 'http://even-more-gems.example.com/'
s3 = URI.parse 'http://other-gems.example.com/some_subdir'
@cmd.handle_options %W[--source #{s1} --source #{s2}]
@cmd.handle_options %W[--source #{s1} --source #{s2} --source #{s3}]
assert_equal [s1, s2], Gem.sources
assert_equal [s1.to_s, s2.to_s, "#{s3}/"], Gem.sources
end
def test_update_sources_option
@ -77,7 +78,7 @@ class TestGemLocalRemoteOptions < RubyGemTestCase
@cmd.handle_options %W[--source #{s1}]
end
assert_equal %w[http://gems.example.com], Gem.sources
assert_equal [@gem_repo], Gem.sources
end
end

View file

@ -24,7 +24,7 @@ require 'rubygems/remote_fetcher'
# Note that the proxy server is not a *real* proxy server. But our
# software doesn't really care, as long as we hit the proxy URL when a
# proxy is configured.
#
class TestGemRemoteFetcher < RubyGemTestCase
include Gem::DefaultUserInteraction
@ -105,7 +105,7 @@ gems:
@a1, @a1_gem = util_gem 'a', '1' do |s| s.executables << 'a_bin' end
Gem::RemoteFetcher.instance_variable_set :@fetcher, nil
Gem::RemoteFetcher.fetcher = nil
end
def test_self_fetcher
@ -144,7 +144,7 @@ gems:
def test_fetch_size_socket_error
fetcher = Gem::RemoteFetcher.new nil
def fetcher.connect_to(host, port)
def fetcher.connection_for(uri)
raise SocketError
end
@ -153,7 +153,8 @@ gems:
fetcher.fetch_size uri
end
assert_equal "SocketError (SocketError)\n\tgetting size of #{uri}", e.message
assert_equal "SocketError (SocketError)\n\tfetching size (#{uri})",
e.message
end
def test_no_proxy
@ -182,7 +183,7 @@ gems:
@test_data
end
raise Gem::RemoteFetcher::FetchError, "haha!"
raise Gem::RemoteFetcher::FetchError.new("haha!", nil)
end
end
@ -371,7 +372,8 @@ gems:
fetcher.fetch_path 'uri'
end
assert_equal 'EOFError: EOFError reading uri', e.message
assert_equal 'EOFError: EOFError (uri)', e.message
assert_equal 'uri', e.uri
end
def test_fetch_path_socket_error
@ -383,7 +385,8 @@ gems:
fetcher.fetch_path 'uri'
end
assert_equal 'SocketError: SocketError reading uri', e.message
assert_equal 'SocketError: SocketError (uri)', e.message
assert_equal 'uri', e.uri
end
def test_fetch_path_system_call_error
@ -397,8 +400,9 @@ gems:
fetcher.fetch_path 'uri'
end
assert_match %r|ECONNREFUSED:.*connect\(2\) reading uri\z|,
assert_match %r|ECONNREFUSED:.*connect\(2\) \(uri\)\z|,
e.message
assert_equal 'uri', e.uri
end
def test_get_proxy_from_env_empty
@ -494,7 +498,8 @@ gems:
fetcher.send :open_uri_or_path, 'http://gems.example.com/redirect'
end
assert_equal 'too many redirects', e.message
assert_equal 'too many redirects (http://gems.example.com/redirect)',
e.message
end
def test_zip

View file

@ -14,12 +14,121 @@ class TestGemServer < RubyGemTestCase
super
@a1 = quick_gem 'a', '1'
@a2 = quick_gem 'a', '2'
@server = Gem::Server.new Gem.dir, process_based_port, false
@req = WEBrick::HTTPRequest.new :Logger => nil
@res = WEBrick::HTTPResponse.new :HTTPVersion => '1.0'
end
def test_Marshal
data = StringIO.new "GET /Marshal.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
@req.parse data
@server.Marshal @req, @res
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'application/octet-stream', @res['content-type']
si = Gem::SourceIndex.new
si.add_specs @a1, @a2
assert_equal si, Marshal.load(@res.body)
end
def test_Marshal_Z
data = StringIO.new "GET /Marshal.#{Gem.marshal_version}.Z HTTP/1.0\r\n\r\n"
@req.parse data
@server.Marshal @req, @res
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'application/x-deflate', @res['content-type']
si = Gem::SourceIndex.new
si.add_specs @a1, @a2
assert_equal si, Marshal.load(Gem.inflate(@res.body))
end
def test_latest_specs
data = StringIO.new "GET /latest_specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
@req.parse data
@server.latest_specs @req, @res
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'application/octet-stream', @res['content-type']
assert_equal [['a', Gem::Version.new(2), Gem::Platform::RUBY]],
Marshal.load(@res.body)
end
def test_latest_specs_gz
data = StringIO.new "GET /latest_specs.#{Gem.marshal_version}.gz HTTP/1.0\r\n\r\n"
@req.parse data
@server.latest_specs @req, @res
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'application/x-gzip', @res['content-type']
assert_equal [['a', Gem::Version.new(2), Gem::Platform::RUBY]],
Marshal.load(Gem.gunzip(@res.body))
end
def test_quick_a_1_gemspec_rz
data = StringIO.new "GET /quick/a-1.gemspec.rz HTTP/1.0\r\n\r\n"
@req.parse data
@server.quick @req, @res
assert_equal 200, @res.status, @res.body
assert @res['date']
assert_equal 'application/x-deflate', @res['content-type']
spec = YAML.load Gem.inflate(@res.body)
assert_equal 'a', spec.name
assert_equal Gem::Version.new(1), spec.version
end
def test_quick_a_1_mswin32_gemspec_rz
a1_p = quick_gem 'a', '1' do |s| s.platform = Gem::Platform.local end
data = StringIO.new "GET /quick/a-1-#{Gem::Platform.local}.gemspec.rz HTTP/1.0\r\n\r\n"
@req.parse data
@server.quick @req, @res
assert_equal 200, @res.status, @res.body
assert @res['date']
assert_equal 'application/x-deflate', @res['content-type']
spec = YAML.load Gem.inflate(@res.body)
assert_equal 'a', spec.name
assert_equal Gem::Version.new(1), spec.version
assert_equal Gem::Platform.local, spec.platform
end
def test_quick_common_substrings
ab1 = quick_gem 'ab', '1'
data = StringIO.new "GET /quick/a-1.gemspec.rz HTTP/1.0\r\n\r\n"
@req.parse data
@server.quick @req, @res
assert_equal 200, @res.status, @res.body
assert @res['date']
assert_equal 'application/x-deflate', @res['content-type']
spec = YAML.load Gem.inflate(@res.body)
assert_equal 'a', spec.name
assert_equal Gem::Version.new(1), spec.version
end
def test_quick_index
data = StringIO.new "GET /quick/index HTTP/1.0\r\n\r\n"
@req.parse data
@ -29,7 +138,7 @@ class TestGemServer < RubyGemTestCase
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'text/plain', @res['content-type']
assert_equal "a-1", @res.body
assert_equal "a-1\na-2", @res.body
end
def test_quick_index_rz
@ -40,65 +149,35 @@ class TestGemServer < RubyGemTestCase
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'text/plain', @res['content-type']
assert_equal "a-1", Zlib::Inflate.inflate(@res.body)
assert_equal 'application/x-deflate', @res['content-type']
assert_equal "a-1\na-2", Gem.inflate(@res.body)
end
def test_quick_a_1_gemspec_rz
data = StringIO.new "GET /quick/a-1.gemspec.rz HTTP/1.0\r\n\r\n"
def test_quick_latest_index
data = StringIO.new "GET /quick/latest_index HTTP/1.0\r\n\r\n"
@req.parse data
@server.quick @req, @res
assert_equal 200, @res.status, @res.body
assert @res['date']
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'text/plain', @res['content-type']
spec = YAML.load Zlib::Inflate.inflate(@res.body)
assert_equal 'a', spec.name
assert_equal Gem::Version.new(1), spec.version
assert_equal 'a-2', @res.body
end
def test_quick_a_1_mswin32_gemspec_rz
a1_p = quick_gem 'a', '1' do |s| s.platform = Gem::Platform.local end
si = Gem::SourceIndex.new @a1.full_name => @a1, a1_p.full_name => a1_p
@server.source_index = si
data = StringIO.new "GET /quick/a-1-#{Gem::Platform.local}.gemspec.rz HTTP/1.0\r\n\r\n"
def test_quick_latest_index_rz
data = StringIO.new "GET /quick/latest_index.rz HTTP/1.0\r\n\r\n"
@req.parse data
@server.quick @req, @res
assert_equal 200, @res.status, @res.body
assert @res['date']
assert_equal 'text/plain', @res['content-type']
spec = YAML.load Zlib::Inflate.inflate(@res.body)
assert_equal 'a', spec.name
assert_equal Gem::Version.new(1), spec.version
assert_equal Gem::Platform.local, spec.platform
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'application/x-deflate', @res['content-type']
assert_equal 'a-2', Gem.inflate(@res.body)
end
def test_quick_common_substrings
ab1 = quick_gem 'ab', '1'
si = Gem::SourceIndex.new @a1.full_name => @a1, ab1.full_name => ab1
@server.source_index = si
data = StringIO.new "GET /quick/a-1.gemspec.rz HTTP/1.0\r\n\r\n"
@req.parse data
@server.quick @req, @res
assert_equal 200, @res.status, @res.body
assert @res['date']
assert_equal 'text/plain', @res['content-type']
spec = YAML.load Zlib::Inflate.inflate(@res.body)
assert_equal 'a', spec.name
assert_equal Gem::Version.new(1), spec.version
end
def test_quick_z_9_gemspec_rz
def test_quick_missing
data = StringIO.new "GET /quick/z-9.gemspec.rz HTTP/1.0\r\n\r\n"
@req.parse data
@ -111,5 +190,112 @@ class TestGemServer < RubyGemTestCase
assert_equal 404, @res.status
end
def test_quick_marshal_a_1_gemspec_rz
data = StringIO.new "GET /quick/Marshal.#{Gem.marshal_version}/a-1.gemspec.rz HTTP/1.0\r\n\r\n"
@req.parse data
@server.quick @req, @res
assert_equal 200, @res.status, @res.body
assert @res['date']
assert_equal 'application/x-deflate', @res['content-type']
spec = Marshal.load Gem.inflate(@res.body)
assert_equal 'a', spec.name
assert_equal Gem::Version.new(1), spec.version
end
def test_quick_marshal_a_1_mswin32_gemspec_rz
a1_p = quick_gem 'a', '1' do |s| s.platform = Gem::Platform.local end
data = StringIO.new "GET /quick/Marshal.#{Gem.marshal_version}/a-1-#{Gem::Platform.local}.gemspec.rz HTTP/1.0\r\n\r\n"
@req.parse data
@server.quick @req, @res
assert_equal 200, @res.status, @res.body
assert @res['date']
assert_equal 'application/x-deflate', @res['content-type']
spec = Marshal.load Gem.inflate(@res.body)
assert_equal 'a', spec.name
assert_equal Gem::Version.new(1), spec.version
assert_equal Gem::Platform.local, spec.platform
end
def test_root
data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
@req.parse data
@server.root @req, @res
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'text/html', @res['content-type']
end
def test_specs
data = StringIO.new "GET /specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
@req.parse data
@server.specs @req, @res
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'application/octet-stream', @res['content-type']
assert_equal [['a', Gem::Version.new(1), Gem::Platform::RUBY],
['a', Gem::Version.new(2), Gem::Platform::RUBY]],
Marshal.load(@res.body)
end
def test_specs_gz
data = StringIO.new "GET /specs.#{Gem.marshal_version}.gz HTTP/1.0\r\n\r\n"
@req.parse data
@server.specs @req, @res
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'application/x-gzip', @res['content-type']
assert_equal [['a', Gem::Version.new(1), Gem::Platform::RUBY],
['a', Gem::Version.new(2), Gem::Platform::RUBY]],
Marshal.load(Gem.gunzip(@res.body))
end
def test_yaml
data = StringIO.new "GET /yaml.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
@req.parse data
@server.yaml @req, @res
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'text/plain', @res['content-type']
si = Gem::SourceIndex.new
si.add_specs @a1, @a2
assert_equal si, YAML.load(@res.body)
end
def test_yaml_Z
data = StringIO.new "GET /yaml.#{Gem.marshal_version}.Z HTTP/1.0\r\n\r\n"
@req.parse data
@server.yaml @req, @res
assert_equal 200, @res.status, @res.body
assert_match %r| \d\d:\d\d:\d\d |, @res['date']
assert_equal 'application/x-deflate', @res['content-type']
si = Gem::SourceIndex.new
si.add_specs @a1, @a2
assert_equal si, YAML.load(Gem.inflate(@res.body))
end
end

View file

@ -23,6 +23,141 @@ class TestGemSourceIndex < RubyGemTestCase
util_setup_fake_fetcher
end
def test_self_from_gems_in
spec_dir = File.join @gemhome, 'specifications'
FileUtils.rm_r spec_dir
FileUtils.mkdir_p spec_dir
a1 = quick_gem 'a', '1' do |spec| spec.author = 'author 1' end
spec_file = File.join spec_dir, "#{a1.full_name}.gemspec"
File.open spec_file, 'w' do |fp|
fp.write a1.to_ruby
end
si = Gem::SourceIndex.from_gems_in spec_dir
assert_equal [spec_dir], si.spec_dirs
assert_equal [a1.full_name], si.gems.keys
end
def test_self_load_specification
spec_dir = File.join @gemhome, 'specifications'
FileUtils.rm_r spec_dir
FileUtils.mkdir_p spec_dir
a1 = quick_gem 'a', '1' do |spec| spec.author = 'author 1' end
spec_file = File.join spec_dir, "#{a1.full_name}.gemspec"
File.open spec_file, 'w' do |fp|
fp.write a1.to_ruby
end
spec = Gem::SourceIndex.load_specification spec_file
assert_equal a1.author, spec.author
end
def test_self_load_specification_exception
spec_dir = File.join @gemhome, 'specifications'
FileUtils.mkdir_p spec_dir
spec_file = File.join spec_dir, 'a-1.gemspec'
File.open spec_file, 'w' do |fp|
fp.write 'raise Exception, "epic fail"'
end
use_ui @ui do
assert_equal nil, Gem::SourceIndex.load_specification(spec_file)
end
assert_equal '', @ui.output
expected = <<-EOF
WARNING: #<Exception: epic fail>
raise Exception, "epic fail"
WARNING: Invalid .gemspec format in '#{spec_file}'
EOF
assert_equal expected, @ui.error
end
def test_self_load_specification_interrupt
spec_dir = File.join @gemhome, 'specifications'
FileUtils.mkdir_p spec_dir
spec_file = File.join spec_dir, 'a-1.gemspec'
File.open spec_file, 'w' do |fp|
fp.write 'raise Interrupt, "^C"'
end
use_ui @ui do
assert_raise Interrupt do
Gem::SourceIndex.load_specification(spec_file)
end
end
assert_equal '', @ui.output
assert_equal '', @ui.error
end
def test_self_load_specification_syntax_error
spec_dir = File.join @gemhome, 'specifications'
FileUtils.mkdir_p spec_dir
spec_file = File.join spec_dir, 'a-1.gemspec'
File.open spec_file, 'w' do |fp|
fp.write '1 +'
end
use_ui @ui do
assert_equal nil, Gem::SourceIndex.load_specification(spec_file)
end
assert_equal '', @ui.output
expected = <<-EOF
WARNING: compile error
#{spec_file}:1: syntax error, unexpected $end
WARNING: 1 +
EOF
assert_equal expected, @ui.error
end
def test_self_load_specification_system_exit
spec_dir = File.join @gemhome, 'specifications'
FileUtils.mkdir_p spec_dir
spec_file = File.join spec_dir, 'a-1.gemspec'
File.open spec_file, 'w' do |fp|
fp.write 'raise SystemExit, "bye-bye"'
end
use_ui @ui do
assert_raise SystemExit do
Gem::SourceIndex.load_specification(spec_file)
end
end
assert_equal '', @ui.output
assert_equal '', @ui.error
end
def test_create_from_directory
# TODO
end
@ -43,16 +178,16 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
assert paths.empty?, paths.join(', ')
end
def test_fetch_bulk_index_error
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}.Z"] = proc { raise SocketError }
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = proc { raise SocketError }
@fetcher.data["#{@gem_repo}/yaml.Z"] = proc { raise SocketError }
@fetcher.data["#{@gem_repo}/yaml"] = proc { raise SocketError }
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}.Z"] = proc { raise SocketError }
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = proc { raise SocketError }
@fetcher.data["#{@gem_repo}yaml.Z"] = proc { raise SocketError }
@fetcher.data["#{@gem_repo}yaml"] = proc { raise SocketError }
e = assert_raise Gem::RemoteSourceException do
use_ui @ui do
@ -62,10 +197,10 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}", paths.shift
assert_equal "#{@gem_repo}/yaml.Z", paths.shift
assert_equal "#{@gem_repo}/yaml", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}", paths.shift
assert_equal "#{@gem_repo}yaml.Z", paths.shift
assert_equal "#{@gem_repo}yaml", paths.shift
assert paths.empty?, paths.join(', ')
@ -74,12 +209,12 @@ class TestGemSourceIndex < RubyGemTestCase
end
def test_fetch_bulk_index_fallback
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}.Z"] =
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}.Z"] =
proc { raise SocketError }
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] =
proc { raise SocketError }
@fetcher.data["#{@gem_repo}/yaml.Z"] = proc { raise SocketError }
@fetcher.data["#{@gem_repo}/yaml"] = @source_index.to_yaml
@fetcher.data["#{@gem_repo}yaml.Z"] = proc { raise SocketError }
@fetcher.data["#{@gem_repo}yaml"] = @source_index.to_yaml
use_ui @ui do
fetched_index = @source_index.fetch_bulk_index @uri
@ -90,10 +225,10 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}", paths.shift
assert_equal "#{@gem_repo}/yaml.Z", paths.shift
assert_equal "#{@gem_repo}/yaml", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}", paths.shift
assert_equal "#{@gem_repo}yaml.Z", paths.shift
assert_equal "#{@gem_repo}yaml", paths.shift
assert paths.empty?, paths.join(', ')
end
@ -102,8 +237,8 @@ class TestGemSourceIndex < RubyGemTestCase
marshal = @source_index.dump
marshal[0] = (Marshal::MAJOR_VERSION - 1).chr
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = marshal
@fetcher.data["#{@gem_repo}/yaml"] = @source_index.to_yaml
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = marshal
@fetcher.data["#{@gem_repo}yaml"] = @source_index.to_yaml
use_ui @ui do
fetched_index = @source_index.fetch_bulk_index @uri
@ -114,10 +249,10 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}", paths.shift
assert_equal "#{@gem_repo}/yaml.Z", paths.shift
assert_equal "#{@gem_repo}/yaml", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}", paths.shift
assert_equal "#{@gem_repo}yaml.Z", paths.shift
assert_equal "#{@gem_repo}yaml", paths.shift
assert paths.empty?, paths.join(', ')
end
@ -133,8 +268,8 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}", paths.shift
assert paths.empty?, paths.join(', ')
end
@ -143,8 +278,8 @@ class TestGemSourceIndex < RubyGemTestCase
index = util_zip @gem_names
latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
@fetcher.data["#{@gem_repo}/quick/index.rz"] = index
@fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = latest_index
@fetcher.data["#{@gem_repo}quick/index.rz"] = index
@fetcher.data["#{@gem_repo}quick/latest_index.rz"] = latest_index
quick_index = @source_index.fetch_quick_index @uri, false
assert_equal [@a2.full_name, @b2.full_name].sort,
@ -152,7 +287,7 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/latest_index.rz", paths.shift
assert_equal "#{@gem_repo}quick/latest_index.rz", paths.shift
assert paths.empty?, paths.join(', ')
end
@ -161,8 +296,8 @@ class TestGemSourceIndex < RubyGemTestCase
index = util_zip @gem_names
latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
@fetcher.data["#{@gem_repo}/quick/index.rz"] = index
@fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = latest_index
@fetcher.data["#{@gem_repo}quick/index.rz"] = index
@fetcher.data["#{@gem_repo}quick/latest_index.rz"] = latest_index
quick_index = @source_index.fetch_quick_index @uri, true
assert_equal [@a1.full_name, @a2.full_name, @b2.full_name].sort,
@ -170,13 +305,13 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
assert_equal "#{@gem_repo}quick/index.rz", paths.shift
assert paths.empty?, paths.join(', ')
end
def test_fetch_quick_index_error
@fetcher.data["#{@gem_repo}/quick/index.rz"] =
@fetcher.data["#{@gem_repo}quick/index.rz"] =
proc { raise Exception }
e = assert_raise Gem::OperationNotSupportedError do
@ -187,7 +322,7 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
assert_equal "#{@gem_repo}quick/index.rz", paths.shift
assert paths.empty?, paths.join(', ')
end
@ -195,22 +330,22 @@ class TestGemSourceIndex < RubyGemTestCase
def test_fetch_quick_index_fallback
index = util_zip @gem_names
@fetcher.data["#{@gem_repo}/quick/index.rz"] = index
@fetcher.data["#{@gem_repo}quick/index.rz"] = index
quick_index = @source_index.fetch_quick_index @uri, false
assert_equal @gem_names.split, quick_index.sort
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/latest_index.rz", paths.shift
assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
assert_equal "#{@gem_repo}quick/latest_index.rz", paths.shift
assert_equal "#{@gem_repo}quick/index.rz", paths.shift
assert paths.empty?, paths.join(', ')
end
def test_fetch_quick_index_subdir
latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
repo = URI.parse "#{@gem_repo}/~nobody/mirror/"
repo = URI.parse "#{@gem_repo}~nobody/mirror/"
@fetcher.data["#{repo}quick/latest_index.rz"] = latest_index
@ -226,7 +361,7 @@ class TestGemSourceIndex < RubyGemTestCase
end
def test_fetch_single_spec
a1_spec_url = "#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz"
a1_spec_url = "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz"
@fetcher.data[a1_spec_url] = util_zip Marshal.dump(@a1)
spec = @source_index.send :fetch_single_spec, URI.parse(@gem_repo),
@ -242,7 +377,7 @@ class TestGemSourceIndex < RubyGemTestCase
end
def test_fetch_single_spec_subdir
repo = URI.parse "#{@gem_repo}/~nobody/mirror/"
repo = URI.parse "#{@gem_repo}~nobody/mirror/"
a1_spec_url = "#{repo}quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz"
@fetcher.data[a1_spec_url] = util_zip Marshal.dump(@a1)
@ -259,7 +394,7 @@ class TestGemSourceIndex < RubyGemTestCase
end
def test_fetch_single_spec_yaml
a1_spec_url = "#{@gem_repo}/quick/#{@a1.full_name}.gemspec.rz"
a1_spec_url = "#{@gem_repo}quick/#{@a1.full_name}.gemspec.rz"
@fetcher.data[a1_spec_url] = util_zip @a1.to_yaml
repo = URI.parse @gem_repo
@ -270,14 +405,14 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz", paths.shift
assert_equal "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz", paths.shift
assert_equal a1_spec_url, paths.shift
assert paths.empty?, paths.join(', ')
end
def test_fetch_single_spec_yaml_subdir
repo = URI.parse "#{@gem_repo}/~nobody/mirror/"
repo = URI.parse "#{@gem_repo}~nobody/mirror/"
a1_spec_url = "#{repo}quick/#{@a1.full_name}.gemspec.rz"
@fetcher.data[a1_spec_url] = util_zip @a1.to_yaml
@ -377,12 +512,12 @@ class TestGemSourceIndex < RubyGemTestCase
end
def test_outdated
util_setup_source_info_cache
util_setup_spec_fetcher
assert_equal [], @source_index.outdated
updated = quick_gem @a2.name, (@a2.version.bump)
util_setup_source_info_cache updated
util_setup_spec_fetcher updated
assert_equal [updated.name], @source_index.outdated
@ -390,7 +525,7 @@ class TestGemSourceIndex < RubyGemTestCase
s.platform = Gem::Platform.new 'x86-other_platform1'
end
util_setup_source_info_cache updated, updated_platform
util_setup_spec_fetcher updated, updated_platform
assert_equal [updated_platform.name], @source_index.outdated
end
@ -411,6 +546,16 @@ class TestGemSourceIndex < RubyGemTestCase
assert source_index.gems.include?(@a1.full_name)
end
def test_refresh_bang_not_from_dir
source_index = Gem::SourceIndex.new
e = assert_raise RuntimeError do
source_index.refresh!
end
assert_equal 'source index not created from disk', e.message
end
def test_remove_extra
@source_index.add_spec @a1
@source_index.add_spec @a2
@ -516,8 +661,8 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}quick/index.rz", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
assert paths.empty?, paths.join(', ')
end
@ -528,7 +673,7 @@ class TestGemSourceIndex < RubyGemTestCase
latest_names = [@a2, @a_evil9, @b2, @c1_2].map { |s| s.full_name }
latest_index = util_zip latest_names.join("\n")
@fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = latest_index
@fetcher.data["#{@gem_repo}quick/latest_index.rz"] = latest_index
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
"#{@b2.full_name}.gemspec.rz"
@ -541,7 +686,7 @@ class TestGemSourceIndex < RubyGemTestCase
end
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/latest_index.rz", paths.shift
assert_equal "#{@gem_repo}quick/latest_index.rz", paths.shift
assert_equal marshal_uri, paths.shift
assert paths.empty?, paths.join(', ')
@ -554,7 +699,7 @@ class TestGemSourceIndex < RubyGemTestCase
Gem.configuration = Gem::ConfigFile.new([])
quick_index = util_zip @all_gem_names.join("\n")
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
@fetcher.data["#{@gem_repo}quick/index.rz"] = quick_index
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
"#{@b2.full_name}.gemspec.rz"
@ -567,7 +712,7 @@ class TestGemSourceIndex < RubyGemTestCase
end
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
assert_equal "#{@gem_repo}quick/index.rz", paths.shift
assert_equal marshal_uri, paths.shift
assert paths.empty?, paths.join(', ')
@ -580,12 +725,12 @@ class TestGemSourceIndex < RubyGemTestCase
Gem.configuration = Gem::ConfigFile.new([])
quick_index = util_zip @all_gem_names.join("\n")
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
@fetcher.data["#{@gem_repo}quick/index.rz"] = quick_index
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
"#{@b2.full_name}.gemspec.rz"
yaml_uri = "#{@gem_repo}/quick/#{@b2.full_name}.gemspec.rz"
yaml_uri = "#{@gem_repo}quick/#{@b2.full_name}.gemspec.rz"
@fetcher.data[yaml_uri] = util_zip @b2.to_yaml
use_ui @ui do
@ -595,7 +740,7 @@ class TestGemSourceIndex < RubyGemTestCase
end
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
assert_equal "#{@gem_repo}quick/index.rz", paths.shift
assert_equal marshal_uri, paths.shift
assert_equal yaml_uri, paths.shift
@ -609,7 +754,7 @@ class TestGemSourceIndex < RubyGemTestCase
Gem.configuration = Gem::ConfigFile.new([])
quick_index = util_zip @all_gem_names.join("\n")
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
@fetcher.data["#{@gem_repo}quick/index.rz"] = quick_index
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
"#{@b2.full_name}.gemspec.rz"
@ -617,7 +762,7 @@ class TestGemSourceIndex < RubyGemTestCase
marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr
@fetcher.data[marshal_uri] = util_zip marshal_data
yaml_uri = "#{@gem_repo}/quick/#{@b2.full_name}.gemspec.rz"
yaml_uri = "#{@gem_repo}quick/#{@b2.full_name}.gemspec.rz"
@fetcher.data[yaml_uri] = util_zip @b2.to_yaml
use_ui @ui do
@ -627,7 +772,7 @@ class TestGemSourceIndex < RubyGemTestCase
end
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
assert_equal "#{@gem_repo}quick/index.rz", paths.shift
assert_equal marshal_uri, paths.shift
assert_equal yaml_uri, paths.shift
@ -637,14 +782,14 @@ class TestGemSourceIndex < RubyGemTestCase
end
def test_update_subdir
@gem_repo = @gem_repo + "/subdir"
@gem_repo = @gem_repo + 'subdir/'
util_setup_bulk_fetch true
@source_index.gems.replace({})
assert_equal [], @source_index.gems.keys.sort
uri = @uri.to_s + "/subdir"
uri = @uri.to_s + 'subdir/'
use_ui @ui do
@source_index.update uri, true
@ -656,8 +801,8 @@ class TestGemSourceIndex < RubyGemTestCase
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/index.rz", paths.shift
assert_equal "#{@gem_repo}/Marshal.#{@marshal_version}.Z", paths.shift
assert_equal "#{@gem_repo}quick/index.rz", paths.shift
assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
assert paths.empty?, paths.join(', ')
end
@ -684,9 +829,9 @@ class TestGemSourceIndex < RubyGemTestCase
source_index = @source_index.dump
if compressed then
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}.Z"] = util_zip source_index
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}.Z"] = util_zip source_index
else
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = source_index
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = source_index
end
end

View file

@ -36,6 +36,7 @@ class TestGemSourceInfoCache < RubyGemTestCase
def teardown
super
Gem.sources.replace @original_sources
Gem::SourceInfoCache.instance_variable_set :@cache, nil
end
def test_self_cache_refreshes
@ -43,7 +44,7 @@ class TestGemSourceInfoCache < RubyGemTestCase
si = Gem::SourceIndex.new
si.add_spec @a1
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = si.dump
Gem.sources.replace %W[#{@gem_repo}]
@ -52,8 +53,9 @@ class TestGemSourceInfoCache < RubyGemTestCase
assert_kind_of Gem::SourceInfoCache, Gem::SourceInfoCache.cache
assert_equal Gem::SourceInfoCache.cache.object_id,
Gem::SourceInfoCache.cache.object_id
assert_match %r|Bulk updating|, @ui.output
end
assert_match %r|Bulk updating|, @ui.output
end
def test_self_cache_skips_refresh_based_on_configuration
@ -61,7 +63,7 @@ class TestGemSourceInfoCache < RubyGemTestCase
si = Gem::SourceIndex.new
si.add_spec @a1
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = si.dump
Gem.sources.replace %w[#{@gem_repo}]
@ -78,7 +80,7 @@ class TestGemSourceInfoCache < RubyGemTestCase
si = Gem::SourceIndex.new
si.add_spec @a1
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = si.dump
Gem::SourceInfoCache.instance_variable_set :@cache, nil
sice = Gem::SourceInfoCacheEntry.new si, 0
@ -106,7 +108,7 @@ class TestGemSourceInfoCache < RubyGemTestCase
end
def test_cache_data_irreparable
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = @source_index.dump
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = @source_index.dump
data = { @gem_repo => { 'totally' => 'borked' } }

View file

@ -15,9 +15,9 @@ class TestGemSourceInfoCacheEntry < RubyGemTestCase
end
def test_refresh
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}.Z"] =
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}.Z"] =
proc { raise }
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = @si.dump
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = @si.dump
use_ui @ui do
@sic_e.refresh @gem_repo, true
@ -30,18 +30,20 @@ class TestGemSourceInfoCacheEntry < RubyGemTestCase
a1_name = @a1.full_name
a2_name = @a2.full_name
@fetcher.data["#{@gem_repo}/quick/index.rz"] =
@fetcher.data["#{@gem_repo}quick/index.rz"] =
util_zip [a1_name, a2_name].join("\n")
@fetcher.data["#{@gem_repo}/quick/latest_index.rz"] = util_zip a2_name
@fetcher.data["#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{a1_name}.gemspec.rz"] = util_zip Marshal.dump(@a1)
@fetcher.data["#{@gem_repo}/quick/Marshal.#{Gem.marshal_version}/#{a2_name}.gemspec.rz"] = util_zip Marshal.dump(@a2)
@fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] =
@fetcher.data["#{@gem_repo}quick/latest_index.rz"] = util_zip a2_name
@fetcher.data["#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{a1_name}.gemspec.rz"] = util_zip Marshal.dump(@a1)
@fetcher.data["#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{a2_name}.gemspec.rz"] = util_zip Marshal.dump(@a2)
@fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] =
Marshal.dump @si
sic_e = Gem::SourceInfoCacheEntry.new Gem::SourceIndex.new, 0
assert_equal [], sic_e.source_index.map { |n,| n }
use_ui @ui do
sic_e.refresh @gem_repo, false
assert sic_e.refresh(@gem_repo, false)
end
assert_equal [a2_name], sic_e.source_index.map { |n,| n }.sort
@ -63,7 +65,7 @@ class TestGemSourceInfoCacheEntry < RubyGemTestCase
si = Gem::SourceIndex.new
si.add_spec @a1
si.add_spec @b2
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
@fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = si.dump
use_ui @ui do
@sic_e.refresh @gem_repo, true

View file

@ -0,0 +1,303 @@
require 'test/unit'
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/spec_fetcher'
class TestGemSpecFetcher < RubyGemTestCase
def setup
super
@uri = URI.parse @gem_repo
util_setup_fake_fetcher
@source_index.add_spec @pl1
@specs = @source_index.gems.sort.map do |name, spec|
[spec.name, spec.version, spec.original_platform]
end.sort
@fetcher.data["#{@gem_repo}specs.#{Gem.marshal_version}.gz"] =
util_gzip(Marshal.dump(@specs))
@latest_specs = @source_index.latest_specs.sort.map do |spec|
[spec.name, spec.version, spec.original_platform]
end
@fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] =
util_gzip(Marshal.dump(@latest_specs))
@sf = Gem::SpecFetcher.new
end
def test_fetch_all
@fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a1.full_name}.gemspec.rz"] =
util_zip(Marshal.dump(@a1))
@fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a2.full_name}.gemspec.rz"] =
util_zip(Marshal.dump(@a2))
dep = Gem::Dependency.new 'a', 1
specs_and_sources = @sf.fetch dep, true
spec_names = specs_and_sources.map do |spec, source_uri|
[spec.full_name, source_uri]
end
expected = [[@a1.full_name, @gem_repo], [@a2.full_name, @gem_repo]]
assert_equal expected, spec_names
assert_same specs_and_sources.first.last, specs_and_sources.last.last
end
def test_fetch_latest
@fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a1.full_name}.gemspec.rz"] =
util_zip(Marshal.dump(@a1))
@fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a2.full_name}.gemspec.rz"] =
util_zip(Marshal.dump(@a2))
dep = Gem::Dependency.new 'a', 1
specs_and_sources = @sf.fetch dep
spec_names = specs_and_sources.map do |spec, source_uri|
[spec.full_name, source_uri]
end
assert_equal [[@a2.full_name, @gem_repo]], spec_names
end
def test_fetch_legacy_repo
@fetcher.data["#{@gem_repo}specs.#{Gem.marshal_version}.gz"] = nil
@fetcher.data["#{@gem_repo}yaml"] = ''
util_setup_source_info_cache @a1, @a2
dep = Gem::Dependency.new 'a', 1
specs = nil
use_ui @ui do
specs = @sf.fetch dep, true
end
expected = <<-EOF
WARNING: RubyGems 1.2+ index not found for:
\thttp://gems.example.com/
RubyGems will revert to legacy indexes degrading performance.
EOF
assert_equal expected, @ui.error
specs = specs.map { |spec, source_uri| [spec.full_name, source_uri] }
expected = [
[@a1.full_name, @gem_repo],
[@a2.full_name, @gem_repo],
]
assert_equal expected, specs
end
def test_fetch_platform
util_set_arch 'i386-linux'
@fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@pl1.original_name}.gemspec.rz"] =
util_zip(Marshal.dump(@pl1))
dep = Gem::Dependency.new 'pl', 1
specs_and_sources = @sf.fetch dep
spec_names = specs_and_sources.map do |spec, source_uri|
[spec.full_name, source_uri]
end
assert_equal [[@pl1.full_name, @gem_repo]], spec_names
end
def test_fetch_spec
spec_uri = "#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a1.full_name}.gemspec"
@fetcher.data["#{spec_uri}.rz"] = util_zip(Marshal.dump(@a1))
spec = @sf.fetch_spec ['a', Gem::Version.new(1), 'ruby'], @uri
assert_equal @a1.full_name, spec.full_name
cache_dir = @sf.cache_dir URI.parse(spec_uri)
cache_file = File.join cache_dir, "#{@a1.full_name}.gemspec"
assert File.exist?(cache_file)
end
def test_fetch_spec_cached
spec_uri = "#{@gem_repo}/#{Gem::MARSHAL_SPEC_DIR}#{@a1.full_name}.gemspec"
@fetcher.data["#{spec_uri}.rz"] = nil
cache_dir = @sf.cache_dir URI.parse(spec_uri)
FileUtils.mkdir_p cache_dir
cache_file = File.join cache_dir, "#{@a1.full_name}.gemspec"
open cache_file, 'wb' do |io|
Marshal.dump @a1, io
end
spec = @sf.fetch_spec ['a', Gem::Version.new(1), 'ruby'], @uri
assert_equal @a1.full_name, spec.full_name
end
def test_fetch_spec_platform
@fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@pl1.original_name}.gemspec.rz"] =
util_zip(Marshal.dump(@pl1))
spec = @sf.fetch_spec ['pl', Gem::Version.new(1), 'i386-linux'], @uri
assert_equal @pl1.full_name, spec.full_name
end
def test_fetch_spec_platform_ruby
@fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a1.full_name}.gemspec.rz"] =
util_zip(Marshal.dump(@a1))
spec = @sf.fetch_spec ['a', Gem::Version.new(1), nil], @uri
assert_equal @a1.full_name, spec.full_name
spec = @sf.fetch_spec ['a', Gem::Version.new(1), ''], @uri
assert_equal @a1.full_name, spec.full_name
end
def test_find_matching_all
dep = Gem::Dependency.new 'a', 1
specs = @sf.find_matching dep, true
expected = [
[['a', Gem::Version.new(1), Gem::Platform::RUBY], @gem_repo],
[['a', Gem::Version.new(2), Gem::Platform::RUBY], @gem_repo],
]
assert_equal expected, specs
end
def test_find_matching_latest
dep = Gem::Dependency.new 'a', 1
specs = @sf.find_matching dep
expected = [
[['a', Gem::Version.new(2), Gem::Platform::RUBY], @gem_repo],
]
assert_equal expected, specs
end
def test_find_matching_platform
util_set_arch 'i386-linux'
dep = Gem::Dependency.new 'pl', 1
specs = @sf.find_matching dep
expected = [
[['pl', Gem::Version.new(1), 'i386-linux'], @gem_repo],
]
assert_equal expected, specs
util_set_arch 'i386-freebsd6'
dep = Gem::Dependency.new 'pl', 1
specs = @sf.find_matching dep
assert_equal [], specs
end
def test_find_all_platforms
util_set_arch 'i386-freebsd6'
dep = Gem::Dependency.new 'pl', 1
specs = @sf.find_matching dep, false, false
expected = [
[['pl', Gem::Version.new(1), 'i386-linux'], @gem_repo],
]
assert_equal expected, specs
end
def test_list
specs = @sf.list
assert_equal [@uri], specs.keys
assert_equal @latest_specs, specs[@uri].sort
end
def test_list_all
specs = @sf.list true
assert_equal [@uri], specs.keys
assert_equal @specs, specs[@uri].sort
end
def test_list_cache
specs = @sf.list
assert !specs[@uri].empty?
@fetcher.data["#{@gem_repo}/latest_specs.#{Gem.marshal_version}.gz"] = nil
cached_specs = @sf.list
assert_equal specs, cached_specs
end
def test_list_cache_all
specs = @sf.list true
assert !specs[@uri].empty?
@fetcher.data["#{@gem_repo}/specs.#{Gem.marshal_version}.gz"] = nil
cached_specs = @sf.list true
assert_equal specs, cached_specs
end
def test_load_specs
specs = @sf.load_specs @uri, 'specs'
expected = [
['a', Gem::Version.new(1), Gem::Platform::RUBY],
['a', Gem::Version.new(2), Gem::Platform::RUBY],
['a_evil', Gem::Version.new(9), Gem::Platform::RUBY],
['c', Gem::Version.new('1.2'), Gem::Platform::RUBY],
['pl', Gem::Version.new(1), 'i386-linux'],
]
assert_equal expected, specs
cache_dir = File.join Gem.user_home, '.gem', 'specs', 'gems.example.com%80'
assert File.exist?(cache_dir), "#{cache_dir} does not exist"
cache_file = File.join cache_dir, "specs.#{Gem.marshal_version}"
assert File.exist?(cache_file)
end
def test_load_specs_cached
@fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] = nil
@fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}"] =
' ' * Marshal.dump(@latest_specs).length
cache_dir = File.join Gem.user_home, '.gem', 'specs', 'gems.example.com:80'
FileUtils.mkdir_p cache_dir
cache_file = File.join cache_dir, "latest_specs.#{Gem.marshal_version}"
open cache_file, 'wb' do |io|
Marshal.dump @latest_specs, io
end
specs = @sf.load_specs @uri, 'specs'
assert_equal @specs, specs
end
end

View file

@ -213,6 +213,15 @@ end
assert_equal 'old_platform', same_spec.original_platform
end
def test_add_dependency_with_explicit_type
gem = quick_gem "awesome", "1.0" do |awesome|
awesome.add_development_dependency "monkey"
end
monkey = gem.dependencies.detect { |d| d.name == "monkey" }
assert_equal(:development, monkey.type)
end
def test_author
assert_equal 'A User', @a1.author
end
@ -282,6 +291,20 @@ end
assert_equal [rake, jabber, pqa], @a1.dependencies
end
def test_dependencies_scoped_by_type
gem = quick_gem "awesome", "1.0" do |awesome|
awesome.add_runtime_dependency "bonobo", []
awesome.add_development_dependency "monkey", []
end
bonobo = Gem::Dependency.new("bonobo", [])
monkey = Gem::Dependency.new("monkey", [], :development)
assert_equal([bonobo, monkey], gem.dependencies)
assert_equal([bonobo], gem.runtime_dependencies)
assert_equal([monkey], gem.development_dependencies)
end
def test_description
assert_equal 'This is a test description', @a1.description
end
@ -423,6 +446,15 @@ end
@a1.full_gem_path
end
def test_full_gem_path_double_slash
gemhome = @gemhome.sub(/\w\//, '\&/')
@a1.loaded_from = File.join gemhome, 'specifications',
"#{@a1.full_name}.gemspec"
assert_equal File.join(@gemhome, 'gems', @a1.full_name),
@a1.full_gem_path
end
def test_full_name
assert_equal 'a-1', @a1.full_name
@ -531,6 +563,17 @@ end
assert_equal ['A working computer'], @a1.requirements
end
def test_runtime_dependencies_legacy
# legacy gems don't have a type
@a1.runtime_dependencies.each do |dep|
dep.instance_variable_set :@type, nil
end
expected = %w[rake jabber4r pqa]
assert_equal expected, @a1.runtime_dependencies.map { |d| d.name }
end
def test_spaceship_name
s1 = quick_gem 'a', '1'
s2 = quick_gem 'b', '1'
@ -570,6 +613,8 @@ end
end
def test_to_ruby
@a2.add_runtime_dependency 'b', '1'
@a2.dependencies.first.instance_variable_set :@type, nil
@a2.required_rubygems_version = Gem::Requirement.new '> 0'
ruby_code = @a2.to_ruby
@ -578,8 +623,6 @@ end
s.name = %q{a}
s.version = \"2\"
s.specification_version = #{Gem::Specification::CURRENT_SPECIFICATION_VERSION} if s.respond_to? :specification_version=
s.required_rubygems_version = Gem::Requirement.new(\"> 0\") if s.respond_to? :required_rubygems_version=
s.authors = [\"A User\"]
s.date = %q{#{Gem::Specification::TODAY.strftime "%Y-%m-%d"}}
@ -591,6 +634,19 @@ end
s.require_paths = [\"lib\"]
s.rubygems_version = %q{#{Gem::RubyGemsVersion}}
s.summary = %q{this is a summary}
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = #{Gem::Specification::CURRENT_SPECIFICATION_VERSION}
if current_version >= 3 then
s.add_runtime_dependency(%q<b>, [\"= 1\"])
else
s.add_dependency(%q<b>, [\"= 1\"])
end
else
s.add_dependency(%q<b>, [\"= 1\"])
end
end
"
@ -613,8 +669,6 @@ end
s.version = \"1\"
s.platform = Gem::Platform.new(#{expected_platform})
s.specification_version = 2 if s.respond_to? :specification_version=
s.required_rubygems_version = Gem::Requirement.new(\">= 0\") if s.respond_to? :required_rubygems_version=
s.authors = [\"A User\"]
s.date = %q{#{Gem::Specification::TODAY.strftime "%Y-%m-%d"}}
@ -633,9 +687,24 @@ end
s.summary = %q{this is a summary}
s.test_files = [\"test/suite.rb\"]
s.add_dependency(%q<rake>, [\"> 0.4\"])
s.add_dependency(%q<jabber4r>, [\"> 0.0.0\"])
s.add_dependency(%q<pqa>, [\"> 0.4\", \"<= 0.6\"])
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3
if current_version >= 3 then
s.add_runtime_dependency(%q<rake>, [\"> 0.4\"])
s.add_runtime_dependency(%q<jabber4r>, [\"> 0.0.0\"])
s.add_runtime_dependency(%q<pqa>, [\"> 0.4\", \"<= 0.6\"])
else
s.add_dependency(%q<rake>, [\"> 0.4\"])
s.add_dependency(%q<jabber4r>, [\"> 0.0.0\"])
s.add_dependency(%q<pqa>, [\"> 0.4\", \"<= 0.6\"])
end
else
s.add_dependency(%q<rake>, [\"> 0.4\"])
s.add_dependency(%q<jabber4r>, [\"> 0.0.0\"])
s.add_dependency(%q<pqa>, [\"> 0.4\", \"<= 0.6\"])
end
end
"

View file

@ -15,6 +15,12 @@ class TestGemUninstaller < GemInstallerTestCase
end
end
def test_initialize_expand_path
uninstaller = Gem::Uninstaller.new nil, :install_dir => '/foo//bar'
assert_match %r|/foo/bar$|, uninstaller.instance_variable_get(:@gem_home)
end
def test_remove_executables_force_keep
uninstaller = Gem::Uninstaller.new nil, :executables => false
@ -39,5 +45,20 @@ class TestGemUninstaller < GemInstallerTestCase
assert_equal false, File.exist?(File.join(@gemhome, 'bin', 'executable'))
end
def test_path_ok_eh
uninstaller = Gem::Uninstaller.new nil
assert_equal true, uninstaller.path_ok?(@spec)
end
def test_path_ok_eh_legacy
uninstaller = Gem::Uninstaller.new nil
@spec.loaded_from.gsub! @spec.full_name, '\&-legacy'
@spec.platform = 'legacy'
assert_equal true, uninstaller.path_ok?(@spec)
end
end

View file

@ -71,10 +71,14 @@ class TestGemVersion < RubyGemTestCase
end
def test_eql_eh
v = Gem::Version.new("1.2")
v1_2 = Gem::Version.new '1.2'
v1_2_0 = Gem::Version.new '1.2.0'
assert_equal true, v.eql?(@v1_2)
assert_equal true, @v1_2.eql?(v)
assert_equal true, v1_2.eql?(@v1_2)
assert_equal true, @v1_2.eql?(v1_2)
assert_equal false, v1_2_0.eql?(@v1_2)
assert_equal false, @v1_2.eql?(v1_2_0)
assert_equal false, @v1_2.eql?(@v1_3)
assert_equal false, @v1_3.eql?(@v1_2)
@ -91,8 +95,13 @@ class TestGemVersion < RubyGemTestCase
end
def test_hash
v = Gem::Version.new("1.2")
assert_equal v.hash, @v1_2.hash
v1_2 = Gem::Version.new "1.2"
v1_2_0 = Gem::Version.new "1.2.0"
assert_equal v1_2.hash, @v1_2.hash
assert_not_equal v1_2_0.hash, @v1_2.hash
assert_not_equal @v1_2.hash, @v1_3.hash
end

View file

@ -52,7 +52,7 @@ class TestKernel < RubyGemTestCase
gem 'a', '= 2'
end
assert_match(/activate a \(= 2\)/, ex.message)
assert_match(/activate a \(= 2, runtime\)/, ex.message)
assert_match(/activated a-1/, ex.message)
assert $:.any? { |p| %r{a-1/lib} =~ p }