git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@15873 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
drbrain 2008-03-31 22:40:06 +00:00
Родитель dc8359969e
Коммит 8cc45aae94
82 изменённых файлов: 5776 добавлений и 2928 удалений

Просмотреть файл

@ -1,3 +1,7 @@
Tue Apr 1 07:31:58 2008 Eric Hodel <drbrain@segment7.net>
* lib/rubygems* test/rubygems*: Import RubyGems 1.1.0.
Tue Apr 1 03:20:40 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* configure.in (RUBY_SETJMP, RUBY_LONGJMP, RUBY_JMP_BUF): prefers

13
bin/gem
Просмотреть файл

@ -7,11 +7,12 @@
require 'rubygems'
require 'rubygems/gem_runner'
require 'rubygems/exceptions'
required_version = Gem::Requirement.new ">= 1.8.3"
required_version = Gem::Requirement.new "> 1.8.3"
unless required_version.satisfied_by? Gem::Version.new(RUBY_VERSION) then
abort "Expected Ruby Version #{required_version}, was #{RUBY_VERSION}"
unless required_version.satisfied_by? Gem.ruby_version then
abort "Expected Ruby Version #{required_version}, was #{Gem.ruby_version}"
end
# We need to preserve the original ARGV to use for passing gem options
@ -19,5 +20,9 @@ end
# it...its for the source building process.
args = !ARGV.include?("--") ? ARGV.clone : ARGV[0...ARGV.index("--")]
Gem::GemRunner.new.run args
begin
Gem::GemRunner.new.run args
rescue Gem::SystemExitException => e
exit e.exit_code
end

Просмотреть файл

@ -1,207 +1,214 @@
# depends on: array.rb dir.rb env.rb file.rb hash.rb module.rb regexp.rb
# empty gem_prelude.rb
#
# p Gem::Enable
if defined?(Gem::Enable) && Gem::Enable
#t = Time.now
module Kernel
if defined?(Gem::Enable) && Gem::Enable then
def gem(gem_name, *version_requirements)
Gem.push_gem_version_on_load_path(gem_name, *version_requirements)
end
module Kernel
end
module Gem
ConfigMap = {
:sitedir => RbConfig::CONFIG["sitedir"],
:ruby_version => RbConfig::CONFIG["ruby_version"],
:libdir => RbConfig::CONFIG["libdir"],
:sitelibdir => RbConfig::CONFIG["sitelibdir"],
:arch => RbConfig::CONFIG["arch"],
:bindir => RbConfig::CONFIG["bindir"],
:EXEEXT => RbConfig::CONFIG["EXEEXT"],
:RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
:ruby_install_name => RbConfig::CONFIG["ruby_install_name"]
}
class << self
def default_dir
if defined? RUBY_FRAMEWORK_VERSION
return File.join(File.dirname(ConfigMap[:sitedir]), "Gems")
else
File.join(ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version])
end
end
def dir
@gem_home ||= nil
set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home
@gem_home
end
def path
@gem_path ||= nil
unless @gem_path
paths = [ENV['GEM_PATH']]
paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
set_paths(paths.compact.join(File::PATH_SEPARATOR))
end
@gem_path
end
# Set the Gem home directory (as reported by +dir+).
def set_home(home)
@gem_home = home
ensure_gem_subdirectories(@gem_home)
end
def set_paths(gpaths)
if gpaths
@gem_path = gpaths.split(File::PATH_SEPARATOR)
@gem_path << Gem.dir
else
@gem_path = [Gem.dir]
end
@gem_path.uniq!
@gem_path.each do |gp| ensure_gem_subdirectories(gp) end
end
def ensure_gem_subdirectories(path)
def gem(gem_name, *version_requirements)
Gem.push_gem_version_on_load_path(gem_name, *version_requirements)
end
end
module QuickLoader
module Gem
ConfigMap = {
:sitedir => RbConfig::CONFIG["sitedir"],
:ruby_version => RbConfig::CONFIG["ruby_version"],
:libdir => RbConfig::CONFIG["libdir"],
:sitelibdir => RbConfig::CONFIG["sitelibdir"],
:arch => RbConfig::CONFIG["arch"],
:bindir => RbConfig::CONFIG["bindir"],
:EXEEXT => RbConfig::CONFIG["EXEEXT"],
:RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
:ruby_install_name => RbConfig::CONFIG["ruby_install_name"]
}
class << self
def load_full_rubygems_library
class << Gem
Gem.methods(false).each do |method_name|
undef_method method_name
end
def default_dir
if defined? RUBY_FRAMEWORK_VERSION
return File.join(File.dirname(ConfigMap[:sitedir]), "Gems")
else
File.join(ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version])
end
Kernel.send :undef_method, :gem
$".delete File.join(Gem::ConfigMap[:libdir], 'ruby',
Gem::ConfigMap[:ruby_version], 'rubygems.rb')
require 'rubygems'
end
def dir
@gem_home ||= nil
set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home
@gem_home
end
def path
@gem_path ||= nil
unless @gem_path
paths = [ENV['GEM_PATH']]
paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
set_paths(paths.compact.join(File::PATH_SEPARATOR))
end
@gem_path
end
# Set the Gem home directory (as reported by +dir+).
def set_home(home)
@gem_home = home
ensure_gem_subdirectories(@gem_home)
end
def set_paths(gpaths)
if gpaths
@gem_path = gpaths.split(File::PATH_SEPARATOR)
@gem_path << Gem.dir
else
@gem_path = [Gem.dir]
end
@gem_path.uniq!
@gem_path.each do |gp| ensure_gem_subdirectories(gp) end
end
def ensure_gem_subdirectories(path)
end
end
GemPaths = {}
GemVersions = {}
def push_gem_version_on_load_path(gem_name, *version_requirements)
if version_requirements.empty?
unless GemPaths.has_key?(gem_name)
raise LoadError.new("Could not find RubyGem #{gem_name} (>= 0)\n")
module QuickLoader
class << self
def load_full_rubygems_library
class << Gem
Gem.methods(false).each do |method_name|
undef_method method_name
end
end
Kernel.send :undef_method, :gem
$".delete File.join(Gem::ConfigMap[:libdir], 'ruby',
Gem::ConfigMap[:ruby_version], 'rubygems.rb')
require 'rubygems'
end
# highest version gems already active
return false
else
if version_requirements.length > 1
end
GemPaths = {}
GemVersions = {}
def push_gem_version_on_load_path(gem_name, *version_requirements)
if version_requirements.empty?
unless GemPaths.has_key?(gem_name)
raise LoadError.new("Could not find RubyGem #{gem_name} (>= 0)\n")
end
# highest version gems already active
return false
else
if version_requirements.length > 1
QuickLoader.load_full_rubygems_library
return gem(gem_name, *version_requirements)
end
requirement, version = version_requirements[0].split
requirement.strip!
if requirement == ">" || requirement == ">="
if (GemVersions[gem_name] <=> Gem.calculate_integers_for_gem_version(version)) >= 0
return false
end
elsif requirement == "~>"
loaded_version = GemVersions[gem_name]
required_version = Gem.calculate_integers_for_gem_version(version)
if loaded_version && (loaded_version[0] == required_version[0])
return false
end
end
QuickLoader.load_full_rubygems_library
return gem(gem_name, *version_requirements)
gem(gem_name, *version_requirements)
end
requirement, version = version_requirements[0].split
requirement.strip!
if requirement == ">" || requirement == ">="
if (GemVersions[gem_name] <=> Gem.calculate_integers_for_gem_version(version)) >= 0
return false
end
elsif requirement == "~>"
loaded_version = GemVersions[gem_name]
required_version = Gem.calculate_integers_for_gem_version(version)
if loaded_version && (loaded_version[0] == required_version[0])
return false
end
end
QuickLoader.load_full_rubygems_library
gem(gem_name, *version_requirements)
end
end
def calculate_integers_for_gem_version(gem_version)
numbers = gem_version.split(".").collect {|n| n.to_i}
numbers.pop while numbers.last == 0
numbers << 0 if numbers.empty?
numbers
end
def push_all_highest_version_gems_on_load_path
Gem.path.each do |path|
gems_directory = File.join(path, "gems")
if File.exist?(gems_directory)
Dir.entries(gems_directory).each do |gem_directory_name|
next if gem_directory_name == "." || gem_directory_name == ".."
dash = gem_directory_name.rindex("-")
next if dash.nil?
gem_name = gem_directory_name[0...dash]
current_version = GemVersions[gem_name]
new_version = calculate_integers_for_gem_version(gem_directory_name[dash+1..-1])
if current_version
if (current_version <=> new_version) == -1
def calculate_integers_for_gem_version(gem_version)
numbers = gem_version.split(".").collect {|n| n.to_i}
numbers.pop while numbers.last == 0
numbers << 0 if numbers.empty?
numbers
end
def push_all_highest_version_gems_on_load_path
Gem.path.each do |path|
gems_directory = File.join(path, "gems")
if File.exist?(gems_directory)
Dir.entries(gems_directory).each do |gem_directory_name|
next if gem_directory_name == "." || gem_directory_name == ".."
dash = gem_directory_name.rindex("-")
next if dash.nil?
gem_name = gem_directory_name[0...dash]
current_version = GemVersions[gem_name]
new_version = calculate_integers_for_gem_version(gem_directory_name[dash+1..-1])
if current_version
if (current_version <=> new_version) == -1
GemVersions[gem_name] = new_version
GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
end
else
GemVersions[gem_name] = new_version
GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
end
else
GemVersions[gem_name] = new_version
GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
end
end
end
end
require_paths = []
GemPaths.values.each do |path|
if File.exist?(File.join(path, ".require_paths"))
require_paths.concat(File.read(File.join(path, ".require_paths")).split.map {|require_path| File.join(path, require_path)})
else
require_paths << File.join(path, "bin") if File.exist?(File.join(path, "bin"))
require_paths << File.join(path, "lib") if File.exist?(File.join(path, "lib"))
require_paths = []
GemPaths.values.each do |path|
if File.exist?(File.join(path, ".require_paths"))
require_paths.concat(File.read(File.join(path, ".require_paths")).split.map {|require_path| File.join(path, require_path)})
else
require_paths << File.join(path, "bin") if File.exist?(File.join(path, "bin"))
require_paths << File.join(path, "lib") if File.exist?(File.join(path, "lib"))
end
end
# "tag" the first require_path inserted into the $LOAD_PATH to enable
# indexing correctly with rubygems proper when it inserts an explicitly
# gem version
unless require_paths.empty?
require_paths.first.instance_variable_set(:@gem_prelude_index, true)
end
# gem directories must come after -I and ENV['RUBYLIB']
$:[$:.index(ConfigMap[:sitelibdir]),0] = require_paths
end
# "tag" the first require_path inserted into the $LOAD_PATH to enable
# indexing correctly with rubygems proper when it inserts an explicitly
# gem version
unless require_paths.empty?
require_paths.first.instance_variable_set(:@gem_prelude_index, true)
def const_missing(constant)
QuickLoader.load_full_rubygems_library
Gem.const_get(constant)
end
def method_missing(method, *args, &block)
QuickLoader.load_full_rubygems_library
super unless Gem.respond_to?(method)
Gem.send(method, *args, &block)
end
# gem directories must come after -I and ENV['RUBYLIB']
$:[$:.index(ConfigMap[:sitelibdir]),0] = require_paths
end
def const_missing(constant)
QuickLoader.load_full_rubygems_library
Gem.const_get(constant)
end
extend QuickLoader
def method_missing(method, *args, &block)
QuickLoader.load_full_rubygems_library
super unless Gem.respond_to?(method)
Gem.send(method, *args, &block)
end
end
extend QuickLoader
begin
Gem.push_all_highest_version_gems_on_load_path
$" << File.join(Gem::ConfigMap[:libdir], "ruby",
Gem::ConfigMap[:ruby_version], "rubygems.rb")
rescue Exception => e
puts "Error loading gem paths on load path in gem_prelude"
puts e
puts e.backtrace.join("\n")
end
end
begin
Gem.push_all_highest_version_gems_on_load_path
$" << File.join(Gem::ConfigMap[:libdir], "ruby",
Gem::ConfigMap[:ruby_version], "rubygems.rb")
rescue Exception => e
puts "Error loading gem paths on load path in gem_prelude"
puts e
puts e.backtrace.join("\n")
end
#puts "Gem load in #{Time.now - t} seconds"
end # Gem::Enable

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -65,13 +65,20 @@ EOM
end
def write_package
Package.open(@spec.file_name, "w", @signer) do |pkg|
pkg.metadata = @spec.to_yaml
@spec.files.each do |file|
next if File.directory? file
pkg.add_file_simple(file, File.stat(@spec.file_name).mode & 0777,
File.size(file)) do |os|
os.write File.open(file, "rb"){|f|f.read}
open @spec.file_name, 'wb' do |gem_io|
Gem::Package.open gem_io, 'w', @signer do |pkg|
pkg.metadata = @spec.to_yaml
@spec.files.each do |file|
next if File.directory? file
stat = File.stat file
mode = stat.mode & 0777
size = stat.size
pkg.add_file_simple file, mode, size do |tar_io|
tar_io.write open(file, "rb") { |f| f.read }
end
end
end
end

Просмотреть файл

@ -123,6 +123,7 @@ module Gem
end
private
def load_and_instantiate(command_name)
command_name = command_name.to_s
retried = false

Просмотреть файл

@ -2,92 +2,90 @@ require 'rubygems/command'
require 'rubygems/source_index'
require 'rubygems/dependency_list'
module Gem
module Commands
class CleanupCommand < Command
def initialize
super(
'cleanup',
class Gem::Commands::CleanupCommand < Gem::Command
def initialize
super 'cleanup',
'Clean up old versions of installed gems in the local repository',
{
:force => false,
:test => false,
:install_dir => Gem.dir
})
add_option('-d', '--dryrun', "") do |value, options|
options[:dryrun] = true
end
end
:force => false, :test => false, :install_dir => Gem.dir
def arguments # :nodoc:
"GEMNAME name of gem to cleanup"
end
add_option('-d', '--dryrun', "") do |value, options|
options[:dryrun] = true
end
end
def defaults_str # :nodoc:
"--no-dryrun"
end
def arguments # :nodoc:
"GEMNAME name of gem to cleanup"
end
def usage # :nodoc:
"#{program_name} [GEMNAME ...]"
end
def defaults_str # :nodoc:
"--no-dryrun"
end
def execute
say "Cleaning up installed gems..."
srcindex = Gem::SourceIndex.from_installed_gems
primary_gems = {}
def usage # :nodoc:
"#{program_name} [GEMNAME ...]"
end
srcindex.each do |name, spec|
if primary_gems[spec.name].nil? or primary_gems[spec.name].version < spec.version
primary_gems[spec.name] = spec
end
end
def execute
say "Cleaning up installed gems..."
primary_gems = {}
gems_to_cleanup = []
unless options[:args].empty? then
options[:args].each do |gem_name|
specs = Gem.cache.search(/^#{gem_name}$/i)
specs.each do |spec|
gems_to_cleanup << spec
end
end
else
srcindex.each do |name, spec|
gems_to_cleanup << spec
end
end
gems_to_cleanup = gems_to_cleanup.select { |spec|
primary_gems[spec.name].version != spec.version
}
uninstall_command = Gem::CommandManager.instance['uninstall']
deplist = DependencyList.new
gems_to_cleanup.uniq.each do |spec| deplist.add(spec) end
deplist.dependency_order.each do |spec|
if options[:dryrun] then
say "Dry Run Mode: Would uninstall #{spec.full_name}"
else
say "Attempting uninstall on #{spec.full_name}"
options[:args] = [spec.name]
options[:version] = "= #{spec.version}"
options[:executables] = true
uninstall_command.merge_options(options)
begin
uninstall_command.execute
rescue Gem::DependencyRemovalException => ex
say "Unable to uninstall #{spec.full_name} ... continuing with remaining gems"
end
end
end
say "Clean Up Complete"
Gem.source_index.each do |name, spec|
if primary_gems[spec.name].nil? or
primary_gems[spec.name].version < spec.version then
primary_gems[spec.name] = spec
end
end
gems_to_cleanup = []
unless options[:args].empty? then
options[:args].each do |gem_name|
specs = Gem.cache.search(/^#{gem_name}$/i)
specs.each do |spec|
gems_to_cleanup << spec
end
end
else
Gem.source_index.each do |name, spec|
gems_to_cleanup << spec
end
end
gems_to_cleanup = gems_to_cleanup.select { |spec|
primary_gems[spec.name].version != spec.version
}
uninstall_command = Gem::CommandManager.instance['uninstall']
deplist = Gem::DependencyList.new
gems_to_cleanup.uniq.each do |spec| deplist.add spec end
deps = deplist.strongly_connected_components.flatten.reverse
deps.each do |spec|
if options[:dryrun] then
say "Dry Run Mode: Would uninstall #{spec.full_name}"
else
say "Attempting to uninstall #{spec.full_name}"
options[:args] = [spec.name]
options[:version] = "= #{spec.version}"
options[:executables] = false
uninstaller = Gem::Uninstaller.new spec.name, options
begin
uninstaller.uninstall
rescue Gem::DependencyRemovalException,
Gem::GemNotInHomeException => e
say "Unable to uninstall #{spec.full_name}:"
say "\t#{e.class}: #{e.message}"
end
end
end
say "Clean Up Complete"
end
end

Просмотреть файл

@ -25,19 +25,18 @@ class Gem::Commands::EnvironmentCommand < Gem::Command
def execute
out = ''
arg = options[:args][0]
if begins?("packageversion", arg) then
case arg
when /^packageversion/ then
out << Gem::RubyGemsPackageVersion
elsif begins?("version", arg) then
when /^version/ then
out << Gem::RubyGemsVersion
elsif begins?("gemdir", arg) then
when /^gemdir/, /^gemhome/, /^home/, /^GEM_HOME/ then
out << Gem.dir
elsif begins?("gempath", arg) then
out << Gem.path.join("\n")
elsif begins?("remotesources", arg) then
when /^gempath/, /^path/, /^GEM_PATH/ then
out << Gem.path.join(File::PATH_SEPARATOR)
when /^remotesources/ then
out << Gem.sources.join("\n")
elsif arg then
fail Gem::CommandLineError, "Unknown enviroment option [#{arg}]"
else
when nil then
out = "RubyGems Environment:\n"
out << " - RUBYGEMS VERSION: #{Gem::RubyGemsVersion} (#{Gem::RubyGemsPackageVersion})\n"
@ -75,6 +74,9 @@ class Gem::Commands::EnvironmentCommand < Gem::Command
Gem.sources.each do |s|
out << " - #{s}\n"
end
else
fail Gem::CommandLineError, "Unknown enviroment option [#{arg}]"
end
say out
true

Просмотреть файл

@ -44,17 +44,15 @@ class Gem::Commands::FetchCommand < Gem::Command
spec, source_uri = specs_and_sources.last
gem_file = "#{spec.full_name}.gem"
gem_path = File.join source_uri, 'gems', gem_file
gem = Gem::RemoteFetcher.fetcher.fetch_path gem_path
File.open gem_file, 'wb' do |fp|
fp.write gem
if spec.nil? then
alert_error "Could not find #{gem_name} in any repository"
next
end
say "Downloaded #{gem_file}"
path = Gem::RemoteFetcher.fetcher.download spec, source_uri
FileUtils.mv path, "#{spec.full_name}.gem"
say "Downloaded #{spec.full_name}"
end
end

Просмотреть файл

@ -62,13 +62,15 @@ class Gem::Commands::InstallCommand < Gem::Command
:install_dir => options[:install_dir],
:security_policy => options[:security_policy],
:wrappers => options[:wrappers],
:bin_dir => options[:bin_dir]
}
exit_code = 0
get_all_gem_names.each do |gem_name|
begin
inst = Gem::DependencyInstaller.new gem_name, options[:version],
install_options
inst.install
inst = Gem::DependencyInstaller.new install_options
inst.install gem_name, options[:version]
inst.installed_gems.each do |spec|
say "Successfully installed #{spec.full_name}"
@ -77,8 +79,10 @@ class Gem::Commands::InstallCommand < Gem::Command
installed_gems.push(*inst.installed_gems)
rescue Gem::InstallError => e
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
exit_code |= 1
rescue Gem::GemNotFoundException => e
alert_error e.message
exit_code |= 2
# rescue => e
# # TODO: Fix this handle to allow the error to propagate to
# # the top level handler. Examine the other errors as
@ -121,6 +125,8 @@ class Gem::Commands::InstallCommand < Gem::Command
end
end
end
raise Gem::SystemExitException, exit_code
end
end

Просмотреть файл

@ -6,10 +6,8 @@ module Gem
class ListCommand < QueryCommand
def initialize
super(
'list',
'Display all gems whose name starts with STRING'
)
super 'list', 'Display gems whose name starts with STRING'
remove_option('--name-matches')
end

Просмотреть файл

@ -2,7 +2,7 @@ require 'yaml'
require 'zlib'
require 'rubygems/command'
require 'rubygems/gem_open_uri'
require 'open-uri'
class Gem::Commands::MirrorCommand < Gem::Command

Просмотреть файл

@ -1,15 +1,25 @@
require 'rubygems/command'
require 'rubygems/local_remote_options'
require 'rubygems/source_info_cache'
require 'rubygems/version_option'
class Gem::Commands::QueryCommand < Gem::Command
include Gem::LocalRemoteOptions
include Gem::VersionOption
def initialize(name = 'query',
summary = 'Query gem information in local or remote repositories')
super name, summary,
:name => /.*/, :domain => :local, :details => false, :versions => true
:name => //, :domain => :local, :details => false, :versions => true,
:installed => false, :version => Gem::Requirement.default
add_option('-i', '--[no-]installed',
'Check for installed gem') do |value, options|
options[:installed] = value
end
add_version_option
add_option('-n', '--name-matches REGEXP',
'Name of gem(s) to query on matches the',
@ -28,33 +38,70 @@ class Gem::Commands::QueryCommand < Gem::Command
options[:details] = false unless value
end
add_option('-a', '--all',
'Display all gem versions') do |value, options|
options[:all] = value
end
add_local_remote_options
end
def defaults_str # :nodoc:
"--local --name-matches '.*' --no-details --versions"
"--local --name-matches // --no-details --versions --no-installed"
end
def execute
exit_code = 0
name = options[:name]
if options[:installed] then
if name.source.empty? then
alert_error "You must specify a gem name"
exit_code |= 4
elsif installed? name.source, options[:version] then
say "true"
else
say "false"
exit_code |= 1
end
raise Gem::SystemExitException, exit_code
end
if local? then
say
say "*** LOCAL GEMS ***"
say
output_query_results Gem.cache.search(name)
output_query_results Gem.source_index.search(name)
end
if remote? then
say
say "*** REMOTE GEMS ***"
say
output_query_results Gem::SourceInfoCache.search(name)
begin
Gem::SourceInfoCache.cache.refresh options[:all]
rescue Gem::RemoteFetcher::FetchError
# no network
end
output_query_results Gem::SourceInfoCache.search(name, false, true)
end
end
private
##
# Check if gem +name+ version +version+ is installed.
def installed?(name, version = Gem::Requirement.default)
dep = Gem::Dependency.new name, version
!Gem.source_index.search(dep).empty?
end
def output_query_results(gemspecs)
output = []
gem_list_with_version = {}
@ -98,7 +145,7 @@ class Gem::Commands::QueryCommand < Gem::Command
##
# Used for wrapping and indenting text
#
def format_text(text, wrap, indent=0)
result = []
work = text.dup

Просмотреть файл

@ -39,8 +39,11 @@ class Gem::Commands::SourcesCommand < Gem::Command
options[:list] = !(options[:add] || options[:remove] || options[:clear_all] || options[:update])
if options[:clear_all] then
remove_cache_file("user", Gem::SourceInfoCache.user_cache_file)
remove_cache_file("system", Gem::SourceInfoCache.system_cache_file)
sic = Gem::SourceInfoCache
remove_cache_file 'user', sic.user_cache_file
remove_cache_file 'latest user', sic.latest_user_cache_file
remove_cache_file 'system', sic.system_cache_file
remove_cache_file 'latest system', sic.latest_system_cache_file
end
if options[:add] then
@ -48,7 +51,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
sice = Gem::SourceInfoCacheEntry.new nil, nil
begin
sice.refresh source_uri
sice.refresh source_uri, true
Gem::SourceInfoCache.cache_data[source_uri] = sice
Gem::SourceInfoCache.cache.update
@ -66,7 +69,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
end
if options[:update] then
Gem::SourceInfoCache.cache.refresh
Gem::SourceInfoCache.cache.refresh true
Gem::SourceInfoCache.cache.flush
say "source cache successfully updated"
@ -78,6 +81,11 @@ class Gem::Commands::SourcesCommand < Gem::Command
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
@ -100,11 +108,12 @@ class Gem::Commands::SourcesCommand < Gem::Command
private
def remove_cache_file(desc, fn)
FileUtils.rm_rf fn rescue nil
if ! File.exist?(fn)
def remove_cache_file(desc, path)
FileUtils.rm_rf path
if not File.exist?(path) then
say "*** Removed #{desc} source cache ***"
elsif ! File.writable?(fn)
elsif not File.writable?(path) then
say "*** Unable to remove #{desc} source cache (write protected) ***"
else
say "*** Unable to remove #{desc} source cache ***"

Просмотреть файл

@ -3,6 +3,7 @@ require 'rubygems/command'
require 'rubygems/local_remote_options'
require 'rubygems/version_option'
require 'rubygems/source_info_cache'
require 'rubygems/format'
class Gem::Commands::SpecificationCommand < Gem::Command
@ -41,13 +42,16 @@ class Gem::Commands::SpecificationCommand < Gem::Command
gem = get_one_gem_name
if local? then
source_index = Gem::SourceIndex.from_installed_gems
specs.push(*source_index.search(/\A#{gem}\z/, options[:version]))
if File.exist? gem then
specs << Gem::Format.from_file_by_path(gem).spec rescue nil
end
if specs.empty? then
specs.push(*Gem.source_index.search(/\A#{gem}\z/, options[:version]))
end
end
if remote? then
alert_warning "Remote information is not complete\n\n"
Gem::SourceInfoCache.cache_data.each do |_,sice|
specs.push(*sice.source_index.search(gem, options[:version]))
end

Просмотреть файл

@ -35,6 +35,11 @@ module Gem
options[:install_dir] = File.expand_path(value)
end
add_option('-n', '--bindir DIR',
'Directory to remove binaries from') do |value, options|
options[:bin_dir] = File.expand_path(value)
end
add_version_option
add_platform_option
end
@ -54,7 +59,13 @@ module Gem
def execute
get_all_gem_names.each do |gem_name|
Gem::Uninstaller.new(gem_name, options).uninstall
begin
Gem::Uninstaller.new(gem_name, options).uninstall
rescue Gem::GemNotInHomeException => e
spec = e.spec
alert("In order to remove #{spec.name}, please execute:\n" \
"\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
end
end
end
end

Просмотреть файл

@ -38,6 +38,7 @@ class Gem::Commands::UnpackCommand < Gem::Command
def execute
gemname = get_one_gem_name
path = get_path(gemname, options[:version])
if path then
basename = File.basename(path).sub(/\.gem$/, '')
target_dir = File.expand_path File.join(options[:target], basename)
@ -66,16 +67,27 @@ class Gem::Commands::UnpackCommand < Gem::Command
# source directories?
def get_path(gemname, version_req)
return gemname if gemname =~ /\.gem$/i
specs = Gem::SourceIndex.from_installed_gems.search(/\A#{gemname}\z/, version_req)
specs = Gem::source_index.search(/\A#{gemname}\z/, version_req)
selected = specs.sort_by { |s| s.version }.last
return nil if selected.nil?
# We expect to find (basename).gem in the 'cache' directory.
# Furthermore, the name match must be exact (ignoring case).
if gemname =~ /^#{selected.name}$/i
filename = selected.full_name + '.gem'
return File.join(Gem.dir, 'cache', filename)
path = nil
Gem.path.find do |gem_dir|
path = File.join gem_dir, 'cache', filename
File.exist? path
end
path
else
return nil
nil
end
end

Просмотреть файл

@ -1,8 +1,10 @@
require 'rubygems/command'
require 'rubygems/command_manager'
require 'rubygems/install_update_options'
require 'rubygems/local_remote_options'
require 'rubygems/source_info_cache'
require 'rubygems/version_option'
require 'rubygems/commands/install_command'
class Gem::Commands::UpdateCommand < Gem::Command
@ -45,7 +47,7 @@ class Gem::Commands::UpdateCommand < Gem::Command
def execute
if options[:system] then
say "Updating RubyGems..."
say "Updating RubyGems"
unless options[:args].empty? then
fail "No gem names are allowed with the --system option"
@ -53,10 +55,10 @@ class Gem::Commands::UpdateCommand < Gem::Command
options[:args] = ["rubygems-update"]
else
say "Updating installed gems..."
say "Updating installed gems"
end
hig = highest_installed_gems = {}
hig = {}
Gem::SourceIndex.from_installed_gems.each do |name, spec|
if hig[spec.name].nil? or hig[spec.name].version < spec.version then
@ -64,25 +66,28 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
end
remote_gemspecs = Gem::SourceInfoCache.search(//)
pattern = if options[:args].empty? then
//
else
Regexp.union(*options[:args])
end
gems_to_update = if options[:args].empty? then
which_to_update(highest_installed_gems, remote_gemspecs)
else
options[:args]
end
remote_gemspecs = Gem::SourceInfoCache.search pattern
options[:domain] = :remote # install from remote source
gems_to_update = which_to_update hig, remote_gemspecs
updated = []
# HACK use the real API
install_command = Gem::CommandManager.instance['install']
gems_to_update.uniq.sort.each do |name|
say "Attempting remote update of #{name}"
options[:args] = [name]
options[:ignore_dependencies] = true # HACK skip seen gems instead
install_command.merge_options(options)
install_command.execute
next if updated.any? { |spec| spec.name == name }
say "Updating #{name}"
installer = Gem::DependencyInstaller.new options
installer.install name
installer.installed_gems.each do |spec|
updated << spec
say "Successfully installed #{spec.full_name}"
end
end
if gems_to_update.include? "rubygems-update" then
@ -97,12 +102,10 @@ class Gem::Commands::UpdateCommand < Gem::Command
say "RubyGems system software updated" if installed
else
updated = gems_to_update.uniq.sort.collect { |g| g.to_s }
if updated.empty? then
say "Nothing to update"
else
say "Gems updated: #{updated.join ', '}"
say "Gems updated: #{updated.map { |spec| spec.name }.join ', '}"
end
end
end

Просмотреть файл

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

Просмотреть файл

@ -11,6 +11,9 @@ module Gem
if defined? RUBY_FRAMEWORK_VERSION then
File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
ConfigMap[:ruby_version]
elsif defined? RUBY_ENGINE then
File.join ConfigMap[:libdir], RUBY_ENGINE, 'gems',
ConfigMap[:ruby_version]
else
File.join ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version]
end
@ -29,7 +32,11 @@ module Gem
# The default directory for binaries
def self.default_bindir
Config::CONFIG['bindir']
if defined? RUBY_FRAMEWORK_VERSION then # mac framework support
'/usr/bin'
else # generic install
ConfigMap[:bindir]
end
end
# The default system-wide source info cache directory.

Просмотреть файл

@ -22,8 +22,7 @@ class Gem::DependencyInstaller
}
##
# Creates a new installer instance that will install +gem_name+ using
# version requirement +version+ and +options+.
# Creates a new installer instance.
#
# Options are:
# :env_shebang:: See Gem::Installer::new.
@ -36,7 +35,7 @@ class Gem::DependencyInstaller
# :install_dir: See Gem::Installer#install.
# :security_policy: See Gem::Installer::new and Gem::Security.
# :wrappers: See Gem::Installer::new
def initialize(gem_name, version = nil, options = {})
def initialize(options = {})
options = DEFAULT_OPTIONS.merge options
@env_shebang = options[:env_shebang]
@domain = options[:domain]
@ -46,49 +45,9 @@ class Gem::DependencyInstaller
@install_dir = options[:install_dir] || Gem.dir
@security_policy = options[:security_policy]
@wrappers = options[:wrappers]
@bin_dir = options[:bin_dir]
@installed_gems = []
spec_and_source = nil
glob = if File::ALT_SEPARATOR then
gem_name.gsub File::ALT_SEPARATOR, File::SEPARATOR
else
gem_name
end
local_gems = Dir["#{glob}*"].sort.reverse
unless local_gems.empty? then
local_gems.each do |gem_file|
next unless gem_file =~ /gem$/
begin
spec = Gem::Format.from_file_by_path(gem_file).spec
spec_and_source = [spec, gem_file]
break
rescue SystemCallError, Gem::Package::FormatError
end
end
end
if spec_and_source.nil? then
version ||= Gem::Requirement.default
@dep = Gem::Dependency.new gem_name, version
spec_and_sources = find_gems_with_sources(@dep).reverse
spec_and_source = spec_and_sources.find do |spec, source|
Gem::Platform.match spec.platform
end
end
if spec_and_source.nil? then
raise Gem::GemNotFoundException,
"could not find #{gem_name} locally or in a repository"
end
@specs_and_sources = [spec_and_source]
gather_dependencies
end
##
@ -107,73 +66,32 @@ class Gem::DependencyInstaller
end
if @domain == :both or @domain == :remote then
gems_and_sources.push(*Gem::SourceInfoCache.search_with_source(dep, true))
begin
requirements = dep.version_requirements.requirements.map do |req, ver|
req
end
all = requirements.length > 1 ||
requirements.first != ">=" || requirements.first != ">"
found = Gem::SourceInfoCache.search_with_source dep, true, all
gems_and_sources.push(*found)
rescue Gem::RemoteFetcher::FetchError => e
if Gem.configuration.really_verbose then
say "Error fetching remote data:\t\t#{e.message}"
say "Falling back to local-only install"
end
@domain = :local
end
end
gems_and_sources.sort_by do |gem, source|
[gem, source !~ /^http:\/\// ? 1 : 0] # local gems win
[gem, source =~ /^http:\/\// ? 0 : 1] # local gems win
end
end
##
# 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)
gem_file_name = "#{spec.full_name}.gem"
local_gem_path = File.join @install_dir, 'cache', gem_file_name
Gem.ensure_gem_subdirectories @install_dir
source_uri = URI.parse source_uri unless URI::Generic === source_uri
scheme = source_uri.scheme
# URI.parse gets confused by MS Windows paths with forward slashes.
scheme = nil if scheme =~ /^[a-z]$/i
case scheme
when 'http' then
unless File.exist? local_gem_path then
begin
say "Downloading gem #{gem_file_name}" if
Gem.configuration.really_verbose
remote_gem_path = source_uri + "gems/#{gem_file_name}"
gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
rescue Gem::RemoteFetcher::FetchError
raise if spec.original_platform == spec.platform
alternate_name = "#{spec.name}-#{spec.version}-#{spec.original_platform}.gem"
say "Failed, downloading gem #{alternate_name}" if
Gem.configuration.really_verbose
remote_gem_path = source_uri + "gems/#{alternate_name}"
gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
end
File.open local_gem_path, 'wb' do |fp|
fp.write gem
end
end
when nil, 'file' then # TODO test for local overriding cache
begin
FileUtils.cp source_uri.to_s, local_gem_path
rescue Errno::EACCES
local_gem_path = source_uri.to_s
end
say "Using local gem #{local_gem_path}" if
Gem.configuration.really_verbose
else
raise Gem::InstallError, "unsupported URI scheme #{source_uri.scheme}"
end
local_gem_path
end
##
# Gathers all dependencies necessary for the installation from local and
# remote sources unless the ignore_dependencies was given.
@ -208,9 +126,57 @@ class Gem::DependencyInstaller
@gems_to_install = dependency_list.dependency_order.reverse
end
def find_spec_by_name_and_version gem_name, version = Gem::Requirement.default
spec_and_source = nil
glob = if File::ALT_SEPARATOR then
gem_name.gsub File::ALT_SEPARATOR, File::SEPARATOR
else
gem_name
end
local_gems = Dir["#{glob}*"].sort.reverse
unless local_gems.empty? then
local_gems.each do |gem_file|
next unless gem_file =~ /gem$/
begin
spec = Gem::Format.from_file_by_path(gem_file).spec
spec_and_source = [spec, gem_file]
break
rescue SystemCallError, Gem::Package::FormatError
end
end
end
if spec_and_source.nil? then
dep = Gem::Dependency.new gem_name, version
spec_and_sources = find_gems_with_sources(dep).reverse
spec_and_source = spec_and_sources.find { |spec, source|
Gem::Platform.match spec.platform
}
end
if spec_and_source.nil? then
raise Gem::GemNotFoundException,
"could not find #{gem_name} locally or in a repository"
end
@specs_and_sources = [spec_and_source]
end
##
# Installs the gem and all its dependencies.
def install
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
else
@specs_and_sources = [find_gems_with_sources(dep_or_name).last]
end
gather_dependencies
spec_dir = File.join @install_dir, 'specifications'
source_index = Gem::SourceIndex.from_gems_in spec_dir
@ -219,10 +185,11 @@ class Gem::DependencyInstaller
# HACK is this test for full_name acceptable?
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
_, source_uri = @specs_and_sources.assoc spec
local_gem_path = download spec, source_uri
local_gem_path = Gem::RemoteFetcher.fetcher.download spec, source_uri
inst = Gem::Installer.new local_gem_path,
:env_shebang => @env_shebang,
@ -231,7 +198,8 @@ class Gem::DependencyInstaller
:ignore_dependencies => @ignore_dependencies,
:install_dir => @install_dir,
:security_policy => @security_policy,
:wrappers => @wrappers
:wrappers => @wrappers,
:bin_dir => @bin_dir
spec = inst.install

Просмотреть файл

@ -13,7 +13,10 @@ class Gem::DependencyRemovalException < Gem::Exception; end
##
# Raised when attempting to uninstall a gem that isn't in GEM_HOME.
class Gem::GemNotInHomeException < Gem::Exception; end
class Gem::GemNotInHomeException < Gem::Exception
attr_accessor :spec
end
class Gem::DocumentError < Gem::Exception; end
@ -65,3 +68,17 @@ class Gem::RemoteSourceException < Gem::Exception; end
class Gem::VerificationError < Gem::Exception; end
##
# Raised to indicate that a system exit should occur with the specified
# exit_code
class Gem::SystemExitException < SystemExit
attr_accessor :exit_code
def initialize(exit_code)
@exit_code = exit_code
super "Exiting RubyGems with exit_code #{exit_code}"
end
end

Просмотреть файл

@ -43,15 +43,12 @@ module Gem
# check for old version gem
if File.read(file_path, 20).include?("MD5SUM =")
#alert_warning "Gem #{file_path} is in old format."
require 'rubygems/old_format'
format = OldFormat.from_file_by_path(file_path)
else
begin
f = File.open(file_path, 'rb')
format = from_io(f, file_path, security_policy)
ensure
f.close unless f.closed?
open file_path, Gem.binary_mode do |io|
format = from_io io, file_path, security_policy
end
end
@ -65,15 +62,24 @@ module Gem
# io:: [IO] Stream from which to read the gem
#
def self.from_io(io, gem_path="(io)", security_policy = nil)
format = self.new(gem_path)
Package.open_from_io(io, 'r', security_policy) do |pkg|
format = new gem_path
Package.open io, 'r', security_policy do |pkg|
format.spec = pkg.metadata
format.file_entries = []
pkg.each do |entry|
format.file_entries << [{"size" => entry.size, "mode" => entry.mode,
"path" => entry.full_name}, entry.read]
size = entry.header.size
mode = entry.header.mode
format.file_entries << [{
"size" => size, "mode" => mode, "path" => entry.full_name,
},
entry.read
]
end
end
format
end

Просмотреть файл

@ -11,6 +11,7 @@ end
##
# Top level class for building the gem repository index.
class Gem::Indexer
include Gem::UserInteraction
@ -25,7 +26,9 @@ class Gem::Indexer
attr_reader :directory
##
# Create an indexer that will index the gems in +directory+.
def initialize(directory)
unless ''.respond_to? :to_xs then
fail "Gem::Indexer requires that the XML Builder library be installed:" \
@ -39,52 +42,60 @@ class Gem::Indexer
@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
@quick_index = Gem::Indexer::QuickIndexBuilder.new 'index', @directory
quick_dir = File.join @directory, 'quick'
@latest_index = Gem::Indexer::LatestIndexBuilder.new 'latest_index', quick_dir
end
##
# Build the index.
def build_index
@master_index.build do
@quick_index.build do
@marshal_index.build do
progress = ui.progress_reporter gem_file_list.size,
@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})"
gem_file_list.each do |gemfile|
if File.size(gemfile.to_s) == 0 then
alert_warning "Skipping zero-length gem: #{gemfile}"
next
end
abbreviate spec
sanitize spec
begin
spec = Gem::Format.from_file_by_path(gemfile).spec
@master_index.add spec
@quick_index.add spec
@marshal_index.add 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
progress.updated spec.original_name
abbreviate spec
sanitize spec
rescue SignalException => e
alert_error "Recieved 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
@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 "Recieved 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
progress.done
say "Generating master indexes (this may take a while)"
end
end
end
@ -95,14 +106,15 @@ class Gem::Indexer
say "Moving index into production dir #{@dest_directory}" if verbose
files = @master_index.files + @quick_index.files + @marshal_index.files
files = @master_index.files + @quick_index.files + @marshal_index.files +
@latest_index.files
files.each do |file|
relative_name = file[/\A#{Regexp.escape @directory}.(.*)/, 1]
dest_name = File.join @dest_directory, relative_name
src_name = File.join @directory, file
dst_name = File.join @dest_directory, file
FileUtils.rm_rf dest_name, :verbose => verbose
FileUtils.mv file, @dest_directory, :verbose => verbose
FileUtils.rm_rf dst_name, :verbose => verbose
FileUtils.mv src_name, @dest_directory, :verbose => verbose
end
end
@ -160,4 +172,5 @@ 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'

Просмотреть файл

@ -22,16 +22,18 @@ class Gem::Indexer::AbstractIndexBuilder
@files = []
end
##
# Build a Gem index. Yields to block to handle the details of the
# actual building. Calls +begin_index+, +end_index+ and +cleanup+ at
# appropriate times to customize basic operations.
def build
FileUtils.mkdir_p @directory unless File.exist? @directory
raise "not a directory: #{@directory}" unless File.directory? @directory
file_path = File.join @directory, @filename
@files << file_path
@files << @filename
File.open file_path, "wb" do |file|
@file = file
@ -39,14 +41,20 @@ class Gem::Indexer::AbstractIndexBuilder
yield
end_index
end
cleanup
ensure
@file = nil
end
##
# Compress the given file.
def compress(filename, ext="rz")
zipped = zip(File.open(filename, 'rb'){ |fp| fp.read })
data = open filename, 'rb' do |fp| fp.read end
zipped = zip data
File.open "#{filename}.#{ext}", "wb" do |file|
file.write zipped
end

Просмотреть файл

@ -0,0 +1,35 @@
require 'rubygems/indexer'
##
# Construct the latest Gem index file.
class Gem::Indexer::LatestIndexBuilder < Gem::Indexer::AbstractIndexBuilder
def start_index
super
@index = Gem::SourceIndex.new
end
def end_index
super
latest = @index.latest_specs.sort.map { |spec| spec.original_name }
@file.write latest.join("\n")
end
def cleanup
super
compress @file.path
@files.delete 'latest_index' # HACK installed via QuickIndexBuilder :/
end
def add(spec)
@index.add_spec(spec)
end
end

Просмотреть файл

@ -1,6 +1,8 @@
require 'rubygems/indexer'
##
# Construct the master Gem index file.
class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
def start_index
@ -10,6 +12,7 @@ class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
def end_index
super
@file.puts "--- !ruby/object:#{@index.class}"
@file.puts "gems:"
@ -28,11 +31,9 @@ class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
index_file_name = File.join @directory, @filename
compress index_file_name, "Z"
compressed_file_name = "#{index_file_name}.Z"
paranoid index_file_name, "#{index_file_name}.Z"
paranoid index_file_name, compressed_file_name
@files << compressed_file_name
@files << "#{@filename}.Z"
end
def add(spec)
@ -41,12 +42,12 @@ class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
private
def paranoid(fn, compressed_fn)
data = File.open(fn, 'rb') do |fp| fp.read end
compressed_data = File.open(compressed_fn, 'rb') do |fp| fp.read end
def paranoid(path, compressed_path)
data = Gem.read_binary path
compressed_data = Gem.read_binary compressed_path
if data != unzip(compressed_data) then
fail "Compressed file #{compressed_fn} does not match uncompressed file #{fn}"
raise "Compressed file #{compressed_path} does not match uncompressed file #{path}"
end
end

Просмотреть файл

@ -1,7 +1,9 @@
require 'rubygems/indexer'
##
# Construct a quick index file and all of the individual specs to support
# incremental loading.
class Gem::Indexer::QuickIndexBuilder < Gem::Indexer::AbstractIndexBuilder
def initialize(filename, directory)
@ -13,12 +15,12 @@ class Gem::Indexer::QuickIndexBuilder < Gem::Indexer::AbstractIndexBuilder
def cleanup
super
quick_index_file = File.join(@directory, @filename)
quick_index_file = File.join @directory, @filename
compress quick_index_file
# the complete quick index is in a directory, so move it as a whole
@files.delete quick_index_file
@files << @directory
@files.delete 'index'
@files << 'quick'
end
def add(spec)

Просмотреть файл

@ -25,6 +25,12 @@ module Gem::InstallUpdateOptions
options[:install_dir] = File.expand_path(value)
end
add_option(:"Install/Update", '-n', '--bindir DIR',
'Directory where binary files are',
'located') do |value, options|
options[:bin_dir] = File.expand_path(value)
end
add_option(:"Install/Update", '-d', '--[no-]rdoc',
'Generate RDoc documentation for the gem on',
'install') do |value, options|

Просмотреть файл

@ -63,7 +63,8 @@ class Gem::Installer
:force => false,
:install_dir => Gem.dir,
:exec_format => false,
:env_shebang => false
:env_shebang => false,
:bin_dir => nil
}.merge options
@env_shebang = options[:env_shebang]
@ -74,6 +75,7 @@ class Gem::Installer
@format_executable = options[:format_executable]
@security_policy = options[:security_policy]
@wrappers = options[:wrappers]
@bin_dir = options[:bin_dir]
begin
@format = Gem::Format.from_file_by_path @gem, @security_policy
@ -104,7 +106,7 @@ class Gem::Installer
unless @force then
if rrv = @spec.required_ruby_version then
unless rrv.satisfied_by? Gem::Version.new(RUBY_VERSION) then
unless rrv.satisfied_by? Gem.ruby_version then
raise Gem::InstallError, "#{@spec.name} requires Ruby version #{rrv}"
end
end
@ -225,7 +227,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 = 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
@ -303,7 +305,7 @@ class Gem::Installer
# necessary.
def shebang(bin_file_name)
if @env_shebang then
"#!/usr/bin/env ruby"
"#!/usr/bin/env " + Gem::ConfigMap[:ruby_install_name]
else
path = File.join @gem_dir, @spec.bindir, bin_file_name
@ -352,10 +354,10 @@ TEXT
<<-TEXT
@ECHO OFF
IF NOT "%~f0" == "~f0" GOTO :WinNT
@"#{Gem.ruby}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
@"#{File.basename(Gem.ruby)}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
GOTO :EOF
:WinNT
"%~dp0ruby.exe" "%~dpn0" %*
@"#{File.basename(Gem.ruby)}" "%~dpn0" %*
TEXT
end

Просмотреть файл

@ -45,768 +45,15 @@ module Gem::Package
class TooLongFileName < Error; end
class FormatError < Error; end
module FSyncDir
private
def fsync_dir(dirname)
# make sure this hits the disc
begin
dir = open(dirname, "r")
dir.fsync
rescue # ignore IOError if it's an unpatched (old) Ruby
ensure
dir.close if dir rescue nil
end
end
end
class TarHeader
FIELDS = [:name, :mode, :uid, :gid, :size, :mtime, :checksum, :typeflag,
:linkname, :magic, :version, :uname, :gname, :devmajor,
:devminor, :prefix]
FIELDS.each {|x| attr_reader x}
def self.new_from_stream(stream)
data = stream.read(512)
fields = data.unpack("A100" + # record name
"A8A8A8" + # mode, uid, gid
"A12A12" + # size, mtime
"A8A" + # checksum, typeflag
"A100" + # linkname
"A6A2" + # magic, version
"A32" + # uname
"A32" + # gname
"A8A8" + # devmajor, devminor
"A155") # prefix
name = fields.shift
mode = fields.shift.oct
uid = fields.shift.oct
gid = fields.shift.oct
size = fields.shift.oct
mtime = fields.shift.oct
checksum = fields.shift.oct
typeflag = fields.shift
linkname = fields.shift
magic = fields.shift
version = fields.shift.oct
uname = fields.shift
gname = fields.shift
devmajor = fields.shift.oct
devminor = fields.shift.oct
prefix = fields.shift
empty = (data == "\0" * 512)
new(:name=>name, :mode=>mode, :uid=>uid, :gid=>gid, :size=>size,
:mtime=>mtime, :checksum=>checksum, :typeflag=>typeflag,
:magic=>magic, :version=>version, :uname=>uname, :gname=>gname,
:devmajor=>devmajor, :devminor=>devminor, :prefix=>prefix,
:empty => empty )
end
def initialize(vals)
unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode]
raise ArgumentError, ":name, :size, :prefix and :mode required"
end
vals[:uid] ||= 0
vals[:gid] ||= 0
vals[:mtime] ||= 0
vals[:checksum] ||= ""
vals[:typeflag] ||= "0"
vals[:magic] ||= "ustar"
vals[:version] ||= "00"
vals[:uname] ||= "wheel"
vals[:gname] ||= "wheel"
vals[:devmajor] ||= 0
vals[:devminor] ||= 0
FIELDS.each {|x| instance_variable_set "@#{x.to_s}", vals[x]}
@empty = vals[:empty]
end
def empty?
@empty
end
def to_s
update_checksum
header(checksum)
end
def update_checksum
h = header(" " * 8)
@checksum = oct(calculate_checksum(h), 6)
end
private
def oct(num, len)
"%0#{len}o" % num
end
def calculate_checksum(hdr)
#hdr.split('').map { |c| c[0] }.inject { |a, b| a + b } # HACK rubinius
hdr.unpack("C*").inject{|a,b| a+b}
end
def header(chksum)
# struct tarfile_entry_posix {
# char name[100]; # ASCII + (Z unless filled)
# char mode[8]; # 0 padded, octal, null
# char uid[8]; # ditto
# char gid[8]; # ditto
# char size[12]; # 0 padded, octal, null
# char mtime[12]; # 0 padded, octal, null
# char checksum[8]; # 0 padded, octal, null, space
# char typeflag[1]; # file: "0" dir: "5"
# char linkname[100]; # ASCII + (Z unless filled)
# char magic[6]; # "ustar\0"
# char version[2]; # "00"
# char uname[32]; # ASCIIZ
# char gname[32]; # ASCIIZ
# char devmajor[8]; # 0 padded, octal, null
# char devminor[8]; # o padded, octal, null
# char prefix[155]; # ASCII + (Z unless filled)
# };
arr = [name, oct(mode, 7), oct(uid, 7), oct(gid, 7), oct(size, 11),
oct(mtime, 11), chksum, " ", typeflag, linkname, magic, version,
uname, gname, oct(devmajor, 7), oct(devminor, 7), prefix]
str = arr.pack("a100a8a8a8a12a12" + # name, mode, uid, gid, size, mtime
"a7aaa100a6a2" + # chksum, typeflag, linkname, magic, version
"a32a32a8a8a155") # uname, gname, devmajor, devminor, prefix
str + "\0" * ((512 - str.size) % 512)
end
end
class TarWriter
class FileOverflow < StandardError; end
class BlockNeeded < StandardError; end
class BoundedStream
attr_reader :limit, :written
def initialize(io, limit)
@io = io
@limit = limit
@written = 0
end
def write(data)
if data.size + @written > @limit
raise FileOverflow,
"You tried to feed more data than fits in the file."
end
@io.write data
@written += data.size
data.size
end
end
class RestrictedStream
def initialize(anIO)
@io = anIO
end
def write(data)
@io.write data
end
end
def self.new(anIO)
writer = super(anIO)
return writer unless block_given?
begin
yield writer
ensure
writer.close
end
nil
end
def initialize(anIO)
@io = anIO
@closed = false
end
def add_file_simple(name, mode, size)
raise BlockNeeded unless block_given?
raise ClosedIO if @closed
name, prefix = split_name(name)
header = TarHeader.new(:name => name, :mode => mode,
:size => size, :prefix => prefix).to_s
@io.write header
os = BoundedStream.new(@io, size)
yield os
#FIXME: what if an exception is raised in the block?
min_padding = size - os.written
@io.write("\0" * min_padding)
remainder = (512 - (size % 512)) % 512
@io.write("\0" * remainder)
end
def add_file(name, mode)
raise BlockNeeded unless block_given?
raise ClosedIO if @closed
raise NonSeekableIO unless @io.respond_to? :pos=
name, prefix = split_name(name)
init_pos = @io.pos
@io.write "\0" * 512 # placeholder for the header
yield RestrictedStream.new(@io)
#FIXME: what if an exception is raised in the block?
#FIXME: what if an exception is raised in the block?
size = @io.pos - init_pos - 512
remainder = (512 - (size % 512)) % 512
@io.write("\0" * remainder)
final_pos = @io.pos
@io.pos = init_pos
header = TarHeader.new(:name => name, :mode => mode,
:size => size, :prefix => prefix).to_s
@io.write header
@io.pos = final_pos
end
def mkdir(name, mode)
raise ClosedIO if @closed
name, prefix = split_name(name)
header = TarHeader.new(:name => name, :mode => mode, :typeflag => "5",
:size => 0, :prefix => prefix).to_s
@io.write header
nil
end
def flush
raise ClosedIO if @closed
@io.flush if @io.respond_to? :flush
end
def close
#raise ClosedIO if @closed
return if @closed
@io.write "\0" * 1024
@closed = true
end
private
def split_name name
raise TooLongFileName if name.size > 256
if name.size <= 100
prefix = ""
else
parts = name.split(/\//)
newname = parts.pop
nxt = ""
loop do
nxt = parts.pop
break if newname.size + 1 + nxt.size > 100
newname = nxt + "/" + newname
end
prefix = (parts + [nxt]).join "/"
name = newname
raise TooLongFileName if name.size > 100 || prefix.size > 155
end
return name, prefix
end
end
class TarReader
include Gem::Package
class UnexpectedEOF < StandardError; end
module InvalidEntry
def read(len=nil); raise ClosedIO; end
def getc; raise ClosedIO; end
def rewind; raise ClosedIO; end
end
class Entry
TarHeader::FIELDS.each{|x| attr_reader x}
def initialize(header, anIO)
@io = anIO
@name = header.name
@mode = header.mode
@uid = header.uid
@gid = header.gid
@size = header.size
@mtime = header.mtime
@checksum = header.checksum
@typeflag = header.typeflag
@linkname = header.linkname
@magic = header.magic
@version = header.version
@uname = header.uname
@gname = header.gname
@devmajor = header.devmajor
@devminor = header.devminor
@prefix = header.prefix
@read = 0
@orig_pos = @io.pos
end
def read(len = nil)
return nil if @read >= @size
len ||= @size - @read
max_read = [len, @size - @read].min
ret = @io.read(max_read)
@read += ret.size
ret
end
def getc
return nil if @read >= @size
ret = @io.getc
@read += 1 if ret
ret
end
def is_directory?
@typeflag == "5"
end
def is_file?
@typeflag == "0"
end
def eof?
@read >= @size
end
def pos
@read
end
def rewind
raise NonSeekableIO unless @io.respond_to? :pos=
@io.pos = @orig_pos
@read = 0
end
alias_method :is_directory, :is_directory?
alias_method :is_file, :is_file?
def bytes_read
@read
end
def full_name
if @prefix != ""
File.join(@prefix, @name)
else
@name
end
end
def close
invalidate
end
private
def invalidate
extend InvalidEntry
end
end
def self.new(anIO)
reader = super(anIO)
return reader unless block_given?
begin
yield reader
ensure
reader.close
end
nil
end
def initialize(anIO)
@io = anIO
@init_pos = anIO.pos
end
def each(&block)
each_entry(&block)
end
# do not call this during a #each or #each_entry iteration
def rewind
if @init_pos == 0
raise NonSeekableIO unless @io.respond_to? :rewind
@io.rewind
else
raise NonSeekableIO unless @io.respond_to? :pos=
@io.pos = @init_pos
end
end
def each_entry
loop do
return if @io.eof?
header = TarHeader.new_from_stream(@io)
return if header.empty?
entry = Entry.new header, @io
size = entry.size
yield entry
skip = (512 - (size % 512)) % 512
if @io.respond_to? :seek
# avoid reading...
@io.seek(size - entry.bytes_read, IO::SEEK_CUR)
else
pending = size - entry.bytes_read
while pending > 0
bread = @io.read([pending, 4096].min).size
raise UnexpectedEOF if @io.eof?
pending -= bread
end
end
@io.read(skip) # discard trailing zeros
# make sure nobody can use #read, #getc or #rewind anymore
entry.close
end
end
def close
end
end
class TarInput
include FSyncDir
include Enumerable
attr_reader :metadata
class << self; private :new end
def initialize(io, security_policy = nil)
@io = io
@tarreader = TarReader.new(@io)
has_meta = false
data_sig, meta_sig, data_dgst, meta_dgst = nil, nil, nil, nil
dgst_algo = security_policy ? Gem::Security::OPT[:dgst_algo] : nil
@tarreader.each do |entry|
case entry.full_name
when "metadata"
@metadata = load_gemspec(entry.read)
has_meta = true
break
when "metadata.gz"
begin
# if we have a security_policy, then pre-read the metadata file
# and calculate it's digest
sio = nil
if security_policy
Gem.ensure_ssl_available
sio = StringIO.new(entry.read)
meta_dgst = dgst_algo.digest(sio.string)
sio.rewind
end
gzis = Zlib::GzipReader.new(sio || entry)
# YAML wants an instance of IO
@metadata = load_gemspec(gzis)
has_meta = true
ensure
gzis.close unless gzis.nil?
end
when 'metadata.gz.sig'
meta_sig = entry.read
when 'data.tar.gz.sig'
data_sig = entry.read
when 'data.tar.gz'
if security_policy
Gem.ensure_ssl_available
data_dgst = dgst_algo.digest(entry.read)
end
end
end
if security_policy then
Gem.ensure_ssl_available
# map trust policy from string to actual class (or a serialized YAML
# file, if that exists)
if String === security_policy then
if Gem::Security::Policy.key? security_policy then
# load one of the pre-defined security policies
security_policy = Gem::Security::Policy[security_policy]
elsif File.exist? security_policy then
# FIXME: this doesn't work yet
security_policy = YAML.load File.read(security_policy)
else
raise Gem::Exception, "Unknown trust policy '#{security_policy}'"
end
end
if data_sig && data_dgst && meta_sig && meta_dgst then
# the user has a trust policy, and we have a signed gem
# file, so use the trust policy to verify the gem signature
begin
security_policy.verify_gem(data_sig, data_dgst, @metadata.cert_chain)
rescue Exception => e
raise "Couldn't verify data signature: #{e}"
end
begin
security_policy.verify_gem(meta_sig, meta_dgst, @metadata.cert_chain)
rescue Exception => e
raise "Couldn't verify metadata signature: #{e}"
end
elsif security_policy.only_signed
raise Gem::Exception, "Unsigned gem"
else
# FIXME: should display warning here (trust policy, but
# either unsigned or badly signed gem file)
end
end
@tarreader.rewind
@fileops = Gem::FileOperations.new
raise FormatError, "No metadata found!" unless has_meta
end
# Attempt to YAML-load a gemspec from the given _io_ parameter. Return
# nil if it fails.
def load_gemspec(io)
Gem::Specification.from_yaml(io)
rescue Gem::Exception
nil
end
def self.open(filename, security_policy = nil, &block)
open_from_io(File.open(filename, "rb"), security_policy, &block)
end
def self.open_from_io(io, security_policy = nil, &block)
raise "Want a block" unless block_given?
begin
is = new(io, security_policy)
yield is
ensure
is.close if is
end
end
def each(&block)
@tarreader.each do |entry|
next unless entry.full_name == "data.tar.gz"
is = zipped_stream(entry)
begin
TarReader.new(is) do |inner|
inner.each(&block)
end
ensure
is.close if is
end
end
@tarreader.rewind
end
# Return an IO stream for the zipped entry.
#
# NOTE: Originally this method used two approaches, Return a GZipReader
# directly, or read the GZipReader into a string and return a StringIO on
# the string. The string IO approach was used for versions of ZLib before
# 1.2.1 to avoid buffer errors on windows machines. Then we found that
# errors happened with 1.2.1 as well, so we changed the condition. Then
# we discovered errors occurred with versions as late as 1.2.3. At this
# point (after some benchmarking to show we weren't seriously crippling
# the unpacking speed) we threw our hands in the air and declared that
# this method would use the String IO approach on all platforms at all
# times. And that's the way it is.
def zipped_stream(entry)
if defined? Rubinius then
zis = Zlib::GzipReader.new entry
dis = zis.read
is = StringIO.new(dis)
else
# This is Jamis Buck's ZLib workaround for some unknown issue
entry.read(10) # skip the gzip header
zis = Zlib::Inflate.new(-Zlib::MAX_WBITS)
is = StringIO.new(zis.inflate(entry.read))
end
ensure
zis.finish if zis
end
def extract_entry(destdir, entry, expected_md5sum = nil)
if entry.is_directory?
dest = File.join(destdir, entry.full_name)
if file_class.dir? dest
@fileops.chmod entry.mode, dest, :verbose=>false
else
@fileops.mkdir_p(dest, :mode => entry.mode, :verbose=>false)
end
fsync_dir dest
fsync_dir File.join(dest, "..")
return
end
# it's a file
md5 = Digest::MD5.new if expected_md5sum
destdir = File.join(destdir, File.dirname(entry.full_name))
@fileops.mkdir_p(destdir, :mode => 0755, :verbose=>false)
destfile = File.join(destdir, File.basename(entry.full_name))
@fileops.chmod(0600, destfile, :verbose=>false) rescue nil # Errno::ENOENT
file_class.open(destfile, "wb", entry.mode) do |os|
loop do
data = entry.read(4096)
break unless data
md5 << data if expected_md5sum
os.write(data)
end
os.fsync
end
@fileops.chmod(entry.mode, destfile, :verbose=>false)
fsync_dir File.dirname(destfile)
fsync_dir File.join(File.dirname(destfile), "..")
if expected_md5sum && expected_md5sum != md5.hexdigest
raise BadCheckSum
end
end
def close
@io.close
@tarreader.close
end
private
def file_class
File
end
end
class TarOutput
class << self; private :new end
def initialize(io)
@io = io
@external = TarWriter.new @io
end
def external_handle
@external
end
def self.open(filename, signer = nil, &block)
io = File.open(filename, "wb")
open_from_io(io, signer, &block)
nil
end
def self.open_from_io(io, signer = nil, &block)
outputter = new(io)
metadata = nil
set_meta = lambda{|x| metadata = x}
raise "Want a block" unless block_given?
begin
data_sig, meta_sig = nil, nil
outputter.external_handle.add_file("data.tar.gz", 0644) do |inner|
begin
sio = signer ? StringIO.new : nil
os = Zlib::GzipWriter.new(sio || inner)
TarWriter.new(os) do |inner_tar_stream|
klass = class << inner_tar_stream; self end
klass.send(:define_method, :metadata=, &set_meta)
block.call inner_tar_stream
end
ensure
os.flush
os.finish
#os.close
# if we have a signing key, then sign the data
# digest and return the signature
data_sig = nil
if signer
dgst_algo = Gem::Security::OPT[:dgst_algo]
dig = dgst_algo.digest(sio.string)
data_sig = signer.sign(dig)
inner.write(sio.string)
end
end
end
# if we have a data signature, then write it to the gem too
if data_sig
sig_file = 'data.tar.gz.sig'
outputter.external_handle.add_file(sig_file, 0644) do |os|
os.write(data_sig)
end
end
outputter.external_handle.add_file("metadata.gz", 0644) do |os|
begin
sio = signer ? StringIO.new : nil
gzos = Zlib::GzipWriter.new(sio || os)
gzos.write metadata
ensure
gzos.flush
gzos.finish
# if we have a signing key, then sign the metadata
# digest and return the signature
if signer
dgst_algo = Gem::Security::OPT[:dgst_algo]
dig = dgst_algo.digest(sio.string)
meta_sig = signer.sign(dig)
os.write(sio.string)
end
end
end
# if we have a metadata signature, then write to the gem as
# well
if meta_sig
sig_file = 'metadata.gz.sig'
outputter.external_handle.add_file(sig_file, 0644) do |os|
os.write(meta_sig)
end
end
ensure
outputter.close
end
nil
end
def close
@external.close
@io.close
end
end
#FIXME: refactor the following 2 methods
def self.open(dest, mode = "r", signer = nil, &block)
raise "Block needed" unless block_given?
case mode
when "r"
security_policy = signer
TarInput.open(dest, security_policy, &block)
when "w"
TarOutput.open(dest, signer, &block)
else
raise "Unknown Package open mode"
end
end
def self.open_from_io(io, mode = "r", signer = nil, &block)
raise "Block needed" unless block_given?
case mode
when "r"
security_policy = signer
TarInput.open_from_io(io, security_policy, &block)
when "w"
TarOutput.open_from_io(io, signer, &block)
else
raise "Unknown Package open mode"
end
def self.open(io, mode = "r", signer = nil, &block)
tar_type = case mode
when 'r' then TarInput
when 'w' then TarOutput
else
raise "Unknown Package open mode"
end
tar_type.open(io, signer, &block)
end
def self.pack(src, destname, signer = nil)
@ -836,19 +83,13 @@ module Gem::Package
end
end
class << self
def file_class
File
end
def dir_class
Dir
end
def find_class # HACK kill me
Find
end
end
end
require 'rubygems/package/f_sync_dir'
require 'rubygems/package/tar_header'
require 'rubygems/package/tar_input'
require 'rubygems/package/tar_output'
require 'rubygems/package/tar_reader'
require 'rubygems/package/tar_reader/entry'
require 'rubygems/package/tar_writer'

Просмотреть файл

@ -0,0 +1,24 @@
#++
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#--
require 'rubygems/package'
module Gem::Package::FSyncDir
private
##
# make sure this hits the disc
def fsync_dir(dirname)
dir = open dirname, 'r'
dir.fsync
rescue # ignore IOError if it's an unpatched (old) Ruby
ensure
dir.close if dir rescue nil
end
end

Просмотреть файл

@ -0,0 +1,245 @@
#++
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#--
require 'rubygems/package'
##
#--
# struct tarfile_entry_posix {
# char name[100]; # ASCII + (Z unless filled)
# char mode[8]; # 0 padded, octal, null
# char uid[8]; # ditto
# char gid[8]; # ditto
# char size[12]; # 0 padded, octal, null
# char mtime[12]; # 0 padded, octal, null
# char checksum[8]; # 0 padded, octal, null, space
# char typeflag[1]; # file: "0" dir: "5"
# char linkname[100]; # ASCII + (Z unless filled)
# char magic[6]; # "ustar\0"
# char version[2]; # "00"
# char uname[32]; # ASCIIZ
# char gname[32]; # ASCIIZ
# char devmajor[8]; # 0 padded, octal, null
# char devminor[8]; # o padded, octal, null
# char prefix[155]; # ASCII + (Z unless filled)
# };
#++
class Gem::Package::TarHeader
FIELDS = [
:checksum,
:devmajor,
:devminor,
:gid,
:gname,
:linkname,
:magic,
:mode,
:mtime,
:name,
:prefix,
:size,
:typeflag,
:uid,
:uname,
:version,
]
PACK_FORMAT = 'a100' + # name
'a8' + # mode
'a8' + # uid
'a8' + # gid
'a12' + # size
'a12' + # mtime
'a7a' + # chksum
'a' + # typeflag
'a100' + # linkname
'a6' + # magic
'a2' + # version
'a32' + # uname
'a32' + # gname
'a8' + # devmajor
'a8' + # devminor
'a155' # prefix
UNPACK_FORMAT = 'A100' + # name
'A8' + # mode
'A8' + # uid
'A8' + # gid
'A12' + # size
'A12' + # mtime
'A8' + # checksum
'A' + # typeflag
'A100' + # linkname
'A6' + # magic
'A2' + # version
'A32' + # uname
'A32' + # gname
'A8' + # devmajor
'A8' + # devminor
'A155' # prefix
attr_reader(*FIELDS)
def self.from(stream)
header = stream.read 512
empty = (header == "\0" * 512)
fields = header.unpack UNPACK_FORMAT
name = fields.shift
mode = fields.shift.oct
uid = fields.shift.oct
gid = fields.shift.oct
size = fields.shift.oct
mtime = fields.shift.oct
checksum = fields.shift.oct
typeflag = fields.shift
linkname = fields.shift
magic = fields.shift
version = fields.shift.oct
uname = fields.shift
gname = fields.shift
devmajor = fields.shift.oct
devminor = fields.shift.oct
prefix = fields.shift
new :name => name,
:mode => mode,
:uid => uid,
:gid => gid,
:size => size,
:mtime => mtime,
:checksum => checksum,
:typeflag => typeflag,
:linkname => linkname,
:magic => magic,
:version => version,
:uname => uname,
:gname => gname,
:devmajor => devmajor,
:devminor => devminor,
:prefix => prefix,
:empty => empty
# HACK unfactor for Rubinius
#new :name => fields.shift,
# :mode => fields.shift.oct,
# :uid => fields.shift.oct,
# :gid => fields.shift.oct,
# :size => fields.shift.oct,
# :mtime => fields.shift.oct,
# :checksum => fields.shift.oct,
# :typeflag => fields.shift,
# :linkname => fields.shift,
# :magic => fields.shift,
# :version => fields.shift.oct,
# :uname => fields.shift,
# :gname => fields.shift,
# :devmajor => fields.shift.oct,
# :devminor => fields.shift.oct,
# :prefix => fields.shift,
# :empty => empty
end
def initialize(vals)
unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] then
raise ArgumentError, ":name, :size, :prefix and :mode required"
end
vals[:uid] ||= 0
vals[:gid] ||= 0
vals[:mtime] ||= 0
vals[:checksum] ||= ""
vals[:typeflag] ||= "0"
vals[:magic] ||= "ustar"
vals[:version] ||= "00"
vals[:uname] ||= "wheel"
vals[:gname] ||= "wheel"
vals[:devmajor] ||= 0
vals[:devminor] ||= 0
FIELDS.each do |name|
instance_variable_set "@#{name}", vals[name]
end
@empty = vals[:empty]
end
def empty?
@empty
end
def ==(other)
self.class === other and
@checksum == other.checksum and
@devmajor == other.devmajor and
@devminor == other.devminor and
@gid == other.gid and
@gname == other.gname and
@linkname == other.linkname and
@magic == other.magic and
@mode == other.mode and
@mtime == other.mtime and
@name == other.name and
@prefix == other.prefix and
@size == other.size and
@typeflag == other.typeflag and
@uid == other.uid and
@uname == other.uname and
@version == other.version
end
def to_s
update_checksum
header
end
def update_checksum
header = header " " * 8
@checksum = oct calculate_checksum(header), 6
end
private
def calculate_checksum(header)
header.unpack("C*").inject { |a, b| a + b }
end
def header(checksum = @checksum)
header = [
name,
oct(mode, 7),
oct(uid, 7),
oct(gid, 7),
oct(size, 11),
oct(mtime, 11),
checksum,
" ",
typeflag,
linkname,
magic,
oct(version, 2),
uname,
gname,
oct(devmajor, 7),
oct(devminor, 7),
prefix
]
header = header.pack PACK_FORMAT
header << ("\0" * ((512 - header.size) % 512))
end
def oct(num, len)
"%0#{len}o" % num
end
end

Просмотреть файл

@ -0,0 +1,219 @@
#++
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#--
require 'rubygems/package'
class Gem::Package::TarInput
include Gem::Package::FSyncDir
include Enumerable
attr_reader :metadata
private_class_method :new
def self.open(io, security_policy = nil, &block)
is = new io, security_policy
yield is
ensure
is.close if is
end
def initialize(io, security_policy = nil)
@io = io
@tarreader = Gem::Package::TarReader.new @io
has_meta = false
data_sig, meta_sig, data_dgst, meta_dgst = nil, nil, nil, nil
dgst_algo = security_policy ? Gem::Security::OPT[:dgst_algo] : nil
@tarreader.each do |entry|
case entry.full_name
when "metadata"
@metadata = load_gemspec entry.read
has_meta = true
when "metadata.gz"
begin
# if we have a security_policy, then pre-read the metadata file
# and calculate it's digest
sio = nil
if security_policy
Gem.ensure_ssl_available
sio = StringIO.new(entry.read)
meta_dgst = dgst_algo.digest(sio.string)
sio.rewind
end
gzis = Zlib::GzipReader.new(sio || entry)
# YAML wants an instance of IO
@metadata = load_gemspec(gzis)
has_meta = true
ensure
gzis.close unless gzis.nil?
end
when 'metadata.gz.sig'
meta_sig = entry.read
when 'data.tar.gz.sig'
data_sig = entry.read
when 'data.tar.gz'
if security_policy
Gem.ensure_ssl_available
data_dgst = dgst_algo.digest(entry.read)
end
end
end
if security_policy then
Gem.ensure_ssl_available
# map trust policy from string to actual class (or a serialized YAML
# file, if that exists)
if String === security_policy then
if Gem::Security::Policy.key? security_policy then
# load one of the pre-defined security policies
security_policy = Gem::Security::Policy[security_policy]
elsif File.exist? security_policy then
# FIXME: this doesn't work yet
security_policy = YAML.load File.read(security_policy)
else
raise Gem::Exception, "Unknown trust policy '#{security_policy}'"
end
end
if data_sig && data_dgst && meta_sig && meta_dgst then
# the user has a trust policy, and we have a signed gem
# file, so use the trust policy to verify the gem signature
begin
security_policy.verify_gem(data_sig, data_dgst, @metadata.cert_chain)
rescue Exception => e
raise "Couldn't verify data signature: #{e}"
end
begin
security_policy.verify_gem(meta_sig, meta_dgst, @metadata.cert_chain)
rescue Exception => e
raise "Couldn't verify metadata signature: #{e}"
end
elsif security_policy.only_signed
raise Gem::Exception, "Unsigned gem"
else
# FIXME: should display warning here (trust policy, but
# either unsigned or badly signed gem file)
end
end
@tarreader.rewind
@fileops = Gem::FileOperations.new
raise Gem::Package::FormatError, "No metadata found!" unless has_meta
end
def close
@io.close
@tarreader.close
end
def each(&block)
@tarreader.each do |entry|
next unless entry.full_name == "data.tar.gz"
is = zipped_stream entry
begin
Gem::Package::TarReader.new is do |inner|
inner.each(&block)
end
ensure
is.close if is
end
end
@tarreader.rewind
end
def extract_entry(destdir, entry, expected_md5sum = nil)
if entry.directory? then
dest = File.join(destdir, entry.full_name)
if File.dir? dest then
@fileops.chmod entry.header.mode, dest, :verbose=>false
else
@fileops.mkdir_p dest, :mode => entry.header.mode, :verbose => false
end
fsync_dir dest
fsync_dir File.join(dest, "..")
return
end
# it's a file
md5 = Digest::MD5.new if expected_md5sum
destdir = File.join destdir, File.dirname(entry.full_name)
@fileops.mkdir_p destdir, :mode => 0755, :verbose => false
destfile = File.join destdir, File.basename(entry.full_name)
@fileops.chmod 0600, destfile, :verbose => false rescue nil # Errno::ENOENT
open destfile, "wb", entry.header.mode do |os|
loop do
data = entry.read 4096
break unless data
# HACK shouldn't we check the MD5 before writing to disk?
md5 << data if expected_md5sum
os.write(data)
end
os.fsync
end
@fileops.chmod entry.header.mode, destfile, :verbose => false
fsync_dir File.dirname(destfile)
fsync_dir File.join(File.dirname(destfile), "..")
if expected_md5sum && expected_md5sum != md5.hexdigest then
raise Gem::Package::BadCheckSum
end
end
# Attempt to YAML-load a gemspec from the given _io_ parameter. Return
# nil if it fails.
def load_gemspec(io)
Gem::Specification.from_yaml io
rescue Gem::Exception
nil
end
##
# Return an IO stream for the zipped entry.
#
# NOTE: Originally this method used two approaches, Return a GZipReader
# directly, or read the GZipReader into a string and return a StringIO on
# the string. The string IO approach was used for versions of ZLib before
# 1.2.1 to avoid buffer errors on windows machines. Then we found that
# errors happened with 1.2.1 as well, so we changed the condition. Then
# we discovered errors occurred with versions as late as 1.2.3. At this
# point (after some benchmarking to show we weren't seriously crippling
# the unpacking speed) we threw our hands in the air and declared that
# this method would use the String IO approach on all platforms at all
# times. And that's the way it is.
def zipped_stream(entry)
if defined? Rubinius then
zis = Zlib::GzipReader.new entry
dis = zis.read
is = StringIO.new(dis)
else
# This is Jamis Buck's Zlib workaround for some unknown issue
entry.read(10) # skip the gzip header
zis = Zlib::Inflate.new(-Zlib::MAX_WBITS)
is = StringIO.new(zis.inflate(entry.read))
end
ensure
zis.finish if zis
end
end

Просмотреть файл

@ -0,0 +1,143 @@
#++
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#--
require 'rubygems/package'
##
# TarOutput is a wrapper to TarWriter that builds gem-format tar file.
#
# Gem-format tar files contain the following files:
# [data.tar.gz] A gzipped tar file containing the files that compose the gem
# which will be extracted into the gem/ dir on installation.
# [metadata.gz] A YAML format Gem::Specification.
# [data.tar.gz.sig] A signature for the gem's data.tar.gz.
# [metadata.gz.sig] A signature for the gem's metadata.gz.
#
# See TarOutput::open for usage details.
class Gem::Package::TarOutput
##
# Creates a new TarOutput which will yield a TarWriter object for the
# data.tar.gz portion of a gem-format tar file.
#
# See #initialize for details on +io+ and +signer+.
#
# See #add_gem_contents for details on adding metadata to the tar file.
def self.open(io, signer = nil, &block) # :yield: data_tar_writer
tar_outputter = new io, signer
tar_outputter.add_gem_contents(&block)
tar_outputter.add_metadata
tar_outputter.add_signatures
ensure
tar_outputter.close
end
##
# Creates a new TarOutput that will write a gem-format tar file to +io+. If
# +signer+ is given, the data.tar.gz and metadata.gz will be signed and
# the signatures will be added to the tar file.
def initialize(io, signer)
@io = io
@signer = signer
@tar_writer = Gem::Package::TarWriter.new @io
@metadata = nil
@data_signature = nil
@meta_signature = nil
end
##
# Yields a TarWriter for the data.tar.gz inside a gem-format tar file.
# The yielded TarWriter has been extended with a #metadata= method for
# attaching a YAML format Gem::Specification which will be written by
# add_metadata.
def add_gem_contents
@tar_writer.add_file "data.tar.gz", 0644 do |inner|
sio = @signer ? StringIO.new : nil
Zlib::GzipWriter.wrap(sio || inner) do |os|
Gem::Package::TarWriter.new os do |data_tar_writer|
def data_tar_writer.metadata() @metadata end
def data_tar_writer.metadata=(metadata) @metadata = metadata end
yield data_tar_writer
@metadata = data_tar_writer.metadata
end
end
# if we have a signing key, then sign the data
# digest and return the signature
if @signer then
digest = Gem::Security::OPT[:dgst_algo].digest sio.string
@data_signature = @signer.sign digest
inner.write sio.string
end
end
self
end
##
# Adds metadata.gz to the gem-format tar file which was saved from a
# previous #add_gem_contents call.
def add_metadata
return if @metadata.nil?
@tar_writer.add_file "metadata.gz", 0644 do |io|
begin
sio = @signer ? StringIO.new : nil
gzos = Zlib::GzipWriter.new(sio || io)
gzos.write @metadata
ensure
gzos.flush
gzos.finish
# if we have a signing key, then sign the metadata digest and return
# the signature
if @signer then
digest = Gem::Security::OPT[:dgst_algo].digest sio.string
@meta_signature = @signer.sign digest
io.write sio.string
end
end
end
end
##
# Adds data.tar.gz.sig and metadata.gz.sig to the gem-format tar files if
# a Gem::Security::Signer was sent to initialize.
def add_signatures
if @data_signature then
@tar_writer.add_file 'data.tar.gz.sig', 0644 do |io|
io.write @data_signature
end
end
if @meta_signature then
@tar_writer.add_file 'metadata.gz.sig', 0644 do |io|
io.write @meta_signature
end
end
end
##
# Closes the TarOutput.
def close
@tar_writer.close
end
end

Просмотреть файл

@ -0,0 +1,86 @@
#++
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#--
require 'rubygems/package'
class Gem::Package::TarReader
include Gem::Package
class UnexpectedEOF < StandardError; end
def self.new(io)
reader = super
return reader unless block_given?
begin
yield reader
ensure
reader.close
end
nil
end
def initialize(io)
@io = io
@init_pos = io.pos
end
def close
end
def each
loop do
return if @io.eof?
header = Gem::Package::TarHeader.from @io
return if header.empty?
entry = Gem::Package::TarReader::Entry.new header, @io
size = entry.header.size
yield entry
skip = (512 - (size % 512)) % 512
if @io.respond_to? :seek then
# avoid reading...
@io.seek(size - entry.bytes_read, IO::SEEK_CUR)
else
pending = size - entry.bytes_read
while pending > 0 do
bread = @io.read([pending, 4096].min).size
raise UnexpectedEOF if @io.eof?
pending -= bread
end
end
@io.read skip # discard trailing zeros
# make sure nobody can use #read, #getc or #rewind anymore
entry.close
end
end
alias each_entry each
##
# NOTE: Do not call #rewind during #each
def rewind
if @init_pos == 0 then
raise Gem::Package::NonSeekableIO unless @io.respond_to? :rewind
@io.rewind
else
raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
@io.pos = @init_pos
end
end
end

Просмотреть файл

@ -0,0 +1,99 @@
#++
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#--
require 'rubygems/package'
class Gem::Package::TarReader::Entry
attr_reader :header
def initialize(header, io)
@closed = false
@header = header
@io = io
@orig_pos = @io.pos
@read = 0
end
def check_closed # :nodoc:
raise IOError, "closed #{self.class}" if closed?
end
def bytes_read
@read
end
def close
@closed = true
end
def closed?
@closed
end
def eof?
check_closed
@read >= @header.size
end
def full_name
if @header.prefix != "" then
File.join @header.prefix, @header.name
else
@header.name
end
end
def getc
check_closed
return nil if @read >= @header.size
ret = @io.getc
@read += 1 if ret
ret
end
def directory?
@header.typeflag == "5"
end
def file?
@header.typeflag == "0"
end
def pos
check_closed
bytes_read
end
def read(len = nil)
check_closed
return nil if @read >= @header.size
len ||= @header.size - @read
max_read = [len, @header.size - @read].min
ret = @io.read max_read
@read += ret.size
ret
end
def rewind
check_closed
raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
@io.pos = @orig_pos
@read = 0
end
end

Просмотреть файл

@ -0,0 +1,180 @@
#++
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
#--
require 'rubygems/package'
class Gem::Package::TarWriter
class FileOverflow < StandardError; end
class BoundedStream
attr_reader :limit, :written
def initialize(io, limit)
@io = io
@limit = limit
@written = 0
end
def write(data)
if data.size + @written > @limit
raise FileOverflow, "You tried to feed more data than fits in the file."
end
@io.write data
@written += data.size
data.size
end
end
class RestrictedStream
def initialize(io)
@io = io
end
def write(data)
@io.write data
end
end
def self.new(io)
writer = super
return writer unless block_given?
begin
yield writer
ensure
writer.close
end
nil
end
def initialize(io)
@io = io
@closed = false
end
def add_file(name, mode)
check_closed
raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
name, prefix = split_name name
init_pos = @io.pos
@io.write "\0" * 512 # placeholder for the header
yield RestrictedStream.new(@io) if block_given?
size = @io.pos - init_pos - 512
remainder = (512 - (size % 512)) % 512
@io.write "\0" * remainder
final_pos = @io.pos
@io.pos = init_pos
header = Gem::Package::TarHeader.new :name => name, :mode => mode,
:size => size, :prefix => prefix
@io.write header
@io.pos = final_pos
self
end
def add_file_simple(name, mode, size)
check_closed
name, prefix = split_name name
header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
:size => size, :prefix => prefix).to_s
@io.write header
os = BoundedStream.new @io, size
yield os if block_given?
min_padding = size - os.written
@io.write("\0" * min_padding)
remainder = (512 - (size % 512)) % 512
@io.write("\0" * remainder)
self
end
def check_closed
raise IOError, "closed #{self.class}" if closed?
end
def close
check_closed
@io.write "\0" * 1024
flush
@closed = true
end
def closed?
@closed
end
def flush
check_closed
@io.flush if @io.respond_to? :flush
end
def mkdir(name, mode)
check_closed
name, prefix = split_name(name)
header = Gem::Package::TarHeader.new :name => name, :mode => mode,
:typeflag => "5", :size => 0,
:prefix => prefix
@io.write header
self
end
def split_name(name) # :nodoc:
raise Gem::Package::TooLongFileName if name.size > 256
if name.size <= 100 then
prefix = ""
else
parts = name.split(/\//)
newname = parts.pop
nxt = ""
loop do
nxt = parts.pop
break if newname.size + 1 + nxt.size > 100
newname = nxt + "/" + newname
end
prefix = (parts + [nxt]).join "/"
name = newname
if name.size > 100 or prefix.size > 155 then
raise Gem::Package::TooLongFileName
end
end
return name, prefix
end
end

Просмотреть файл

@ -2,7 +2,6 @@ require 'net/http'
require 'uri'
require 'rubygems'
require 'rubygems/gem_open_uri'
##
# RemoteFetcher handles the details of fetching gems and gem information from
@ -10,6 +9,8 @@ require 'rubygems/gem_open_uri'
class Gem::RemoteFetcher
include Gem::UserInteraction
class FetchError < Gem::Exception; end
@fetcher = nil
@ -29,6 +30,10 @@ class Gem::RemoteFetcher
# 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
@connections = {}
@requests = Hash.new 0
@proxy_uri =
case proxy
when :no_proxy then nil
@ -38,6 +43,65 @@ class Gem::RemoteFetcher
end
end
##
# 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
source_uri = URI.parse source_uri unless URI::Generic === source_uri
scheme = source_uri.scheme
# URI.parse gets confused by MS Windows paths with forward slashes.
scheme = nil if scheme =~ /^[a-z]$/i
case scheme
when 'http' then
unless File.exist? local_gem_path then
begin
say "Downloading gem #{gem_file_name}" if
Gem.configuration.really_verbose
remote_gem_path = source_uri + "gems/#{gem_file_name}"
gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
rescue Gem::RemoteFetcher::FetchError
raise if spec.original_platform == spec.platform
alternate_name = "#{spec.original_name}.gem"
say "Failed, downloading gem #{alternate_name}" if
Gem.configuration.really_verbose
remote_gem_path = source_uri + "gems/#{alternate_name}"
gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
end
File.open local_gem_path, 'wb' do |fp|
fp.write gem
end
end
when nil, 'file' then # TODO test for local overriding cache
begin
FileUtils.cp source_uri.to_s, local_gem_path
rescue Errno::EACCES
local_gem_path = source_uri.to_s
end
say "Using local gem #{local_gem_path}" if
Gem.configuration.really_verbose
else
raise Gem::InstallError, "unsupported URI scheme #{source_uri.scheme}"
end
local_gem_path
end
# Downloads +uri+.
def fetch_path(uri)
open_uri_or_path(uri) do |input|
@ -47,9 +111,8 @@ class Gem::RemoteFetcher
raise FetchError, "timed out fetching #{uri}"
rescue IOError, SocketError, SystemCallError => e
raise FetchError, "#{e.class}: #{e} reading #{uri}"
rescue OpenURI::HTTPError => e
body = e.io.readlines.join "\n\t"
message = "#{e.class}: #{e} reading #{uri}\n\t#{body}"
rescue => e
message = "#{e.class}: #{e} reading #{uri}"
raise FetchError, message
end
@ -83,7 +146,8 @@ class Gem::RemoteFetcher
end
rescue SocketError, SystemCallError, Timeout::Error => e
raise FetchError, "#{e.message} (#{e.class})\n\tgetting size of #{uri}"
raise Gem::RemoteFetcher::FetchError,
"#{e.message} (#{e.class})\n\tgetting size of #{uri}"
end
private
@ -131,26 +195,77 @@ class Gem::RemoteFetcher
# 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, &block)
def open_uri_or_path(uri, depth = 0, &block)
if file_uri?(uri)
open(get_file_uri_path(uri), &block)
else
connection_options = {
"User-Agent" => "RubyGems/#{Gem::RubyGemsVersion} #{Gem::Platform.local}"
}
if @proxy_uri
http_proxy_url = "#{@proxy_uri.scheme}://#{@proxy_uri.host}:#{@proxy_uri.port}"
connection_options[:proxy_http_basic_authentication] = [http_proxy_url, unescape(@proxy_uri.user)||'', unescape(@proxy_uri.password)||'']
end
uri = URI.parse uri unless URI::Generic === uri
unless uri.nil? || uri.user.nil? || uri.user.empty? then
connection_options[:http_basic_authentication] =
[unescape(uri.user), unescape(uri.password)]
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
open(uri, connection_options, &block)
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
retried = false
begin
@requests[connection_id] += 1
response = connection.request(request)
rescue EOFError
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
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
open_uri_or_path(response['Location'], depth + 1, &block)
else
raise Gem::RemoteFetcher::FetchError,
"bad response #{response.message} #{response.code}"
end
end
end

Просмотреть файл

@ -16,6 +16,8 @@ class Gem::Requirement
include Comparable
attr_reader :requirements
OPS = {
"=" => lambda { |v, r| v == r },
"!=" => lambda { |v, r| v != r },

Просмотреть файл

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

Просмотреть файл

@ -4,6 +4,7 @@
# See LICENSE.txt for permissions.
#++
require 'rubygems'
require 'rubygems/gem_openssl'
# = Signed Gems README

Просмотреть файл

@ -1,7 +1,7 @@
require 'webrick'
require 'rdoc/template'
require 'yaml'
require 'zlib'
require 'erb'
require 'rubygems'
@ -27,107 +27,87 @@ class Gem::Server
include Gem::UserInteraction
DOC_TEMPLATE = <<-WEBPAGE
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<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>
<div id="fileHeader">
<h1>RubyGems Documentation Index</h1>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
<div id="description">
<h1>Summary</h1>
<p>There are %gem_count% gems installed:</p>
<p>
START:specs
IFNOT:is_last
<a href="#%name%">%name%</a>,
ENDIF:is_last
IF:is_last
<a href="#%name%">%name%</a>.
ENDIF:is_last
END:specs
<h1>Gems</h1>
<dl>
START:specs
<dt>
IF:first_name_entry
<a name="%name%"></a>
ENDIF:first_name_entry
<b>%name% %version%</b>
IF:rdoc_installed
<a href="%doc_path%">[rdoc]</a>
ENDIF:rdoc_installed
IFNOT:rdoc_installed
<span title="rdoc not installed">[rdoc]</span>
ENDIF:rdoc_installed
IF:homepage
<a href="%homepage%" title="%homepage%">[www]</a>
ENDIF:homepage
IFNOT:homepage
<span title="no homepage available">[www]</span>
ENDIF:homepage
IF:has_deps
- depends on
START:dependencies
IFNOT:is_last
<a href="#%name%" title="%version%">%name%</a>,
ENDIF:is_last
IF:is_last
<a href="#%name%" title="%version%">%name%</a>.
ENDIF:is_last
END:dependencies
ENDIF:has_deps
</dt>
<dd>
%summary%
IF:executables
<br/>
IF:only_one_executable
Executable is
ENDIF:only_one_executable
IFNOT:only_one_executable
Executables are
ENDIF:only_one_executable
START:executables
IFNOT:is_last
<span class="context-item-name">%executable%</span>,
ENDIF:is_last
IF:is_last
<span class="context-item-name">%executable%</span>.
ENDIF:is_last
END:executables
ENDIF:executables
<br/>
<br/>
</dd>
END:specs
</dl>
DOC_TEMPLATE = <<-'WEBPAGE'
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<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>
<div id="fileHeader">
<h1>RubyGems Documentation Index</h1>
</div>
</div>
<!-- banner header -->
<div id="bodyContent">
<div id="contextContent">
<div id="description">
<h1>Summary</h1>
<p>There are <%=values["gem_count"]%> gems installed:</p>
<p>
<%= values["specs"].map { |v| "<a href=\"#{v["name"]}\">#{v["name"]}</a>" }.join ', ' %>.
<h1>Gems</h1>
<dl>
<% values["specs"].each do |spec| %>
<dt>
<% if spec["first_name_entry"] then %>
<a name="<%=spec["name"]%>"></a>
<% end %>
<b><%=spec["name"]%> <%=spec["version"]%></b>
<% if spec["rdoc_installed"] then %>
<a href="<%=spec["doc_path"]%>">[rdoc]</a>
<% else %>
<span title="rdoc not installed">[rdoc]</span>
<% end %>
<% if spec["homepage"] then %>
<a href="<%=spec["homepage"]%>" title="<%=spec["homepage"]%>">[www]</a>
<% else %>
<span title="no homepage available">[www]</span>
<% end %>
<% if spec["has_deps"] then %>
- depends on
<%= spec["dependencies"].map { |v| "<a href=\"#{v["name"]}\">#{v["name"]}</a>" }.join ', ' %>.
<% end %>
</dt>
<dd>
<%=spec["summary"]%>
<% if spec["executables"] then %>
<br/>
<% if spec["only_one_executable"] then %>
Executable is
<% else %>
Executables are
<%end%>
<%= spec["executables"].map { |v| "<span class=\"context-item-name\">#{v["executable"]}</span>"}.join ', ' %>.
<%end%>
<br/>
<br/>
</dd>
<% end %>
</dl>
</div>
</div>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
<div id="validator-badges">
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
</div>
</body>
</html>
</body>
</html>
WEBPAGE
# CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108
@ -496,11 +476,12 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
end
# create page from template
template = TemplatePage.new(DOC_TEMPLATE)
template = ERB.new(DOC_TEMPLATE)
res['content-type'] = 'text/html'
template.write_html_on res.body,
"gem_count" => specs.size.to_s, "specs" => specs,
"total_file_count" => total_file_count.to_s
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
paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }

Просмотреть файл

@ -8,437 +8,512 @@ require 'rubygems'
require 'rubygems/user_interaction'
require 'rubygems/specification'
module Gem
##
# The SourceIndex object indexes all the gems available from a
# particular source (e.g. a list of gem directories, or a remote
# source). A SourceIndex maps a gem full name to a gem
# specification.
#
# NOTE:: The class used to be named Cache, but that became
# confusing when cached source fetchers where introduced. The
# constant Gem::Cache is an alias for this class to allow old
# YAMLized source index objects to load properly.
# The SourceIndex object indexes all the gems available from a
# particular source (e.g. a list of gem directories, or a remote
# source). A SourceIndex maps a gem full name to a gem
# specification.
#
# NOTE:: The class used to be named Cache, but that became
# confusing when cached source fetchers where introduced. The
# constant Gem::Cache is an alias for this class to allow old
# YAMLized source index objects to load properly.
#
class SourceIndex
class Gem::SourceIndex
include Enumerable
include Enumerable
include Gem::UserInteraction
class << self
include Gem::UserInteraction
# Class Methods. -------------------------------------------------
class << self
include Gem::UserInteraction
# Factory method to construct a source index instance for a given
# path.
#
# deprecated::
# If supplied, from_installed_gems will act just like
# +from_gems_in+. This argument is deprecated and is provided
# just for backwards compatibility, and should not generally
# be used.
#
# return::
# SourceIndex instance
#
def from_installed_gems(*deprecated)
if deprecated.empty?
from_gems_in(*installed_spec_directories)
else
from_gems_in(*deprecated) # HACK warn
end
end
# Return a list of directories in the current gem path that
# contain specifications.
#
# return::
# List of directory paths (all ending in "../specifications").
#
def installed_spec_directories
Gem.path.collect { |dir| File.join(dir, "specifications") }
end
# Factory method to construct a source index instance for a
# given path.
#
# spec_dirs::
# List of directories to search for specifications. Each
# directory should have a "specifications" subdirectory
# containing the gem specifications.
#
# return::
# SourceIndex instance
#
def from_gems_in(*spec_dirs)
self.new.load_gems_in(*spec_dirs)
end
# Load a specification from a file (eval'd Ruby code)
#
# file_name:: [String] The .gemspec file
# return:: Specification instance or nil if an error occurs
#
def load_specification(file_name)
begin
spec_code = File.read(file_name).untaint
gemspec = eval spec_code, binding, file_name
if gemspec.is_a?(Gem::Specification)
gemspec.loaded_from = file_name
return gemspec
end
alert_warning "File '#{file_name}' does not evaluate to a gem specification"
rescue SyntaxError => e
alert_warning e
alert_warning spec_code
rescue Exception => e
alert_warning(e.inspect.to_s + "\n" + spec_code)
alert_warning "Invalid .gemspec format in '#{file_name}'"
end
return nil
end
end
# Instance Methods -----------------------------------------------
# Constructs a source index instance from the provided
# specifications
##
# Factory method to construct a source index instance for a given
# path.
#
# specifications::
# [Hash] hash of [Gem name, Gem::Specification] pairs
#
def initialize(specifications={})
@gems = specifications
end
# Reconstruct the source index from the list of source
# directories.
def load_gems_in(*spec_dirs)
@gems.clear
specs = Dir.glob File.join("{#{spec_dirs.join(',')}}", "*.gemspec")
# deprecated::
# If supplied, from_installed_gems will act just like
# +from_gems_in+. This argument is deprecated and is provided
# just for backwards compatibility, and should not generally
# be used.
#
# return::
# SourceIndex instance
specs.each do |file_name|
gemspec = self.class.load_specification(file_name.untaint)
add_spec(gemspec) if gemspec
end
self
end
# Returns a Hash of name => Specification of the latest versions of each
# gem in this index.
def latest_specs
result, latest = Hash.new { |h,k| h[k] = [] }, {}
self.each do |_, spec| # SourceIndex is not a hash, so we're stuck with each
name = spec.name
curr_ver = spec.version
prev_ver = latest[name]
next unless prev_ver.nil? or curr_ver >= prev_ver
if prev_ver.nil? or curr_ver > prev_ver then
result[name].clear
latest[name] = curr_ver
end
result[name] << spec
end
result.values.flatten
end
# Add a gem specification to the source index.
def add_spec(gem_spec)
@gems[gem_spec.full_name] = gem_spec
end
# Remove a gem specification named +full_name+.
def remove_spec(full_name)
@gems.delete(full_name)
end
# Iterate over the specifications in the source index.
def each(&block) # :yields: gem.full_name, gem
@gems.each(&block)
end
# The gem specification given a full gem spec name.
def specification(full_name)
@gems[full_name]
end
# The signature for the source index. Changes in the signature
# indicate a change in the index.
def index_signature
require 'rubygems/digest/sha2'
Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
end
# The signature for the given gem specification.
def gem_signature(gem_full_name)
require 'rubygems/digest/sha2'
Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
end
def size
@gems.size
end
alias length size
# Find a gem by an exact match on the short name.
def find_name(gem_name, version_requirement = Gem::Requirement.default)
search(/^#{gem_name}$/, version_requirement)
end
# Search for a gem by Gem::Dependency +gem_pattern+. If +only_platform+
# is true, only gems matching Gem::Platform.local will be returned. An
# Array of matching Gem::Specification objects is returned.
#
# For backwards compatibility, a String or Regexp pattern may be passed as
# +gem_pattern+, and a Gem::Requirement for +platform_only+. This
# behavior is deprecated and will be removed.
def search(gem_pattern, platform_only = false)
version_requirement = nil
only_platform = false
case gem_pattern # TODO warn after 2008/03, remove three months after
when Regexp then
version_requirement = platform_only || Gem::Requirement.default
when Gem::Dependency then
only_platform = platform_only
version_requirement = gem_pattern.version_requirements
gem_pattern = if gem_pattern.name.empty? then
//
else
/^#{Regexp.escape gem_pattern.name}$/
end
def from_installed_gems(*deprecated)
if deprecated.empty?
from_gems_in(*installed_spec_directories)
else
version_requirement = platform_only || Gem::Requirement.default
gem_pattern = /#{gem_pattern}/i
from_gems_in(*deprecated) # HACK warn
end
unless Gem::Requirement === version_requirement then
version_requirement = Gem::Requirement.create version_requirement
end
specs = @gems.values.select do |spec|
spec.name =~ gem_pattern and
version_requirement.satisfied_by? spec.version
end
if only_platform then
specs = specs.select do |spec|
Gem::Platform.match spec.platform
end
end
specs.sort_by { |s| s.sort_obj }
end
# Refresh the source index from the local file system.
#
# return:: Returns a pointer to itself.
#
def refresh!
load_gems_in(self.class.installed_spec_directories)
##
# Return a list of directories in the current gem path that
# contain specifications.
#
# return::
# List of directory paths (all ending in "../specifications").
def installed_spec_directories
Gem.path.collect { |dir| File.join(dir, "specifications") }
end
# Returns an Array of Gem::Specifications that are not up to date.
#
def outdated
dep = Gem::Dependency.new '', Gem::Requirement.default
##
# Creates a new SourceIndex from the ruby format gem specifications in
# +spec_dirs+.
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
end
outdateds
def from_gems_in(*spec_dirs)
self.new.load_gems_in(*spec_dirs)
end
def update(source_uri)
use_incremental = false
##
# Loads a ruby-format specification from +file_name+ and returns the
# loaded spec.
def load_specification(file_name)
begin
gem_names = fetch_quick_index source_uri
remove_extra gem_names
missing_gems = find_missing gem_names
spec_code = File.read(file_name).untaint
gemspec = eval spec_code, binding, file_name
if gemspec.is_a?(Gem::Specification)
gemspec.loaded_from = file_name
return gemspec
end
alert_warning "File '#{file_name}' does not evaluate to a gem specification"
rescue SyntaxError => e
alert_warning e
alert_warning spec_code
rescue Exception => e
alert_warning(e.inspect.to_s + "\n" + spec_code)
alert_warning "Invalid .gemspec format in '#{file_name}'"
end
return nil
end
return false if missing_gems.size.zero?
end
say "missing #{missing_gems.size} gems" if
missing_gems.size > 0 and Gem.configuration.really_verbose
##
# Constructs a source index instance from the provided
# specifications
#
# specifications::
# [Hash] hash of [Gem name, Gem::Specification] pairs
use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold
rescue Gem::OperationNotSupportedError => ex
alert_error "Falling back to bulk fetch: #{ex.message}" if
Gem.configuration.really_verbose
use_incremental = false
def initialize(specifications={})
@gems = specifications
end
##
# Reconstruct the source index from the specifications in +spec_dirs+.
def load_gems_in(*spec_dirs)
@gems.clear
spec_dirs.reverse_each do |spec_dir|
spec_files = Dir.glob File.join(spec_dir, '*.gemspec')
spec_files.each do |spec_file|
gemspec = self.class.load_specification spec_file.untaint
add_spec gemspec if gemspec
end
end
self
end
##
# Returns a Hash of name => Specification of the latest versions of each
# gem in this index.
def latest_specs
result = Hash.new { |h,k| h[k] = [] }
latest = {}
sort.each do |_, spec|
name = spec.name
curr_ver = spec.version
prev_ver = latest.key?(name) ? latest[name].version : nil
next unless prev_ver.nil? or curr_ver >= prev_ver or
latest[name].platform != Gem::Platform::RUBY
if prev_ver.nil? or
(curr_ver > prev_ver and spec.platform == Gem::Platform::RUBY) then
result[name].clear
latest[name] = spec
end
if use_incremental then
update_with_missing(source_uri, missing_gems)
else
new_index = fetch_bulk_index(source_uri)
@gems.replace(new_index.gems)
if spec.platform != Gem::Platform::RUBY then
result[name].delete_if do |result_spec|
result_spec.platform == spec.platform
end
end
true
result[name] << spec
end
def ==(other) # :nodoc:
self.class === other and @gems == other.gems
result.values.flatten
end
##
# Add a gem specification to the source index.
def add_spec(gem_spec)
@gems[gem_spec.full_name] = gem_spec
end
##
# Add gem specifications to the source index.
def add_specs(*gem_specs)
gem_specs.each do |spec|
add_spec spec
end
end
##
# Remove a gem specification named +full_name+.
def remove_spec(full_name)
@gems.delete(full_name)
end
##
# Iterate over the specifications in the source index.
def each(&block) # :yields: gem.full_name, gem
@gems.each(&block)
end
##
# The gem specification given a full gem spec name.
def specification(full_name)
@gems[full_name]
end
##
# The signature for the source index. Changes in the signature indicate a
# change in the index.
def index_signature
require 'rubygems/digest/sha2'
Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
end
##
# The signature for the given gem specification.
def gem_signature(gem_full_name)
require 'rubygems/digest/sha2'
Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
end
def size
@gems.size
end
alias length size
##
# Find a gem by an exact match on the short name.
def find_name(gem_name, version_requirement = Gem::Requirement.default)
search(/^#{gem_name}$/, version_requirement)
end
##
# Search for a gem by Gem::Dependency +gem_pattern+. If +only_platform+
# is true, only gems matching Gem::Platform.local will be returned. An
# Array of matching Gem::Specification objects is returned.
#
# For backwards compatibility, a String or Regexp pattern may be passed as
# +gem_pattern+, and a Gem::Requirement for +platform_only+. This
# behavior is deprecated and will be removed.
def search(gem_pattern, platform_only = false)
version_requirement = nil
only_platform = false
case gem_pattern # TODO warn after 2008/03, remove three months after
when Regexp then
version_requirement = platform_only || Gem::Requirement.default
when Gem::Dependency then
only_platform = platform_only
version_requirement = gem_pattern.version_requirements
gem_pattern = if gem_pattern.name.empty? then
//
else
/^#{Regexp.escape gem_pattern.name}$/
end
else
version_requirement = platform_only || Gem::Requirement.default
gem_pattern = /#{gem_pattern}/i
end
def dump
Marshal.dump(self)
unless Gem::Requirement === version_requirement then
version_requirement = Gem::Requirement.create version_requirement
end
protected
attr_reader :gems
private
def fetcher
require 'rubygems/remote_fetcher'
Gem::RemoteFetcher.fetcher
specs = @gems.values.select do |spec|
spec.name =~ gem_pattern and
version_requirement.satisfied_by? spec.version
end
def fetch_index_from(source_uri)
@fetch_error = nil
if only_platform then
specs = specs.select do |spec|
Gem::Platform.match spec.platform
end
end
indexes = %W[
specs.sort_by { |s| s.sort_obj }
end
##
# Refresh the source index from the local file system.
#
# return:: Returns a pointer to itself.
def refresh!
load_gems_in(self.class.installed_spec_directories)
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
end
outdateds
end
##
# Updates this SourceIndex from +source_uri+. If +all+ is false, only the
# latest gems are fetched.
def update(source_uri, all)
source_uri = URI.parse source_uri unless URI::Generic === source_uri
source_uri.path += '/' unless source_uri.path =~ /\/$/
use_incremental = false
begin
gem_names = fetch_quick_index source_uri, all
remove_extra gem_names
missing_gems = find_missing gem_names
return false if missing_gems.size.zero?
say "Missing metadata for #{missing_gems.size} gems" if
missing_gems.size > 0 and Gem.configuration.really_verbose
use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold
rescue Gem::OperationNotSupportedError => ex
alert_error "Falling back to bulk fetch: #{ex.message}" if
Gem.configuration.really_verbose
use_incremental = false
end
if use_incremental then
update_with_missing(source_uri, missing_gems)
else
new_index = fetch_bulk_index(source_uri)
@gems.replace(new_index.gems)
end
true
end
def ==(other) # :nodoc:
self.class === other and @gems == other.gems
end
def dump
Marshal.dump(self)
end
protected
attr_reader :gems
private
def fetcher
require 'rubygems/remote_fetcher'
Gem::RemoteFetcher.fetcher
end
def fetch_index_from(source_uri)
@fetch_error = nil
indexes = %W[
Marshal.#{Gem.marshal_version}.Z
Marshal.#{Gem.marshal_version}
yaml.Z
yaml
]
indexes.each do |name|
spec_data = nil
begin
spec_data = fetcher.fetch_path("#{source_uri}/#{name}")
spec_data = unzip(spec_data) if name =~ /\.Z$/
if name =~ /Marshal/ then
return Marshal.load(spec_data)
else
return YAML.load(spec_data)
end
rescue => e
if Gem.configuration.really_verbose then
alert_error "Unable to fetch #{name}: #{e.message}"
end
@fetch_error = e
end
end
nil
end
def fetch_bulk_index(source_uri)
say "Bulk updating Gem source index for: #{source_uri}"
index = fetch_index_from(source_uri)
if index.nil? then
raise Gem::RemoteSourceException,
"Error fetching remote gem cache: #{@fetch_error}"
end
@fetch_error = nil
index
end
# Get the quick index needed for incremental updates.
def fetch_quick_index(source_uri)
zipped_index = fetcher.fetch_path source_uri + '/quick/index.rz'
unzip(zipped_index).split("\n")
rescue ::Exception => ex
raise Gem::OperationNotSupportedError,
"No quick index found: " + ex.message
end
# Make a list of full names for all the missing gemspecs.
def find_missing(spec_names)
spec_names.find_all { |full_name|
specification(full_name).nil?
}
end
def remove_extra(spec_names)
dictionary = spec_names.inject({}) { |h, k| h[k] = true; h }
each do |name, spec|
remove_spec name unless dictionary.include? name
end
end
# Unzip the given string.
def unzip(string)
require 'zlib'
Zlib::Inflate.inflate(string)
end
# Tries to fetch Marshal representation first, then YAML
def fetch_single_spec(source_uri, spec_name)
@fetch_error = nil
indexes.each do |name|
spec_data = nil
index = source_uri + name
begin
marshal_uri = source_uri + "/quick/Marshal.#{Gem.marshal_version}/#{spec_name}.gemspec.rz"
zipped = fetcher.fetch_path marshal_uri
return Marshal.load(unzip(zipped))
rescue => ex
@fetch_error = ex
if Gem.configuration.really_verbose then
say "unable to fetch marshal gemspec #{marshal_uri}: #{ex.class} - #{ex}"
end
end
spec_data = fetcher.fetch_path index
spec_data = unzip(spec_data) if name =~ /\.Z$/
begin
yaml_uri = source_uri + "/quick/#{spec_name}.gemspec.rz"
zipped = fetcher.fetch_path yaml_uri
return YAML.load(unzip(zipped))
rescue => ex
@fetch_error = ex
if Gem.configuration.really_verbose then
say "unable to fetch YAML gemspec #{yaml_uri}: #{ex.class} - #{ex}"
end
end
nil
end
# Update the cached source index with the missing names.
def update_with_missing(source_uri, missing_names)
progress = ui.progress_reporter(missing_names.size,
"Updating metadata for #{missing_names.size} gems from #{source_uri}")
missing_names.each do |spec_name|
gemspec = fetch_single_spec(source_uri, spec_name)
if gemspec.nil? then
ui.say "Failed to download spec #{spec_name} from #{source_uri}:\n" \
"\t#{@fetch_error.message}"
if name =~ /Marshal/ then
return Marshal.load(spec_data)
else
add_spec gemspec
progress.updated spec_name
return YAML.load(spec_data)
end
@fetch_error = nil
rescue => e
if Gem.configuration.really_verbose then
alert_error "Unable to fetch #{name}: #{e.message}"
end
@fetch_error = e
end
progress.done
progress.count
end
nil
end
# Cache is an alias for SourceIndex to allow older YAMLized source
# index objects to load properly.
Cache = SourceIndex
def fetch_bulk_index(source_uri)
say "Bulk updating Gem source index for: #{source_uri}"
index = fetch_index_from(source_uri)
if index.nil? then
raise Gem::RemoteSourceException,
"Error fetching remote gem cache: #{@fetch_error}"
end
@fetch_error = nil
index
end
##
# Get the quick index needed for incremental updates.
def fetch_quick_index(source_uri, all)
index = all ? 'index' : 'latest_index'
zipped_index = fetcher.fetch_path source_uri + "quick/#{index}.rz"
unzip(zipped_index).split("\n")
rescue ::Exception => e
unless all then
say "Latest index not found, using quick index" if
Gem.configuration.really_verbose
fetch_quick_index source_uri, true
else
raise Gem::OperationNotSupportedError,
"No quick index found: #{e.message}"
end
end
##
# Make a list of full names for all the missing gemspecs.
def find_missing(spec_names)
spec_names.find_all { |full_name|
specification(full_name).nil?
}
end
def remove_extra(spec_names)
dictionary = spec_names.inject({}) { |h, k| h[k] = true; h }
each do |name, spec|
remove_spec name unless dictionary.include? name
end
end
##
# Unzip the given string.
def unzip(string)
require 'zlib'
Zlib::Inflate.inflate(string)
end
##
# Tries to fetch Marshal representation first, then YAML
def fetch_single_spec(source_uri, spec_name)
@fetch_error = nil
begin
marshal_uri = source_uri + "quick/Marshal.#{Gem.marshal_version}/#{spec_name}.gemspec.rz"
zipped = fetcher.fetch_path marshal_uri
return Marshal.load(unzip(zipped))
rescue => ex
@fetch_error = ex
if Gem.configuration.really_verbose then
say "unable to fetch marshal gemspec #{marshal_uri}: #{ex.class} - #{ex}"
end
end
begin
yaml_uri = source_uri + "quick/#{spec_name}.gemspec.rz"
zipped = fetcher.fetch_path yaml_uri
return YAML.load(unzip(zipped))
rescue => ex
@fetch_error = ex
if Gem.configuration.really_verbose then
say "unable to fetch YAML gemspec #{yaml_uri}: #{ex.class} - #{ex}"
end
end
nil
end
##
# Update the cached source index with the missing names.
def update_with_missing(source_uri, missing_names)
progress = ui.progress_reporter(missing_names.size,
"Updating metadata for #{missing_names.size} gems from #{source_uri}")
missing_names.each do |spec_name|
gemspec = fetch_single_spec(source_uri, spec_name)
if gemspec.nil? then
ui.say "Failed to download spec #{spec_name} from #{source_uri}:\n" \
"\t#{@fetch_error.message}"
else
add_spec gemspec
progress.updated spec_name
end
@fetch_error = nil
end
progress.done
progress.count
end
end
module Gem
# :stopdoc:
# Cache is an alias for SourceIndex to allow older YAMLized source index
# objects to load properly.
Cache = SourceIndex
# :starddoc:
end

Просмотреть файл

@ -4,6 +4,7 @@ require 'rubygems'
require 'rubygems/source_info_cache_entry'
require 'rubygems/user_interaction'
##
# SourceInfoCache stores a copy of the gem index for each gem source.
#
# There are two possible cache locations, the system cache and the user cache:
@ -25,7 +26,7 @@ require 'rubygems/user_interaction'
# @source_index => Gem::SourceIndex
# ...
# }
#
class Gem::SourceInfoCache
include Gem::UserInteraction
@ -37,7 +38,7 @@ class Gem::SourceInfoCache
def self.cache
return @cache if @cache
@cache = new
@cache.refresh if Gem.configuration.update_sources
@cache.refresh false if Gem.configuration.update_sources
@cache
end
@ -45,86 +46,178 @@ class Gem::SourceInfoCache
cache.cache_data
end
# Search all source indexes for +pattern+.
def self.search(pattern, platform_only = false)
cache.search pattern, platform_only
##
# The name of the system cache file.
def self.latest_system_cache_file
File.join File.dirname(system_cache_file),
"latest_#{File.basename system_cache_file}"
end
# Search all source indexes for +pattern+. Only returns gems matching
# Gem.platforms when +only_platform+ is true. See #search_with_source.
def self.search_with_source(pattern, only_platform = false)
cache.search_with_source(pattern, only_platform)
##
# The name of the latest user cache file.
def self.latest_user_cache_file
File.join File.dirname(user_cache_file),
"latest_#{File.basename user_cache_file}"
end
##
# Search all source indexes. See Gem::SourceInfoCache#search.
def self.search(*args)
cache.search(*args)
end
##
# Search all source indexes returning the source_uri. See
# Gem::SourceInfoCache#search_with_source.
def self.search_with_source(*args)
cache.search_with_source(*args)
end
##
# The name of the system cache file. (class method)
def self.system_cache_file
@system_cache_file ||= Gem.default_system_source_cache_dir
end
##
# The name of the user cache file.
def self.user_cache_file
@user_cache_file ||=
ENV['GEMCACHE'] || Gem.default_user_source_cache_dir
end
def initialize # :nodoc:
@cache_data = nil
@cache_file = nil
@dirty = false
@only_latest = true
end
##
# The most recent cache data.
def cache_data
return @cache_data if @cache_data
cache_file # HACK writable check
begin
# Marshal loads 30-40% faster from a String, and 2MB on 20061116 is small
data = File.open cache_file, 'rb' do |fp| fp.read end
@cache_data = Marshal.load data
@only_latest = true
@cache_data.each do |url, sice|
next unless sice.is_a?(Hash)
update
cache = sice['cache']
size = sice['size']
if cache.is_a?(Gem::SourceIndex) and size.is_a?(Numeric) then
new_sice = Gem::SourceInfoCacheEntry.new cache, size
@cache_data[url] = new_sice
else # irreperable, force refetch.
reset_cache_for(url)
end
end
@cache_data
rescue => e
if Gem.configuration.really_verbose then
say "Exception during cache_data handling: #{ex.class} - #{ex}"
say "Cache file was: #{cache_file}"
say "\t#{e.backtrace.join "\n\t"}"
end
reset_cache_data
end
end
@cache_data = read_cache_data latest_cache_file
def reset_cache_for(url)
say "Reseting cache for #{url}" if Gem.configuration.really_verbose
sice = Gem::SourceInfoCacheEntry.new Gem::SourceIndex.new, 0
sice.refresh url # HACK may be unnecessary, see ::cache and #refresh
@cache_data[url] = sice
@cache_data
end
def reset_cache_data
@cache_data = {}
end
##
# The name of the cache file.
# The name of the cache file to be read
def cache_file
return @cache_file if @cache_file
@cache_file = (try_file(system_cache_file) or
try_file(user_cache_file) or
raise "unable to locate a writable cache file")
end
##
# Force cache file to be reset, useful for integration testing of rubygems
def reset_cache_file
@cache_file = nil
end
##
# Write the cache to a local file (if it is dirty).
def flush
write_cache if @dirty
@dirty = false
end
# Refreshes each source in the cache from its repository.
def refresh
def latest_cache_data
latest_cache_data = {}
cache_data.each do |repo, sice|
latest = sice.source_index.latest_specs
new_si = Gem::SourceIndex.new
new_si.add_specs(*latest)
latest_sice = Gem::SourceInfoCacheEntry.new new_si, sice.size
latest_cache_data[repo] = latest_sice
end
latest_cache_data
end
##
# The name of the latest cache file.
def latest_cache_file
File.join File.dirname(cache_file), "latest_#{File.basename cache_file}"
end
##
# The name of the latest system cache file.
def latest_system_cache_file
self.class.latest_system_cache_file
end
##
# The name of the latest user cache file.
def latest_user_cache_file
self.class.latest_user_cache_file
end
def read_all_cache_data
if @only_latest then
@only_latest = false
@cache_data = read_cache_data cache_file
end
end
def read_cache_data(file)
# Marshal loads 30-40% faster from a String, and 2MB on 20061116 is small
data = open file, 'rb' do |fp| fp.read end
cache_data = Marshal.load data
cache_data.each do |url, sice|
next unless sice.is_a?(Hash)
update
cache = sice['cache']
size = sice['size']
if cache.is_a?(Gem::SourceIndex) and size.is_a?(Numeric) then
new_sice = Gem::SourceInfoCacheEntry.new cache, size
cache_data[url] = new_sice
else # irreperable, force refetch.
reset_cache_for url, cache_data
end
end
cache_data
rescue => e
if Gem.configuration.really_verbose then
say "Exception during cache_data handling: #{e.class} - #{e}"
say "Cache file was: #{file}"
say "\t#{e.backtrace.join "\n\t"}"
end
{}
end
##
# Refreshes each source in the cache from its repository. If +all+ is
# false, only latest gems are updated.
def refresh(all)
Gem.sources.each do |source_uri|
cache_entry = cache_data[source_uri]
if cache_entry.nil? then
@ -132,14 +225,34 @@ class Gem::SourceInfoCache
cache_data[source_uri] = cache_entry
end
update if cache_entry.refresh source_uri
update if cache_entry.refresh source_uri, all
end
flush
end
# Searches all source indexes for +pattern+.
def search(pattern, platform_only = false)
def reset_cache_for(url, cache_data)
say "Reseting cache for #{url}" if Gem.configuration.really_verbose
sice = Gem::SourceInfoCacheEntry.new Gem::SourceIndex.new, 0
sice.refresh url, false # HACK may be unnecessary, see ::cache and #refresh
cache_data[url] = sice
cache_data
end
def reset_cache_data
@cache_data = nil
end
##
# Searches all source indexes. See Gem::SourceIndex#search for details on
# +pattern+ and +platform_only+. If +all+ is set to true, the full index
# will be loaded before searching.
def search(pattern, platform_only = false, all = false)
read_all_cache_data if all
cache_data.map do |source_uri, sic_entry|
next unless Gem.sources.include? source_uri
sic_entry.source_index.search pattern, platform_only
@ -150,7 +263,9 @@ class Gem::SourceInfoCache
# only gems matching Gem.platforms will be selected. Returns an Array of
# pairs containing the Gem::Specification found and the source_uri it was
# found at.
def search_with_source(pattern, only_platform = false)
def search_with_source(pattern, only_platform = false, all = false)
read_all_cache_data if all
results = []
cache_data.map do |source_uri, sic_entry|
@ -164,69 +279,76 @@ class Gem::SourceInfoCache
results
end
# Mark the cache as updated (i.e. dirty).
def update
@dirty = true
end
# The name of the system cache file.
def system_cache_file
self.class.system_cache_file
end
# The name of the system cache file. (class method)
def self.system_cache_file
@system_cache_file ||= Gem.default_system_source_cache_dir
end
# The name of the user cache file.
def user_cache_file
self.class.user_cache_file
end
# The name of the user cache file. (class method)
def self.user_cache_file
@user_cache_file ||=
ENV['GEMCACHE'] || Gem.default_user_source_cache_dir
end
# Write data to the proper cache.
def write_cache
open cache_file, "wb" do |f|
f.write Marshal.dump(cache_data)
end
end
##
# Set the source info cache data directly. This is mainly used for unit
# testing when we don't want to read a file system to grab the cached source
# index information. The +hash+ should map a source URL into a
# SourceInfoCacheEntry.
def set_cache_data(hash)
@cache_data = hash
update
end
private
##
# The name of the system cache file.
def system_cache_file
self.class.system_cache_file
end
##
# Determine if +path+ is a candidate for a cache file. Returns +path+ if
# it is, nil if not.
def try_file(path)
return path if File.writable? path
return nil if File.exist? path
dir = File.dirname path
# Determine if +fn+ is a candidate for a cache file. Return fn if
# it is. Return nil if it is not.
def try_file(fn)
return fn if File.writable?(fn)
return nil if File.exist?(fn)
dir = File.dirname(fn)
unless File.exist? dir then
begin
FileUtils.mkdir_p(dir)
FileUtils.mkdir_p dir
rescue RuntimeError, SystemCallError
return nil
end
end
if File.writable?(dir)
File.open(fn, "wb") { |f| f << Marshal.dump({}) }
return fn
if File.writable? dir then
open path, "wb" do |io| io.write Marshal.dump({}) end
return path
end
nil
end
##
# Mark the cache as updated (i.e. dirty).
def update
@dirty = true
end
##
# The name of the user cache file.
def user_cache_file
self.class.user_cache_file
end
##
# Write data to the proper cache.
def write_cache
open cache_file, 'wb' do |io|
io.write Marshal.dump(cache_data)
end
open latest_cache_file, 'wb' do |io|
io.write Marshal.dump(latest_cache_data)
end
end
end

Просмотреть файл

@ -3,24 +3,31 @@ require 'rubygems/source_index'
require 'rubygems/remote_fetcher'
##
# Entrys held by a SourceInfoCache.
# Entries held by a SourceInfoCache.
class Gem::SourceInfoCacheEntry
##
# The source index for this cache entry.
attr_reader :source_index
##
# The size of the of the source entry. Used to determine if the
# source index has changed.
attr_reader :size
##
# Create a cache entry.
def initialize(si, size)
@source_index = si || Gem::SourceIndex.new({})
@size = size
@all = false
end
def refresh(source_uri)
def refresh(source_uri, all)
begin
marshal_uri = URI.join source_uri.to_s, "Marshal.#{Gem.marshal_version}"
remote_size = Gem::RemoteFetcher.fetcher.fetch_size marshal_uri
@ -29,9 +36,12 @@ class Gem::SourceInfoCacheEntry
remote_size = Gem::RemoteFetcher.fetcher.fetch_size yaml_uri
end
return false if @size == remote_size # TODO Use index_signature instead of size?
updated = @source_index.update source_uri
# TODO Use index_signature instead of size?
return false if @size == remote_size and @all
updated = @source_index.update source_uri, all
@size = remote_size
@all = all
updated
end

Просмотреть файл

@ -13,7 +13,7 @@ require 'rubygems/platform'
if RUBY_VERSION < '1.9' then
def Time.today
t = Time.now
t - ((t.to_i + t.gmt_offset) % 86400)
t - ((t.to_f + t.gmt_offset) % 86400)
end unless defined? Time.today
end
# :startdoc:

Просмотреть файл

@ -12,7 +12,7 @@ require 'rubygems/user_interaction'
##
# An Uninstaller.
#
class Gem::Uninstaller
include Gem::UserInteraction
@ -21,8 +21,8 @@ class Gem::Uninstaller
# Constructs an Uninstaller instance
#
# gem:: [String] The Gem name to uninstall
#
def initialize(gem, options)
def initialize(gem, options = {})
@gem = gem
@version = options[:version] || Gem::Requirement.default
gem_home = options[:install_dir] || Gem.dir
@ -30,12 +30,13 @@ class Gem::Uninstaller
@force_executables = options[:executables]
@force_all = options[:all]
@force_ignore = options[:ignore]
@bin_dir = options[:bin_dir]
end
##
# Performs the uninstall of the Gem. This removes the spec, the
# Gem directory, and the cached .gem file,
#
def uninstall
list = Gem.source_index.search(/^#{@gem}$/, @version)
@ -66,18 +67,14 @@ class Gem::Uninstaller
end
##
# Remove executables and batch files (windows only) for the gem as
# it is being installed
#
# gemspec::[Specification] the gem whose executables need to be removed.
#
# Removes installed executables and batch files (windows only) for
# +gemspec+.
def remove_executables(gemspec)
return if gemspec.nil?
if gemspec.executables.size > 0 then
bindir = Gem.bindir @gem_home
raise Gem::FilePermissionError, bindir unless File.writable? bindir
bindir = @bin_dir ? @bin_dir : (Gem.bindir @gem_home)
list = Gem.source_index.search(gemspec.name).delete_if { |spec|
spec.version == gemspec.version
@ -93,14 +90,19 @@ class Gem::Uninstaller
return if executables.size == 0
answer = @force_executables || ask_yes_no(
"Remove executables:\n" \
"\t#{gemspec.executables.join(", ")}\n\nin addition to the gem?",
true) # " # appease ruby-mode - don't ask
answer = if @force_executables.nil? then
ask_yes_no("Remove executables:\n" \
"\t#{gemspec.executables.join(", ")}\n\nin addition to the gem?",
true) # " # appease ruby-mode - don't ask
else
@force_executables
end
unless answer then
say "Executables and scripts will remain installed."
else
raise Gem::FilePermissionError, bindir unless File.writable? bindir
gemspec.executables.each do |exe_name|
say "Removing #{exe_name}"
FileUtils.rm_f File.join(bindir, exe_name)
@ -110,23 +112,22 @@ class Gem::Uninstaller
end
end
##
# Removes all gems in +list+.
#
# list:: the list of all gems to remove
#
# Warning: this method modifies the +list+ parameter. Once it has
# uninstalled a gem, it is removed from that list.
#
# NOTE: removes uninstalled gems from +list+.
def remove_all(list)
list.dup.each { |gem| remove(gem, list) }
list.dup.each { |spec| remove spec, list }
end
#
##
# spec:: the spec of the gem to be uninstalled
# list:: the list of all such gems
#
# Warning: this method modifies the +list+ parameter. Once it has
# uninstalled a gem, it is removed from that list.
#
def remove(spec, list)
unless dependencies_ok? spec then
raise Gem::DependencyRemovalException,
@ -134,10 +135,11 @@ class Gem::Uninstaller
end
unless path_ok? spec then
alert("In order to remove #{spec.name}, please execute:\n" \
"\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
raise Gem::GemNotInHomeException,
e = Gem::GemNotInHomeException.new \
"Gem is not installed in directory #{@gem_home}"
e.spec = spec
raise e
end
raise Gem::FilePermissionError, spec.installation_path unless
@ -182,8 +184,8 @@ class Gem::Uninstaller
def dependencies_ok?(spec)
return true if @force_ignore
srcindex = Gem::SourceIndex.from_installed_gems
deplist = Gem::DependencyList.from_source_index srcindex
source_index = Gem::SourceIndex.from_installed_gems
deplist = Gem::DependencyList.from_source_index source_index
deplist.ok_to_remove?(spec.full_name) || ask_if_ok(spec)
end

Просмотреть файл

@ -68,7 +68,7 @@ module Gem
include DefaultUserInteraction
[
:choose_from_list, :ask, :ask_yes_no, :say, :alert, :alert_warning,
:alert_error, :terminate_interaction!, :terminate_interaction
:alert_error, :terminate_interaction
].each do |methname|
class_eval %{
def #{methname}(*args)
@ -182,16 +182,10 @@ module Gem
ask(question) if question
end
# Terminate the application immediately without running any exit
# handlers.
def terminate_interaction!(status=-1)
exit!(status)
end
# Terminate the appliation normally, running any exit handlers
# that might have been defined.
def terminate_interaction(status=0)
exit(status)
def terminate_interaction(status = 0)
raise Gem::SystemExitException, status
end
# Return a progress reporter object

Просмотреть файл

@ -0,0 +1,86 @@
require 'test/unit'
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/installer'
class Gem::Installer
attr_accessor :gem_dir
attr_writer :format
attr_writer :gem_home
attr_writer :env_shebang
attr_writer :ignore_dependencies
attr_writer :format_executable
attr_writer :security_policy
attr_writer :spec
attr_writer :wrappers
end
class GemInstallerTestCase < RubyGemTestCase
def setup
super
@spec = quick_gem "a"
@gem = File.join @tempdir, "#{@spec.full_name}.gem"
util_build_gem @spec
FileUtils.mv File.join(@gemhome, 'cache', "#{@spec.full_name}.gem"),
@tempdir
@installer = Gem::Installer.new @gem
@installer.gem_dir = util_gem_dir
@installer.gem_home = @gemhome
@installer.spec = @spec
end
def util_gem_bindir(version = '2')
File.join util_gem_dir(version), "bin"
end
def util_gem_dir(version = '2')
File.join @gemhome, "gems", "a-#{version}" # HACK
end
def util_inst_bindir
File.join @gemhome, "bin"
end
def util_make_exec(version = '2', shebang = "#!/usr/bin/ruby")
@spec.executables = ["my_exec"]
FileUtils.mkdir_p util_gem_bindir(version)
exec_file = @installer.formatted_program_filename "my_exec"
exec_path = File.join util_gem_bindir(version), exec_file
File.open exec_path, 'w' do |f|
f.puts shebang
end
end
def util_setup_gem(ui = @ui) # HACK fix use_ui to make this automatic
@spec.files = File.join('lib', 'code.rb')
@spec.executables << 'executable'
@spec.extensions << File.join('ext', 'a', 'mkrf_conf.rb')
Dir.chdir @tempdir do
FileUtils.mkdir_p 'bin'
FileUtils.mkdir_p 'lib'
FileUtils.mkdir_p File.join('ext', 'a')
File.open File.join('bin', 'executable'), 'w' do |f| f.puts '1' end
File.open File.join('lib', 'code.rb'), 'w' do |f| f.puts '1' end
File.open File.join('ext', 'a', 'mkrf_conf.rb'), 'w' do |f|
f << <<-EOF
File.open 'Rakefile', 'w' do |rf| rf.puts "task :default" end
EOF
end
use_ui ui do
FileUtils.rm @gem
Gem::Builder.new(@spec).build
end
end
@installer = Gem::Installer.new @gem
end
end

Просмотреть файл

@ -0,0 +1,146 @@
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/package'
class File
# straight from setup.rb
def self.dir?(path)
# for corrupted windows stat()
File.directory?((path[-1,1] == '/') ? path : path + '/')
end
def self.read_b(name)
File.open(name, "rb") { |f| f.read }
end
end
class TarTestCase < RubyGemTestCase
def ASCIIZ(str, length)
str + "\0" * (length - str.length)
end
def SP(s)
s + " "
end
def SP_Z(s)
s + " \0"
end
def Z(s)
s + "\0"
end
def assert_headers_equal(expected, actual)
expected = expected.to_s unless String === expected
actual = actual.to_s unless String === actual
fields = %w[
name 100
mode 8
uid 8
gid 8
size 12
mtime 12
checksum 8
typeflag 1
linkname 100
magic 6
version 2
uname 32
gname 32
devmajor 8
devminor 8
prefix 155
]
offset = 0
until fields.empty? do
name = fields.shift
length = fields.shift.to_i
if name == "checksum" then
chksum_off = offset
offset += length
next
end
assert_equal expected[offset, length], actual[offset, length],
"Field #{name} of the tar header differs."
offset += length
end
assert_equal expected[chksum_off, 8], actual[chksum_off, 8]
end
def calc_checksum(header)
sum = header.unpack("C*").inject{|s,a| s + a}
SP(Z(to_oct(sum, 6)))
end
def header(type, fname, dname, length, mode, checksum = nil)
checksum ||= " " * 8
arr = [ # struct tarfile_entry_posix
ASCIIZ(fname, 100), # char name[100]; ASCII + (Z unless filled)
Z(to_oct(mode, 7)), # char mode[8]; 0 padded, octal null
Z(to_oct(0, 7)), # char uid[8]; ditto
Z(to_oct(0, 7)), # char gid[8]; ditto
Z(to_oct(length, 11)), # char size[12]; 0 padded, octal, null
Z(to_oct(0, 11)), # char mtime[12]; 0 padded, octal, null
checksum, # char checksum[8]; 0 padded, octal, null, space
type, # char typeflag[1]; file: "0" dir: "5"
"\0" * 100, # char linkname[100]; ASCII + (Z unless filled)
"ustar\0", # char magic[6]; "ustar\0"
"00", # char version[2]; "00"
ASCIIZ("wheel", 32), # char uname[32]; ASCIIZ
ASCIIZ("wheel", 32), # char gname[32]; ASCIIZ
Z(to_oct(0, 7)), # char devmajor[8]; 0 padded, octal, null
Z(to_oct(0, 7)), # char devminor[8]; 0 padded, octal, null
ASCIIZ(dname, 155) # char prefix[155]; ASCII + (Z unless filled)
]
format = "C100C8C8C8C12C12C8CC100C6C2C32C32C8C8C155"
h = if RUBY_VERSION >= "1.9" then
arr.join
else
arr = arr.join("").split(//).map{|x| x[0]}
arr.pack format
end
ret = h + "\0" * (512 - h.size)
assert_equal(512, ret.size)
ret
end
def tar_dir_header(name, prefix, mode)
h = header("5", name, prefix, 0, mode)
checksum = calc_checksum(h)
header("5", name, prefix, 0, mode, checksum)
end
def tar_file_header(fname, dname, mode, length)
h = header("0", fname, dname, length, mode)
checksum = calc_checksum(h)
header("0", fname, dname, length, mode, checksum)
end
def to_oct(n, pad_size)
"%0#{pad_size}o" % n
end
def util_entry(tar)
io = TempIO.new tar
header = Gem::Package::TarHeader.from io
entry = Gem::Package::TarReader::Entry.new header, io
end
def util_dir_entry
util_entry tar_dir_header("foo", "bar", 0)
end
end

Просмотреть файл

@ -10,9 +10,10 @@ at_exit { $SAFE = 1 }
require 'fileutils'
require 'test/unit'
require 'tmpdir'
require 'tempfile'
require 'uri'
require 'rubygems/gem_open_uri'
require 'rubygems/source_info_cache'
require 'rubygems/package'
require File.join(File.expand_path(File.dirname(__FILE__)), 'mockgemui')
@ -56,6 +57,20 @@ class FakeFetcher
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)
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
@ -76,6 +91,7 @@ class RubyGemTestCase < Test::Unit::TestCase
@gemhome = File.join @tempdir, "gemhome"
@gemcache = File.join(@gemhome, "source_cache")
@usrcache = File.join(@gemhome, ".gem", "user_cache")
@latest_usrcache = File.join(@gemhome, ".gem", "latest_user_cache")
FileUtils.mkdir_p @gemhome
@ -101,6 +117,11 @@ class RubyGemTestCase < Test::Unit::TestCase
end
@marshal_version = "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
@private_key = File.expand_path File.join(File.dirname(__FILE__),
'private_key.pem')
@public_cert = File.expand_path File.join(File.dirname(__FILE__),
'public_cert.pem')
end
def teardown
@ -135,25 +156,52 @@ class RubyGemTestCase < Test::Unit::TestCase
end
def prep_cache_files(lc)
[ [lc.system_cache_file, 'sys'],
[lc.user_cache_file, 'usr'],
].each do |fn, data|
FileUtils.mkdir_p File.dirname(fn).untaint
open(fn.dup.untaint, "wb") { |f| f.write(Marshal.dump({'key' => data})) }
@usr_si ||= Gem::SourceIndex.new
@usr_sice ||= Gem::SourceInfoCacheEntry.new @usr_si, 0
@sys_si ||= Gem::SourceIndex.new
@sys_sice ||= Gem::SourceInfoCacheEntry.new @sys_si, 0
latest_si = Gem::SourceIndex.new
latest_si.add_specs(*@sys_si.latest_specs)
latest_sys_sice = Gem::SourceInfoCacheEntry.new latest_si, 0
latest_si = Gem::SourceIndex.new
latest_si.add_specs(*@usr_si.latest_specs)
latest_usr_sice = Gem::SourceInfoCacheEntry.new latest_si, 0
[ [lc.system_cache_file, @sys_sice],
[lc.latest_system_cache_file, latest_sys_sice],
[lc.user_cache_file, @usr_sice],
[lc.latest_user_cache_file, latest_usr_sice],
].each do |filename, data|
FileUtils.mkdir_p File.dirname(filename).untaint
open filename.dup.untaint, 'wb' do |f|
f.write Marshal.dump({ @gem_repo => data })
end
end
end
def read_cache(fn)
open(fn.dup.untaint) { |f| Marshal.load f.read }
def read_cache(path)
open path.dup.untaint, 'rb' do |io|
Marshal.load io.read
end
end
def read_binary(path)
Gem.read_binary path
end
def write_file(path)
path = File.join(@gemhome, path)
dir = File.dirname path
FileUtils.mkdir_p dir
File.open(path, "w") { |io|
yield(io)
}
open path, 'wb' do |io|
yield io
end
path
end
@ -204,6 +252,23 @@ class RubyGemTestCase < Test::Unit::TestCase
end
end
def util_gem(name, version, &block)
spec = quick_gem(name, version, &block)
util_build_gem spec
cache_file = File.join @tempdir, 'gems', "#{spec.original_name}.gem"
FileUtils.mv File.join(@gemhome, 'cache', "#{spec.original_name}.gem"),
cache_file
FileUtils.rm File.join(@gemhome, 'specifications',
"#{spec.full_name}.gemspec")
spec.loaded_from = nil
spec.loaded = false
[spec, cache_file]
end
def util_make_gems
init = proc do |s|
s.files = %w[lib/code.rb]
@ -212,6 +277,7 @@ class RubyGemTestCase < Test::Unit::TestCase
@a1 = quick_gem('a', '1', &init)
@a2 = quick_gem('a', '2', &init)
@a_evil9 = quick_gem('a_evil', '9', &init)
@b2 = quick_gem('b', '2', &init)
@c1_2 = quick_gem('c', '1.2', &init)
@pl1 = quick_gem 'pl', '1' do |s| # l for legacy
@ -227,7 +293,7 @@ class RubyGemTestCase < Test::Unit::TestCase
write_file File.join(*%W[gems #{@c1_2.original_name} lib code.rb]) do end
write_file File.join(*%W[gems #{@pl1.original_name} lib code.rb]) do end
[@a1, @a2, @b2, @c1_2, @pl1].each { |spec| util_build_gem spec }
[@a1, @a2, @a_evil9, @b2, @c1_2, @pl1].each { |spec| util_build_gem spec }
FileUtils.rm_r File.join(@gemhome, 'gems', @pl1.original_name)
@ -256,32 +322,19 @@ class RubyGemTestCase < Test::Unit::TestCase
@fetcher = FakeFetcher.new
@fetcher.uri = @uri
@gem1 = quick_gem 'gem_one' do |gem|
gem.files = %w[Rakefile lib/gem_one.rb]
end
util_make_gems
@gem2 = quick_gem 'gem_two' do |gem|
gem.files = %w[Rakefile lib/gem_two.rb]
end
@gem3 = quick_gem 'gem_three' do |gem| # missing gem
gem.files = %w[Rakefile lib/gem_three.rb]
end
# this gem has a higher version and longer name than the gem we want
@gem4 = quick_gem 'gem_one_evil', '666' do |gem|
gem.files = %w[Rakefile lib/gem_one.rb]
end
@all_gems = [@gem1, @gem2, @gem3, @gem4].sort
@all_gems = [@a1, @a2, @a_evil9, @b2, @c1_2].sort
@all_gem_names = @all_gems.map { |gem| gem.full_name }
gem_names = [@gem1.full_name, @gem2.full_name, @gem4.full_name]
gem_names = [@a1.full_name, @a2.full_name, @b2.full_name]
@gem_names = gem_names.sort.join("\n")
@source_index = Gem::SourceIndex.new @gem1.full_name => @gem1,
@gem2.full_name => @gem2,
@gem4.full_name => @gem4
@source_index = Gem::SourceIndex.new
@source_index.add_spec @a1
@source_index.add_spec @a2
@source_index.add_spec @a_evil9
@source_index.add_spec @c1_2
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
end
@ -294,7 +347,12 @@ class RubyGemTestCase < Test::Unit::TestCase
sice = Gem::SourceInfoCacheEntry.new si, 0
sic = Gem::SourceInfoCache.new
sic.set_cache_data( { @gem_repo => sice } )
sic.update
sic.write_cache
sic.reset_cache_data
Gem::SourceInfoCache.instance_variable_set :@cache, sic
si
end
@ -313,3 +371,30 @@ 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

Просмотреть файл

@ -15,9 +15,8 @@ class MockGemUi < Gem::StreamUI
def initialize(input="")
super(StringIO.new(input), StringIO.new, StringIO.new)
@terminated = false
@banged = false
end
def input
@ins.string
end
@ -30,22 +29,15 @@ class MockGemUi < Gem::StreamUI
@errs.string
end
def banged?
@banged
end
def terminated?
@terminated
end
def terminate_interaction!(status=1)
@terminated = true
@banged = true
fail TermError
end
def terminate_interaction(status=0)
@terminated = true
fail TermError
raise TermError
end
end

Просмотреть файл

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAm24C6xixiAxO+i1f3L8XRMwrmLkt6BvT60mZ7g8HsklH3af7
KNHA6vo/G6sujs2UsNO4HY8BTEneiVOXXWQlcsJ+Z5wEPlIu4zFueAmLefx+n9lE
ulNIUDoyUenKX4spoMRnX8k4lXL05ho/6JFq0JdDY2DmAaQ4vvTz5mh9kZiybtHQ
fzcpbA51uY+sjdQRCPDHyUUfh0SmWJlLYMwcBdVeCiGUPBLi+iP5x1btO4uiJK6Q
IMaV1H3SUCYtKGQKl7qwFd8k8ZBcHYOtmK61tupg3vqWQc0em6SxPj5lws8+1MVK
twBNIDx24jF4ntxBRNKMZ7FN5SHbobAgDYkPAQIDAQABAoIBAGQilgK8X/PUajVH
clEXU3hhSV0VQHwfIYKeYms6h6zXBVPKW0dLC0zXeDztJgueasMZQ67XaPCrTpGO
px/l2zJ6F1HM8/bqn4aDXDY9f/xRLYryQRMBgL8fHzgitNylHWaT4j2Vt7yg2SI9
mxrMRNKqASJPVR+Nm3l6+n9gpjVb99wEucWplPPHI6KhXLYPZOqSwt+zaH5roz3k
UQmMs0Bs4hF1SzVl0n+KNoXHOwswVrmBWXgWvm2OhnwY2e26jfejc8toJc/ShAJ7
C9exnrdimcgEKbd22Sum4G00CDYhcrG5LHHqkgwifcAEVctrvBZBZHGgpxlO8a8U
eF2Vr7kCgYEAykdrBlzp7Fn9xzUInBQ3NXTTYAq51lpuJdmHQmPuTSY0buoHkd9f
xbUCZ2qR9QAesrx4hI0qGLetc8IOKDoWx2rPepCCvO3Kx61o1SB5fAvBue03qVoq
HqACX3Uk24Em8zAz9xuP13ETH/wU7sUbUxRHMCre6ZDmlxn4g5l+Nl8CgYEAxLVl
22yBx0dfRr3UsHY9rxll2gIlnfnYfiJzq8wetzt/TfztRV5ILz7FyWqL5d7IoqkA
fT2V4HAasRJASnKohwJe7z5M/H2ExwkGNFvY+jefb2CoUl5WouK9AlhbqBk3zmHi
sY5GqQkAp/kHMntEin+sErJw6mkgAGdser3a9p8CgYEAqi31w++tunRnxw4+RRnY
7Pdx0k6T1NxV6TAe1ONAHNY0rM/mOHqml65W7GzDiU1lhlh8SIB/VzZJDqfHw15D
xdh94A7uf0bMILwrA4wDyTIW9Xa3Kpq57vQNqwPiU25QN69pOM+Ob+IpBfLOJafc
+kOINOUMj5Kh/aQS6Zzci58CgYEAk24dlFKEBjbRCvU2FrfYTYcsljPru7ZJc2gg
588J6m0WYf5CWy5pzbcviGFpzvSlzXv7GOLylQ+QgcxbETFUbDPzsT4xd0AgJwj1
dIKuYgMUZOa94VZBer2TydEtiRS1heJJhKhM/1329u4nXceTvHYqIq1JAfeee48I
eAoZtaMCgYBz1FjWFQnMTD5nmyPEEZneoBPAR5+9jwOps+IYOoHtazoMFszzd0qo
JZW3Ihn9KRrVSxfFApKS/ZwjiZ+tJUk7DE/v/0l0sszefY7s8b0pL1lpeZSoL71e
QoG1WLXUiDV3BRlmyOAF1h3p12KRTLgwubN51ajECwcs3QwE+ZT8Gg==
-----END RSA PRIVATE KEY-----

Просмотреть файл

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMRAwDgYDVQQDDAdkcmJy
YWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZFgNu
ZXQwHhcNMDcxMjIxMDIwNDE0WhcNMDgxMjIwMDIwNDE0WjBBMRAwDgYDVQQDDAdk
cmJyYWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZ
FgNuZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbbgLrGLGIDE76
LV/cvxdEzCuYuS3oG9PrSZnuDweySUfdp/so0cDq+j8bqy6OzZSw07gdjwFMSd6J
U5ddZCVywn5nnAQ+Ui7jMW54CYt5/H6f2US6U0hQOjJR6cpfiymgxGdfyTiVcvTm
Gj/okWrQl0NjYOYBpDi+9PPmaH2RmLJu0dB/NylsDnW5j6yN1BEI8MfJRR+HRKZY
mUtgzBwF1V4KIZQ8EuL6I/nHVu07i6IkrpAgxpXUfdJQJi0oZAqXurAV3yTxkFwd
g62YrrW26mDe+pZBzR6bpLE+PmXCzz7UxUq3AE0gPHbiMXie3EFE0oxnsU3lIduh
sCANiQ8BAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
BBS5k4Z75VSpdM0AclG2UvzFA/VW5DANBgkqhkiG9w0BAQUFAAOCAQEAHagT4lfX
kP/hDaiwGct7XPuVGbrOsKRVD59FF5kETBxEc9UQ1clKWngf8JoVuEoKD774dW19
bU0GOVWO+J6FMmT/Cp7nuFJ79egMf/gy4gfUfQMuvfcr6DvZUPIs9P/TlK59iMYF
DIOQ3DxdF3rMzztNUCizN4taVscEsjCcgW6WkUJnGdqlu3OHWpQxZBJkBTjPCoc6
UW6on70SFPmAy/5Cq0OJNGEWBfgD9q7rrs/X8GGwUWqXb85RXnUVi/P8Up75E0ag
14jEc90kN+C7oI/AGCBN0j6JnEtYIEJZibjjDJTSMWlUKKkj30kq7hlUC2CepJ4v
x52qPcexcYZR7w==
-----END CERTIFICATE-----

Просмотреть файл

@ -19,6 +19,7 @@ class TestGem < RubyGemTestCase
expected = [
File.join(@gemhome, *%W[gems #{@a1.full_name} lib]),
File.join(@gemhome, *%W[gems #{@a2.full_name} lib]),
File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]),
File.join(@gemhome, *%W[gems #{@b2.full_name} lib]),
File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
File.join(@gemhome, *%W[gems #{@pl1.full_name} lib]),
@ -213,6 +214,7 @@ class TestGem < RubyGemTestCase
expected = [
File.join(@gemhome, *%W[gems #{@a2.full_name} lib]),
File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]),
File.join(@gemhome, *%W[gems #{@b2.full_name} lib]),
File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
File.join(@gemhome, *%W[gems #{@pl1.full_name} lib]),
@ -226,7 +228,7 @@ class TestGem < RubyGemTestCase
install_gem foo
Gem.source_index = nil
Gem.activate 'foo', false
Gem.activate 'foo'
assert_equal true, Gem.loaded_specs.keys.include?('foo')
end
@ -235,9 +237,29 @@ class TestGem < RubyGemTestCase
assert_equal [Gem.dir], Gem.path
end
def test_self_path_APPLE_GEM_HOME
Gem.clear_paths
Gem.const_set :APPLE_GEM_HOME, '/tmp/apple_gem_home'
assert Gem.path.include?('/tmp/apple_gem_home')
ensure
Gem.send :remove_const, :APPLE_GEM_HOME
end
def test_self_path_APPLE_GEM_HOME_GEM_PATH
Gem.clear_paths
ENV['GEM_PATH'] = @gemhome
Gem.const_set :APPLE_GEM_HOME, '/tmp/apple_gem_home'
assert !Gem.path.include?('/tmp/apple_gem_home')
ensure
Gem.send :remove_const, :APPLE_GEM_HOME
end
def test_self_path_ENV_PATH
Gem.clear_paths
path_count = Gem.path.size
path_count -= 1 if defined? APPLE_GEM_HOME
Gem.clear_paths
util_ensure_gem_dirs
@ -257,8 +279,8 @@ class TestGem < RubyGemTestCase
ENV['GEM_PATH'] = dirs.join File::PATH_SEPARATOR
assert_equal @gemhome, Gem.dir
paths = [Gem.dir]
paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
assert_equal @additional + paths, Gem.path
end
@ -270,8 +292,8 @@ class TestGem < RubyGemTestCase
ENV['GEM_PATH'] = @additional.join(File::PATH_SEPARATOR)
assert_equal @gemhome, Gem.dir
paths = [Gem.dir]
paths.insert(0, APPLE_GEM_HOME) if defined? APPLE_GEM_HOME
assert_equal @additional + paths, Gem.path
end
@ -284,6 +306,18 @@ class TestGem < RubyGemTestCase
assert_equal File.dirname(File.dirname(file_name)), Gem.prefix
end
def test_self_prefix_odd
orig_sitelibdir = Gem::ConfigMap[:sitelibdir]
file_name = File.expand_path __FILE__
prefix = File.join File.dirname(File.dirname(file_name)), 'lib'
Gem::ConfigMap[:sitelibdir] = prefix.sub(/[\w]\//, '\&/')
assert_nil Gem.prefix
ensure
Gem::ConfigMap[:sitelibdir] = orig_sitelibdir
end
def test_self_required_location
util_make_gems
@ -295,6 +329,13 @@ class TestGem < RubyGemTestCase
Gem.required_location("a", "code.rb", "= 2")
end
def test_self_ruby_version
version = RUBY_VERSION.dup
version << ".#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
assert_equal Gem::Version.new(version), Gem.ruby_version
end
def test_self_searcher
assert_kind_of Gem::GemPathSearcher, Gem.searcher
end

Просмотреть файл

@ -67,11 +67,12 @@ class TestGemCommandManager < RubyGemTestCase
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[:bin_dir]
#check settings
check_options = nil
@command_manager.process_args(
"install --force --test --local --rdoc --install-dir . --version 3.0 --no-wrapper")
"install --force --test --local --rdoc --install-dir . --version 3.0 --no-wrapper --bindir . ")
assert_equal true, check_options[:test]
assert_equal true, check_options[:generate_rdoc]
assert_equal true, check_options[:force]
@ -79,6 +80,7 @@ class TestGemCommandManager < RubyGemTestCase
assert_equal false, check_options[:wrappers]
assert_equal Gem::Requirement.new('3.0'), check_options[:version]
assert_equal Dir.pwd, check_options[:install_dir]
assert_equal Dir.pwd, check_options[:bin_dir]
#check remote domain
check_options = nil
@ -164,7 +166,7 @@ class TestGemCommandManager < RubyGemTestCase
#check defaults
@command_manager.process_args("query")
assert_equal(/.*/, check_options[:name])
assert_equal(//, check_options[:name])
assert_equal :local, check_options[:domain]
assert_equal false, check_options[:details]

Просмотреть файл

@ -62,6 +62,21 @@ class TestGemCommandsEnvironmentCommand < RubyGemTestCase
assert_equal '', @ui.error
end
def test_execute_gempath_multiple
Gem.clear_paths
path = [@gemhome, "#{@gemhome}2"].join File::PATH_SEPARATOR
ENV['GEM_PATH'] = path
@cmd.send :handle_options, %w[gempath]
use_ui @ui do
@cmd.execute
end
assert_equal "#{Gem.path.join File::PATH_SEPARATOR}\n", @ui.output
assert_equal '', @ui.error
end
def test_execute_packageversion
@cmd.send :handle_options, %w[packageversion]

Просмотреть файл

@ -15,13 +15,12 @@ class TestGemCommandsFetchCommand < RubyGemTestCase
def test_execute
util_setup_fake_fetcher
util_build_gem @gem1
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
@source_index.dump
@fetcher.data["#{@gem_repo}/gems/#{@gem1.full_name}.gem"] =
File.read(File.join(@gemhome, 'cache', "#{@gem1.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] = [@gem1.name]
@cmd.options[:args] = [@a2.name]
use_ui @ui do
Dir.chdir @tempdir do
@ -29,7 +28,7 @@ class TestGemCommandsFetchCommand < RubyGemTestCase
end
end
assert File.exist?(File.join(@tempdir, "#{@gem1.full_name}.gem"))
assert File.exist?(File.join(@tempdir, "#{@a2.full_name}.gem"))
end
end

Просмотреть файл

@ -34,25 +34,26 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
util_setup_fake_fetcher
@cmd.options[:domain] = :local
gem1 = quick_gem 'gem_one'
util_build_gem gem1
FileUtils.mv File.join(@gemhome, 'cache', "#{@gem1.full_name}.gem"),
FileUtils.mv File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"),
File.join(@tempdir)
@cmd.options[:args] = [gem1.name]
@cmd.options[:args] = [@a2.name]
use_ui @ui do
orig_dir = Dir.pwd
begin
Dir.chdir @tempdir
@cmd.execute
e = assert_raises Gem::SystemExitException do
@cmd.execute
end
assert_equal 0, e.exit_code
ensure
Dir.chdir orig_dir
end
end
out = @ui.output.split "\n"
assert_equal "Successfully installed #{@gem1.full_name}", out.shift
assert_equal "Successfully installed #{@a2.full_name}", out.shift
assert_equal "1 gem installed", out.shift
assert out.empty?, out.inspect
end
@ -61,14 +62,17 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
util_setup_fake_fetcher
@cmd.options[:domain] = :local
@cmd.options[:args] = %w[gem_one]
@cmd.options[:args] = %w[no_such_gem]
use_ui @ui do
@cmd.execute
e = assert_raises Gem::SystemExitException do
@cmd.execute
end
assert_equal 2, e.exit_code
end
# HACK no repository was checked
assert_equal "ERROR: could not find gem_one locally or in a repository\n",
assert_equal "ERROR: could not find no_such_gem locally or in a repository\n",
@ui.error
end
@ -88,7 +92,10 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
@cmd.options[:args] = %w[nonexistent]
use_ui @ui do
@cmd.execute
e = assert_raises Gem::SystemExitException do
@cmd.execute
end
assert_equal 2, e.exit_code
end
assert_equal "ERROR: could not find nonexistent locally or in a repository\n",
@ -100,25 +107,27 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
@cmd.options[:generate_ri] = true
util_setup_fake_fetcher
util_build_gem @gem1
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
@source_index.dump
@fetcher.data["#{@gem_repo}/gems/gem_one-0.0.2.gem"] =
File.read(File.join(@gemhome, 'cache', "#{@gem1.full_name}.gem"))
@fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] =
read_binary(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
@cmd.options[:args] = [@gem1.name]
@cmd.options[:args] = [@a2.name]
use_ui @ui do
@cmd.execute
e = assert_raises Gem::SystemExitException do
@cmd.execute
end
assert_equal 0, e.exit_code
end
out = @ui.output.split "\n"
assert_match %r|Bulk updating|, out.shift
assert_equal "Successfully installed #{@gem1.full_name}", out.shift
assert_equal "Successfully installed #{@a2.full_name}", out.shift
assert_equal "1 gem installed", out.shift
assert_equal "Installing ri documentation for #{@gem1.full_name}...",
assert_equal "Installing ri documentation for #{@a2.full_name}...",
out.shift
assert_equal "Installing RDoc documentation for #{@gem1.full_name}...",
assert_equal "Installing RDoc documentation for #{@a2.full_name}...",
out.shift
assert out.empty?, out.inspect
end
@ -127,31 +136,30 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
util_setup_fake_fetcher
@cmd.options[:domain] = :local
gem1 = quick_gem 'gem_one'
util_build_gem gem1
FileUtils.mv File.join(@gemhome, 'cache', "#{@gem1.full_name}.gem"),
FileUtils.mv File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"),
File.join(@tempdir)
gem2 = quick_gem 'gem_two'
util_build_gem gem2
FileUtils.mv File.join(@gemhome, 'cache', "#{@gem2.full_name}.gem"),
FileUtils.mv File.join(@gemhome, 'cache', "#{@b2.full_name}.gem"),
File.join(@tempdir)
@cmd.options[:args] = [gem1.name, gem2.name]
@cmd.options[:args] = [@a2.name, @b2.name]
use_ui @ui do
orig_dir = Dir.pwd
begin
Dir.chdir @tempdir
@cmd.execute
e = assert_raises Gem::SystemExitException do
@cmd.execute
end
assert_equal 0, e.exit_code
ensure
Dir.chdir orig_dir
end
end
out = @ui.output.split "\n"
assert_equal "Successfully installed #{@gem1.full_name}", out.shift
assert_equal "Successfully installed #{@gem2.full_name}", out.shift
assert_equal "Successfully installed #{@a2.full_name}", out.shift
assert_equal "Successfully installed #{@b2.full_name}", out.shift
assert_equal "2 gems installed", out.shift
assert out.empty?, out.inspect
end

Просмотреть файл

@ -7,20 +7,31 @@ class TestGemCommandsQueryCommand < RubyGemTestCase
def setup
super
@foo_gem = quick_gem 'foo' do |spec|
spec.summary = 'This is a lot of text. ' * 5
end
@foo_gem_p = quick_gem 'foo' do |spec|
spec.summary = 'This is a lot of text. ' * 5
spec.platform = Gem::Platform::CURRENT
end
@bar_gem = quick_gem 'bar'
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
raise Gem::RemoteFetcher::FetchError
end
end
def test_execute
util_setup_source_info_cache @foo_gem, @foo_gem_p
cache = Gem::SourceInfoCache.cache
cache.update
cache.write_cache
cache.reset_cache_data
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]
@ -32,7 +43,43 @@ class TestGemCommandsQueryCommand < RubyGemTestCase
*** REMOTE GEMS ***
foo (2)
a (2)
EOF
assert_equal expected, @ui.output
assert_equal '', @ui.error
end
def test_execute_all
cache = Gem::SourceInfoCache.cache
cache.update
cache.write_cache
cache.reset_cache_data
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]
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
*** REMOTE GEMS ***
Updating metadata for 1 gems from http://gems.example.com/
.
complete
a (2, 1)
EOF
assert_equal expected, @ui.output
@ -40,8 +87,6 @@ foo (2)
end
def test_execute_details
util_setup_source_info_cache @foo_gem
@cmd.handle_options %w[-r -d]
use_ui @ui do
@ -52,18 +97,94 @@ foo (2)
*** REMOTE GEMS ***
foo (2)
This is a lot of text. This is a lot of text. This is a lot of
text. This is a lot of text. This is a lot of text.
a (2, 1)
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)
this is a summary
EOF
assert_equal expected, @ui.output
assert_equal '', @ui.error
end
def test_execute_no_versions
util_setup_source_info_cache @foo_gem, @bar_gem
def test_execute_installed
@cmd.handle_options %w[-n c --installed]
e = assert_raise Gem::SystemExitException do
use_ui @ui do
@cmd.execute
end
end
assert_equal 0, e.exit_code
assert_equal "true\n", @ui.output
assert_equal '', @ui.error
end
def test_execute_installed_no_name
@cmd.handle_options %w[--installed]
e = assert_raise Gem::SystemExitException do
use_ui @ui do
@cmd.execute
end
end
assert_equal '', @ui.output
assert_equal "ERROR: You must specify a gem name\n", @ui.error
assert_equal 4, e.exit_code
end
def test_execute_installed_not_installed
@cmd.handle_options %w[-n not_installed --installed]
e = assert_raise Gem::SystemExitException do
use_ui @ui do
@cmd.execute
end
end
assert_equal "false\n", @ui.output
assert_equal '', @ui.error
assert_equal 1, e.exit_code
end
def test_execute_installed_version
@cmd.handle_options %w[-n c --installed --version 1.2]
e = assert_raise Gem::SystemExitException do
use_ui @ui do
@cmd.execute
end
end
assert_equal "true\n", @ui.output
assert_equal '', @ui.error
assert_equal 0, e.exit_code
end
def test_execute_installed_version_not_installed
@cmd.handle_options %w[-n c --installed --version 2]
e = assert_raise Gem::SystemExitException do
use_ui @ui do
@cmd.execute
end
end
assert_equal "false\n", @ui.output
assert_equal '', @ui.error
assert_equal 1, e.exit_code
end
def test_execute_no_versions
@cmd.handle_options %w[-r --no-versions]
use_ui @ui do
@ -74,8 +195,8 @@ foo (2)
*** REMOTE GEMS ***
bar
foo
a
pl
EOF
assert_equal expected, @ui.output

Просмотреть файл

@ -20,7 +20,7 @@ class TestGemCommandsServerCommand < RubyGemTestCase
@cmd.send :handle_options, %w[-p 9999 -d /nonexistent --daemon]
assert_equal true, @cmd.options[:daemon]
assert_equal '/nonexistent', @cmd.options[:gemdir]
assert_equal File.expand_path('/nonexistent'), @cmd.options[:gemdir]
assert_equal 9999, @cmd.options[:port]
end
end

Просмотреть файл

@ -31,10 +31,11 @@ class TestGemCommandsSourcesCommand < RubyGemTestCase
def test_execute_add
util_setup_fake_fetcher
@si = Gem::SourceIndex.new @gem1.full_name => @gem1.name
si = Gem::SourceIndex.new
si.add_spec @a1
@fetcher.data["http://beta-gems.example.com/Marshal.#{@marshal_version}"] =
@si.dump
si.dump
@cmd.handle_options %w[--add http://beta-gems.example.com]
@ -45,7 +46,7 @@ class TestGemCommandsSourcesCommand < RubyGemTestCase
end
expected = <<-EOF
Bulk updating Gem source index for: http://beta-gems.example.com
Bulk updating Gem source index for: http://beta-gems.example.com/
http://beta-gems.example.com added to sources
EOF
@ -60,14 +61,11 @@ http://beta-gems.example.com added to sources
def test_execute_add_nonexistent_source
util_setup_fake_fetcher
@si = Gem::SourceIndex.new @gem1.full_name => @gem1.name
@fetcher.data["http://beta-gems.example.com/Marshal.#{@marshal_version}"] =
proc do
raise Gem::RemoteFetcher::FetchError, 'it died'
end
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
@cmd.handle_options %w[--add http://beta-gems.example.com]
@ -104,6 +102,41 @@ beta-gems.example.com is not a URI
assert_equal '', @ui.error
end
def test_execute_clear_all
@cmd.handle_options %w[--clear-all]
util_setup_source_info_cache
cache = Gem::SourceInfoCache.cache
cache.update
cache.write_cache
assert File.exist?(cache.system_cache_file),
'system cache file'
assert File.exist?(cache.latest_system_cache_file),
'latest system cache file'
use_ui @ui do
@cmd.execute
end
expected = <<-EOF
*** Removed user source cache ***
*** Removed latest user source cache ***
*** Removed system source cache ***
*** Removed latest system source cache ***
EOF
assert_equal expected, @ui.output
assert_equal '', @ui.error
assert !File.exist?(cache.system_cache_file),
'system cache file'
assert !File.exist?(cache.latest_system_cache_file),
'latest system cache file'
end
def test_execute_remove
@cmd.handle_options %W[--remove #{@gem_repo}]
@ -122,20 +155,43 @@ beta-gems.example.com is not a URI
assert_equal [], Gem::SourceInfoCache.cache_data.keys
end
def test_execute_remove_no_network
@cmd.handle_options %W[--remove #{@gem_repo}]
util_setup_fake_fetcher
@fetcher.data["#{@gem_repo}/Marshal.#{Gem.marshal_version}"] = proc do
raise Gem::RemoteFetcher::FetchError
end
use_ui @ui do
@cmd.execute
end
expected = "#{@gem_repo} removed from sources\n"
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_source_info_cache
util_setup_fake_fetcher
@si = Gem::SourceIndex.new @gem1.full_name => @gem1.name
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = @si.dump
si = Gem::SourceIndex.new
si.add_spec @a1
@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

Просмотреть файл

@ -12,6 +12,7 @@ class TestGemCommandsSpecificationCommand < RubyGemTestCase
def test_execute
foo = quick_gem 'foo'
Gem.source_index.add_spec foo
@cmd.options[:args] = %w[foo]
@ -87,7 +88,6 @@ class TestGemCommandsSpecificationCommand < RubyGemTestCase
assert_match %r|\A--- !ruby/object:Gem::Specification|, @ui.output
assert_match %r|name: foo|, @ui.output
assert_equal "WARNING: Remote information is not complete\n\n", @ui.error
end
end

Просмотреть файл

@ -17,15 +17,57 @@ class TestGemCommandsUnpackCommand < RubyGemTestCase
@cmd.options[:args] = %w[a]
use_ui @ui do
Dir.chdir @tempdir do
@cmd.execute
end
use_ui @ui do
Dir.chdir @tempdir do
@cmd.execute
end
end
assert File.exist?(File.join(@tempdir, 'a-2'))
end
def test_execute_gem_path
util_make_gems
Gem.clear_paths
gemhome2 = File.join @tempdir, 'gemhome2'
Gem.send :set_paths, [gemhome2, @gemhome].join(File::PATH_SEPARATOR)
Gem.send :set_home, gemhome2
@cmd.options[:args] = %w[a]
use_ui @ui do
Dir.chdir @tempdir do
@cmd.execute
end
end
assert File.exist?(File.join(@tempdir, 'a-2'))
end
def test_execute_gem_path_missing
util_make_gems
Gem.clear_paths
gemhome2 = File.join @tempdir, 'gemhome2'
Gem.send :set_paths, [gemhome2, @gemhome].join(File::PATH_SEPARATOR)
Gem.send :set_home, gemhome2
@cmd.options[:args] = %w[z]
use_ui @ui do
Dir.chdir @tempdir do
@cmd.execute
end
end
assert_equal '', @ui.output
end
def test_execute_with_target_option
util_make_gems

Просмотреть файл

@ -0,0 +1,174 @@
require 'test/unit'
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/commands/update_command'
class TestGemCommandsUpdateCommand < RubyGemTestCase
def setup
super
@cmd = Gem::Commands::UpdateCommand.new
util_setup_fake_fetcher
@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
end
def test_execute
util_remove_gems
Gem::Installer.new(@a1_path).install
@cmd.options[:args] = []
use_ui @ui do
@cmd.execute
end
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
assert out.empty?, out.inspect
end
# before:
# a1 -> c1.2
# after:
# a2 -> b2 # new dependency
# a2 -> c2
def test_execute_dependencies
@a1.add_dependency 'c', '1.2'
@c2 = quick_gem 'c', '2' do |s|
s.files = %w[lib/code.rb]
s.require_paths = %w[lib]
end
@a2.add_dependency 'c', '2'
@a2.add_dependency 'b', '2'
@b2_path = File.join @gemhome, 'cache', "#{@b2.full_name}.gem"
@c1_2_path = File.join @gemhome, 'cache', "#{@c1_2.full_name}.gem"
@c2_path = File.join @gemhome, 'cache', "#{@c2.full_name}.gem"
@source_index = Gem::SourceIndex.new
@source_index.add_spec @a1
@source_index.add_spec @a2
@source_index.add_spec @b2
@source_index.add_spec @c1_2
@source_index.add_spec @c2
util_build_gem @a1
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"] =
read_binary @c1_2_path
@fetcher.data["#{@gem_repo}/gems/#{@c2.full_name}.gem"] = read_binary @c2_path
util_remove_gems
Gem::Installer.new(@c1_2_path).install
Gem::Installer.new(@a1_path).install
@cmd.options[:args] = []
use_ui @ui do
@cmd.execute
end
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 #{@c2.full_name}", out.shift
assert_equal "Successfully installed #{@b2.full_name}", out.shift
assert_equal "Successfully installed #{@a2.full_name}", out.shift
assert_equal "Gems updated: #{@c2.name}, #{@b2.name}, #{@a2.name}",
out.shift
assert out.empty?, out.inspect
end
def test_execute_named
util_remove_gems
Gem::Installer.new(@a1_path).install
@cmd.options[:args] = [@a1.name]
use_ui @ui do
@cmd.execute
end
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
assert out.empty?, out.inspect
end
def test_execute_named_up_to_date
util_remove_gems
Gem::Installer.new(@a2_path).install
@cmd.options[:args] = [@a2.name]
use_ui @ui do
@cmd.execute
end
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
Gem::Installer.new(@a2_path).install
@cmd.options[:args] = []
use_ui @ui do
@cmd.execute
end
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

Просмотреть файл

@ -54,8 +54,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'a'
inst.install
inst = Gem::DependencyInstaller.new
inst.install 'a'
end
assert_equal Gem::SourceIndex.new(@a1.full_name => @a1),
@ -70,8 +70,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'b'
inst.install
inst = Gem::DependencyInstaller.new
inst.install 'b'
end
assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
@ -84,8 +84,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'b'
inst.install
inst = Gem::DependencyInstaller.new
inst.install 'b'
end
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
@ -102,8 +102,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'f'
inst.install
inst = Gem::DependencyInstaller.new
inst.install 'f'
end
assert_equal %w[f-2], inst.installed_gems.map { |s| s.full_name }
@ -114,19 +114,49 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'a-1.gem'
inst.install
inst = Gem::DependencyInstaller.new :domain => :local
inst.install 'a-1.gem'
end
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_local_dependency
FileUtils.mv @a1_gem, @tempdir
FileUtils.mv @b1_gem, @tempdir
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new :domain => :local
inst.install 'b-1.gem'
end
assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_local_dependency_installed
FileUtils.mv @a1_gem, @tempdir
FileUtils.mv @b1_gem, @tempdir
inst = nil
Dir.chdir @tempdir do
Gem::Installer.new('a-1.gem').install
inst = Gem::DependencyInstaller.new :domain => :local
inst.install 'b-1.gem'
end
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_local_subdir
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'gems/a-1.gem'
inst.install
inst = Gem::DependencyInstaller.new :domain => :local
inst.install 'gems/a-1.gem'
end
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
@ -137,12 +167,11 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'a', nil, :env_shebang => true,
:wrappers => true
inst.install
inst = Gem::DependencyInstaller.new :env_shebang => true, :wrappers => true
inst.install 'a'
end
assert_match %r|\A#!/usr/bin/env ruby\n|,
assert_match %r|\A#!/usr/bin/env #{Gem::ConfigMap[:RUBY_INSTALL_NAME]}\n|,
File.read(File.join(@gemhome, 'bin', 'a_bin'))
end
@ -153,8 +182,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'b', nil, :force => true
inst.install
inst = Gem::DependencyInstaller.new :force => true
inst.install 'b'
end
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
@ -165,8 +194,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'b', nil, :ignore_dependencies => true
inst.install
inst = Gem::DependencyInstaller.new :ignore_dependencies => true
inst.install 'b'
end
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
@ -179,8 +208,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'a', nil, :install_dir => gemhome2
inst.install
inst = Gem::DependencyInstaller.new :install_dir => gemhome2
inst.install 'a'
end
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
@ -201,8 +230,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'b', nil, :domain => :both
inst.install
inst = Gem::DependencyInstaller.new :domain => :both
inst.install 'b'
end
assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
@ -217,14 +246,34 @@ class TestGemDependencyInstaller < RubyGemTestCase
assert_equal b1_expected, b1.loaded_from
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
end
FileUtils.mv @a1_gem, @tempdir
FileUtils.mv @b1_gem, @tempdir
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new :domain => :both
inst.install 'b'
end
assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_domain_local
FileUtils.mv @b1_gem, @tempdir
inst = nil
Dir.chdir @tempdir do
e = assert_raise Gem::InstallError do
inst = Gem::DependencyInstaller.new 'b', nil, :domain => :local
inst.install
inst = Gem::DependencyInstaller.new :domain => :local
inst.install 'b'
end
assert_equal 'b requires a (>= 0)', e.message
end
@ -240,8 +289,43 @@ class TestGemDependencyInstaller < RubyGemTestCase
@fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
inst = Gem::DependencyInstaller.new 'a', nil, :domain => :remote
inst.install
inst = Gem::DependencyInstaller.new :domain => :remote
inst.install 'a'
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_remote
a1_data = nil
File.open @a1_gem, 'rb' do |fp|
a1_data = fp.read
end
@fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
inst = Gem::DependencyInstaller.new
Dir.chdir @tempdir do
inst.install 'a'
end
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_remote_dep
a1_data = nil
File.open @a1_gem, 'rb' do |fp|
a1_data = fp.read
end
@fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
inst = Gem::DependencyInstaller.new
Dir.chdir @tempdir do
dep = Gem::Dependency.new @a1.name, @a1.version
inst.install dep
end
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
end
@ -266,8 +350,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
@fetcher.data["http://gems.example.com/gems/#{a2_o.full_name}.gem"] =
a2_o_data
inst = Gem::DependencyInstaller.new 'a', nil, :domain => :remote
inst.install
inst = Gem::DependencyInstaller.new :domain => :remote
inst.install 'a'
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
end
@ -278,8 +362,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'a'
inst.install
inst = Gem::DependencyInstaller.new
inst.install 'a'
end
assert_equal Gem::SourceIndex.new(@a1.full_name => @a1),
@ -290,13 +374,17 @@ class TestGemDependencyInstaller < RubyGemTestCase
if defined? OpenSSL then
def test_install_security_policy
FileUtils.mv @a1_gem, @cache_dir
FileUtils.mv @b1_gem, @cache_dir
data = File.open(@a1_gem, 'rb') { |f| f.read }
@fetcher.data['http://gems.example.com/gems/a-1.gem'] = data
data = File.open(@b1_gem, 'rb') { |f| f.read }
@fetcher.data['http://gems.example.com/gems/b-1.gem'] = data
policy = Gem::Security::HighSecurity
inst = Gem::DependencyInstaller.new 'b', nil, :security_policy => policy
inst = Gem::DependencyInstaller.new :security_policy => policy
e = assert_raise Gem::Exception do
inst.install
inst.install 'b'
end
assert_equal 'Unsigned gem', e.message
@ -305,145 +393,48 @@ class TestGemDependencyInstaller < RubyGemTestCase
end
end
def test_install_wrappers
FileUtils.mv @a1_gem, @cache_dir
inst = Gem::DependencyInstaller.new 'a', :wrappers => true
# Wrappers don't work on mswin
unless win_platform? then
def test_install_no_wrappers
@fetcher.data['http://gems.example.com/gems/a-1.gem'] = read_binary(@a1_gem)
inst.install
inst = Gem::DependencyInstaller.new :wrappers => false
inst.install 'a'
assert_match %r|This file was generated by RubyGems.|,
File.read(File.join(@gemhome, 'bin', 'a_bin'))
assert_no_match(%r|This file was generated by RubyGems.|,
File.read(File.join(@gemhome, 'bin', 'a_bin')))
end
end
def test_install_version
FileUtils.mv @d1_gem, @cache_dir
FileUtils.mv @d2_gem, @cache_dir
inst = Gem::DependencyInstaller.new 'd', '= 1'
data = File.open(@d2_gem, 'rb') { |f| f.read }
@fetcher.data['http://gems.example.com/gems/d-2.gem'] = data
inst.install
data = File.open(@d1_gem, 'rb') { |f| f.read }
@fetcher.data['http://gems.example.com/gems/d-1.gem'] = data
inst = Gem::DependencyInstaller.new
inst.install 'd', '= 1'
assert_equal %w[d-1], inst.installed_gems.map { |s| s.full_name }
end
def test_install_version_default
FileUtils.mv @d1_gem, @cache_dir
FileUtils.mv @d2_gem, @cache_dir
inst = Gem::DependencyInstaller.new 'd'
data = File.open(@d2_gem, 'rb') { |f| f.read }
@fetcher.data['http://gems.example.com/gems/d-2.gem'] = data
inst.install
data = File.open(@d1_gem, 'rb') { |f| f.read }
@fetcher.data['http://gems.example.com/gems/d-1.gem'] = data
inst = Gem::DependencyInstaller.new
inst.install 'd'
assert_equal %w[d-2], inst.installed_gems.map { |s| s.full_name }
end
def test_download
a1_data = nil
File.open @a1_gem, 'rb' do |fp|
a1_data = fp.read
end
@fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
inst = Gem::DependencyInstaller.new 'a'
a1_cache_gem = File.join(@gemhome, 'cache', "#{@a1.full_name}.gem")
assert_equal a1_cache_gem, inst.download(@a1, 'http://gems.example.com')
assert File.exist?(a1_cache_gem)
end
def test_download_cached
FileUtils.mv @a1_gem, @cache_dir
inst = Gem::DependencyInstaller.new 'a'
assert_equal File.join(@gemhome, 'cache', "#{@a1.full_name}.gem"),
inst.download(@a1, 'http://gems.example.com')
end
def test_download_local
FileUtils.mv @a1_gem, @tempdir
local_path = File.join @tempdir, "#{@a1.full_name}.gem"
inst = nil
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'a'
end
assert_equal File.join(@gemhome, 'cache', "#{@a1.full_name}.gem"),
inst.download(@a1, local_path)
end
def test_download_install_dir
a1_data = nil
File.open @a1_gem, 'rb' do |fp|
a1_data = fp.read
end
@fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
install_dir = File.join @tempdir, 'more_gems'
inst = Gem::DependencyInstaller.new 'a', nil, :install_dir => install_dir
a1_cache_gem = File.join install_dir, 'cache', "#{@a1.full_name}.gem"
assert_equal a1_cache_gem, inst.download(@a1, 'http://gems.example.com')
assert File.exist?(a1_cache_gem)
end
unless win_platform? then # File.chmod doesn't work
def test_download_local_read_only
FileUtils.mv @a1_gem, @tempdir
local_path = File.join @tempdir, "#{@a1.full_name}.gem"
inst = nil
File.chmod 0555, File.join(@gemhome, 'cache')
Dir.chdir @tempdir do
inst = Gem::DependencyInstaller.new 'a'
end
assert_equal File.join(@tempdir, "#{@a1.full_name}.gem"),
inst.download(@a1, local_path)
ensure
File.chmod 0755, File.join(@gemhome, 'cache')
end
end
def test_download_platform_legacy
original_platform = 'old-platform'
e1, e1_gem = util_gem 'e', '1' do |s|
s.platform = Gem::Platform::CURRENT
s.instance_variable_set :@original_platform, original_platform
end
e1_data = nil
File.open e1_gem, 'rb' do |fp|
e1_data = fp.read
end
@fetcher.data["http://gems.example.com/gems/e-1-#{original_platform}.gem"] = e1_data
inst = Gem::DependencyInstaller.new 'a'
e1_cache_gem = File.join(@gemhome, 'cache', "#{e1.full_name}.gem")
assert_equal e1_cache_gem, inst.download(e1, 'http://gems.example.com')
assert File.exist?(e1_cache_gem)
end
def test_download_unsupported
inst = Gem::DependencyInstaller.new 'a'
e = assert_raise Gem::InstallError do
inst.download @a1, 'ftp://gems.rubyforge.org'
end
assert_equal 'unsupported URI scheme ftp', e.message
end
def test_find_gems_gems_with_sources
inst = Gem::DependencyInstaller.new 'a'
inst = Gem::DependencyInstaller.new
dep = Gem::Dependency.new 'b', '>= 0'
assert_equal [[@b1, 'http://gems.example.com']],
@ -452,7 +443,7 @@ class TestGemDependencyInstaller < RubyGemTestCase
def test_find_gems_with_sources_local
FileUtils.mv @a1_gem, @tempdir
inst = Gem::DependencyInstaller.new 'b'
inst = Gem::DependencyInstaller.new
dep = Gem::Dependency.new 'a', '>= 0'
gems = nil
@ -462,7 +453,7 @@ class TestGemDependencyInstaller < RubyGemTestCase
assert_equal 2, gems.length
remote = gems.first
assert_equal @a1, remote.first, 'remote spec'
assert_equal 'a-1', remote.first.full_name, 'remote spec'
assert_equal 'http://gems.example.com', remote.last, 'remote path'
local = gems.last
@ -472,7 +463,9 @@ class TestGemDependencyInstaller < RubyGemTestCase
end
def test_gather_dependencies
inst = Gem::DependencyInstaller.new 'b'
inst = Gem::DependencyInstaller.new
inst.find_spec_by_name_and_version 'b'
inst.gather_dependencies
assert_equal %w[a-1 b-1], inst.gems_to_install.map { |s| s.full_name }
end
@ -488,7 +481,9 @@ class TestGemDependencyInstaller < RubyGemTestCase
@fetcher.uri = URI.parse 'http://gems.example.com'
@fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
inst = Gem::DependencyInstaller.new 'c'
inst = Gem::DependencyInstaller.new
inst.find_spec_by_name_and_version 'c'
inst.gather_dependencies
assert_equal %w[b-2 c-1], inst.gems_to_install.map { |s| s.full_name }
end
@ -496,14 +491,18 @@ class TestGemDependencyInstaller < RubyGemTestCase
def test_gather_dependencies_platform_alternate
util_set_arch 'cpu-my_platform1'
inst = Gem::DependencyInstaller.new 'w'
inst = Gem::DependencyInstaller.new
inst.find_spec_by_name_and_version 'w'
inst.gather_dependencies
assert_equal %w[x-1-cpu-my_platform-1 w-1],
inst.gems_to_install.map { |s| s.full_name }
end
def test_gather_dependencies_platform_bump
inst = Gem::DependencyInstaller.new 'z'
inst = Gem::DependencyInstaller.new
inst.find_spec_by_name_and_version 'z'
inst.gather_dependencies
assert_equal %w[y-1 z-1], inst.gems_to_install.map { |s| s.full_name }
end
@ -518,27 +517,11 @@ class TestGemDependencyInstaller < RubyGemTestCase
@fetcher.uri = URI.parse 'http://gems.example.com'
@fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
inst = Gem::DependencyInstaller.new 'e'
inst = Gem::DependencyInstaller.new
inst.find_spec_by_name_and_version 'e'
inst.gather_dependencies
assert_equal %w[d-1 e-1], inst.gems_to_install.map { |s| s.full_name }
end
def util_gem(name, version, &block)
spec = quick_gem(name, version, &block)
util_build_gem spec
cache_file = File.join @tempdir, 'gems', "#{spec.original_name}.gem"
FileUtils.mv File.join(@gemhome, 'cache', "#{spec.original_name}.gem"),
cache_file
FileUtils.rm File.join(@gemhome, 'specifications',
"#{spec.full_name}.gemspec")
spec.loaded_from = nil
spec.loaded = false
[spec, cache_file]
end
end

Просмотреть файл

@ -47,16 +47,19 @@ class TestGemExtConfigureBuilder < RubyGemTestCase
end
end
expected = %r|configure failed:
shell_error_msg = %r{(\./configure: No such file or directory)|(Can't open \./configure)}
sh_prefix_configure = "sh ./configure --prefix="
expected = %r(configure failed:
sh \./configure --prefix=#{Regexp.escape @dest_path}
.*?: \./configure: No such file or directory
|
#{Regexp.escape sh_prefix_configure}#{Regexp.escape @dest_path}
.*?: #{shell_error_msg}
)
assert_match expected, error.message
assert_equal "sh ./configure --prefix=#{@dest_path}", output.shift
assert_match %r|\./configure: No such file or directory\n|, output.shift
assert_equal "#{sh_prefix_configure}#{@dest_path}", output.shift
assert_match %r(#{shell_error_msg}\n), output.shift
assert_equal true, output.empty?
end

Просмотреть файл

@ -22,7 +22,7 @@ class TestGemFormat < RubyGemTestCase
gems = Dir[File.join(@gemhome, 'cache', '*.gem')]
names = [@a1, @a2, @b2, @c1_2, @pl1].map do |spec|
names = [@a1, @a2, @a_evil9, @b2, @c1_2, @pl1].map do |spec|
spec.original_name
end

Просмотреть файл

@ -53,6 +53,11 @@ class TestGemIndexer < RubyGemTestCase
assert_indexed quickdir, "index"
assert_indexed quickdir, "index.rz"
assert_indexed quickdir, "latest_index"
assert_indexed quickdir, "latest_index.rz"
assert_no_match %r|a-1|, File.read(File.join(quickdir, 'latest_index'))
assert_indexed quickdir, "#{@a1.full_name}.gemspec.rz"
assert_indexed quickdir, "#{@a2.full_name}.gemspec.rz"
assert_indexed quickdir, "#{@b2.full_name}.gemspec.rz"
@ -74,8 +79,8 @@ class TestGemIndexer < RubyGemTestCase
end
expected = <<-EOF
Generating index for 5 gems in #{@tempdir}
.....
Generating index for 6 gems in #{@tempdir}
......
Loaded all gems
Generating master indexes (this may take a while)
EOF

Просмотреть файл

@ -4,63 +4,10 @@
# See LICENSE.txt for permissions.
#++
require 'test/unit'
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
require 'rubygems/installer'
require File.join(File.expand_path(File.dirname(__FILE__)),
'gem_installer_test_case')
class Gem::Installer
attr_accessor :gem_dir
attr_writer :format
attr_writer :gem_home
attr_writer :env_shebang
attr_writer :ignore_dependencies
attr_writer :format_executable
attr_writer :security_policy
attr_writer :spec
attr_writer :wrappers
end
class TestGemInstaller < RubyGemTestCase
def setup
super
@spec = quick_gem "a"
@gem = File.join @tempdir, "#{@spec.full_name}.gem"
util_build_gem @spec
FileUtils.mv File.join(@gemhome, 'cache', "#{@spec.full_name}.gem"),
@tempdir
@installer = Gem::Installer.new @gem
@installer.gem_dir = util_gem_dir
@installer.gem_home = @gemhome
@installer.spec = @spec
end
def util_gem_dir(version = '2')
File.join @gemhome, "gems", "a-#{version}" # HACK
end
def util_gem_bindir(version = '2')
File.join util_gem_dir(version), "bin"
end
def util_inst_bindir
File.join @gemhome, "bin"
end
def util_make_exec(version = '2', shebang = "#!/usr/bin/ruby")
@spec.executables = ["my_exec"]
FileUtils.mkdir_p util_gem_bindir(version)
exec_file = @installer.formatted_program_filename "my_exec"
exec_path = File.join util_gem_bindir(version), exec_file
File.open exec_path, 'w' do |f|
f.puts shebang
end
end
class TestGemInstaller < GemInstallerTestCase
def test_app_script_text
util_make_exec '2', ''
@ -162,7 +109,7 @@ load 'my_exec'
@installer.gem_dir = '/nonexistent'
expanded_gem_dir = @installer.send(:expand_and_validate_gem_dir)
if win_platform?
expected = File.join(Config::CONFIG['bindir'][0..2], 'nonexistent').downcase
expected = File.expand_path('/nonexistent').downcase
expanded_gem_dir = expanded_gem_dir.downcase
else
expected = '/nonexistent'
@ -768,7 +715,7 @@ load 'my_exec'
@installer.env_shebang = true
shebang = @installer.shebang 'my_exec'
assert_equal "#!/usr/bin/env ruby", shebang
assert_equal "#!/usr/bin/env #{Gem::ConfigMap[:RUBY_INSTALL_NAME]}", shebang
end
def test_shebang_nested
@ -855,31 +802,5 @@ load 'my_exec'
File.join @gemhome, 'cache', "#{spec.full_name}.gem"
end
def util_setup_gem
@spec.files = File.join('lib', 'code.rb')
@spec.executables << 'executable'
@spec.extensions << File.join('ext', 'a', 'mkrf_conf.rb')
Dir.chdir @tempdir do
FileUtils.mkdir_p 'bin'
FileUtils.mkdir_p 'lib'
FileUtils.mkdir_p File.join('ext', 'a')
File.open File.join('bin', 'executable'), 'w' do |f| f.puts '1' end
File.open File.join('lib', 'code.rb'), 'w' do |f| f.puts '1' end
File.open File.join('ext', 'a', 'mkrf_conf.rb'), 'w' do |f|
f << <<-EOF
File.open 'Rakefile', 'w' do |rf| rf.puts "task :default" end
EOF
end
use_ui @ui do
FileUtils.rm @gem
Gem::Builder.new(@spec).build
end
end
@installer = Gem::Installer.new @gem
end
end

Просмотреть файл

@ -0,0 +1,137 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require File.join(File.expand_path(File.dirname(__FILE__)),
'gem_package_tar_test_case')
require 'rubygems/package'
class TestGemPackageTarHeader < TarTestCase
def setup
super
header = {
:name => 'x',
:mode => 0644,
:uid => 1000,
:gid => 10000,
:size => 100,
:mtime => 12345,
:typeflag => '0',
:linkname => 'link',
:uname => 'user',
:gname => 'group',
:devmajor => 1,
:devminor => 2,
:prefix => 'y',
}
@tar_header = Gem::Package::TarHeader.new header
end
def test_self_from
io = TempIO.new @tar_header.to_s
new_header = Gem::Package::TarHeader.from io
assert_headers_equal @tar_header, new_header
end
def test_initialize
assert_equal '', @tar_header.checksum, 'checksum'
assert_equal 1, @tar_header.devmajor, 'devmajor'
assert_equal 2, @tar_header.devminor, 'devminor'
assert_equal 10000, @tar_header.gid, 'gid'
assert_equal 'group', @tar_header.gname, 'gname'
assert_equal 'link', @tar_header.linkname, 'linkname'
assert_equal 'ustar', @tar_header.magic, 'magic'
assert_equal 0644, @tar_header.mode, 'mode'
assert_equal 12345, @tar_header.mtime, 'mtime'
assert_equal 'x', @tar_header.name, 'name'
assert_equal 'y', @tar_header.prefix, 'prefix'
assert_equal 100, @tar_header.size, 'size'
assert_equal '0', @tar_header.typeflag, 'typeflag'
assert_equal 1000, @tar_header.uid, 'uid'
assert_equal 'user', @tar_header.uname, 'uname'
assert_equal '00', @tar_header.version, 'version'
assert !@tar_header.empty?, 'empty'
end
def test_initialize_bad
assert_raises ArgumentError do
Gem::Package::TarHeader.new :name => '', :size => '', :mode => ''
end
assert_raises ArgumentError do
Gem::Package::TarHeader.new :name => '', :size => '', :prefix => ''
end
assert_raises ArgumentError do
Gem::Package::TarHeader.new :name => '', :prefix => '', :mode => ''
end
assert_raises ArgumentError do
Gem::Package::TarHeader.new :prefix => '', :size => '', :mode => ''
end
end
def test_empty_eh
assert !@tar_header.empty?
@tar_header = Gem::Package::TarHeader.new :name => 'x', :prefix => '',
:mode => 0, :size => 0,
:empty => true
assert @tar_header.empty?
end
def test_equals2
assert_equal @tar_header, @tar_header
assert_equal @tar_header, @tar_header.dup
end
def test_to_s
expected = <<-EOF.split("\n").join
x\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\0000000644\0000001750\0000023420\00000000000144\00000000030071
\000012467\000 0link\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000ustar\00000user\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
group\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\0000000001\0000000002\000y\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000
EOF
assert_headers_equal expected, @tar_header
end
def test_update_checksum
assert_equal '', @tar_header.checksum
@tar_header.update_checksum
assert_equal '012467', @tar_header.checksum
end
end

Просмотреть файл

@ -0,0 +1,119 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require File.join(File.expand_path(File.dirname(__FILE__)),
'gem_package_tar_test_case')
require 'rubygems/package/tar_input'
class TestGemPackageTarInput < TarTestCase
# Sometimes the setgid bit doesn't take. Don't know if this is a problem on
# all systems, or just some. But for now, we will ignore it in the tests.
SETGID_BIT = 02000
def setup
super
inner_tar = tar_file_header("bla", "", 0612, 10)
inner_tar += "0123456789" + "\0" * 502
inner_tar += tar_file_header("foo", "", 0636, 5)
inner_tar += "01234" + "\0" * 507
inner_tar += tar_dir_header("__dir__", "", 0600)
inner_tar += "\0" * 1024
str = TempIO.new
begin
os = Zlib::GzipWriter.new str
os.write inner_tar
ensure
os.finish
end
str.rewind
@file = File.join @tempdir, 'bla.tar'
File.open @file, 'wb' do |f|
f.write tar_file_header("data.tar.gz", "", 0644, str.string.size)
f.write str.string
f.write "\0" * ((512 - (str.string.size % 512)) % 512 )
@spec = Gem::Specification.new do |spec|
spec.author = "Mauricio :)"
end
meta = @spec.to_yaml
f.write tar_file_header("metadata", "", 0644, meta.size)
f.write meta + "\0" * (1024 - meta.size)
f.write "\0" * 1024
end
@entry_names = %w{bla foo __dir__}
@entry_sizes = [10, 5, 0]
#FIXME: are these modes system dependent?
@entry_modes = [0100612, 0100636, 040600]
@entry_files = %W[#{@tempdir}/bla #{@tempdir}/foo]
@entry_contents = %w[0123456789 01234]
end
def test_each_works
open @file, 'rb' do |io|
Gem::Package::TarInput.open io do |tar_input|
count = 0
tar_input.each_with_index do |entry, i|
count = i
assert_kind_of Gem::Package::TarReader::Entry, entry
assert_equal @entry_names[i], entry.header.name
assert_equal @entry_sizes[i], entry.header.size
end
assert_equal 2, count
assert_equal @spec, tar_input.metadata
end
end
end
def test_extract_entry_works
open @file, 'rb' do |io|
Gem::Package::TarInput.open io do |tar_input|
assert_equal @spec, tar_input.metadata
count = 0
tar_input.each_with_index do |entry, i|
count = i
tar_input.extract_entry @tempdir, entry
name = File.join @tempdir, entry.header.name
if entry.directory?
assert File.dir?(name)
else
assert File.file?(name)
assert_equal @entry_sizes[i], File.stat(name).size
#FIXME: win32? !!
end
unless Gem.win_platform? then
assert_equal @entry_modes[i], File.stat(name).mode & (~SETGID_BIT)
end
end
assert_equal 2, count
end
end
@entry_files.each_with_index do |x, i|
assert File.file?(x)
assert_equal @entry_contents[i], File.read_b(x)
end
end
end

Просмотреть файл

@ -0,0 +1,104 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require File.join(File.expand_path(File.dirname(__FILE__)),
'gem_package_tar_test_case')
require 'rubygems/package/tar_output'
class TestGemPackageTarOutput < TarTestCase
def setup
super
@file = File.join @tempdir, 'bla2.tar'
end
def test_self_open
open @file, 'wb' do |tar_io|
Gem::Package::TarOutput.open tar_io do |tar_writer|
tar_writer.add_file_simple 'README', 0, 17 do |io|
io.write "This is a README\n"
end
tar_writer.metadata = "This is some metadata\n"
end
end
files = util_extract
name, data = files.shift
assert_equal 'data.tar.gz', name
gz = Zlib::GzipReader.new StringIO.new(data)
Gem::Package::TarReader.new gz do |tar_reader|
tar_reader.each do |entry|
assert_equal 'README', entry.full_name
assert_equal "This is a README\n", entry.read
end
end
gz.close
name, data = files.shift
assert_equal 'metadata.gz', name
gz = Zlib::GzipReader.new StringIO.new(data)
assert_equal "This is some metadata\n", gz.read
assert files.empty?
ensure
gz.close if gz
end
if defined? OpenSSL then
def test_self_open_signed
signer = Gem::Security::Signer.new @private_key, [@public_cert]
open @file, 'wb' do |tar_io|
Gem::Package::TarOutput.open tar_io, signer do |tar_writer|
tar_writer.add_file_simple 'README', 0, 17 do |io|
io.write "This is a README\n"
end
tar_writer.metadata = "This is some metadata\n"
end
end
files = util_extract
name, data = files.shift
assert_equal 'data.tar.gz', name
name, data = files.shift
assert_equal 'metadata.gz', name
name, data = files.shift
assert_equal 'data.tar.gz.sig', name
name, data = files.shift
assert_equal 'metadata.gz.sig', name
assert files.empty?
end
end
def util_extract
files = []
open @file, 'rb' do |io|
Gem::Package::TarReader.new io do |tar_reader|
tar_reader.each do |entry|
files << [entry.full_name, entry.read]
end
end
end
files
end
end

Просмотреть файл

@ -0,0 +1,53 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require File.join(File.expand_path(File.dirname(__FILE__)),
'gem_package_tar_test_case')
require 'rubygems/package'
class TestGemPackageTarReader < TarTestCase
def test_each_entry
tar = tar_dir_header "foo", "bar", 0
tar << tar_file_header("bar", "baz", 0, 0)
io = TempIO.new tar
entries = 0
Gem::Package::TarReader.new io do |tar_reader|
tar_reader.each_entry do |entry|
assert_kind_of Gem::Package::TarReader::Entry, entry
entries += 1
end
end
assert_equal 2, entries
end
def test_rewind
content = ('a'..'z').to_a.join(" ")
str = tar_file_header("lib/foo", "", 010644, content.size) + content +
"\0" * (512 - content.size)
str << "\0" * 1024
Gem::Package::TarReader.new(TempIO.new(str)) do |tar_reader|
3.times do
tar_reader.rewind
i = 0
tar_reader.each_entry do |entry|
assert_equal(content, entry.read)
i += 1
end
assert_equal(1, i)
end
end
end
end

Просмотреть файл

@ -0,0 +1,116 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require File.join(File.expand_path(File.dirname(__FILE__)),
'gem_package_tar_test_case')
require 'rubygems/package'
class TestGemPackageTarReaderEntry < TarTestCase
def setup
super
@contents = ('a'..'z').to_a.join * 100
@tar = ''
@tar << tar_file_header("lib/foo", "", 0, @contents.size)
@tar << @contents
@tar << "\0" * (512 - (@tar.size % 512))
@entry = util_entry @tar
end
def test_bytes_read
assert_equal 0, @entry.bytes_read
@entry.getc
assert_equal 1, @entry.bytes_read
end
def test_close
@entry.close
assert @entry.bytes_read
e = assert_raise IOError do @entry.eof? end
assert_equal 'closed Gem::Package::TarReader::Entry', e.message
e = assert_raise IOError do @entry.getc end
assert_equal 'closed Gem::Package::TarReader::Entry', e.message
e = assert_raise IOError do @entry.pos end
assert_equal 'closed Gem::Package::TarReader::Entry', e.message
e = assert_raise IOError do @entry.read end
assert_equal 'closed Gem::Package::TarReader::Entry', e.message
e = assert_raise IOError do @entry.rewind end
assert_equal 'closed Gem::Package::TarReader::Entry', e.message
end
def test_closed_eh
@entry.close
assert @entry.closed?
end
def test_eof_eh
@entry.read
assert @entry.eof?
end
def test_full_name
assert_equal 'lib/foo', @entry.full_name
end
def test_getc
assert_equal ?a, @entry.getc
end
def test_directory_eh
assert_equal false, @entry.directory?
assert_equal true, util_dir_entry.directory?
end
def test_file_eh
assert_equal true, @entry.file?
assert_equal false, util_dir_entry.file?
end
def test_pos
assert_equal 0, @entry.pos
@entry.getc
assert_equal 1, @entry.pos
end
def test_read
assert_equal @contents, @entry.read
end
def test_read_big
assert_equal @contents, @entry.read(@contents.size * 2)
end
def test_read_small
assert_equal @contents[0...100], @entry.read(100)
end
def test_rewind
char = @entry.getc
@entry.rewind
assert_equal 0, @entry.pos
assert_equal char, @entry.getc
end
end

Просмотреть файл

@ -0,0 +1,151 @@
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
require File.join(File.expand_path(File.dirname(__FILE__)),
'gem_package_tar_test_case')
require 'rubygems/package/tar_writer'
class TestTarWriter < TarTestCase
def setup
super
@data = 'abcde12345'
@io = TempIO.new
@tar_writer = Gem::Package::TarWriter.new @io
end
def teardown
@tar_writer.close unless @tar_writer.closed?
super
end
def test_add_file
@tar_writer.add_file 'x', 0644 do |f| f.write 'a' * 10 end
assert_headers_equal(tar_file_header('x', '', 0644, 10),
@io.string[0, 512])
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
assert_equal 1024, @io.pos
end
def test_add_file_simple
@tar_writer.add_file_simple 'x', 0644, 10 do |io| io.write "a" * 10 end
assert_headers_equal(tar_file_header('x', '', 0644, 10),
@io.string[0, 512])
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
assert_equal 1024, @io.pos
end
def test_add_file_simple_padding
@tar_writer.add_file_simple 'x', 0, 100
assert_headers_equal tar_file_header('x', '', 0, 100),
@io.string[0, 512]
assert_equal "\0" * 512, @io.string[512, 512]
end
def test_add_file_simple_data
@tar_writer.add_file_simple("lib/foo/bar", 0, 10) { |f| f.write @data }
@tar_writer.flush
assert_equal @data + ("\0" * (512-@data.size)),
@io.string[512, 512]
end
def test_add_file_simple_size
assert_raise Gem::Package::TarWriter::FileOverflow do
@tar_writer.add_file_simple("lib/foo/bar", 0, 10) do |io|
io.write "1" * 11
end
end
end
def test_add_file_unseekable
assert_raise Gem::Package::NonSeekableIO do
Gem::Package::TarWriter.new(Object.new).add_file 'x', 0
end
end
def test_close
@tar_writer.close
assert_equal "\0" * 1024, @io.string
e = assert_raise IOError do
@tar_writer.close
end
assert_equal 'closed Gem::Package::TarWriter', e.message
e = assert_raise IOError do
@tar_writer.flush
end
assert_equal 'closed Gem::Package::TarWriter', e.message
e = assert_raise IOError do
@tar_writer.add_file 'x', 0
end
assert_equal 'closed Gem::Package::TarWriter', e.message
e = assert_raise IOError do
@tar_writer.add_file_simple 'x', 0, 0
end
assert_equal 'closed Gem::Package::TarWriter', e.message
e = assert_raise IOError do
@tar_writer.mkdir 'x', 0
end
assert_equal 'closed Gem::Package::TarWriter', e.message
end
def test_mkdir
@tar_writer.mkdir 'foo', 0644
assert_headers_equal tar_dir_header('foo', '', 0644),
@io.string[0, 512]
assert_equal 512, @io.pos
end
def test_split_name
assert_equal ['b' * 100, 'a' * 155],
@tar_writer.split_name("#{'a' * 155}/#{'b' * 100}")
assert_equal ["#{'qwer/' * 19}bla", 'a' * 151],
@tar_writer.split_name("#{'a' * 151}/#{'qwer/' * 19}bla")
end
def test_split_name_too_long_name
name = File.join 'a', 'b' * 100
assert_equal ['b' * 100, 'a'], @tar_writer.split_name(name)
assert_raise Gem::Package::TooLongFileName do
name = File.join 'a', 'b' * 101
@tar_writer.split_name name
end
end
def test_split_name_too_long_prefix
name = File.join 'a' * 155, 'b'
assert_equal ['b', 'a' * 155], @tar_writer.split_name(name)
assert_raise Gem::Package::TooLongFileName do
name = File.join 'a' * 156, 'b'
@tar_writer.split_name name
end
end
def test_split_name_too_long_total
assert_raise Gem::Package::TooLongFileName do
@tar_writer.split_name 'a' * 257
end
end
end

Просмотреть файл

@ -97,6 +97,13 @@ gems:
@server_uri = base_server_uri + "/yaml"
@server_z_uri = base_server_uri + "/yaml.Z"
# REFACTOR: copied from test_gem_dependency_installer.rb
@gems_dir = File.join @tempdir, 'gems'
@cache_dir = File.join @gemhome, 'cache'
FileUtils.mkdir @gems_dir
@a1, @a1_gem = util_gem 'a', '1' do |s| s.executables << 'a_bin' end
Gem::RemoteFetcher.instance_variable_set :@fetcher, nil
end
@ -156,6 +163,140 @@ gems:
end
end
def util_fuck_with_fetcher data, blow = false
fetcher = Gem::RemoteFetcher.fetcher
fetcher.instance_variable_set :@test_data, data
unless blow then
def fetcher.fetch_path arg
@test_arg = arg
@test_data
end
else
def fetcher.fetch_path arg
# OMG I'm such an ass
class << self; remove_method :fetch_path; end
def self.fetch_path arg
@test_arg = arg
@test_data
end
raise Gem::RemoteFetcher::FetchError, "haha!"
end
end
fetcher
end
def test_download
a1_data = nil
File.open @a1_gem, 'rb' do |fp|
a1_data = fp.read
end
fetcher = util_fuck_with_fetcher a1_data
a1_cache_gem = File.join(@gemhome, 'cache', "#{@a1.full_name}.gem")
assert_equal a1_cache_gem, fetcher.download(@a1, 'http://gems.example.com')
assert_equal("http://gems.example.com/gems/a-1.gem",
fetcher.instance_variable_get(:@test_arg).to_s)
assert File.exist?(a1_cache_gem)
end
def test_download_cached
FileUtils.mv @a1_gem, @cache_dir
inst = Gem::RemoteFetcher.fetcher
assert_equal File.join(@gemhome, 'cache', "#{@a1.full_name}.gem"),
inst.download(@a1, 'http://gems.example.com')
end
def test_download_local
FileUtils.mv @a1_gem, @tempdir
local_path = File.join @tempdir, "#{@a1.full_name}.gem"
inst = nil
Dir.chdir @tempdir do
inst = Gem::RemoteFetcher.fetcher
end
assert_equal File.join(@gemhome, 'cache', "#{@a1.full_name}.gem"),
inst.download(@a1, local_path)
end
def test_download_install_dir
a1_data = nil
File.open @a1_gem, 'rb' do |fp|
a1_data = fp.read
end
fetcher = util_fuck_with_fetcher a1_data
install_dir = File.join @tempdir, 'more_gems'
a1_cache_gem = File.join install_dir, 'cache', "#{@a1.full_name}.gem"
actual = fetcher.download(@a1, 'http://gems.example.com', install_dir)
assert_equal a1_cache_gem, actual
assert_equal("http://gems.example.com/gems/a-1.gem",
fetcher.instance_variable_get(:@test_arg).to_s)
assert File.exist?(a1_cache_gem)
end
unless win_platform? then # File.chmod doesn't work
def test_download_local_read_only
FileUtils.mv @a1_gem, @tempdir
local_path = File.join @tempdir, "#{@a1.full_name}.gem"
inst = nil
File.chmod 0555, File.join(@gemhome, 'cache')
Dir.chdir @tempdir do
inst = Gem::RemoteFetcher.fetcher
end
assert_equal File.join(@tempdir, "#{@a1.full_name}.gem"),
inst.download(@a1, local_path)
ensure
File.chmod 0755, File.join(@gemhome, 'cache')
end
end
def test_download_platform_legacy
original_platform = 'old-platform'
e1, e1_gem = util_gem 'e', '1' do |s|
s.platform = Gem::Platform::CURRENT
s.instance_variable_set :@original_platform, original_platform
end
e1_data = nil
File.open e1_gem, 'rb' do |fp|
e1_data = fp.read
end
fetcher = util_fuck_with_fetcher e1_data, :blow_chunks
e1_cache_gem = File.join(@gemhome, 'cache', "#{e1.full_name}.gem")
assert_equal e1_cache_gem, fetcher.download(e1, 'http://gems.example.com')
assert_equal("http://gems.example.com/gems/#{e1.original_name}.gem",
fetcher.instance_variable_get(:@test_arg).to_s)
assert File.exist?(e1_cache_gem)
end
def test_download_unsupported
inst = Gem::RemoteFetcher.fetcher
e = assert_raise Gem::InstallError do
inst.download @a1, 'ftp://gems.rubyforge.org'
end
assert_equal 'unsupported URI scheme ftp', e.message
end
def test_explicit_proxy
use_ui @ui do
fetcher = Gem::RemoteFetcher.new @proxy_uri
@ -232,22 +373,6 @@ gems:
assert_equal 'EOFError: EOFError reading uri', e.message
end
def test_fetch_path_open_uri_http_error
fetcher = Gem::RemoteFetcher.new nil
def fetcher.open_uri_or_path(uri)
io = StringIO.new 'went boom'
err = OpenURI::HTTPError.new 'error', io
raise err
end
e = assert_raise Gem::RemoteFetcher::FetchError do
fetcher.fetch_path 'uri'
end
assert_equal "OpenURI::HTTPError: error reading uri\n\twent boom", e.message
end
def test_fetch_path_socket_error
fetcher = Gem::RemoteFetcher.new nil
@ -324,6 +449,53 @@ gems:
end
end
def test_open_uri_or_path
fetcher = Gem::RemoteFetcher.new nil
conn = Object.new
def conn.started?() true end
def conn.request(req)
unless defined? @requested then
@requested = true
res = Net::HTTPRedirection.new nil, 301, nil
res.add_field 'Location', 'http://gems.example.com/real_path'
res
else
res = Net::HTTPOK.new nil, 200, nil
def res.body() 'real_path' end
res
end
end
conn = { 'gems.example.com:80' => conn }
fetcher.instance_variable_set :@connections, conn
fetcher.send :open_uri_or_path, 'http://gems.example.com/redirect' do |io|
assert_equal 'real_path', io.read
end
end
def test_open_uri_or_path_limited_redirects
fetcher = Gem::RemoteFetcher.new nil
conn = Object.new
def conn.started?() true end
def conn.request(req)
res = Net::HTTPRedirection.new nil, 301, nil
res.add_field 'Location', 'http://gems.example.com/redirect'
res
end
conn = { 'gems.example.com:80' => conn }
fetcher.instance_variable_set :@connections, conn
e = assert_raise Gem::RemoteFetcher::FetchError do
fetcher.send :open_uri_or_path, 'http://gems.example.com/redirect'
end
assert_equal 'too many redirects', e.message
end
def test_zip
use_ui @ui do
self.class.enable_zip = true

Просмотреть файл

@ -36,7 +36,8 @@ class TestGemSourceIndex < RubyGemTestCase
use_ui @ui do
fetched_index = @source_index.fetch_bulk_index @uri
assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
@c1_2.full_name].sort,
fetched_index.gems.map { |n,s| n }.sort
end
@ -82,7 +83,8 @@ class TestGemSourceIndex < RubyGemTestCase
use_ui @ui do
fetched_index = @source_index.fetch_bulk_index @uri
assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
@c1_2.full_name].sort,
fetched_index.gems.map { |n,s| n }.sort
end
@ -105,7 +107,8 @@ class TestGemSourceIndex < RubyGemTestCase
use_ui @ui do
fetched_index = @source_index.fetch_bulk_index @uri
assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
@c1_2.full_name].sort,
fetched_index.gems.map { |n,s| n }.sort
end
@ -123,7 +126,8 @@ class TestGemSourceIndex < RubyGemTestCase
util_setup_bulk_fetch false
use_ui @ui do
fetched_index = @source_index.fetch_bulk_index @uri
assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
@c1_2.full_name].sort,
fetched_index.gems.map { |n,s| n }.sort
end
@ -136,11 +140,32 @@ class TestGemSourceIndex < RubyGemTestCase
end
def test_fetch_quick_index
quick_index = util_zip @gem_names
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
index = util_zip @gem_names
latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
quick_index = @source_index.fetch_quick_index @uri
assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
@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,
quick_index.sort
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/latest_index.rz", paths.shift
assert paths.empty?, paths.join(', ')
end
def test_fetch_quick_index_all
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
quick_index = @source_index.fetch_quick_index @uri, true
assert_equal [@a1.full_name, @a2.full_name, @b2.full_name].sort,
quick_index.sort
paths = @fetcher.paths
@ -155,7 +180,7 @@ class TestGemSourceIndex < RubyGemTestCase
proc { raise Exception }
e = assert_raise Gem::OperationNotSupportedError do
@source_index.fetch_quick_index @uri
@source_index.fetch_quick_index @uri, true
end
assert_equal 'No quick index found: Exception', e.message
@ -167,41 +192,201 @@ class TestGemSourceIndex < RubyGemTestCase
assert paths.empty?, paths.join(', ')
end
def test_fetch_quick_index_fallback
index = util_zip @gem_names
@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 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/"
@fetcher.data["#{repo}quick/latest_index.rz"] = latest_index
quick_index = @source_index.fetch_quick_index repo, false
assert_equal [@a2.full_name, @b2.full_name].sort,
quick_index.sort
paths = @fetcher.paths
assert_equal "#{repo}quick/latest_index.rz", paths.shift
assert paths.empty?, paths.join(', ')
end
def test_fetch_single_spec
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),
@a1.full_name
assert_equal @a1.full_name, spec.full_name
paths = @fetcher.paths
assert_equal a1_spec_url, paths.shift
assert paths.empty?, paths.join(', ')
end
def test_fetch_single_spec_subdir
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)
spec = @source_index.send :fetch_single_spec, repo, @a1.full_name
assert_equal @a1.full_name, spec.full_name
paths = @fetcher.paths
assert_equal a1_spec_url, paths.shift
assert paths.empty?, paths.join(', ')
end
def test_fetch_single_spec_yaml
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
spec = @source_index.send :fetch_single_spec, repo, @a1.full_name
assert_equal @a1.full_name, spec.full_name
paths = @fetcher.paths
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/"
a1_spec_url = "#{repo}quick/#{@a1.full_name}.gemspec.rz"
@fetcher.data[a1_spec_url] = util_zip @a1.to_yaml
spec = @source_index.send :fetch_single_spec, repo, @a1.full_name
assert_equal @a1.full_name, spec.full_name
paths = @fetcher.paths
assert_equal "#{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_find_missing
missing = @source_index.find_missing [@gem3.full_name]
assert_equal [@gem3.full_name], missing
missing = @source_index.find_missing [@b2.full_name]
assert_equal [@b2.full_name], missing
end
def test_find_missing_none_missing
missing = @source_index.find_missing @gem_names.split
missing = @source_index.find_missing [
@a1.full_name, @a2.full_name, @c1_2.full_name
]
assert_equal [], missing
end
def test_latest_specs
spec = quick_gem @gem1.name, '1'
@source_index.add_spec spec
p1_ruby = quick_gem 'p', '1'
p1_platform = quick_gem 'p', '1' do |spec|
spec.platform = Gem::Platform::CURRENT
end
a1_platform = quick_gem @a1.name, (@a1.version) do |s|
s.platform = Gem::Platform.new 'x86-my_platform1'
end
a2_platform = quick_gem @a2.name, (@a2.version) do |s|
s.platform = Gem::Platform.new 'x86-my_platform1'
end
a2_platform_other = quick_gem @a2.name, (@a2.version) do |s|
s.platform = Gem::Platform.new 'x86-other_platform1'
end
a3_platform_other = quick_gem @a2.name, (@a2.version.bump) do |s|
s.platform = Gem::Platform.new 'x86-other_platform1'
end
@source_index.add_spec p1_ruby
@source_index.add_spec p1_platform
@source_index.add_spec a1_platform
@source_index.add_spec a2_platform
@source_index.add_spec a2_platform_other
@source_index.add_spec a3_platform_other
expected = [
@gem1.full_name,
@gem2.full_name,
@gem4.full_name,
@a2.full_name,
a2_platform.full_name,
a3_platform_other.full_name,
@c1_2.full_name,
@a_evil9.full_name,
p1_ruby.full_name,
p1_platform.full_name,
].sort
assert_equal expected, @source_index.latest_specs.map { |s| s.full_name }.sort
latest_specs = @source_index.latest_specs.map { |s| s.full_name }.sort
assert_equal expected, latest_specs
end
def test_load_gems_in
spec_dir1 = File.join @gemhome, 'specifications'
spec_dir2 = File.join @tempdir, 'gemhome2', 'specifications'
FileUtils.rm_r spec_dir1
FileUtils.mkdir_p spec_dir1
FileUtils.mkdir_p spec_dir2
a1 = quick_gem 'a', '1' do |spec| spec.author = 'author 1' end
a2 = quick_gem 'a', '1' do |spec| spec.author = 'author 2' end
File.open File.join(spec_dir1, "#{a1.full_name}.gemspec"), 'w' do |fp|
fp.write a1.to_ruby
end
File.open File.join(spec_dir2, "#{a2.full_name}.gemspec"), 'w' do |fp|
fp.write a2.to_ruby
end
@source_index.load_gems_in spec_dir1, spec_dir2
assert_equal a1.author, @source_index.specification(a1.full_name).author
end
def test_outdated
sic = Gem::SourceInfoCache.new
Gem::SourceInfoCache.instance_variable_set :@cache, sic
util_setup_source_info_cache
assert_equal [], @source_index.outdated
updated = quick_gem @gem1.name, (@gem1.version.bump)
updated = quick_gem @a2.name, (@a2.version.bump)
util_setup_source_info_cache updated
assert_equal [updated.name], @source_index.outdated
updated_platform = quick_gem @gem1.name, (updated.version.bump) do |s|
updated_platform = quick_gem @a2.name, (updated.version.bump) do |s|
s.platform = Gem::Platform.new 'x86-other_platform1'
end
@ -211,28 +396,34 @@ class TestGemSourceIndex < RubyGemTestCase
end
def test_remove_extra
@source_index.remove_extra [@gem1.full_name]
assert_equal [@gem1.full_name], @source_index.gems.map { |n,s| n }
@source_index.add_spec @a1
@source_index.add_spec @a2
@source_index.remove_extra [@a1.full_name]
assert_equal [@a1.full_name], @source_index.gems.map { |n,s| n }
end
def test_remove_extra_no_changes
gems = @gem_names.split.sort
gems = [@a1.full_name, @a2.full_name]
@source_index.add_spec @a1
@source_index.add_spec @a2
@source_index.remove_extra gems
assert_equal gems, @source_index.gems.map { |n,s| n }.sort
end
def test_search
assert_equal [@gem1, @gem4], @source_index.search("gem_one")
assert_equal [@gem1], @source_index.search("gem_one", "= 2")
assert_equal [@a1, @a2, @a_evil9], @source_index.search('a')
assert_equal [@a2], @source_index.search('a', '= 2')
assert_equal [], @source_index.search("bogusstring")
assert_equal [], @source_index.search("gem_one", "= 3.2.1")
assert_equal [], @source_index.search('bogusstring')
assert_equal [], @source_index.search('a', '= 3')
@a1 = quick_gem 'a', '1'
@a2 = quick_gem 'a', '2'
source_index = Gem::SourceIndex.new @a1.full_name => @a1,
@a2.full_name => @a2
source_index = Gem::SourceIndex.new
source_index.add_spec @a1
source_index.add_spec @a2
assert_equal [@a1], source_index.search(@a1.name, '= 1')
@ -276,7 +467,7 @@ class TestGemSourceIndex < RubyGemTestCase
end
def test_specification
assert_equal @gem1, @source_index.specification(@gem1.full_name)
assert_equal @a1, @source_index.specification(@a1.full_name)
assert_nil @source_index.specification("foo-1.2.4")
end
@ -298,9 +489,11 @@ class TestGemSourceIndex < RubyGemTestCase
assert_equal [], @source_index.gems.keys.sort
use_ui @ui do
@source_index.update @uri
@source_index.update @uri, true
assert_equal @gem_names.split, @source_index.gems.keys.sort
assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
@c1_2.full_name],
@source_index.gems.keys.sort
end
paths = @fetcher.paths
@ -315,15 +508,42 @@ class TestGemSourceIndex < RubyGemTestCase
old_gem_conf = Gem.configuration
Gem.configuration = Gem::ConfigFile.new([])
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
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
"#{@b2.full_name}.gemspec.rz"
@fetcher.data[marshal_uri] = util_zip Marshal.dump(@b2)
use_ui @ui do
@source_index.update @uri, false
assert_equal latest_names, @source_index.gems.keys.sort
end
paths = @fetcher.paths
assert_equal "#{@gem_repo}/quick/latest_index.rz", paths.shift
assert_equal marshal_uri, paths.shift
assert paths.empty?, paths.join(', ')
ensure
Gem.configuration = old_gem_conf
end
def test_update_incremental_all
old_gem_conf = Gem.configuration
Gem.configuration = Gem::ConfigFile.new([])
quick_index = util_zip @all_gem_names.join("\n")
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
"#{@gem3.full_name}.gemspec.rz"
@fetcher.data[marshal_uri] = util_zip Marshal.dump(@gem3)
"#{@b2.full_name}.gemspec.rz"
@fetcher.data[marshal_uri] = util_zip Marshal.dump(@b2)
use_ui @ui do
@source_index.update @uri
@source_index.update @uri, true
assert_equal @all_gem_names, @source_index.gems.keys.sort
end
@ -345,13 +565,13 @@ class TestGemSourceIndex < RubyGemTestCase
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
"#{@gem3.full_name}.gemspec.rz"
"#{@b2.full_name}.gemspec.rz"
yaml_uri = "#{@gem_repo}/quick/#{@gem3.full_name}.gemspec.rz"
@fetcher.data[yaml_uri] = util_zip @gem3.to_yaml
yaml_uri = "#{@gem_repo}/quick/#{@b2.full_name}.gemspec.rz"
@fetcher.data[yaml_uri] = util_zip @b2.to_yaml
use_ui @ui do
@source_index.update @uri
@source_index.update @uri, true
assert_equal @all_gem_names, @source_index.gems.keys.sort
end
@ -374,16 +594,16 @@ class TestGemSourceIndex < RubyGemTestCase
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
"#{@gem3.full_name}.gemspec.rz"
marshal_data = Marshal.dump(@gem3)
"#{@b2.full_name}.gemspec.rz"
marshal_data = Marshal.dump(@b2)
marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr
@fetcher.data[marshal_uri] = util_zip marshal_data
yaml_uri = "#{@gem_repo}/quick/#{@gem3.full_name}.gemspec.rz"
@fetcher.data[yaml_uri] = util_zip @gem3.to_yaml
yaml_uri = "#{@gem_repo}/quick/#{@b2.full_name}.gemspec.rz"
@fetcher.data[yaml_uri] = util_zip @b2.to_yaml
use_ui @ui do
@source_index.update @uri
@source_index.update @uri, true
assert_equal @all_gem_names, @source_index.gems.keys.sort
end
@ -398,22 +618,48 @@ class TestGemSourceIndex < RubyGemTestCase
Gem.configuration = old_gem_conf
end
def test_update_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"
use_ui @ui do
@source_index.update uri, true
assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
@c1_2.full_name],
@source_index.gems.keys.sort
end
paths = @fetcher.paths
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
def test_update_with_missing
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
"#{@gem3.full_name}.gemspec.rz"
dumped = Marshal.dump @gem3
"#{@c1_2.full_name}.gemspec.rz"
dumped = Marshal.dump @c1_2
@fetcher.data[marshal_uri] = util_zip(dumped)
use_ui @ui do
@source_index.update_with_missing @uri, [@gem3.full_name]
@source_index.update_with_missing @uri, [@c1_2.full_name]
end
spec = @source_index.specification(@gem3.full_name)
spec = @source_index.specification(@c1_2.full_name)
# We don't care about the equality of undumped attributes
@gem3.files = spec.files
@gem3.loaded_from = spec.loaded_from
@c1_2.files = spec.files
@c1_2.loaded_from = spec.loaded_from
assert_equal @gem3, spec
assert_equal @c1_2, spec
end
def util_setup_bulk_fetch(compressed)
@ -427,3 +673,4 @@ class TestGemSourceIndex < RubyGemTestCase
end
end

Просмотреть файл

@ -25,7 +25,12 @@ class TestGemSourceInfoCache < RubyGemTestCase
@sic = Gem::SourceInfoCache.new
@sic.instance_variable_set :@fetcher, @fetcher
@si_new = Gem::SourceIndex.new
@sice_new = Gem::SourceInfoCacheEntry.new @si_new, 0
prep_cache_files @sic
@sic.reset_cache_data
end
def teardown
@ -35,8 +40,10 @@ class TestGemSourceInfoCache < RubyGemTestCase
def test_self_cache_refreshes
Gem.configuration.update_sources = true #true by default
source_index = Gem::SourceIndex.new 'key' => 'sys'
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = source_index.dump
si = Gem::SourceIndex.new
si.add_spec @a1
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
Gem.sources.replace %W[#{@gem_repo}]
@ -51,8 +58,10 @@ class TestGemSourceInfoCache < RubyGemTestCase
def test_self_cache_skips_refresh_based_on_configuration
Gem.configuration.update_sources = false
source_index = Gem::SourceIndex.new 'key' => 'sys'
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = source_index.dump
si = Gem::SourceIndex.new
si.add_spec @a1
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
Gem.sources.replace %w[#{@gem_repo}]
@ -66,20 +75,24 @@ class TestGemSourceInfoCache < RubyGemTestCase
end
def test_self_cache_data
source_index = Gem::SourceIndex.new 'key' => 'sys'
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = source_index.dump
si = Gem::SourceIndex.new
si.add_spec @a1
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
Gem::SourceInfoCache.instance_variable_set :@cache, nil
sice = Gem::SourceInfoCacheEntry.new source_index, 0
sice = Gem::SourceInfoCacheEntry.new si, 0
use_ui @ui do
assert_equal source_index.gems,
Gem::SourceInfoCache.cache_data[@gem_repo].source_index.gems
gems = Gem::SourceInfoCache.cache_data[@gem_repo].source_index.gems
gem_names = gems.map { |_, spec| spec.full_name }
assert_equal si.gems.map { |_,spec| spec.full_name }, gem_names
end
end
def test_cache_data
assert_equal [['key','sys']], @sic.cache_data.to_a.sort
assert_equal [[@gem_repo, @usr_sice]], @sic.cache_data.to_a.sort
end
def test_cache_data_dirty
@ -97,7 +110,14 @@ class TestGemSourceInfoCache < RubyGemTestCase
data = { @gem_repo => { 'totally' => 'borked' } }
[@sic.system_cache_file, @sic.user_cache_file].each do |fn|
cache_files = [
@sic.system_cache_file,
@sic.latest_system_cache_file,
@sic.user_cache_file,
@sic.latest_user_cache_file
]
cache_files.each do |fn|
FileUtils.mkdir_p File.dirname(fn)
open(fn, "wb") { |f| f.write Marshal.dump(data) }
end
@ -113,7 +133,9 @@ class TestGemSourceInfoCache < RubyGemTestCase
def test_cache_data_none_readable
FileUtils.chmod 0222, @sic.system_cache_file
FileUtils.chmod 0222, @sic.latest_system_cache_file
FileUtils.chmod 0222, @sic.user_cache_file
FileUtils.chmod 0222, @sic.latest_user_cache_file
return if (File.stat(@sic.system_cache_file).mode & 0222) != 0222
return if (File.stat(@sic.user_cache_file).mode & 0222) != 0222
# HACK for systems that don't support chmod
@ -129,6 +151,16 @@ class TestGemSourceInfoCache < RubyGemTestCase
assert_equal 'unable to locate a writable cache file', e.message
end
def test_cache_data_nonexistent
FileUtils.rm @sic.system_cache_file
FileUtils.rm @sic.latest_system_cache_file
FileUtils.rm @sic.user_cache_file
FileUtils.rm @sic.latest_user_cache_file
# TODO test verbose output
assert_equal [], @sic.cache_data.to_a.sort
end
def test_cache_data_repair
data = {
@gem_repo => {
@ -152,7 +184,8 @@ class TestGemSourceInfoCache < RubyGemTestCase
def test_cache_data_user_fallback
FileUtils.chmod 0444, @sic.system_cache_file
assert_equal [['key','usr']], @sic.cache_data.to_a.sort
assert_equal [[@gem_repo, @usr_sice]], @sic.cache_data.to_a.sort
end
def test_cache_file
@ -174,60 +207,118 @@ class TestGemSourceInfoCache < RubyGemTestCase
end
def test_flush
@sic.cache_data['key'] = 'new'
@sic.cache_data[@gem_repo] = @sice_new
@sic.update
@sic.flush
assert_equal [['key','new']], read_cache(@sic.system_cache_file).to_a.sort
assert_equal [[@gem_repo, @sice_new]],
read_cache(@sic.system_cache_file).to_a.sort
end
def test_latest_cache_data
util_make_gems
sice = Gem::SourceInfoCacheEntry.new @source_index, 0
@sic.set_cache_data @gem_repo => sice
latest = @sic.latest_cache_data
gems = latest[@gem_repo].source_index.search('a').map { |s| s.full_name }
assert_equal %w[a-2 a_evil-9], gems
end
def test_latest_cache_file
latest_cache_file = File.join File.dirname(@gemcache),
"latest_#{File.basename @gemcache}"
assert_equal latest_cache_file, @sic.latest_cache_file
end
def test_latest_system_cache_file
assert_equal File.join(Gem.dir, "latest_source_cache"),
@sic.latest_system_cache_file
end
def test_latest_user_cache_file
assert_equal @latest_usrcache, @sic.latest_user_cache_file
end
def test_read_system_cache
assert_equal [['key','sys']], @sic.cache_data.to_a.sort
assert_equal [[@gem_repo, @sys_sice]], @sic.cache_data.to_a.sort
end
def test_read_user_cache
FileUtils.chmod 0444, @sic.system_cache_file
FileUtils.chmod 0444, @sic.user_cache_file
FileUtils.chmod 0444, @sic.latest_user_cache_file
assert_equal [['key','usr']], @sic.cache_data.to_a.sort
@si = Gem::SourceIndex.new
@si.add_specs @a1, @a2
@sice = Gem::SourceInfoCacheEntry.new @si, 0
@sic.set_cache_data({ @gem_repo => @sice })
@sic.update
@sic.write_cache
@sic.reset_cache_data
user_cache_data = @sic.cache_data.to_a.sort
assert_equal 1, user_cache_data.length
user_cache_data = user_cache_data.first
assert_equal @gem_repo, user_cache_data.first
gems = user_cache_data.last.source_index.map { |_,spec| spec.full_name }
assert_equal [@a2.full_name], gems
end
def test_search
si = Gem::SourceIndex.new @gem1.full_name => @gem1
cache_data = {
@gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
}
si = Gem::SourceIndex.new
si.add_spec @a1
cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
@sic.instance_variable_set :@cache_data, cache_data
assert_equal [@gem1], @sic.search(//)
assert_equal [@a1], @sic.search(//)
end
def test_search_all
util_make_gems
sice = Gem::SourceInfoCacheEntry.new @source_index, 0
@sic.set_cache_data @gem_repo => sice
@sic.update
@sic.write_cache
@sic.reset_cache_data
gem_names = @sic.search(//, false, true).map { |spec| spec.full_name }
assert_equal %w[a-1 a-2 a_evil-9 c-1.2], gem_names
end
def test_search_dependency
si = Gem::SourceIndex.new @gem1.full_name => @gem1
cache_data = {
@gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
}
si = Gem::SourceIndex.new
si.add_spec @a1
cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
@sic.instance_variable_set :@cache_data, cache_data
dep = Gem::Dependency.new @gem1.name, @gem1.version
dep = Gem::Dependency.new @a1.name, @a1.version
assert_equal [@gem1], @sic.search(dep)
assert_equal [@a1], @sic.search(dep)
end
def test_search_no_matches
si = Gem::SourceIndex.new @gem1.full_name => @gem1
cache_data = {
@gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
}
si = Gem::SourceIndex.new
si.add_spec @a1
cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
@sic.instance_variable_set :@cache_data, cache_data
assert_equal [], @sic.search(/nonexistent/)
end
def test_search_no_matches_in_source
si = Gem::SourceIndex.new @gem1.full_name => @gem1
cache_data = {
@gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
}
si = Gem::SourceIndex.new
si.add_spec @a1
cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
@sic.instance_variable_set :@cache_data, cache_data
Gem.sources.replace %w[more-gems.example.com]
@ -235,13 +326,12 @@ class TestGemSourceInfoCache < RubyGemTestCase
end
def test_search_with_source
si = Gem::SourceIndex.new @gem1.full_name => @gem1
cache_data = {
@gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
}
si = Gem::SourceIndex.new
si.add_spec @a1
cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
@sic.instance_variable_set :@cache_data, cache_data
assert_equal [[@gem1, @gem_repo]],
assert_equal [[@a1, @gem_repo]],
@sic.search_with_source(//)
end
@ -254,45 +344,81 @@ class TestGemSourceInfoCache < RubyGemTestCase
end
def test_write_cache
@sic.cache_data['key'] = 'new'
@sic.cache_data[@gem_repo] = @sice_new
@sic.write_cache
assert_equal [['key', 'new']],
assert_equal [[@gem_repo, @sice_new]],
read_cache(@sic.system_cache_file).to_a.sort
assert_equal [['key', 'usr']],
assert_equal [[@gem_repo, @usr_sice]],
read_cache(@sic.user_cache_file).to_a.sort
end
def test_write_cache_user
FileUtils.chmod 0444, @sic.system_cache_file
@sic.set_cache_data({'key' => 'new'})
@sic.set_cache_data({@gem_repo => @sice_new})
@sic.update
@sic.write_cache
assert_equal [['key', 'sys']], read_cache(@sic.system_cache_file).to_a.sort
assert_equal [['key', 'new']], read_cache(@sic.user_cache_file).to_a.sort
assert File.exist?(@sic.user_cache_file), 'user_cache_file'
assert File.exist?(@sic.latest_user_cache_file),
'latest_user_cache_file exists'
assert_equal [[@gem_repo, @sys_sice]],
read_cache(@sic.system_cache_file).to_a.sort
assert_equal [[@gem_repo, @sice_new]],
read_cache(@sic.user_cache_file).to_a.sort
end
def test_write_cache_user_from_scratch
FileUtils.rm_rf @sic.user_cache_file
FileUtils.rm_rf @sic.latest_user_cache_file
FileUtils.chmod 0444, @sic.system_cache_file
@sic.set_cache_data({'key' => 'new'})
FileUtils.chmod 0444, @sic.latest_system_cache_file
@si = Gem::SourceIndex.new
@si.add_specs @a1, @a2
@sice = Gem::SourceInfoCacheEntry.new @si, 0
@sic.set_cache_data({ @gem_repo => @sice })
@sic.update
@sic.write_cache
assert_equal [['key', 'sys']], read_cache(@sic.system_cache_file).to_a.sort
assert_equal [['key', 'new']], read_cache(@sic.user_cache_file).to_a.sort
assert File.exist?(@sic.user_cache_file), 'system_cache_file'
assert File.exist?(@sic.latest_user_cache_file),
'latest_system_cache_file'
user_cache_data = read_cache(@sic.user_cache_file).to_a.sort
assert_equal 1, user_cache_data.length
user_cache_data = user_cache_data.first
assert_equal @gem_repo, user_cache_data.first
gems = user_cache_data.last.source_index.map { |_,spec| spec.full_name }
assert_equal [@a1.full_name, @a2.full_name], gems
user_cache_data = read_cache(@sic.latest_user_cache_file).to_a.sort
assert_equal 1, user_cache_data.length
user_cache_data = user_cache_data.first
assert_equal @gem_repo, user_cache_data.first
gems = user_cache_data.last.source_index.map { |_,spec| spec.full_name }
assert_equal [@a2.full_name], gems
end
def test_write_cache_user_no_directory
FileUtils.rm_rf File.dirname(@sic.user_cache_file)
FileUtils.chmod 0444, @sic.system_cache_file
@sic.set_cache_data({'key' => 'new'})
@sic.set_cache_data({ @gem_repo => @sice_new })
@sic.update
@sic.write_cache
assert_equal [['key','sys']], read_cache(@sic.system_cache_file).to_a.sort
assert_equal [['key','new']], read_cache(@sic.user_cache_file).to_a.sort
assert_equal [[@gem_repo, @sys_sice]],
read_cache(@sic.system_cache_file).to_a.sort
assert_equal [[@gem_repo, @sice_new]],
read_cache(@sic.user_cache_file).to_a.sort
end
end

Просмотреть файл

@ -9,37 +9,68 @@ class TestGemSourceInfoCacheEntry < RubyGemTestCase
util_setup_fake_fetcher
@si = Gem::SourceIndex.new @gem1.full_name => @gem1.name
@si = Gem::SourceIndex.new
@si.add_spec @a1
@sic_e = Gem::SourceInfoCacheEntry.new @si, @si.dump.size
end
def test_refresh
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}.Z"] =
proc { raise Exception }
proc { raise }
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = @si.dump
assert_nothing_raised do
@sic_e.refresh @gem_repo
use_ui @ui do
@sic_e.refresh @gem_repo, true
end
end
def test_refresh_all
@si.add_spec @a2
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
sic_e = Gem::SourceInfoCacheEntry.new Gem::SourceIndex.new, 0
use_ui @ui do
sic_e.refresh @gem_repo, false
end
assert_equal [a2_name], sic_e.source_index.map { |n,| n }.sort
use_ui @ui do
sic_e.refresh @gem_repo, true
end
assert_equal [a1_name, a2_name], sic_e.source_index.map { |n,| n }.sort
end
def test_refresh_bad_uri
assert_raise URI::BadURIError do
@sic_e.refresh 'gems.example.com'
@sic_e.refresh 'gems.example.com', true
end
end
def test_refresh_update
si = Gem::SourceIndex.new @gem1.full_name => @gem1,
@gem2.full_name => @gem2
si = Gem::SourceIndex.new
si.add_spec @a1
si.add_spec @b2
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
use_ui @ui do
@sic_e.refresh @gem_repo
@sic_e.refresh @gem_repo, true
end
new_gem = @sic_e.source_index.specification(@gem2.full_name)
assert_equal @gem2.full_name, new_gem.full_name
new_gem = @sic_e.source_index.specification(@b2.full_name)
assert_equal @b2.full_name, new_gem.full_name
end
end

Просмотреть файл

@ -0,0 +1,43 @@
require File.join(File.expand_path(File.dirname(__FILE__)),
'gem_installer_test_case')
require 'rubygems/uninstaller'
class TestGemUninstaller < GemInstallerTestCase
def setup
super
ui = MockGemUi.new
util_setup_gem ui
use_ui ui do
@installer.install
end
end
def test_remove_executables_force_keep
uninstaller = Gem::Uninstaller.new nil, :executables => false
use_ui @ui do
uninstaller.remove_executables @spec
end
assert_equal true, File.exist?(File.join(@gemhome, 'bin', 'executable'))
assert_equal "Executables and scripts will remain installed.\n", @ui.output
end
def test_remove_executables_force_remove
uninstaller = Gem::Uninstaller.new nil, :executables => true
use_ui @ui do
uninstaller.remove_executables @spec
end
assert_equal "Removing executable\n", @ui.output
assert_equal false, File.exist?(File.join(@gemhome, 'bin', 'executable'))
end
end