mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Import RubyGems 1.1.0
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@15873 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
dc8359969e
commit
8cc45aae94
82 changed files with 5776 additions and 2928 deletions
|
@ -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>
|
Tue Apr 1 03:20:40 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* configure.in (RUBY_SETJMP, RUBY_LONGJMP, RUBY_JMP_BUF): prefers
|
* configure.in (RUBY_SETJMP, RUBY_LONGJMP, RUBY_JMP_BUF): prefers
|
||||||
|
|
13
bin/gem
13
bin/gem
|
@ -7,11 +7,12 @@
|
||||||
|
|
||||||
require 'rubygems'
|
require 'rubygems'
|
||||||
require 'rubygems/gem_runner'
|
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
|
unless required_version.satisfied_by? Gem.ruby_version then
|
||||||
abort "Expected Ruby Version #{required_version}, was #{RUBY_VERSION}"
|
abort "Expected Ruby Version #{required_version}, was #{Gem.ruby_version}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# We need to preserve the original ARGV to use for passing gem options
|
# 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.
|
# it...its for the source building process.
|
||||||
args = !ARGV.include?("--") ? ARGV.clone : ARGV[0...ARGV.index("--")]
|
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
|
||||||
|
|
||||||
|
|
347
gem_prelude.rb
347
gem_prelude.rb
|
@ -1,207 +1,214 @@
|
||||||
|
# depends on: array.rb dir.rb env.rb file.rb hash.rb module.rb regexp.rb
|
||||||
|
|
||||||
# empty gem_prelude.rb
|
# empty gem_prelude.rb
|
||||||
#
|
#
|
||||||
# p Gem::Enable
|
# p Gem::Enable
|
||||||
|
|
||||||
if defined?(Gem::Enable) && Gem::Enable
|
if defined?(Gem::Enable) && Gem::Enable then
|
||||||
#t = Time.now
|
|
||||||
|
|
||||||
module Kernel
|
|
||||||
|
|
||||||
def gem(gem_name, *version_requirements)
|
module Kernel
|
||||||
Gem.push_gem_version_on_load_path(gem_name, *version_requirements)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
def gem(gem_name, *version_requirements)
|
||||||
|
Gem.push_gem_version_on_load_path(gem_name, *version_requirements)
|
||||||
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)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
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
|
class << self
|
||||||
def load_full_rubygems_library
|
|
||||||
class << Gem
|
def default_dir
|
||||||
Gem.methods(false).each do |method_name|
|
if defined? RUBY_FRAMEWORK_VERSION
|
||||||
undef_method method_name
|
return File.join(File.dirname(ConfigMap[:sitedir]), "Gems")
|
||||||
end
|
else
|
||||||
|
File.join(ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version])
|
||||||
end
|
end
|
||||||
|
|
||||||
Kernel.send :undef_method, :gem
|
|
||||||
|
|
||||||
$".delete File.join(Gem::ConfigMap[:libdir], 'ruby',
|
|
||||||
Gem::ConfigMap[:ruby_version], 'rubygems.rb')
|
|
||||||
|
|
||||||
require 'rubygems'
|
|
||||||
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)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
GemPaths = {}
|
module QuickLoader
|
||||||
GemVersions = {}
|
|
||||||
|
class << self
|
||||||
def push_gem_version_on_load_path(gem_name, *version_requirements)
|
def load_full_rubygems_library
|
||||||
if version_requirements.empty?
|
class << Gem
|
||||||
unless GemPaths.has_key?(gem_name)
|
Gem.methods(false).each do |method_name|
|
||||||
raise LoadError.new("Could not find RubyGem #{gem_name} (>= 0)\n")
|
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
|
end
|
||||||
# highest version gems already active
|
end
|
||||||
return false
|
|
||||||
else
|
GemPaths = {}
|
||||||
if version_requirements.length > 1
|
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
|
QuickLoader.load_full_rubygems_library
|
||||||
return gem(gem_name, *version_requirements)
|
gem(gem_name, *version_requirements)
|
||||||
end
|
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
|
||||||
end
|
|
||||||
|
|
||||||
def calculate_integers_for_gem_version(gem_version)
|
def calculate_integers_for_gem_version(gem_version)
|
||||||
numbers = gem_version.split(".").collect {|n| n.to_i}
|
numbers = gem_version.split(".").collect {|n| n.to_i}
|
||||||
numbers.pop while numbers.last == 0
|
numbers.pop while numbers.last == 0
|
||||||
numbers << 0 if numbers.empty?
|
numbers << 0 if numbers.empty?
|
||||||
numbers
|
numbers
|
||||||
end
|
end
|
||||||
|
|
||||||
def push_all_highest_version_gems_on_load_path
|
def push_all_highest_version_gems_on_load_path
|
||||||
Gem.path.each do |path|
|
Gem.path.each do |path|
|
||||||
gems_directory = File.join(path, "gems")
|
gems_directory = File.join(path, "gems")
|
||||||
if File.exist?(gems_directory)
|
if File.exist?(gems_directory)
|
||||||
Dir.entries(gems_directory).each do |gem_directory_name|
|
Dir.entries(gems_directory).each do |gem_directory_name|
|
||||||
next if gem_directory_name == "." || gem_directory_name == ".."
|
next if gem_directory_name == "." || gem_directory_name == ".."
|
||||||
dash = gem_directory_name.rindex("-")
|
dash = gem_directory_name.rindex("-")
|
||||||
next if dash.nil?
|
next if dash.nil?
|
||||||
gem_name = gem_directory_name[0...dash]
|
gem_name = gem_directory_name[0...dash]
|
||||||
current_version = GemVersions[gem_name]
|
current_version = GemVersions[gem_name]
|
||||||
new_version = calculate_integers_for_gem_version(gem_directory_name[dash+1..-1])
|
new_version = calculate_integers_for_gem_version(gem_directory_name[dash+1..-1])
|
||||||
if current_version
|
if current_version
|
||||||
if (current_version <=> new_version) == -1
|
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
|
GemVersions[gem_name] = new_version
|
||||||
GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
|
GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
|
||||||
end
|
end
|
||||||
else
|
|
||||||
GemVersions[gem_name] = new_version
|
|
||||||
GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
require_paths = []
|
require_paths = []
|
||||||
GemPaths.values.each do |path|
|
|
||||||
if File.exist?(File.join(path, ".require_paths"))
|
GemPaths.values.each do |path|
|
||||||
require_paths.concat(File.read(File.join(path, ".require_paths")).split.map {|require_path| File.join(path, require_path)})
|
if File.exist?(File.join(path, ".require_paths"))
|
||||||
else
|
require_paths.concat(File.read(File.join(path, ".require_paths")).split.map {|require_path| File.join(path, require_path)})
|
||||||
require_paths << File.join(path, "bin") if File.exist?(File.join(path, "bin"))
|
else
|
||||||
require_paths << File.join(path, "lib") if File.exist?(File.join(path, "lib"))
|
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
|
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
|
end
|
||||||
|
|
||||||
# "tag" the first require_path inserted into the $LOAD_PATH to enable
|
def const_missing(constant)
|
||||||
# indexing correctly with rubygems proper when it inserts an explicitly
|
QuickLoader.load_full_rubygems_library
|
||||||
# gem version
|
Gem.const_get(constant)
|
||||||
unless require_paths.empty?
|
end
|
||||||
require_paths.first.instance_variable_set(:@gem_prelude_index, true)
|
|
||||||
|
def method_missing(method, *args, &block)
|
||||||
|
QuickLoader.load_full_rubygems_library
|
||||||
|
super unless Gem.respond_to?(method)
|
||||||
|
Gem.send(method, *args, &block)
|
||||||
end
|
end
|
||||||
# gem directories must come after -I and ENV['RUBYLIB']
|
|
||||||
$:[$:.index(ConfigMap[:sitelibdir]),0] = require_paths
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def const_missing(constant)
|
extend QuickLoader
|
||||||
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
|
|
||||||
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
|
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
|
|
||||||
|
|
1063
lib/rubygems.rb
1063
lib/rubygems.rb
File diff suppressed because it is too large
Load diff
|
@ -65,13 +65,20 @@ EOM
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_package
|
def write_package
|
||||||
Package.open(@spec.file_name, "w", @signer) do |pkg|
|
open @spec.file_name, 'wb' do |gem_io|
|
||||||
pkg.metadata = @spec.to_yaml
|
Gem::Package.open gem_io, 'w', @signer do |pkg|
|
||||||
@spec.files.each do |file|
|
pkg.metadata = @spec.to_yaml
|
||||||
next if File.directory? file
|
|
||||||
pkg.add_file_simple(file, File.stat(@spec.file_name).mode & 0777,
|
@spec.files.each do |file|
|
||||||
File.size(file)) do |os|
|
next if File.directory? file
|
||||||
os.write File.open(file, "rb"){|f|f.read}
|
|
||||||
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -123,6 +123,7 @@ module Gem
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def load_and_instantiate(command_name)
|
def load_and_instantiate(command_name)
|
||||||
command_name = command_name.to_s
|
command_name = command_name.to_s
|
||||||
retried = false
|
retried = false
|
||||||
|
|
|
@ -2,92 +2,90 @@ require 'rubygems/command'
|
||||||
require 'rubygems/source_index'
|
require 'rubygems/source_index'
|
||||||
require 'rubygems/dependency_list'
|
require 'rubygems/dependency_list'
|
||||||
|
|
||||||
module Gem
|
class Gem::Commands::CleanupCommand < Gem::Command
|
||||||
module Commands
|
|
||||||
class CleanupCommand < Command
|
def initialize
|
||||||
def initialize
|
super 'cleanup',
|
||||||
super(
|
|
||||||
'cleanup',
|
|
||||||
'Clean up old versions of installed gems in the local repository',
|
'Clean up old versions of installed gems in the local repository',
|
||||||
{
|
:force => false, :test => false, :install_dir => Gem.dir
|
||||||
:force => false,
|
|
||||||
:test => false,
|
|
||||||
:install_dir => Gem.dir
|
|
||||||
})
|
|
||||||
add_option('-d', '--dryrun', "") do |value, options|
|
|
||||||
options[:dryrun] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def arguments # :nodoc:
|
add_option('-d', '--dryrun', "") do |value, options|
|
||||||
"GEMNAME name of gem to cleanup"
|
options[:dryrun] = true
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def defaults_str # :nodoc:
|
def arguments # :nodoc:
|
||||||
"--no-dryrun"
|
"GEMNAME name of gem to cleanup"
|
||||||
end
|
end
|
||||||
|
|
||||||
def usage # :nodoc:
|
def defaults_str # :nodoc:
|
||||||
"#{program_name} [GEMNAME ...]"
|
"--no-dryrun"
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def usage # :nodoc:
|
||||||
say "Cleaning up installed gems..."
|
"#{program_name} [GEMNAME ...]"
|
||||||
srcindex = Gem::SourceIndex.from_installed_gems
|
end
|
||||||
primary_gems = {}
|
|
||||||
|
|
||||||
srcindex.each do |name, spec|
|
def execute
|
||||||
if primary_gems[spec.name].nil? or primary_gems[spec.name].version < spec.version
|
say "Cleaning up installed gems..."
|
||||||
primary_gems[spec.name] = spec
|
primary_gems = {}
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
gems_to_cleanup = []
|
Gem.source_index.each do |name, spec|
|
||||||
|
if primary_gems[spec.name].nil? or
|
||||||
unless options[:args].empty? then
|
primary_gems[spec.name].version < spec.version then
|
||||||
options[:args].each do |gem_name|
|
primary_gems[spec.name] = spec
|
||||||
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"
|
|
||||||
end
|
end
|
||||||
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -25,19 +25,18 @@ class Gem::Commands::EnvironmentCommand < Gem::Command
|
||||||
def execute
|
def execute
|
||||||
out = ''
|
out = ''
|
||||||
arg = options[:args][0]
|
arg = options[:args][0]
|
||||||
if begins?("packageversion", arg) then
|
case arg
|
||||||
|
when /^packageversion/ then
|
||||||
out << Gem::RubyGemsPackageVersion
|
out << Gem::RubyGemsPackageVersion
|
||||||
elsif begins?("version", arg) then
|
when /^version/ then
|
||||||
out << Gem::RubyGemsVersion
|
out << Gem::RubyGemsVersion
|
||||||
elsif begins?("gemdir", arg) then
|
when /^gemdir/, /^gemhome/, /^home/, /^GEM_HOME/ then
|
||||||
out << Gem.dir
|
out << Gem.dir
|
||||||
elsif begins?("gempath", arg) then
|
when /^gempath/, /^path/, /^GEM_PATH/ then
|
||||||
out << Gem.path.join("\n")
|
out << Gem.path.join(File::PATH_SEPARATOR)
|
||||||
elsif begins?("remotesources", arg) then
|
when /^remotesources/ then
|
||||||
out << Gem.sources.join("\n")
|
out << Gem.sources.join("\n")
|
||||||
elsif arg then
|
when nil then
|
||||||
fail Gem::CommandLineError, "Unknown enviroment option [#{arg}]"
|
|
||||||
else
|
|
||||||
out = "RubyGems Environment:\n"
|
out = "RubyGems Environment:\n"
|
||||||
|
|
||||||
out << " - RUBYGEMS VERSION: #{Gem::RubyGemsVersion} (#{Gem::RubyGemsPackageVersion})\n"
|
out << " - RUBYGEMS VERSION: #{Gem::RubyGemsVersion} (#{Gem::RubyGemsPackageVersion})\n"
|
||||||
|
@ -75,6 +74,9 @@ class Gem::Commands::EnvironmentCommand < Gem::Command
|
||||||
Gem.sources.each do |s|
|
Gem.sources.each do |s|
|
||||||
out << " - #{s}\n"
|
out << " - #{s}\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
fail Gem::CommandLineError, "Unknown enviroment option [#{arg}]"
|
||||||
end
|
end
|
||||||
say out
|
say out
|
||||||
true
|
true
|
||||||
|
|
|
@ -44,17 +44,15 @@ class Gem::Commands::FetchCommand < Gem::Command
|
||||||
|
|
||||||
spec, source_uri = specs_and_sources.last
|
spec, source_uri = specs_and_sources.last
|
||||||
|
|
||||||
gem_file = "#{spec.full_name}.gem"
|
if spec.nil? then
|
||||||
|
alert_error "Could not find #{gem_name} in any repository"
|
||||||
gem_path = File.join source_uri, 'gems', gem_file
|
next
|
||||||
|
|
||||||
gem = Gem::RemoteFetcher.fetcher.fetch_path gem_path
|
|
||||||
|
|
||||||
File.open gem_file, 'wb' do |fp|
|
|
||||||
fp.write gem
|
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -62,13 +62,15 @@ class Gem::Commands::InstallCommand < Gem::Command
|
||||||
:install_dir => options[:install_dir],
|
:install_dir => options[:install_dir],
|
||||||
:security_policy => options[:security_policy],
|
:security_policy => options[:security_policy],
|
||||||
:wrappers => options[:wrappers],
|
:wrappers => options[:wrappers],
|
||||||
|
:bin_dir => options[:bin_dir]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit_code = 0
|
||||||
|
|
||||||
get_all_gem_names.each do |gem_name|
|
get_all_gem_names.each do |gem_name|
|
||||||
begin
|
begin
|
||||||
inst = Gem::DependencyInstaller.new gem_name, options[:version],
|
inst = Gem::DependencyInstaller.new install_options
|
||||||
install_options
|
inst.install gem_name, options[:version]
|
||||||
inst.install
|
|
||||||
|
|
||||||
inst.installed_gems.each do |spec|
|
inst.installed_gems.each do |spec|
|
||||||
say "Successfully installed #{spec.full_name}"
|
say "Successfully installed #{spec.full_name}"
|
||||||
|
@ -77,8 +79,10 @@ class Gem::Commands::InstallCommand < Gem::Command
|
||||||
installed_gems.push(*inst.installed_gems)
|
installed_gems.push(*inst.installed_gems)
|
||||||
rescue Gem::InstallError => e
|
rescue Gem::InstallError => e
|
||||||
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
|
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
|
||||||
|
exit_code |= 1
|
||||||
rescue Gem::GemNotFoundException => e
|
rescue Gem::GemNotFoundException => e
|
||||||
alert_error e.message
|
alert_error e.message
|
||||||
|
exit_code |= 2
|
||||||
# rescue => e
|
# rescue => e
|
||||||
# # TODO: Fix this handle to allow the error to propagate to
|
# # TODO: Fix this handle to allow the error to propagate to
|
||||||
# # the top level handler. Examine the other errors as
|
# # the top level handler. Examine the other errors as
|
||||||
|
@ -121,6 +125,8 @@ class Gem::Commands::InstallCommand < Gem::Command
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
raise Gem::SystemExitException, exit_code
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,10 +6,8 @@ module Gem
|
||||||
class ListCommand < QueryCommand
|
class ListCommand < QueryCommand
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
super(
|
super 'list', 'Display gems whose name starts with STRING'
|
||||||
'list',
|
|
||||||
'Display all gems whose name starts with STRING'
|
|
||||||
)
|
|
||||||
remove_option('--name-matches')
|
remove_option('--name-matches')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ require 'yaml'
|
||||||
require 'zlib'
|
require 'zlib'
|
||||||
|
|
||||||
require 'rubygems/command'
|
require 'rubygems/command'
|
||||||
require 'rubygems/gem_open_uri'
|
require 'open-uri'
|
||||||
|
|
||||||
class Gem::Commands::MirrorCommand < Gem::Command
|
class Gem::Commands::MirrorCommand < Gem::Command
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,25 @@
|
||||||
require 'rubygems/command'
|
require 'rubygems/command'
|
||||||
require 'rubygems/local_remote_options'
|
require 'rubygems/local_remote_options'
|
||||||
require 'rubygems/source_info_cache'
|
require 'rubygems/source_info_cache'
|
||||||
|
require 'rubygems/version_option'
|
||||||
|
|
||||||
class Gem::Commands::QueryCommand < Gem::Command
|
class Gem::Commands::QueryCommand < Gem::Command
|
||||||
|
|
||||||
include Gem::LocalRemoteOptions
|
include Gem::LocalRemoteOptions
|
||||||
|
include Gem::VersionOption
|
||||||
|
|
||||||
def initialize(name = 'query',
|
def initialize(name = 'query',
|
||||||
summary = 'Query gem information in local or remote repositories')
|
summary = 'Query gem information in local or remote repositories')
|
||||||
super name, summary,
|
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',
|
add_option('-n', '--name-matches REGEXP',
|
||||||
'Name of gem(s) to query on matches the',
|
'Name of gem(s) to query on matches the',
|
||||||
|
@ -28,33 +38,70 @@ class Gem::Commands::QueryCommand < Gem::Command
|
||||||
options[:details] = false unless value
|
options[:details] = false unless value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
add_option('-a', '--all',
|
||||||
|
'Display all gem versions') do |value, options|
|
||||||
|
options[:all] = value
|
||||||
|
end
|
||||||
|
|
||||||
add_local_remote_options
|
add_local_remote_options
|
||||||
end
|
end
|
||||||
|
|
||||||
def defaults_str # :nodoc:
|
def defaults_str # :nodoc:
|
||||||
"--local --name-matches '.*' --no-details --versions"
|
"--local --name-matches // --no-details --versions --no-installed"
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
|
exit_code = 0
|
||||||
|
|
||||||
name = options[:name]
|
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
|
if local? then
|
||||||
say
|
say
|
||||||
say "*** LOCAL GEMS ***"
|
say "*** LOCAL GEMS ***"
|
||||||
say
|
say
|
||||||
output_query_results Gem.cache.search(name)
|
|
||||||
|
output_query_results Gem.source_index.search(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
if remote? then
|
if remote? then
|
||||||
say
|
say
|
||||||
say "*** REMOTE GEMS ***"
|
say "*** REMOTE GEMS ***"
|
||||||
say
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
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)
|
def output_query_results(gemspecs)
|
||||||
output = []
|
output = []
|
||||||
gem_list_with_version = {}
|
gem_list_with_version = {}
|
||||||
|
@ -98,7 +145,7 @@ class Gem::Commands::QueryCommand < Gem::Command
|
||||||
|
|
||||||
##
|
##
|
||||||
# Used for wrapping and indenting text
|
# Used for wrapping and indenting text
|
||||||
#
|
|
||||||
def format_text(text, wrap, indent=0)
|
def format_text(text, wrap, indent=0)
|
||||||
result = []
|
result = []
|
||||||
work = text.dup
|
work = text.dup
|
||||||
|
|
|
@ -39,8 +39,11 @@ class Gem::Commands::SourcesCommand < Gem::Command
|
||||||
options[:list] = !(options[:add] || options[:remove] || options[:clear_all] || options[:update])
|
options[:list] = !(options[:add] || options[:remove] || options[:clear_all] || options[:update])
|
||||||
|
|
||||||
if options[:clear_all] then
|
if options[:clear_all] then
|
||||||
remove_cache_file("user", Gem::SourceInfoCache.user_cache_file)
|
sic = Gem::SourceInfoCache
|
||||||
remove_cache_file("system", Gem::SourceInfoCache.system_cache_file)
|
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
|
end
|
||||||
|
|
||||||
if options[:add] then
|
if options[:add] then
|
||||||
|
@ -48,7 +51,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
|
||||||
|
|
||||||
sice = Gem::SourceInfoCacheEntry.new nil, nil
|
sice = Gem::SourceInfoCacheEntry.new nil, nil
|
||||||
begin
|
begin
|
||||||
sice.refresh source_uri
|
sice.refresh source_uri, true
|
||||||
|
|
||||||
Gem::SourceInfoCache.cache_data[source_uri] = sice
|
Gem::SourceInfoCache.cache_data[source_uri] = sice
|
||||||
Gem::SourceInfoCache.cache.update
|
Gem::SourceInfoCache.cache.update
|
||||||
|
@ -66,7 +69,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
|
||||||
end
|
end
|
||||||
|
|
||||||
if options[:update] then
|
if options[:update] then
|
||||||
Gem::SourceInfoCache.cache.refresh
|
Gem::SourceInfoCache.cache.refresh true
|
||||||
Gem::SourceInfoCache.cache.flush
|
Gem::SourceInfoCache.cache.flush
|
||||||
|
|
||||||
say "source cache successfully updated"
|
say "source cache successfully updated"
|
||||||
|
@ -78,6 +81,11 @@ class Gem::Commands::SourcesCommand < Gem::Command
|
||||||
unless Gem.sources.include? source_uri then
|
unless Gem.sources.include? source_uri then
|
||||||
say "source #{source_uri} not present in cache"
|
say "source #{source_uri} not present in cache"
|
||||||
else
|
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_data.delete source_uri
|
||||||
Gem::SourceInfoCache.cache.update
|
Gem::SourceInfoCache.cache.update
|
||||||
Gem::SourceInfoCache.cache.flush
|
Gem::SourceInfoCache.cache.flush
|
||||||
|
@ -100,11 +108,12 @@ class Gem::Commands::SourcesCommand < Gem::Command
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def remove_cache_file(desc, fn)
|
def remove_cache_file(desc, path)
|
||||||
FileUtils.rm_rf fn rescue nil
|
FileUtils.rm_rf path
|
||||||
if ! File.exist?(fn)
|
|
||||||
|
if not File.exist?(path) then
|
||||||
say "*** Removed #{desc} source cache ***"
|
say "*** Removed #{desc} source cache ***"
|
||||||
elsif ! File.writable?(fn)
|
elsif not File.writable?(path) then
|
||||||
say "*** Unable to remove #{desc} source cache (write protected) ***"
|
say "*** Unable to remove #{desc} source cache (write protected) ***"
|
||||||
else
|
else
|
||||||
say "*** Unable to remove #{desc} source cache ***"
|
say "*** Unable to remove #{desc} source cache ***"
|
||||||
|
|
|
@ -3,6 +3,7 @@ require 'rubygems/command'
|
||||||
require 'rubygems/local_remote_options'
|
require 'rubygems/local_remote_options'
|
||||||
require 'rubygems/version_option'
|
require 'rubygems/version_option'
|
||||||
require 'rubygems/source_info_cache'
|
require 'rubygems/source_info_cache'
|
||||||
|
require 'rubygems/format'
|
||||||
|
|
||||||
class Gem::Commands::SpecificationCommand < Gem::Command
|
class Gem::Commands::SpecificationCommand < Gem::Command
|
||||||
|
|
||||||
|
@ -41,13 +42,16 @@ class Gem::Commands::SpecificationCommand < Gem::Command
|
||||||
gem = get_one_gem_name
|
gem = get_one_gem_name
|
||||||
|
|
||||||
if local? then
|
if local? then
|
||||||
source_index = Gem::SourceIndex.from_installed_gems
|
if File.exist? gem then
|
||||||
specs.push(*source_index.search(/\A#{gem}\z/, options[:version]))
|
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
|
end
|
||||||
|
|
||||||
if remote? then
|
if remote? then
|
||||||
alert_warning "Remote information is not complete\n\n"
|
|
||||||
|
|
||||||
Gem::SourceInfoCache.cache_data.each do |_,sice|
|
Gem::SourceInfoCache.cache_data.each do |_,sice|
|
||||||
specs.push(*sice.source_index.search(gem, options[:version]))
|
specs.push(*sice.source_index.search(gem, options[:version]))
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,6 +35,11 @@ module Gem
|
||||||
options[:install_dir] = File.expand_path(value)
|
options[:install_dir] = File.expand_path(value)
|
||||||
end
|
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_version_option
|
||||||
add_platform_option
|
add_platform_option
|
||||||
end
|
end
|
||||||
|
@ -54,7 +59,13 @@ module Gem
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
get_all_gem_names.each do |gem_name|
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,6 +38,7 @@ class Gem::Commands::UnpackCommand < Gem::Command
|
||||||
def execute
|
def execute
|
||||||
gemname = get_one_gem_name
|
gemname = get_one_gem_name
|
||||||
path = get_path(gemname, options[:version])
|
path = get_path(gemname, options[:version])
|
||||||
|
|
||||||
if path then
|
if path then
|
||||||
basename = File.basename(path).sub(/\.gem$/, '')
|
basename = File.basename(path).sub(/\.gem$/, '')
|
||||||
target_dir = File.expand_path File.join(options[:target], basename)
|
target_dir = File.expand_path File.join(options[:target], basename)
|
||||||
|
@ -66,16 +67,27 @@ class Gem::Commands::UnpackCommand < Gem::Command
|
||||||
# source directories?
|
# source directories?
|
||||||
def get_path(gemname, version_req)
|
def get_path(gemname, version_req)
|
||||||
return gemname if gemname =~ /\.gem$/i
|
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
|
selected = specs.sort_by { |s| s.version }.last
|
||||||
|
|
||||||
return nil if selected.nil?
|
return nil if selected.nil?
|
||||||
|
|
||||||
# We expect to find (basename).gem in the 'cache' directory.
|
# We expect to find (basename).gem in the 'cache' directory.
|
||||||
# Furthermore, the name match must be exact (ignoring case).
|
# Furthermore, the name match must be exact (ignoring case).
|
||||||
if gemname =~ /^#{selected.name}$/i
|
if gemname =~ /^#{selected.name}$/i
|
||||||
filename = selected.full_name + '.gem'
|
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
|
else
|
||||||
return nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
require 'rubygems/command'
|
require 'rubygems/command'
|
||||||
|
require 'rubygems/command_manager'
|
||||||
require 'rubygems/install_update_options'
|
require 'rubygems/install_update_options'
|
||||||
require 'rubygems/local_remote_options'
|
require 'rubygems/local_remote_options'
|
||||||
require 'rubygems/source_info_cache'
|
require 'rubygems/source_info_cache'
|
||||||
require 'rubygems/version_option'
|
require 'rubygems/version_option'
|
||||||
|
require 'rubygems/commands/install_command'
|
||||||
|
|
||||||
class Gem::Commands::UpdateCommand < Gem::Command
|
class Gem::Commands::UpdateCommand < Gem::Command
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ class Gem::Commands::UpdateCommand < Gem::Command
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
if options[:system] then
|
if options[:system] then
|
||||||
say "Updating RubyGems..."
|
say "Updating RubyGems"
|
||||||
|
|
||||||
unless options[:args].empty? then
|
unless options[:args].empty? then
|
||||||
fail "No gem names are allowed with the --system option"
|
fail "No gem names are allowed with the --system option"
|
||||||
|
@ -53,10 +55,10 @@ class Gem::Commands::UpdateCommand < Gem::Command
|
||||||
|
|
||||||
options[:args] = ["rubygems-update"]
|
options[:args] = ["rubygems-update"]
|
||||||
else
|
else
|
||||||
say "Updating installed gems..."
|
say "Updating installed gems"
|
||||||
end
|
end
|
||||||
|
|
||||||
hig = highest_installed_gems = {}
|
hig = {}
|
||||||
|
|
||||||
Gem::SourceIndex.from_installed_gems.each do |name, spec|
|
Gem::SourceIndex.from_installed_gems.each do |name, spec|
|
||||||
if hig[spec.name].nil? or hig[spec.name].version < spec.version then
|
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
|
||||||
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
|
remote_gemspecs = Gem::SourceInfoCache.search pattern
|
||||||
which_to_update(highest_installed_gems, remote_gemspecs)
|
|
||||||
else
|
|
||||||
options[:args]
|
|
||||||
end
|
|
||||||
|
|
||||||
options[:domain] = :remote # install from remote source
|
gems_to_update = which_to_update hig, remote_gemspecs
|
||||||
|
|
||||||
|
updated = []
|
||||||
|
|
||||||
# HACK use the real API
|
# HACK use the real API
|
||||||
install_command = Gem::CommandManager.instance['install']
|
|
||||||
|
|
||||||
gems_to_update.uniq.sort.each do |name|
|
gems_to_update.uniq.sort.each do |name|
|
||||||
say "Attempting remote update of #{name}"
|
next if updated.any? { |spec| spec.name == name }
|
||||||
options[:args] = [name]
|
say "Updating #{name}"
|
||||||
options[:ignore_dependencies] = true # HACK skip seen gems instead
|
installer = Gem::DependencyInstaller.new options
|
||||||
install_command.merge_options(options)
|
installer.install name
|
||||||
install_command.execute
|
installer.installed_gems.each do |spec|
|
||||||
|
updated << spec
|
||||||
|
say "Successfully installed #{spec.full_name}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if gems_to_update.include? "rubygems-update" then
|
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
|
say "RubyGems system software updated" if installed
|
||||||
else
|
else
|
||||||
updated = gems_to_update.uniq.sort.collect { |g| g.to_s }
|
|
||||||
|
|
||||||
if updated.empty? then
|
if updated.empty? then
|
||||||
say "Nothing to update"
|
say "Nothing to update"
|
||||||
else
|
else
|
||||||
say "Gems updated: #{updated.join ', '}"
|
say "Gems updated: #{updated.map { |spec| spec.name }.join ', '}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,7 +28,7 @@ module Kernel
|
||||||
rescue LoadError => load_error
|
rescue LoadError => load_error
|
||||||
if load_error.message =~ /\A[Nn]o such file to load -- #{Regexp.escape path}\z/ and
|
if load_error.message =~ /\A[Nn]o such file to load -- #{Regexp.escape path}\z/ and
|
||||||
spec = Gem.searcher.find(path) then
|
spec = Gem.searcher.find(path) then
|
||||||
Gem.activate(spec.name, false, "= #{spec.version}")
|
Gem.activate(spec.name, "= #{spec.version}")
|
||||||
gem_original_require path
|
gem_original_require path
|
||||||
else
|
else
|
||||||
raise load_error
|
raise load_error
|
||||||
|
|
|
@ -11,6 +11,9 @@ module Gem
|
||||||
if defined? RUBY_FRAMEWORK_VERSION then
|
if defined? RUBY_FRAMEWORK_VERSION then
|
||||||
File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
|
File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
|
||||||
ConfigMap[:ruby_version]
|
ConfigMap[:ruby_version]
|
||||||
|
elsif defined? RUBY_ENGINE then
|
||||||
|
File.join ConfigMap[:libdir], RUBY_ENGINE, 'gems',
|
||||||
|
ConfigMap[:ruby_version]
|
||||||
else
|
else
|
||||||
File.join ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version]
|
File.join ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version]
|
||||||
end
|
end
|
||||||
|
@ -29,7 +32,11 @@ module Gem
|
||||||
|
|
||||||
# The default directory for binaries
|
# The default directory for binaries
|
||||||
def self.default_bindir
|
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
|
end
|
||||||
|
|
||||||
# The default system-wide source info cache directory.
|
# 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
|
# Creates a new installer instance.
|
||||||
# version requirement +version+ and +options+.
|
|
||||||
#
|
#
|
||||||
# Options are:
|
# Options are:
|
||||||
# :env_shebang:: See Gem::Installer::new.
|
# :env_shebang:: See Gem::Installer::new.
|
||||||
|
@ -36,7 +35,7 @@ class Gem::DependencyInstaller
|
||||||
# :install_dir: See Gem::Installer#install.
|
# :install_dir: See Gem::Installer#install.
|
||||||
# :security_policy: See Gem::Installer::new and Gem::Security.
|
# :security_policy: See Gem::Installer::new and Gem::Security.
|
||||||
# :wrappers: See Gem::Installer::new
|
# :wrappers: See Gem::Installer::new
|
||||||
def initialize(gem_name, version = nil, options = {})
|
def initialize(options = {})
|
||||||
options = DEFAULT_OPTIONS.merge options
|
options = DEFAULT_OPTIONS.merge options
|
||||||
@env_shebang = options[:env_shebang]
|
@env_shebang = options[:env_shebang]
|
||||||
@domain = options[:domain]
|
@domain = options[:domain]
|
||||||
|
@ -46,49 +45,9 @@ class Gem::DependencyInstaller
|
||||||
@install_dir = options[:install_dir] || Gem.dir
|
@install_dir = options[:install_dir] || Gem.dir
|
||||||
@security_policy = options[:security_policy]
|
@security_policy = options[:security_policy]
|
||||||
@wrappers = options[:wrappers]
|
@wrappers = options[:wrappers]
|
||||||
|
@bin_dir = options[:bin_dir]
|
||||||
|
|
||||||
@installed_gems = []
|
@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
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -107,73 +66,32 @@ class Gem::DependencyInstaller
|
||||||
end
|
end
|
||||||
|
|
||||||
if @domain == :both or @domain == :remote then
|
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
|
end
|
||||||
|
|
||||||
gems_and_sources.sort_by do |gem, source|
|
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
|
||||||
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
|
# Gathers all dependencies necessary for the installation from local and
|
||||||
# remote sources unless the ignore_dependencies was given.
|
# remote sources unless the ignore_dependencies was given.
|
||||||
|
@ -208,9 +126,57 @@ class Gem::DependencyInstaller
|
||||||
@gems_to_install = dependency_list.dependency_order.reverse
|
@gems_to_install = dependency_list.dependency_order.reverse
|
||||||
end
|
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.
|
# 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'
|
spec_dir = File.join @install_dir, 'specifications'
|
||||||
source_index = Gem::SourceIndex.from_gems_in spec_dir
|
source_index = Gem::SourceIndex.from_gems_in spec_dir
|
||||||
|
|
||||||
|
@ -219,10 +185,11 @@ class Gem::DependencyInstaller
|
||||||
# HACK is this test for full_name acceptable?
|
# HACK is this test for full_name acceptable?
|
||||||
next if source_index.any? { |n,_| n == spec.full_name } and not last
|
next if source_index.any? { |n,_| n == spec.full_name } and not last
|
||||||
|
|
||||||
|
# TODO: make this sorta_verbose so other users can benefit from it
|
||||||
say "Installing gem #{spec.full_name}" if Gem.configuration.really_verbose
|
say "Installing gem #{spec.full_name}" if Gem.configuration.really_verbose
|
||||||
|
|
||||||
_, source_uri = @specs_and_sources.assoc spec
|
_, 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,
|
inst = Gem::Installer.new local_gem_path,
|
||||||
:env_shebang => @env_shebang,
|
:env_shebang => @env_shebang,
|
||||||
|
@ -231,7 +198,8 @@ class Gem::DependencyInstaller
|
||||||
:ignore_dependencies => @ignore_dependencies,
|
:ignore_dependencies => @ignore_dependencies,
|
||||||
:install_dir => @install_dir,
|
:install_dir => @install_dir,
|
||||||
:security_policy => @security_policy,
|
:security_policy => @security_policy,
|
||||||
:wrappers => @wrappers
|
:wrappers => @wrappers,
|
||||||
|
:bin_dir => @bin_dir
|
||||||
|
|
||||||
spec = inst.install
|
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.
|
# 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
|
class Gem::DocumentError < Gem::Exception; end
|
||||||
|
|
||||||
|
@ -65,3 +68,17 @@ class Gem::RemoteSourceException < Gem::Exception; end
|
||||||
|
|
||||||
class Gem::VerificationError < 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
|
# check for old version gem
|
||||||
if File.read(file_path, 20).include?("MD5SUM =")
|
if File.read(file_path, 20).include?("MD5SUM =")
|
||||||
#alert_warning "Gem #{file_path} is in old format."
|
|
||||||
require 'rubygems/old_format'
|
require 'rubygems/old_format'
|
||||||
|
|
||||||
format = OldFormat.from_file_by_path(file_path)
|
format = OldFormat.from_file_by_path(file_path)
|
||||||
else
|
else
|
||||||
begin
|
open file_path, Gem.binary_mode do |io|
|
||||||
f = File.open(file_path, 'rb')
|
format = from_io io, file_path, security_policy
|
||||||
format = from_io(f, file_path, security_policy)
|
|
||||||
ensure
|
|
||||||
f.close unless f.closed?
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -65,15 +62,24 @@ module Gem
|
||||||
# io:: [IO] Stream from which to read the gem
|
# io:: [IO] Stream from which to read the gem
|
||||||
#
|
#
|
||||||
def self.from_io(io, gem_path="(io)", security_policy = nil)
|
def self.from_io(io, gem_path="(io)", security_policy = nil)
|
||||||
format = self.new(gem_path)
|
format = new gem_path
|
||||||
Package.open_from_io(io, 'r', security_policy) do |pkg|
|
|
||||||
|
Package.open io, 'r', security_policy do |pkg|
|
||||||
format.spec = pkg.metadata
|
format.spec = pkg.metadata
|
||||||
format.file_entries = []
|
format.file_entries = []
|
||||||
|
|
||||||
pkg.each do |entry|
|
pkg.each do |entry|
|
||||||
format.file_entries << [{"size" => entry.size, "mode" => entry.mode,
|
size = entry.header.size
|
||||||
"path" => entry.full_name}, entry.read]
|
mode = entry.header.mode
|
||||||
|
|
||||||
|
format.file_entries << [{
|
||||||
|
"size" => size, "mode" => mode, "path" => entry.full_name,
|
||||||
|
},
|
||||||
|
entry.read
|
||||||
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
format
|
format
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Top level class for building the gem repository index.
|
# Top level class for building the gem repository index.
|
||||||
|
|
||||||
class Gem::Indexer
|
class Gem::Indexer
|
||||||
|
|
||||||
include Gem::UserInteraction
|
include Gem::UserInteraction
|
||||||
|
@ -25,7 +26,9 @@ class Gem::Indexer
|
||||||
|
|
||||||
attr_reader :directory
|
attr_reader :directory
|
||||||
|
|
||||||
|
##
|
||||||
# Create an indexer that will index the gems in +directory+.
|
# Create an indexer that will index the gems in +directory+.
|
||||||
|
|
||||||
def initialize(directory)
|
def initialize(directory)
|
||||||
unless ''.respond_to? :to_xs then
|
unless ''.respond_to? :to_xs then
|
||||||
fail "Gem::Indexer requires that the XML Builder library be installed:" \
|
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
|
@master_index = Gem::Indexer::MasterIndexBuilder.new "yaml", @directory
|
||||||
@marshal_index = Gem::Indexer::MarshalIndexBuilder.new marshal_name, @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
|
end
|
||||||
|
|
||||||
|
##
|
||||||
# Build the index.
|
# Build the index.
|
||||||
|
|
||||||
def build_index
|
def build_index
|
||||||
@master_index.build do
|
@master_index.build do
|
||||||
@quick_index.build do
|
@quick_index.build do
|
||||||
@marshal_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}",
|
"Generating index for #{gem_file_list.size} gems in #{@dest_directory}",
|
||||||
"Loaded all gems"
|
"Loaded all gems"
|
||||||
|
|
||||||
gem_file_list.each do |gemfile|
|
gem_file_list.each do |gemfile|
|
||||||
if File.size(gemfile.to_s) == 0 then
|
if File.size(gemfile.to_s) == 0 then
|
||||||
alert_warning "Skipping zero-length gem: #{gemfile}"
|
alert_warning "Skipping zero-length gem: #{gemfile}"
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
spec = Gem::Format.from_file_by_path(gemfile).spec
|
|
||||||
|
|
||||||
unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then
|
|
||||||
alert_warning "Skipping misnamed gem: #{gemfile} => #{spec.full_name} (#{spec.original_name})"
|
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
abbreviate spec
|
begin
|
||||||
sanitize spec
|
spec = Gem::Format.from_file_by_path(gemfile).spec
|
||||||
|
|
||||||
@master_index.add spec
|
unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then
|
||||||
@quick_index.add spec
|
alert_warning "Skipping misnamed gem: #{gemfile} => #{spec.full_name} (#{spec.original_name})"
|
||||||
@marshal_index.add spec
|
next
|
||||||
|
end
|
||||||
|
|
||||||
progress.updated spec.original_name
|
abbreviate spec
|
||||||
|
sanitize spec
|
||||||
|
|
||||||
rescue SignalException => e
|
@master_index.add spec
|
||||||
alert_error "Recieved signal, exiting"
|
@quick_index.add spec
|
||||||
raise
|
@marshal_index.add spec
|
||||||
rescue Exception => e
|
@latest_index.add spec
|
||||||
alert_error "Unable to process #{gemfile}\n#{e.message} (#{e.class})\n\t#{e.backtrace.join "\n\t"}"
|
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
progress.done
|
|
||||||
|
|
||||||
say "Generating master indexes (this may take a while)"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -95,14 +106,15 @@ class Gem::Indexer
|
||||||
|
|
||||||
say "Moving index into production dir #{@dest_directory}" if verbose
|
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|
|
files.each do |file|
|
||||||
relative_name = file[/\A#{Regexp.escape @directory}.(.*)/, 1]
|
src_name = File.join @directory, file
|
||||||
dest_name = File.join @dest_directory, relative_name
|
dst_name = File.join @dest_directory, file
|
||||||
|
|
||||||
FileUtils.rm_rf dest_name, :verbose => verbose
|
FileUtils.rm_rf dst_name, :verbose => verbose
|
||||||
FileUtils.mv file, @dest_directory, :verbose => verbose
|
FileUtils.mv src_name, @dest_directory, :verbose => verbose
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -160,4 +172,5 @@ require 'rubygems/indexer/abstract_index_builder'
|
||||||
require 'rubygems/indexer/master_index_builder'
|
require 'rubygems/indexer/master_index_builder'
|
||||||
require 'rubygems/indexer/quick_index_builder'
|
require 'rubygems/indexer/quick_index_builder'
|
||||||
require 'rubygems/indexer/marshal_index_builder'
|
require 'rubygems/indexer/marshal_index_builder'
|
||||||
|
require 'rubygems/indexer/latest_index_builder'
|
||||||
|
|
||||||
|
|
|
@ -22,16 +22,18 @@ class Gem::Indexer::AbstractIndexBuilder
|
||||||
@files = []
|
@files = []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
# Build a Gem index. Yields to block to handle the details of the
|
# Build a Gem index. Yields to block to handle the details of the
|
||||||
# actual building. Calls +begin_index+, +end_index+ and +cleanup+ at
|
# actual building. Calls +begin_index+, +end_index+ and +cleanup+ at
|
||||||
# appropriate times to customize basic operations.
|
# appropriate times to customize basic operations.
|
||||||
|
|
||||||
def build
|
def build
|
||||||
FileUtils.mkdir_p @directory unless File.exist? @directory
|
FileUtils.mkdir_p @directory unless File.exist? @directory
|
||||||
raise "not a directory: #{@directory}" unless File.directory? @directory
|
raise "not a directory: #{@directory}" unless File.directory? @directory
|
||||||
|
|
||||||
file_path = File.join @directory, @filename
|
file_path = File.join @directory, @filename
|
||||||
|
|
||||||
@files << file_path
|
@files << @filename
|
||||||
|
|
||||||
File.open file_path, "wb" do |file|
|
File.open file_path, "wb" do |file|
|
||||||
@file = file
|
@file = file
|
||||||
|
@ -39,14 +41,20 @@ class Gem::Indexer::AbstractIndexBuilder
|
||||||
yield
|
yield
|
||||||
end_index
|
end_index
|
||||||
end
|
end
|
||||||
|
|
||||||
cleanup
|
cleanup
|
||||||
ensure
|
ensure
|
||||||
@file = nil
|
@file = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
# Compress the given file.
|
# Compress the given file.
|
||||||
|
|
||||||
def compress(filename, ext="rz")
|
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.open "#{filename}.#{ext}", "wb" do |file|
|
||||||
file.write zipped
|
file.write zipped
|
||||||
end
|
end
|
||||||
|
|
35
lib/rubygems/indexer/latest_index_builder.rb
Normal file
35
lib/rubygems/indexer/latest_index_builder.rb
Normal file
|
@ -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'
|
require 'rubygems/indexer'
|
||||||
|
|
||||||
|
##
|
||||||
# Construct the master Gem index file.
|
# Construct the master Gem index file.
|
||||||
|
|
||||||
class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
|
class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
|
||||||
|
|
||||||
def start_index
|
def start_index
|
||||||
|
@ -10,6 +12,7 @@ class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
|
||||||
|
|
||||||
def end_index
|
def end_index
|
||||||
super
|
super
|
||||||
|
|
||||||
@file.puts "--- !ruby/object:#{@index.class}"
|
@file.puts "--- !ruby/object:#{@index.class}"
|
||||||
@file.puts "gems:"
|
@file.puts "gems:"
|
||||||
|
|
||||||
|
@ -28,11 +31,9 @@ class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
|
||||||
index_file_name = File.join @directory, @filename
|
index_file_name = File.join @directory, @filename
|
||||||
|
|
||||||
compress index_file_name, "Z"
|
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 << "#{@filename}.Z"
|
||||||
|
|
||||||
@files << compressed_file_name
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def add(spec)
|
def add(spec)
|
||||||
|
@ -41,12 +42,12 @@ class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def paranoid(fn, compressed_fn)
|
def paranoid(path, compressed_path)
|
||||||
data = File.open(fn, 'rb') do |fp| fp.read end
|
data = Gem.read_binary path
|
||||||
compressed_data = File.open(compressed_fn, 'rb') do |fp| fp.read end
|
compressed_data = Gem.read_binary compressed_path
|
||||||
|
|
||||||
if data != unzip(compressed_data) then
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
require 'rubygems/indexer'
|
require 'rubygems/indexer'
|
||||||
|
|
||||||
|
##
|
||||||
# Construct a quick index file and all of the individual specs to support
|
# Construct a quick index file and all of the individual specs to support
|
||||||
# incremental loading.
|
# incremental loading.
|
||||||
|
|
||||||
class Gem::Indexer::QuickIndexBuilder < Gem::Indexer::AbstractIndexBuilder
|
class Gem::Indexer::QuickIndexBuilder < Gem::Indexer::AbstractIndexBuilder
|
||||||
|
|
||||||
def initialize(filename, directory)
|
def initialize(filename, directory)
|
||||||
|
@ -13,12 +15,12 @@ class Gem::Indexer::QuickIndexBuilder < Gem::Indexer::AbstractIndexBuilder
|
||||||
def cleanup
|
def cleanup
|
||||||
super
|
super
|
||||||
|
|
||||||
quick_index_file = File.join(@directory, @filename)
|
quick_index_file = File.join @directory, @filename
|
||||||
compress quick_index_file
|
compress quick_index_file
|
||||||
|
|
||||||
# the complete quick index is in a directory, so move it as a whole
|
# the complete quick index is in a directory, so move it as a whole
|
||||||
@files.delete quick_index_file
|
@files.delete 'index'
|
||||||
@files << @directory
|
@files << 'quick'
|
||||||
end
|
end
|
||||||
|
|
||||||
def add(spec)
|
def add(spec)
|
||||||
|
|
|
@ -25,6 +25,12 @@ module Gem::InstallUpdateOptions
|
||||||
options[:install_dir] = File.expand_path(value)
|
options[:install_dir] = File.expand_path(value)
|
||||||
end
|
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',
|
add_option(:"Install/Update", '-d', '--[no-]rdoc',
|
||||||
'Generate RDoc documentation for the gem on',
|
'Generate RDoc documentation for the gem on',
|
||||||
'install') do |value, options|
|
'install') do |value, options|
|
||||||
|
|
|
@ -63,7 +63,8 @@ class Gem::Installer
|
||||||
:force => false,
|
:force => false,
|
||||||
:install_dir => Gem.dir,
|
:install_dir => Gem.dir,
|
||||||
:exec_format => false,
|
:exec_format => false,
|
||||||
:env_shebang => false
|
:env_shebang => false,
|
||||||
|
:bin_dir => nil
|
||||||
}.merge options
|
}.merge options
|
||||||
|
|
||||||
@env_shebang = options[:env_shebang]
|
@env_shebang = options[:env_shebang]
|
||||||
|
@ -74,6 +75,7 @@ class Gem::Installer
|
||||||
@format_executable = options[:format_executable]
|
@format_executable = options[:format_executable]
|
||||||
@security_policy = options[:security_policy]
|
@security_policy = options[:security_policy]
|
||||||
@wrappers = options[:wrappers]
|
@wrappers = options[:wrappers]
|
||||||
|
@bin_dir = options[:bin_dir]
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@format = Gem::Format.from_file_by_path @gem, @security_policy
|
@format = Gem::Format.from_file_by_path @gem, @security_policy
|
||||||
|
@ -104,7 +106,7 @@ class Gem::Installer
|
||||||
|
|
||||||
unless @force then
|
unless @force then
|
||||||
if rrv = @spec.required_ruby_version 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}"
|
raise Gem::InstallError, "#{@spec.name} requires Ruby version #{rrv}"
|
||||||
end
|
end
|
||||||
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
|
# 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
|
# the system gem directory, then use the system bin directory, else create
|
||||||
# (or use) a new bin dir under the gem_home.
|
# (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
|
Dir.mkdir bindir unless File.exist? bindir
|
||||||
raise Gem::FilePermissionError.new(bindir) unless File.writable? bindir
|
raise Gem::FilePermissionError.new(bindir) unless File.writable? bindir
|
||||||
|
@ -303,7 +305,7 @@ class Gem::Installer
|
||||||
# necessary.
|
# necessary.
|
||||||
def shebang(bin_file_name)
|
def shebang(bin_file_name)
|
||||||
if @env_shebang then
|
if @env_shebang then
|
||||||
"#!/usr/bin/env ruby"
|
"#!/usr/bin/env " + Gem::ConfigMap[:ruby_install_name]
|
||||||
else
|
else
|
||||||
path = File.join @gem_dir, @spec.bindir, bin_file_name
|
path = File.join @gem_dir, @spec.bindir, bin_file_name
|
||||||
|
|
||||||
|
@ -352,10 +354,10 @@ TEXT
|
||||||
<<-TEXT
|
<<-TEXT
|
||||||
@ECHO OFF
|
@ECHO OFF
|
||||||
IF NOT "%~f0" == "~f0" GOTO :WinNT
|
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
|
GOTO :EOF
|
||||||
:WinNT
|
:WinNT
|
||||||
"%~dp0ruby.exe" "%~dpn0" %*
|
@"#{File.basename(Gem.ruby)}" "%~dpn0" %*
|
||||||
TEXT
|
TEXT
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -45,768 +45,15 @@ module Gem::Package
|
||||||
class TooLongFileName < Error; end
|
class TooLongFileName < Error; end
|
||||||
class FormatError < Error; end
|
class FormatError < Error; end
|
||||||
|
|
||||||
module FSyncDir
|
def self.open(io, mode = "r", signer = nil, &block)
|
||||||
private
|
tar_type = case mode
|
||||||
def fsync_dir(dirname)
|
when 'r' then TarInput
|
||||||
# make sure this hits the disc
|
when 'w' then TarOutput
|
||||||
begin
|
else
|
||||||
dir = open(dirname, "r")
|
raise "Unknown Package open mode"
|
||||||
dir.fsync
|
end
|
||||||
rescue # ignore IOError if it's an unpatched (old) Ruby
|
|
||||||
ensure
|
tar_type.open(io, signer, &block)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.pack(src, destname, signer = nil)
|
def self.pack(src, destname, signer = nil)
|
||||||
|
@ -836,19 +83,13 @@ module Gem::Package
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
|
||||||
def file_class
|
|
||||||
File
|
|
||||||
end
|
|
||||||
|
|
||||||
def dir_class
|
|
||||||
Dir
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_class # HACK kill me
|
|
||||||
Find
|
|
||||||
end
|
|
||||||
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'
|
||||||
|
|
||||||
|
|
24
lib/rubygems/package/f_sync_dir.rb
Normal file
24
lib/rubygems/package/f_sync_dir.rb
Normal file
|
@ -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
|
||||||
|
|
245
lib/rubygems/package/tar_header.rb
Normal file
245
lib/rubygems/package/tar_header.rb
Normal file
|
@ -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
|
||||||
|
|
219
lib/rubygems/package/tar_input.rb
Normal file
219
lib/rubygems/package/tar_input.rb
Normal file
|
@ -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
|
||||||
|
|
143
lib/rubygems/package/tar_output.rb
Normal file
143
lib/rubygems/package/tar_output.rb
Normal file
|
@ -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
|
||||||
|
|
86
lib/rubygems/package/tar_reader.rb
Normal file
86
lib/rubygems/package/tar_reader.rb
Normal file
|
@ -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
|
||||||
|
|
99
lib/rubygems/package/tar_reader/entry.rb
Normal file
99
lib/rubygems/package/tar_reader/entry.rb
Normal file
|
@ -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
|
||||||
|
|
180
lib/rubygems/package/tar_writer.rb
Normal file
180
lib/rubygems/package/tar_writer.rb
Normal file
|
@ -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 'uri'
|
||||||
|
|
||||||
require 'rubygems'
|
require 'rubygems'
|
||||||
require 'rubygems/gem_open_uri'
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# RemoteFetcher handles the details of fetching gems and gem information from
|
# RemoteFetcher handles the details of fetching gems and gem information from
|
||||||
|
@ -10,6 +9,8 @@ require 'rubygems/gem_open_uri'
|
||||||
|
|
||||||
class Gem::RemoteFetcher
|
class Gem::RemoteFetcher
|
||||||
|
|
||||||
|
include Gem::UserInteraction
|
||||||
|
|
||||||
class FetchError < Gem::Exception; end
|
class FetchError < Gem::Exception; end
|
||||||
|
|
||||||
@fetcher = nil
|
@fetcher = nil
|
||||||
|
@ -29,6 +30,10 @@ class Gem::RemoteFetcher
|
||||||
# HTTP_PROXY_PASS)
|
# HTTP_PROXY_PASS)
|
||||||
# * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
|
# * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
|
||||||
def initialize(proxy)
|
def initialize(proxy)
|
||||||
|
Socket.do_not_reverse_lookup = true
|
||||||
|
|
||||||
|
@connections = {}
|
||||||
|
@requests = Hash.new 0
|
||||||
@proxy_uri =
|
@proxy_uri =
|
||||||
case proxy
|
case proxy
|
||||||
when :no_proxy then nil
|
when :no_proxy then nil
|
||||||
|
@ -38,6 +43,65 @@ class Gem::RemoteFetcher
|
||||||
end
|
end
|
||||||
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+.
|
# Downloads +uri+.
|
||||||
def fetch_path(uri)
|
def fetch_path(uri)
|
||||||
open_uri_or_path(uri) do |input|
|
open_uri_or_path(uri) do |input|
|
||||||
|
@ -47,9 +111,8 @@ class Gem::RemoteFetcher
|
||||||
raise FetchError, "timed out fetching #{uri}"
|
raise FetchError, "timed out fetching #{uri}"
|
||||||
rescue IOError, SocketError, SystemCallError => e
|
rescue IOError, SocketError, SystemCallError => e
|
||||||
raise FetchError, "#{e.class}: #{e} reading #{uri}"
|
raise FetchError, "#{e.class}: #{e} reading #{uri}"
|
||||||
rescue OpenURI::HTTPError => e
|
rescue => e
|
||||||
body = e.io.readlines.join "\n\t"
|
message = "#{e.class}: #{e} reading #{uri}"
|
||||||
message = "#{e.class}: #{e} reading #{uri}\n\t#{body}"
|
|
||||||
raise FetchError, message
|
raise FetchError, message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -83,7 +146,8 @@ class Gem::RemoteFetcher
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue SocketError, SystemCallError, Timeout::Error => e
|
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
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -131,26 +195,77 @@ class Gem::RemoteFetcher
|
||||||
|
|
||||||
# Read the data from the (source based) URI, but if it is a file:// URI,
|
# Read the data from the (source based) URI, but if it is a file:// URI,
|
||||||
# read from the filesystem instead.
|
# 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)
|
if file_uri?(uri)
|
||||||
open(get_file_uri_path(uri), &block)
|
open(get_file_uri_path(uri), &block)
|
||||||
else
|
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
|
uri = URI.parse uri unless URI::Generic === uri
|
||||||
unless uri.nil? || uri.user.nil? || uri.user.empty? then
|
net_http_args = [uri.host, uri.port]
|
||||||
connection_options[:http_basic_authentication] =
|
|
||||||
[unescape(uri.user), unescape(uri.password)]
|
if @proxy_uri then
|
||||||
|
net_http_args += [ @proxy_uri.host,
|
||||||
|
@proxy_uri.port,
|
||||||
|
@proxy_uri.user,
|
||||||
|
@proxy_uri.password
|
||||||
|
]
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@ class Gem::Requirement
|
||||||
|
|
||||||
include Comparable
|
include Comparable
|
||||||
|
|
||||||
|
attr_reader :requirements
|
||||||
|
|
||||||
OPS = {
|
OPS = {
|
||||||
"=" => lambda { |v, r| v == r },
|
"=" => lambda { |v, r| v == r },
|
||||||
"!=" => lambda { |v, r| v != r },
|
"!=" => lambda { |v, r| v != r },
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
# This file is auto-generated by build scripts.
|
# This file is auto-generated by build scripts.
|
||||||
# See: rake update_version
|
# See: rake update_version
|
||||||
module Gem
|
module Gem
|
||||||
RubyGemsVersion = '1.0.1'
|
RubyGemsVersion = '1.1.0'
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
# See LICENSE.txt for permissions.
|
# See LICENSE.txt for permissions.
|
||||||
#++
|
#++
|
||||||
|
|
||||||
|
require 'rubygems'
|
||||||
require 'rubygems/gem_openssl'
|
require 'rubygems/gem_openssl'
|
||||||
|
|
||||||
# = Signed Gems README
|
# = Signed Gems README
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'webrick'
|
require 'webrick'
|
||||||
require 'rdoc/template'
|
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
require 'zlib'
|
require 'zlib'
|
||||||
|
require 'erb'
|
||||||
|
|
||||||
require 'rubygems'
|
require 'rubygems'
|
||||||
|
|
||||||
|
@ -27,107 +27,87 @@ class Gem::Server
|
||||||
|
|
||||||
include Gem::UserInteraction
|
include Gem::UserInteraction
|
||||||
|
|
||||||
DOC_TEMPLATE = <<-WEBPAGE
|
DOC_TEMPLATE = <<-'WEBPAGE'
|
||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
<!DOCTYPE html
|
<!DOCTYPE html
|
||||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
"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>
|
|
||||||
|
|
||||||
|
<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>
|
||||||
</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>
|
||||||
<div id="validator-badges">
|
</body>
|
||||||
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
</html>
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
WEBPAGE
|
WEBPAGE
|
||||||
|
|
||||||
# CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108
|
# 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
|
end
|
||||||
|
|
||||||
# create page from template
|
# create page from template
|
||||||
template = TemplatePage.new(DOC_TEMPLATE)
|
template = ERB.new(DOC_TEMPLATE)
|
||||||
res['content-type'] = 'text/html'
|
res['content-type'] = 'text/html'
|
||||||
template.write_html_on res.body,
|
values = { "gem_count" => specs.size.to_s, "specs" => specs,
|
||||||
"gem_count" => specs.size.to_s, "specs" => specs,
|
"total_file_count" => total_file_count.to_s }
|
||||||
"total_file_count" => total_file_count.to_s
|
result = template.result binding
|
||||||
|
res.body = result
|
||||||
end
|
end
|
||||||
|
|
||||||
paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }
|
paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" }
|
||||||
|
|
|
@ -8,437 +8,512 @@ require 'rubygems'
|
||||||
require 'rubygems/user_interaction'
|
require 'rubygems/user_interaction'
|
||||||
require 'rubygems/specification'
|
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
|
class Gem::SourceIndex
|
||||||
# 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
|
|
||||||
|
|
||||||
include Enumerable
|
include Enumerable
|
||||||
|
|
||||||
|
include Gem::UserInteraction
|
||||||
|
|
||||||
|
class << self
|
||||||
include Gem::UserInteraction
|
include Gem::UserInteraction
|
||||||
|
|
||||||
# Class Methods. -------------------------------------------------
|
##
|
||||||
class << self
|
# Factory method to construct a source index instance for a given
|
||||||
include Gem::UserInteraction
|
# path.
|
||||||
|
|
||||||
# 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
|
|
||||||
#
|
#
|
||||||
# specifications::
|
# deprecated::
|
||||||
# [Hash] hash of [Gem name, Gem::Specification] pairs
|
# If supplied, from_installed_gems will act just like
|
||||||
#
|
# +from_gems_in+. This argument is deprecated and is provided
|
||||||
def initialize(specifications={})
|
# just for backwards compatibility, and should not generally
|
||||||
@gems = specifications
|
# be used.
|
||||||
end
|
#
|
||||||
|
# return::
|
||||||
# Reconstruct the source index from the list of source
|
# SourceIndex instance
|
||||||
# directories.
|
|
||||||
def load_gems_in(*spec_dirs)
|
|
||||||
@gems.clear
|
|
||||||
specs = Dir.glob File.join("{#{spec_dirs.join(',')}}", "*.gemspec")
|
|
||||||
|
|
||||||
specs.each do |file_name|
|
def from_installed_gems(*deprecated)
|
||||||
gemspec = self.class.load_specification(file_name.untaint)
|
if deprecated.empty?
|
||||||
add_spec(gemspec) if gemspec
|
from_gems_in(*installed_spec_directories)
|
||||||
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
|
|
||||||
else
|
else
|
||||||
version_requirement = platform_only || Gem::Requirement.default
|
from_gems_in(*deprecated) # HACK warn
|
||||||
gem_pattern = /#{gem_pattern}/i
|
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
# Refresh the source index from the local file system.
|
##
|
||||||
#
|
# Return a list of directories in the current gem path that
|
||||||
# return:: Returns a pointer to itself.
|
# contain specifications.
|
||||||
#
|
#
|
||||||
def refresh!
|
# return::
|
||||||
load_gems_in(self.class.installed_spec_directories)
|
# List of directory paths (all ending in "../specifications").
|
||||||
|
|
||||||
|
def installed_spec_directories
|
||||||
|
Gem.path.collect { |dir| File.join(dir, "specifications") }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an Array of Gem::Specifications that are not up to date.
|
##
|
||||||
#
|
# Creates a new SourceIndex from the ruby format gem specifications in
|
||||||
def outdated
|
# +spec_dirs+.
|
||||||
dep = Gem::Dependency.new '', Gem::Requirement.default
|
|
||||||
|
|
||||||
remotes = Gem::SourceInfoCache.search dep, true
|
def from_gems_in(*spec_dirs)
|
||||||
|
self.new.load_gems_in(*spec_dirs)
|
||||||
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
|
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
|
begin
|
||||||
gem_names = fetch_quick_index source_uri
|
spec_code = File.read(file_name).untaint
|
||||||
remove_extra gem_names
|
gemspec = eval spec_code, binding, file_name
|
||||||
missing_gems = find_missing gem_names
|
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
|
def initialize(specifications={})
|
||||||
rescue Gem::OperationNotSupportedError => ex
|
@gems = specifications
|
||||||
alert_error "Falling back to bulk fetch: #{ex.message}" if
|
end
|
||||||
Gem.configuration.really_verbose
|
|
||||||
use_incremental = false
|
##
|
||||||
|
# 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
|
end
|
||||||
|
|
||||||
if use_incremental then
|
if spec.platform != Gem::Platform::RUBY then
|
||||||
update_with_missing(source_uri, missing_gems)
|
result[name].delete_if do |result_spec|
|
||||||
else
|
result_spec.platform == spec.platform
|
||||||
new_index = fetch_bulk_index(source_uri)
|
end
|
||||||
@gems.replace(new_index.gems)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
true
|
result[name] << spec
|
||||||
end
|
end
|
||||||
|
|
||||||
def ==(other) # :nodoc:
|
result.values.flatten
|
||||||
self.class === other and @gems == other.gems
|
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
|
end
|
||||||
|
|
||||||
def dump
|
unless Gem::Requirement === version_requirement then
|
||||||
Marshal.dump(self)
|
version_requirement = Gem::Requirement.create version_requirement
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
specs = @gems.values.select do |spec|
|
||||||
|
spec.name =~ gem_pattern and
|
||||||
attr_reader :gems
|
version_requirement.satisfied_by? spec.version
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def fetcher
|
|
||||||
require 'rubygems/remote_fetcher'
|
|
||||||
|
|
||||||
Gem::RemoteFetcher.fetcher
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_index_from(source_uri)
|
if only_platform then
|
||||||
@fetch_error = nil
|
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}.Z
|
||||||
Marshal.#{Gem.marshal_version}
|
Marshal.#{Gem.marshal_version}
|
||||||
yaml.Z
|
yaml.Z
|
||||||
yaml
|
yaml
|
||||||
]
|
]
|
||||||
|
|
||||||
indexes.each do |name|
|
indexes.each do |name|
|
||||||
spec_data = nil
|
spec_data = nil
|
||||||
begin
|
index = source_uri + name
|
||||||
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
|
|
||||||
begin
|
begin
|
||||||
marshal_uri = source_uri + "/quick/Marshal.#{Gem.marshal_version}/#{spec_name}.gemspec.rz"
|
spec_data = fetcher.fetch_path index
|
||||||
zipped = fetcher.fetch_path marshal_uri
|
spec_data = unzip(spec_data) if name =~ /\.Z$/
|
||||||
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
|
if name =~ /Marshal/ then
|
||||||
yaml_uri = source_uri + "/quick/#{spec_name}.gemspec.rz"
|
return Marshal.load(spec_data)
|
||||||
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
|
else
|
||||||
add_spec gemspec
|
return YAML.load(spec_data)
|
||||||
progress.updated spec_name
|
|
||||||
end
|
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
|
end
|
||||||
progress.done
|
|
||||||
progress.count
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Cache is an alias for SourceIndex to allow older YAMLized source
|
def fetch_bulk_index(source_uri)
|
||||||
# index objects to load properly.
|
say "Bulk updating Gem source index for: #{source_uri}"
|
||||||
Cache = SourceIndex
|
|
||||||
|
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
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ require 'rubygems'
|
||||||
require 'rubygems/source_info_cache_entry'
|
require 'rubygems/source_info_cache_entry'
|
||||||
require 'rubygems/user_interaction'
|
require 'rubygems/user_interaction'
|
||||||
|
|
||||||
|
##
|
||||||
# SourceInfoCache stores a copy of the gem index for each gem source.
|
# 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:
|
# 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
|
# @source_index => Gem::SourceIndex
|
||||||
# ...
|
# ...
|
||||||
# }
|
# }
|
||||||
#
|
|
||||||
class Gem::SourceInfoCache
|
class Gem::SourceInfoCache
|
||||||
|
|
||||||
include Gem::UserInteraction
|
include Gem::UserInteraction
|
||||||
|
@ -37,7 +38,7 @@ class Gem::SourceInfoCache
|
||||||
def self.cache
|
def self.cache
|
||||||
return @cache if @cache
|
return @cache if @cache
|
||||||
@cache = new
|
@cache = new
|
||||||
@cache.refresh if Gem.configuration.update_sources
|
@cache.refresh false if Gem.configuration.update_sources
|
||||||
@cache
|
@cache
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -45,86 +46,178 @@ class Gem::SourceInfoCache
|
||||||
cache.cache_data
|
cache.cache_data
|
||||||
end
|
end
|
||||||
|
|
||||||
# Search all source indexes for +pattern+.
|
##
|
||||||
def self.search(pattern, platform_only = false)
|
# The name of the system cache file.
|
||||||
cache.search pattern, platform_only
|
|
||||||
|
def self.latest_system_cache_file
|
||||||
|
File.join File.dirname(system_cache_file),
|
||||||
|
"latest_#{File.basename system_cache_file}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Search all source indexes for +pattern+. Only returns gems matching
|
##
|
||||||
# Gem.platforms when +only_platform+ is true. See #search_with_source.
|
# The name of the latest user cache file.
|
||||||
def self.search_with_source(pattern, only_platform = false)
|
|
||||||
cache.search_with_source(pattern, only_platform)
|
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
|
end
|
||||||
|
|
||||||
def initialize # :nodoc:
|
def initialize # :nodoc:
|
||||||
@cache_data = nil
|
@cache_data = nil
|
||||||
@cache_file = nil
|
@cache_file = nil
|
||||||
@dirty = false
|
@dirty = false
|
||||||
|
@only_latest = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
# The most recent cache data.
|
# The most recent cache data.
|
||||||
|
|
||||||
def cache_data
|
def cache_data
|
||||||
return @cache_data if @cache_data
|
return @cache_data if @cache_data
|
||||||
cache_file # HACK writable check
|
cache_file # HACK writable check
|
||||||
|
|
||||||
begin
|
@only_latest = true
|
||||||
# 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
|
|
||||||
|
|
||||||
@cache_data.each do |url, sice|
|
@cache_data = read_cache_data latest_cache_file
|
||||||
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
|
|
||||||
|
|
||||||
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
|
@cache_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_cache_data
|
##
|
||||||
@cache_data = {}
|
# The name of the cache file.
|
||||||
end
|
|
||||||
|
|
||||||
# The name of the cache file to be read
|
|
||||||
def cache_file
|
def cache_file
|
||||||
return @cache_file if @cache_file
|
return @cache_file if @cache_file
|
||||||
@cache_file = (try_file(system_cache_file) or
|
@cache_file = (try_file(system_cache_file) or
|
||||||
try_file(user_cache_file) or
|
try_file(user_cache_file) or
|
||||||
raise "unable to locate a writable cache file")
|
raise "unable to locate a writable cache file")
|
||||||
end
|
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).
|
# Write the cache to a local file (if it is dirty).
|
||||||
|
|
||||||
def flush
|
def flush
|
||||||
write_cache if @dirty
|
write_cache if @dirty
|
||||||
@dirty = false
|
@dirty = false
|
||||||
end
|
end
|
||||||
|
|
||||||
# Refreshes each source in the cache from its repository.
|
def latest_cache_data
|
||||||
def refresh
|
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|
|
Gem.sources.each do |source_uri|
|
||||||
cache_entry = cache_data[source_uri]
|
cache_entry = cache_data[source_uri]
|
||||||
if cache_entry.nil? then
|
if cache_entry.nil? then
|
||||||
|
@ -132,14 +225,34 @@ class Gem::SourceInfoCache
|
||||||
cache_data[source_uri] = cache_entry
|
cache_data[source_uri] = cache_entry
|
||||||
end
|
end
|
||||||
|
|
||||||
update if cache_entry.refresh source_uri
|
update if cache_entry.refresh source_uri, all
|
||||||
end
|
end
|
||||||
|
|
||||||
flush
|
flush
|
||||||
end
|
end
|
||||||
|
|
||||||
# Searches all source indexes for +pattern+.
|
def reset_cache_for(url, cache_data)
|
||||||
def search(pattern, platform_only = false)
|
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|
|
cache_data.map do |source_uri, sic_entry|
|
||||||
next unless Gem.sources.include? source_uri
|
next unless Gem.sources.include? source_uri
|
||||||
sic_entry.source_index.search pattern, platform_only
|
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
|
# only gems matching Gem.platforms will be selected. Returns an Array of
|
||||||
# pairs containing the Gem::Specification found and the source_uri it was
|
# pairs containing the Gem::Specification found and the source_uri it was
|
||||||
# found at.
|
# 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 = []
|
results = []
|
||||||
|
|
||||||
cache_data.map do |source_uri, sic_entry|
|
cache_data.map do |source_uri, sic_entry|
|
||||||
|
@ -164,69 +279,76 @@ class Gem::SourceInfoCache
|
||||||
results
|
results
|
||||||
end
|
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
|
# 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
|
# 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
|
# index information. The +hash+ should map a source URL into a
|
||||||
# SourceInfoCacheEntry.
|
# SourceInfoCacheEntry.
|
||||||
|
|
||||||
def set_cache_data(hash)
|
def set_cache_data(hash)
|
||||||
@cache_data = hash
|
@cache_data = hash
|
||||||
update
|
update
|
||||||
end
|
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
|
unless File.exist? dir then
|
||||||
begin
|
begin
|
||||||
FileUtils.mkdir_p(dir)
|
FileUtils.mkdir_p dir
|
||||||
rescue RuntimeError, SystemCallError
|
rescue RuntimeError, SystemCallError
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if File.writable?(dir)
|
|
||||||
File.open(fn, "wb") { |f| f << Marshal.dump({}) }
|
if File.writable? dir then
|
||||||
return fn
|
open path, "wb" do |io| io.write Marshal.dump({}) end
|
||||||
|
return path
|
||||||
end
|
end
|
||||||
|
|
||||||
nil
|
nil
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,24 +3,31 @@ require 'rubygems/source_index'
|
||||||
require 'rubygems/remote_fetcher'
|
require 'rubygems/remote_fetcher'
|
||||||
|
|
||||||
##
|
##
|
||||||
# Entrys held by a SourceInfoCache.
|
# Entries held by a SourceInfoCache.
|
||||||
|
|
||||||
class Gem::SourceInfoCacheEntry
|
class Gem::SourceInfoCacheEntry
|
||||||
|
|
||||||
|
##
|
||||||
# The source index for this cache entry.
|
# The source index for this cache entry.
|
||||||
|
|
||||||
attr_reader :source_index
|
attr_reader :source_index
|
||||||
|
|
||||||
|
##
|
||||||
# The size of the of the source entry. Used to determine if the
|
# The size of the of the source entry. Used to determine if the
|
||||||
# source index has changed.
|
# source index has changed.
|
||||||
|
|
||||||
attr_reader :size
|
attr_reader :size
|
||||||
|
|
||||||
|
##
|
||||||
# Create a cache entry.
|
# Create a cache entry.
|
||||||
|
|
||||||
def initialize(si, size)
|
def initialize(si, size)
|
||||||
@source_index = si || Gem::SourceIndex.new({})
|
@source_index = si || Gem::SourceIndex.new({})
|
||||||
@size = size
|
@size = size
|
||||||
|
@all = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def refresh(source_uri)
|
def refresh(source_uri, all)
|
||||||
begin
|
begin
|
||||||
marshal_uri = URI.join source_uri.to_s, "Marshal.#{Gem.marshal_version}"
|
marshal_uri = URI.join source_uri.to_s, "Marshal.#{Gem.marshal_version}"
|
||||||
remote_size = Gem::RemoteFetcher.fetcher.fetch_size marshal_uri
|
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
|
remote_size = Gem::RemoteFetcher.fetcher.fetch_size yaml_uri
|
||||||
end
|
end
|
||||||
|
|
||||||
return false if @size == remote_size # TODO Use index_signature instead of size?
|
# TODO Use index_signature instead of size?
|
||||||
updated = @source_index.update source_uri
|
return false if @size == remote_size and @all
|
||||||
|
|
||||||
|
updated = @source_index.update source_uri, all
|
||||||
@size = remote_size
|
@size = remote_size
|
||||||
|
@all = all
|
||||||
|
|
||||||
updated
|
updated
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@ require 'rubygems/platform'
|
||||||
if RUBY_VERSION < '1.9' then
|
if RUBY_VERSION < '1.9' then
|
||||||
def Time.today
|
def Time.today
|
||||||
t = Time.now
|
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 unless defined? Time.today
|
||||||
end
|
end
|
||||||
# :startdoc:
|
# :startdoc:
|
||||||
|
|
|
@ -12,7 +12,7 @@ require 'rubygems/user_interaction'
|
||||||
|
|
||||||
##
|
##
|
||||||
# An Uninstaller.
|
# An Uninstaller.
|
||||||
#
|
|
||||||
class Gem::Uninstaller
|
class Gem::Uninstaller
|
||||||
|
|
||||||
include Gem::UserInteraction
|
include Gem::UserInteraction
|
||||||
|
@ -21,8 +21,8 @@ class Gem::Uninstaller
|
||||||
# Constructs an Uninstaller instance
|
# Constructs an Uninstaller instance
|
||||||
#
|
#
|
||||||
# gem:: [String] The Gem name to uninstall
|
# gem:: [String] The Gem name to uninstall
|
||||||
#
|
|
||||||
def initialize(gem, options)
|
def initialize(gem, options = {})
|
||||||
@gem = gem
|
@gem = gem
|
||||||
@version = options[:version] || Gem::Requirement.default
|
@version = options[:version] || Gem::Requirement.default
|
||||||
gem_home = options[:install_dir] || Gem.dir
|
gem_home = options[:install_dir] || Gem.dir
|
||||||
|
@ -30,12 +30,13 @@ class Gem::Uninstaller
|
||||||
@force_executables = options[:executables]
|
@force_executables = options[:executables]
|
||||||
@force_all = options[:all]
|
@force_all = options[:all]
|
||||||
@force_ignore = options[:ignore]
|
@force_ignore = options[:ignore]
|
||||||
|
@bin_dir = options[:bin_dir]
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Performs the uninstall of the Gem. This removes the spec, the
|
# Performs the uninstall of the Gem. This removes the spec, the
|
||||||
# Gem directory, and the cached .gem file,
|
# Gem directory, and the cached .gem file,
|
||||||
#
|
|
||||||
def uninstall
|
def uninstall
|
||||||
list = Gem.source_index.search(/^#{@gem}$/, @version)
|
list = Gem.source_index.search(/^#{@gem}$/, @version)
|
||||||
|
|
||||||
|
@ -66,18 +67,14 @@ class Gem::Uninstaller
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Remove executables and batch files (windows only) for the gem as
|
# Removes installed executables and batch files (windows only) for
|
||||||
# it is being installed
|
# +gemspec+.
|
||||||
#
|
|
||||||
# gemspec::[Specification] the gem whose executables need to be removed.
|
|
||||||
#
|
|
||||||
def remove_executables(gemspec)
|
def remove_executables(gemspec)
|
||||||
return if gemspec.nil?
|
return if gemspec.nil?
|
||||||
|
|
||||||
if gemspec.executables.size > 0 then
|
if gemspec.executables.size > 0 then
|
||||||
bindir = Gem.bindir @gem_home
|
bindir = @bin_dir ? @bin_dir : (Gem.bindir @gem_home)
|
||||||
|
|
||||||
raise Gem::FilePermissionError, bindir unless File.writable? bindir
|
|
||||||
|
|
||||||
list = Gem.source_index.search(gemspec.name).delete_if { |spec|
|
list = Gem.source_index.search(gemspec.name).delete_if { |spec|
|
||||||
spec.version == gemspec.version
|
spec.version == gemspec.version
|
||||||
|
@ -93,14 +90,19 @@ class Gem::Uninstaller
|
||||||
|
|
||||||
return if executables.size == 0
|
return if executables.size == 0
|
||||||
|
|
||||||
answer = @force_executables || ask_yes_no(
|
answer = if @force_executables.nil? then
|
||||||
"Remove executables:\n" \
|
ask_yes_no("Remove executables:\n" \
|
||||||
"\t#{gemspec.executables.join(", ")}\n\nin addition to the gem?",
|
"\t#{gemspec.executables.join(", ")}\n\nin addition to the gem?",
|
||||||
true) # " # appease ruby-mode - don't ask
|
true) # " # appease ruby-mode - don't ask
|
||||||
|
else
|
||||||
|
@force_executables
|
||||||
|
end
|
||||||
|
|
||||||
unless answer then
|
unless answer then
|
||||||
say "Executables and scripts will remain installed."
|
say "Executables and scripts will remain installed."
|
||||||
else
|
else
|
||||||
|
raise Gem::FilePermissionError, bindir unless File.writable? bindir
|
||||||
|
|
||||||
gemspec.executables.each do |exe_name|
|
gemspec.executables.each do |exe_name|
|
||||||
say "Removing #{exe_name}"
|
say "Removing #{exe_name}"
|
||||||
FileUtils.rm_f File.join(bindir, exe_name)
|
FileUtils.rm_f File.join(bindir, exe_name)
|
||||||
|
@ -110,23 +112,22 @@ class Gem::Uninstaller
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Removes all gems in +list+.
|
||||||
#
|
#
|
||||||
# list:: the list of all gems to remove
|
# NOTE: removes uninstalled gems from +list+.
|
||||||
#
|
|
||||||
# Warning: this method modifies the +list+ parameter. Once it has
|
|
||||||
# uninstalled a gem, it is removed from that list.
|
|
||||||
#
|
|
||||||
def remove_all(list)
|
def remove_all(list)
|
||||||
list.dup.each { |gem| remove(gem, list) }
|
list.dup.each { |spec| remove spec, list }
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
##
|
||||||
# spec:: the spec of the gem to be uninstalled
|
# spec:: the spec of the gem to be uninstalled
|
||||||
# list:: the list of all such gems
|
# list:: the list of all such gems
|
||||||
#
|
#
|
||||||
# Warning: this method modifies the +list+ parameter. Once it has
|
# Warning: this method modifies the +list+ parameter. Once it has
|
||||||
# uninstalled a gem, it is removed from that list.
|
# uninstalled a gem, it is removed from that list.
|
||||||
#
|
|
||||||
def remove(spec, list)
|
def remove(spec, list)
|
||||||
unless dependencies_ok? spec then
|
unless dependencies_ok? spec then
|
||||||
raise Gem::DependencyRemovalException,
|
raise Gem::DependencyRemovalException,
|
||||||
|
@ -134,10 +135,11 @@ class Gem::Uninstaller
|
||||||
end
|
end
|
||||||
|
|
||||||
unless path_ok? spec then
|
unless path_ok? spec then
|
||||||
alert("In order to remove #{spec.name}, please execute:\n" \
|
e = Gem::GemNotInHomeException.new \
|
||||||
"\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
|
|
||||||
raise Gem::GemNotInHomeException,
|
|
||||||
"Gem is not installed in directory #{@gem_home}"
|
"Gem is not installed in directory #{@gem_home}"
|
||||||
|
e.spec = spec
|
||||||
|
|
||||||
|
raise e
|
||||||
end
|
end
|
||||||
|
|
||||||
raise Gem::FilePermissionError, spec.installation_path unless
|
raise Gem::FilePermissionError, spec.installation_path unless
|
||||||
|
@ -182,8 +184,8 @@ class Gem::Uninstaller
|
||||||
def dependencies_ok?(spec)
|
def dependencies_ok?(spec)
|
||||||
return true if @force_ignore
|
return true if @force_ignore
|
||||||
|
|
||||||
srcindex = Gem::SourceIndex.from_installed_gems
|
source_index = Gem::SourceIndex.from_installed_gems
|
||||||
deplist = Gem::DependencyList.from_source_index srcindex
|
deplist = Gem::DependencyList.from_source_index source_index
|
||||||
deplist.ok_to_remove?(spec.full_name) || ask_if_ok(spec)
|
deplist.ok_to_remove?(spec.full_name) || ask_if_ok(spec)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ module Gem
|
||||||
include DefaultUserInteraction
|
include DefaultUserInteraction
|
||||||
[
|
[
|
||||||
:choose_from_list, :ask, :ask_yes_no, :say, :alert, :alert_warning,
|
:choose_from_list, :ask, :ask_yes_no, :say, :alert, :alert_warning,
|
||||||
:alert_error, :terminate_interaction!, :terminate_interaction
|
:alert_error, :terminate_interaction
|
||||||
].each do |methname|
|
].each do |methname|
|
||||||
class_eval %{
|
class_eval %{
|
||||||
def #{methname}(*args)
|
def #{methname}(*args)
|
||||||
|
@ -182,16 +182,10 @@ module Gem
|
||||||
ask(question) if question
|
ask(question) if question
|
||||||
end
|
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
|
# Terminate the appliation normally, running any exit handlers
|
||||||
# that might have been defined.
|
# that might have been defined.
|
||||||
def terminate_interaction(status=0)
|
def terminate_interaction(status = 0)
|
||||||
exit(status)
|
raise Gem::SystemExitException, status
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return a progress reporter object
|
# Return a progress reporter object
|
||||||
|
|
86
test/rubygems/gem_installer_test_case.rb
Normal file
86
test/rubygems/gem_installer_test_case.rb
Normal file
|
@ -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
|
||||||
|
|
146
test/rubygems/gem_package_tar_test_case.rb
Normal file
146
test/rubygems/gem_package_tar_test_case.rb
Normal file
|
@ -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 'fileutils'
|
||||||
require 'test/unit'
|
require 'test/unit'
|
||||||
require 'tmpdir'
|
require 'tmpdir'
|
||||||
|
require 'tempfile'
|
||||||
require 'uri'
|
require 'uri'
|
||||||
require 'rubygems/gem_open_uri'
|
|
||||||
require 'rubygems/source_info_cache'
|
require 'rubygems/source_info_cache'
|
||||||
|
require 'rubygems/package'
|
||||||
|
|
||||||
require File.join(File.expand_path(File.dirname(__FILE__)), 'mockgemui')
|
require File.join(File.expand_path(File.dirname(__FILE__)), 'mockgemui')
|
||||||
|
|
||||||
|
@ -56,6 +57,20 @@ class FakeFetcher
|
||||||
data.respond_to?(:call) ? data.call : data.length
|
data.respond_to?(:call) ? data.call : data.length
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
class RubyGemTestCase < Test::Unit::TestCase
|
class RubyGemTestCase < Test::Unit::TestCase
|
||||||
|
@ -76,6 +91,7 @@ class RubyGemTestCase < Test::Unit::TestCase
|
||||||
@gemhome = File.join @tempdir, "gemhome"
|
@gemhome = File.join @tempdir, "gemhome"
|
||||||
@gemcache = File.join(@gemhome, "source_cache")
|
@gemcache = File.join(@gemhome, "source_cache")
|
||||||
@usrcache = File.join(@gemhome, ".gem", "user_cache")
|
@usrcache = File.join(@gemhome, ".gem", "user_cache")
|
||||||
|
@latest_usrcache = File.join(@gemhome, ".gem", "latest_user_cache")
|
||||||
|
|
||||||
FileUtils.mkdir_p @gemhome
|
FileUtils.mkdir_p @gemhome
|
||||||
|
|
||||||
|
@ -101,6 +117,11 @@ class RubyGemTestCase < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
@marshal_version = "#{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"
|
@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
|
end
|
||||||
|
|
||||||
def teardown
|
def teardown
|
||||||
|
@ -135,25 +156,52 @@ class RubyGemTestCase < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def prep_cache_files(lc)
|
def prep_cache_files(lc)
|
||||||
[ [lc.system_cache_file, 'sys'],
|
@usr_si ||= Gem::SourceIndex.new
|
||||||
[lc.user_cache_file, 'usr'],
|
@usr_sice ||= Gem::SourceInfoCacheEntry.new @usr_si, 0
|
||||||
].each do |fn, data|
|
|
||||||
FileUtils.mkdir_p File.dirname(fn).untaint
|
@sys_si ||= Gem::SourceIndex.new
|
||||||
open(fn.dup.untaint, "wb") { |f| f.write(Marshal.dump({'key' => data})) }
|
@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
|
||||||
end
|
end
|
||||||
|
|
||||||
def read_cache(fn)
|
def read_cache(path)
|
||||||
open(fn.dup.untaint) { |f| Marshal.load f.read }
|
open path.dup.untaint, 'rb' do |io|
|
||||||
|
Marshal.load io.read
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_binary(path)
|
||||||
|
Gem.read_binary path
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_file(path)
|
def write_file(path)
|
||||||
path = File.join(@gemhome, path)
|
path = File.join(@gemhome, path)
|
||||||
dir = File.dirname path
|
dir = File.dirname path
|
||||||
FileUtils.mkdir_p dir
|
FileUtils.mkdir_p dir
|
||||||
File.open(path, "w") { |io|
|
|
||||||
yield(io)
|
open path, 'wb' do |io|
|
||||||
}
|
yield io
|
||||||
|
end
|
||||||
|
|
||||||
path
|
path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -204,6 +252,23 @@ class RubyGemTestCase < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
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
|
def util_make_gems
|
||||||
init = proc do |s|
|
init = proc do |s|
|
||||||
s.files = %w[lib/code.rb]
|
s.files = %w[lib/code.rb]
|
||||||
|
@ -212,6 +277,7 @@ class RubyGemTestCase < Test::Unit::TestCase
|
||||||
|
|
||||||
@a1 = quick_gem('a', '1', &init)
|
@a1 = quick_gem('a', '1', &init)
|
||||||
@a2 = quick_gem('a', '2', &init)
|
@a2 = quick_gem('a', '2', &init)
|
||||||
|
@a_evil9 = quick_gem('a_evil', '9', &init)
|
||||||
@b2 = quick_gem('b', '2', &init)
|
@b2 = quick_gem('b', '2', &init)
|
||||||
@c1_2 = quick_gem('c', '1.2', &init)
|
@c1_2 = quick_gem('c', '1.2', &init)
|
||||||
@pl1 = quick_gem 'pl', '1' do |s| # l for legacy
|
@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 #{@c1_2.original_name} lib code.rb]) do end
|
||||||
write_file File.join(*%W[gems #{@pl1.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)
|
FileUtils.rm_r File.join(@gemhome, 'gems', @pl1.original_name)
|
||||||
|
|
||||||
|
@ -256,32 +322,19 @@ class RubyGemTestCase < Test::Unit::TestCase
|
||||||
@fetcher = FakeFetcher.new
|
@fetcher = FakeFetcher.new
|
||||||
@fetcher.uri = @uri
|
@fetcher.uri = @uri
|
||||||
|
|
||||||
@gem1 = quick_gem 'gem_one' do |gem|
|
util_make_gems
|
||||||
gem.files = %w[Rakefile lib/gem_one.rb]
|
|
||||||
end
|
|
||||||
|
|
||||||
@gem2 = quick_gem 'gem_two' do |gem|
|
@all_gems = [@a1, @a2, @a_evil9, @b2, @c1_2].sort
|
||||||
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_gem_names = @all_gems.map { |gem| gem.full_name }
|
@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")
|
@gem_names = gem_names.sort.join("\n")
|
||||||
|
|
||||||
@source_index = Gem::SourceIndex.new @gem1.full_name => @gem1,
|
@source_index = Gem::SourceIndex.new
|
||||||
@gem2.full_name => @gem2,
|
@source_index.add_spec @a1
|
||||||
@gem4.full_name => @gem4
|
@source_index.add_spec @a2
|
||||||
|
@source_index.add_spec @a_evil9
|
||||||
|
@source_index.add_spec @c1_2
|
||||||
|
|
||||||
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
|
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
|
||||||
end
|
end
|
||||||
|
@ -294,7 +347,12 @@ class RubyGemTestCase < Test::Unit::TestCase
|
||||||
|
|
||||||
sice = Gem::SourceInfoCacheEntry.new si, 0
|
sice = Gem::SourceInfoCacheEntry.new si, 0
|
||||||
sic = Gem::SourceInfoCache.new
|
sic = Gem::SourceInfoCache.new
|
||||||
|
|
||||||
sic.set_cache_data( { @gem_repo => sice } )
|
sic.set_cache_data( { @gem_repo => sice } )
|
||||||
|
sic.update
|
||||||
|
sic.write_cache
|
||||||
|
sic.reset_cache_data
|
||||||
|
|
||||||
Gem::SourceInfoCache.instance_variable_set :@cache, sic
|
Gem::SourceInfoCache.instance_variable_set :@cache, sic
|
||||||
si
|
si
|
||||||
end
|
end
|
||||||
|
@ -313,3 +371,30 @@ class RubyGemTestCase < Test::Unit::TestCase
|
||||||
|
|
||||||
end
|
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="")
|
def initialize(input="")
|
||||||
super(StringIO.new(input), StringIO.new, StringIO.new)
|
super(StringIO.new(input), StringIO.new, StringIO.new)
|
||||||
@terminated = false
|
@terminated = false
|
||||||
@banged = false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def input
|
def input
|
||||||
@ins.string
|
@ins.string
|
||||||
end
|
end
|
||||||
|
@ -30,22 +29,15 @@ class MockGemUi < Gem::StreamUI
|
||||||
@errs.string
|
@errs.string
|
||||||
end
|
end
|
||||||
|
|
||||||
def banged?
|
|
||||||
@banged
|
|
||||||
end
|
|
||||||
|
|
||||||
def terminated?
|
def terminated?
|
||||||
@terminated
|
@terminated
|
||||||
end
|
end
|
||||||
|
|
||||||
def terminate_interaction!(status=1)
|
|
||||||
@terminated = true
|
|
||||||
@banged = true
|
|
||||||
fail TermError
|
|
||||||
end
|
|
||||||
|
|
||||||
def terminate_interaction(status=0)
|
def terminate_interaction(status=0)
|
||||||
@terminated = true
|
@terminated = true
|
||||||
fail TermError
|
|
||||||
|
raise TermError
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
27
test/rubygems/private_key.pem
Normal file
27
test/rubygems/private_key.pem
Normal file
|
@ -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-----
|
20
test/rubygems/public_cert.pem
Normal file
20
test/rubygems/public_cert.pem
Normal file
|
@ -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 = [
|
expected = [
|
||||||
File.join(@gemhome, *%W[gems #{@a1.full_name} lib]),
|
File.join(@gemhome, *%W[gems #{@a1.full_name} lib]),
|
||||||
File.join(@gemhome, *%W[gems #{@a2.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 #{@b2.full_name} lib]),
|
||||||
File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
|
File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
|
||||||
File.join(@gemhome, *%W[gems #{@pl1.full_name} lib]),
|
File.join(@gemhome, *%W[gems #{@pl1.full_name} lib]),
|
||||||
|
@ -213,6 +214,7 @@ class TestGem < RubyGemTestCase
|
||||||
|
|
||||||
expected = [
|
expected = [
|
||||||
File.join(@gemhome, *%W[gems #{@a2.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 #{@b2.full_name} lib]),
|
||||||
File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
|
File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
|
||||||
File.join(@gemhome, *%W[gems #{@pl1.full_name} lib]),
|
File.join(@gemhome, *%W[gems #{@pl1.full_name} lib]),
|
||||||
|
@ -226,7 +228,7 @@ class TestGem < RubyGemTestCase
|
||||||
install_gem foo
|
install_gem foo
|
||||||
Gem.source_index = nil
|
Gem.source_index = nil
|
||||||
|
|
||||||
Gem.activate 'foo', false
|
Gem.activate 'foo'
|
||||||
|
|
||||||
assert_equal true, Gem.loaded_specs.keys.include?('foo')
|
assert_equal true, Gem.loaded_specs.keys.include?('foo')
|
||||||
end
|
end
|
||||||
|
@ -235,9 +237,29 @@ class TestGem < RubyGemTestCase
|
||||||
assert_equal [Gem.dir], Gem.path
|
assert_equal [Gem.dir], Gem.path
|
||||||
end
|
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
|
def test_self_path_ENV_PATH
|
||||||
Gem.clear_paths
|
Gem.clear_paths
|
||||||
path_count = Gem.path.size
|
path_count = Gem.path.size
|
||||||
|
path_count -= 1 if defined? APPLE_GEM_HOME
|
||||||
Gem.clear_paths
|
Gem.clear_paths
|
||||||
util_ensure_gem_dirs
|
util_ensure_gem_dirs
|
||||||
|
|
||||||
|
@ -257,8 +279,8 @@ class TestGem < RubyGemTestCase
|
||||||
ENV['GEM_PATH'] = dirs.join File::PATH_SEPARATOR
|
ENV['GEM_PATH'] = dirs.join File::PATH_SEPARATOR
|
||||||
|
|
||||||
assert_equal @gemhome, Gem.dir
|
assert_equal @gemhome, Gem.dir
|
||||||
|
|
||||||
paths = [Gem.dir]
|
paths = [Gem.dir]
|
||||||
paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
|
|
||||||
assert_equal @additional + paths, Gem.path
|
assert_equal @additional + paths, Gem.path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -270,8 +292,8 @@ class TestGem < RubyGemTestCase
|
||||||
ENV['GEM_PATH'] = @additional.join(File::PATH_SEPARATOR)
|
ENV['GEM_PATH'] = @additional.join(File::PATH_SEPARATOR)
|
||||||
|
|
||||||
assert_equal @gemhome, Gem.dir
|
assert_equal @gemhome, Gem.dir
|
||||||
|
|
||||||
paths = [Gem.dir]
|
paths = [Gem.dir]
|
||||||
paths.insert(0, APPLE_GEM_HOME) if defined? APPLE_GEM_HOME
|
|
||||||
assert_equal @additional + paths, Gem.path
|
assert_equal @additional + paths, Gem.path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -284,6 +306,18 @@ class TestGem < RubyGemTestCase
|
||||||
assert_equal File.dirname(File.dirname(file_name)), Gem.prefix
|
assert_equal File.dirname(File.dirname(file_name)), Gem.prefix
|
||||||
end
|
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
|
def test_self_required_location
|
||||||
util_make_gems
|
util_make_gems
|
||||||
|
|
||||||
|
@ -295,6 +329,13 @@ class TestGem < RubyGemTestCase
|
||||||
Gem.required_location("a", "code.rb", "= 2")
|
Gem.required_location("a", "code.rb", "= 2")
|
||||||
end
|
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
|
def test_self_searcher
|
||||||
assert_kind_of Gem::GemPathSearcher, Gem.searcher
|
assert_kind_of Gem::GemPathSearcher, Gem.searcher
|
||||||
end
|
end
|
||||||
|
|
|
@ -67,11 +67,12 @@ class TestGemCommandManager < RubyGemTestCase
|
||||||
assert_equal true, check_options[:wrappers]
|
assert_equal true, check_options[:wrappers]
|
||||||
assert_equal Gem::Requirement.default, check_options[:version]
|
assert_equal Gem::Requirement.default, check_options[:version]
|
||||||
assert_equal Gem.dir, check_options[:install_dir]
|
assert_equal Gem.dir, check_options[:install_dir]
|
||||||
|
assert_equal nil, check_options[:bin_dir]
|
||||||
|
|
||||||
#check settings
|
#check settings
|
||||||
check_options = nil
|
check_options = nil
|
||||||
@command_manager.process_args(
|
@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[:test]
|
||||||
assert_equal true, check_options[:generate_rdoc]
|
assert_equal true, check_options[:generate_rdoc]
|
||||||
assert_equal true, check_options[:force]
|
assert_equal true, check_options[:force]
|
||||||
|
@ -79,6 +80,7 @@ class TestGemCommandManager < RubyGemTestCase
|
||||||
assert_equal false, check_options[:wrappers]
|
assert_equal false, check_options[:wrappers]
|
||||||
assert_equal Gem::Requirement.new('3.0'), check_options[:version]
|
assert_equal Gem::Requirement.new('3.0'), check_options[:version]
|
||||||
assert_equal Dir.pwd, check_options[:install_dir]
|
assert_equal Dir.pwd, check_options[:install_dir]
|
||||||
|
assert_equal Dir.pwd, check_options[:bin_dir]
|
||||||
|
|
||||||
#check remote domain
|
#check remote domain
|
||||||
check_options = nil
|
check_options = nil
|
||||||
|
@ -164,7 +166,7 @@ class TestGemCommandManager < RubyGemTestCase
|
||||||
|
|
||||||
#check defaults
|
#check defaults
|
||||||
@command_manager.process_args("query")
|
@command_manager.process_args("query")
|
||||||
assert_equal(/.*/, check_options[:name])
|
assert_equal(//, check_options[:name])
|
||||||
assert_equal :local, check_options[:domain]
|
assert_equal :local, check_options[:domain]
|
||||||
assert_equal false, check_options[:details]
|
assert_equal false, check_options[:details]
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,21 @@ class TestGemCommandsEnvironmentCommand < RubyGemTestCase
|
||||||
assert_equal '', @ui.error
|
assert_equal '', @ui.error
|
||||||
end
|
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
|
def test_execute_packageversion
|
||||||
@cmd.send :handle_options, %w[packageversion]
|
@cmd.send :handle_options, %w[packageversion]
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,12 @@ class TestGemCommandsFetchCommand < RubyGemTestCase
|
||||||
def test_execute
|
def test_execute
|
||||||
util_setup_fake_fetcher
|
util_setup_fake_fetcher
|
||||||
|
|
||||||
util_build_gem @gem1
|
|
||||||
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
|
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
|
||||||
@source_index.dump
|
@source_index.dump
|
||||||
@fetcher.data["#{@gem_repo}/gems/#{@gem1.full_name}.gem"] =
|
@fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] =
|
||||||
File.read(File.join(@gemhome, 'cache', "#{@gem1.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
|
use_ui @ui do
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
|
@ -29,7 +28,7 @@ class TestGemCommandsFetchCommand < RubyGemTestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
assert File.exist?(File.join(@tempdir, "#{@gem1.full_name}.gem"))
|
assert File.exist?(File.join(@tempdir, "#{@a2.full_name}.gem"))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,25 +34,26 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
|
||||||
util_setup_fake_fetcher
|
util_setup_fake_fetcher
|
||||||
@cmd.options[:domain] = :local
|
@cmd.options[:domain] = :local
|
||||||
|
|
||||||
gem1 = quick_gem 'gem_one'
|
FileUtils.mv File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"),
|
||||||
util_build_gem gem1
|
|
||||||
FileUtils.mv File.join(@gemhome, 'cache', "#{@gem1.full_name}.gem"),
|
|
||||||
File.join(@tempdir)
|
File.join(@tempdir)
|
||||||
|
|
||||||
@cmd.options[:args] = [gem1.name]
|
@cmd.options[:args] = [@a2.name]
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
orig_dir = Dir.pwd
|
orig_dir = Dir.pwd
|
||||||
begin
|
begin
|
||||||
Dir.chdir @tempdir
|
Dir.chdir @tempdir
|
||||||
@cmd.execute
|
e = assert_raises Gem::SystemExitException do
|
||||||
|
@cmd.execute
|
||||||
|
end
|
||||||
|
assert_equal 0, e.exit_code
|
||||||
ensure
|
ensure
|
||||||
Dir.chdir orig_dir
|
Dir.chdir orig_dir
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
out = @ui.output.split "\n"
|
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_equal "1 gem installed", out.shift
|
||||||
assert out.empty?, out.inspect
|
assert out.empty?, out.inspect
|
||||||
end
|
end
|
||||||
|
@ -61,14 +62,17 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
|
||||||
util_setup_fake_fetcher
|
util_setup_fake_fetcher
|
||||||
@cmd.options[:domain] = :local
|
@cmd.options[:domain] = :local
|
||||||
|
|
||||||
@cmd.options[:args] = %w[gem_one]
|
@cmd.options[:args] = %w[no_such_gem]
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
@cmd.execute
|
e = assert_raises Gem::SystemExitException do
|
||||||
|
@cmd.execute
|
||||||
|
end
|
||||||
|
assert_equal 2, e.exit_code
|
||||||
end
|
end
|
||||||
|
|
||||||
# HACK no repository was checked
|
# 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
|
@ui.error
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -88,7 +92,10 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
|
||||||
@cmd.options[:args] = %w[nonexistent]
|
@cmd.options[:args] = %w[nonexistent]
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
@cmd.execute
|
e = assert_raises Gem::SystemExitException do
|
||||||
|
@cmd.execute
|
||||||
|
end
|
||||||
|
assert_equal 2, e.exit_code
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal "ERROR: could not find nonexistent locally or in a repository\n",
|
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
|
@cmd.options[:generate_ri] = true
|
||||||
util_setup_fake_fetcher
|
util_setup_fake_fetcher
|
||||||
|
|
||||||
util_build_gem @gem1
|
|
||||||
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
|
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] =
|
||||||
@source_index.dump
|
@source_index.dump
|
||||||
@fetcher.data["#{@gem_repo}/gems/gem_one-0.0.2.gem"] =
|
@fetcher.data["#{@gem_repo}/gems/#{@a2.full_name}.gem"] =
|
||||||
File.read(File.join(@gemhome, 'cache', "#{@gem1.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
|
use_ui @ui do
|
||||||
@cmd.execute
|
e = assert_raises Gem::SystemExitException do
|
||||||
|
@cmd.execute
|
||||||
|
end
|
||||||
|
assert_equal 0, e.exit_code
|
||||||
end
|
end
|
||||||
|
|
||||||
out = @ui.output.split "\n"
|
out = @ui.output.split "\n"
|
||||||
assert_match %r|Bulk updating|, out.shift
|
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 "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
|
out.shift
|
||||||
assert_equal "Installing RDoc documentation for #{@gem1.full_name}...",
|
assert_equal "Installing RDoc documentation for #{@a2.full_name}...",
|
||||||
out.shift
|
out.shift
|
||||||
assert out.empty?, out.inspect
|
assert out.empty?, out.inspect
|
||||||
end
|
end
|
||||||
|
@ -127,31 +136,30 @@ class TestGemCommandsInstallCommand < RubyGemTestCase
|
||||||
util_setup_fake_fetcher
|
util_setup_fake_fetcher
|
||||||
@cmd.options[:domain] = :local
|
@cmd.options[:domain] = :local
|
||||||
|
|
||||||
gem1 = quick_gem 'gem_one'
|
FileUtils.mv File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"),
|
||||||
util_build_gem gem1
|
|
||||||
FileUtils.mv File.join(@gemhome, 'cache', "#{@gem1.full_name}.gem"),
|
|
||||||
File.join(@tempdir)
|
File.join(@tempdir)
|
||||||
|
|
||||||
gem2 = quick_gem 'gem_two'
|
FileUtils.mv File.join(@gemhome, 'cache', "#{@b2.full_name}.gem"),
|
||||||
util_build_gem gem2
|
|
||||||
FileUtils.mv File.join(@gemhome, 'cache', "#{@gem2.full_name}.gem"),
|
|
||||||
File.join(@tempdir)
|
File.join(@tempdir)
|
||||||
|
|
||||||
@cmd.options[:args] = [gem1.name, gem2.name]
|
@cmd.options[:args] = [@a2.name, @b2.name]
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
orig_dir = Dir.pwd
|
orig_dir = Dir.pwd
|
||||||
begin
|
begin
|
||||||
Dir.chdir @tempdir
|
Dir.chdir @tempdir
|
||||||
@cmd.execute
|
e = assert_raises Gem::SystemExitException do
|
||||||
|
@cmd.execute
|
||||||
|
end
|
||||||
|
assert_equal 0, e.exit_code
|
||||||
ensure
|
ensure
|
||||||
Dir.chdir orig_dir
|
Dir.chdir orig_dir
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
out = @ui.output.split "\n"
|
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 "Successfully installed #{@gem2.full_name}", out.shift
|
assert_equal "Successfully installed #{@b2.full_name}", out.shift
|
||||||
assert_equal "2 gems installed", out.shift
|
assert_equal "2 gems installed", out.shift
|
||||||
assert out.empty?, out.inspect
|
assert out.empty?, out.inspect
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,20 +7,31 @@ class TestGemCommandsQueryCommand < RubyGemTestCase
|
||||||
def setup
|
def setup
|
||||||
super
|
super
|
||||||
|
|
||||||
@foo_gem = quick_gem 'foo' do |spec|
|
util_make_gems
|
||||||
spec.summary = 'This is a lot of text. ' * 5
|
|
||||||
end
|
@a2.summary = 'This is a lot of text. ' * 4
|
||||||
@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'
|
|
||||||
|
|
||||||
@cmd = Gem::Commands::QueryCommand.new
|
@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
|
end
|
||||||
|
|
||||||
def test_execute
|
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]
|
@cmd.handle_options %w[-r]
|
||||||
|
|
||||||
|
@ -32,7 +43,43 @@ class TestGemCommandsQueryCommand < RubyGemTestCase
|
||||||
|
|
||||||
*** REMOTE GEMS ***
|
*** 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
|
EOF
|
||||||
|
|
||||||
assert_equal expected, @ui.output
|
assert_equal expected, @ui.output
|
||||||
|
@ -40,8 +87,6 @@ foo (2)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_execute_details
|
def test_execute_details
|
||||||
util_setup_source_info_cache @foo_gem
|
|
||||||
|
|
||||||
@cmd.handle_options %w[-r -d]
|
@cmd.handle_options %w[-r -d]
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
|
@ -52,18 +97,94 @@ foo (2)
|
||||||
|
|
||||||
*** REMOTE GEMS ***
|
*** REMOTE GEMS ***
|
||||||
|
|
||||||
foo (2)
|
a (2, 1)
|
||||||
This is a lot of text. This is a lot of text. This is a lot of
|
This is a lot of text. This is a lot of text. This is a lot of text.
|
||||||
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
|
EOF
|
||||||
|
|
||||||
assert_equal expected, @ui.output
|
assert_equal expected, @ui.output
|
||||||
assert_equal '', @ui.error
|
assert_equal '', @ui.error
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_execute_no_versions
|
def test_execute_installed
|
||||||
util_setup_source_info_cache @foo_gem, @bar_gem
|
@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]
|
@cmd.handle_options %w[-r --no-versions]
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
|
@ -74,8 +195,8 @@ foo (2)
|
||||||
|
|
||||||
*** REMOTE GEMS ***
|
*** REMOTE GEMS ***
|
||||||
|
|
||||||
bar
|
a
|
||||||
foo
|
pl
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
assert_equal expected, @ui.output
|
assert_equal expected, @ui.output
|
||||||
|
|
|
@ -20,7 +20,7 @@ class TestGemCommandsServerCommand < RubyGemTestCase
|
||||||
@cmd.send :handle_options, %w[-p 9999 -d /nonexistent --daemon]
|
@cmd.send :handle_options, %w[-p 9999 -d /nonexistent --daemon]
|
||||||
|
|
||||||
assert_equal true, @cmd.options[: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]
|
assert_equal 9999, @cmd.options[:port]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,10 +31,11 @@ class TestGemCommandsSourcesCommand < RubyGemTestCase
|
||||||
def test_execute_add
|
def test_execute_add
|
||||||
util_setup_fake_fetcher
|
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}"] =
|
@fetcher.data["http://beta-gems.example.com/Marshal.#{@marshal_version}"] =
|
||||||
@si.dump
|
si.dump
|
||||||
|
|
||||||
@cmd.handle_options %w[--add http://beta-gems.example.com]
|
@cmd.handle_options %w[--add http://beta-gems.example.com]
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ class TestGemCommandsSourcesCommand < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
expected = <<-EOF
|
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
|
http://beta-gems.example.com added to sources
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
@ -60,14 +61,11 @@ http://beta-gems.example.com added to sources
|
||||||
def test_execute_add_nonexistent_source
|
def test_execute_add_nonexistent_source
|
||||||
util_setup_fake_fetcher
|
util_setup_fake_fetcher
|
||||||
|
|
||||||
@si = Gem::SourceIndex.new @gem1.full_name => @gem1.name
|
|
||||||
|
|
||||||
@fetcher.data["http://beta-gems.example.com/Marshal.#{@marshal_version}"] =
|
@fetcher.data["http://beta-gems.example.com/Marshal.#{@marshal_version}"] =
|
||||||
proc do
|
proc do
|
||||||
raise Gem::RemoteFetcher::FetchError, 'it died'
|
raise Gem::RemoteFetcher::FetchError, 'it died'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
|
Gem::RemoteFetcher.instance_variable_set :@fetcher, @fetcher
|
||||||
|
|
||||||
@cmd.handle_options %w[--add http://beta-gems.example.com]
|
@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
|
assert_equal '', @ui.error
|
||||||
end
|
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
|
def test_execute_remove
|
||||||
@cmd.handle_options %W[--remove #{@gem_repo}]
|
@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
|
assert_equal [], Gem::SourceInfoCache.cache_data.keys
|
||||||
end
|
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
|
def test_execute_update
|
||||||
@cmd.handle_options %w[--update]
|
@cmd.handle_options %w[--update]
|
||||||
|
|
||||||
util_setup_source_info_cache
|
util_setup_source_info_cache
|
||||||
util_setup_fake_fetcher
|
util_setup_fake_fetcher
|
||||||
@si = Gem::SourceIndex.new @gem1.full_name => @gem1.name
|
si = Gem::SourceIndex.new
|
||||||
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = @si.dump
|
si.add_spec @a1
|
||||||
|
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
@cmd.execute
|
@cmd.execute
|
||||||
end
|
end
|
||||||
|
|
||||||
expected = <<-EOF
|
expected = <<-EOF
|
||||||
Bulk updating Gem source index for: #{@gem_repo}
|
Bulk updating Gem source index for: #{@gem_repo}/
|
||||||
source cache successfully updated
|
source cache successfully updated
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ class TestGemCommandsSpecificationCommand < RubyGemTestCase
|
||||||
|
|
||||||
def test_execute
|
def test_execute
|
||||||
foo = quick_gem 'foo'
|
foo = quick_gem 'foo'
|
||||||
|
Gem.source_index.add_spec foo
|
||||||
|
|
||||||
@cmd.options[:args] = %w[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|\A--- !ruby/object:Gem::Specification|, @ui.output
|
||||||
assert_match %r|name: foo|, @ui.output
|
assert_match %r|name: foo|, @ui.output
|
||||||
assert_equal "WARNING: Remote information is not complete\n\n", @ui.error
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,15 +17,57 @@ class TestGemCommandsUnpackCommand < RubyGemTestCase
|
||||||
|
|
||||||
@cmd.options[:args] = %w[a]
|
@cmd.options[:args] = %w[a]
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
@cmd.execute
|
@cmd.execute
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
assert File.exist?(File.join(@tempdir, 'a-2'))
|
assert File.exist?(File.join(@tempdir, 'a-2'))
|
||||||
end
|
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
|
def test_execute_with_target_option
|
||||||
util_make_gems
|
util_make_gems
|
||||||
|
|
||||||
|
|
174
test/rubygems/test_gem_commands_update_command.rb
Normal file
174
test/rubygems/test_gem_commands_update_command.rb
Normal file
|
@ -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
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'a'
|
inst = Gem::DependencyInstaller.new
|
||||||
inst.install
|
inst.install 'a'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal Gem::SourceIndex.new(@a1.full_name => @a1),
|
assert_equal Gem::SourceIndex.new(@a1.full_name => @a1),
|
||||||
|
@ -70,8 +70,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'b'
|
inst = Gem::DependencyInstaller.new
|
||||||
inst.install
|
inst.install 'b'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
|
assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
|
||||||
|
@ -84,8 +84,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'b'
|
inst = Gem::DependencyInstaller.new
|
||||||
inst.install
|
inst.install 'b'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
|
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
|
||||||
|
@ -102,8 +102,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'f'
|
inst = Gem::DependencyInstaller.new
|
||||||
inst.install
|
inst.install 'f'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal %w[f-2], inst.installed_gems.map { |s| s.full_name }
|
assert_equal %w[f-2], inst.installed_gems.map { |s| s.full_name }
|
||||||
|
@ -114,19 +114,49 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'a-1.gem'
|
inst = Gem::DependencyInstaller.new :domain => :local
|
||||||
inst.install
|
inst.install 'a-1.gem'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
|
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
|
||||||
end
|
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
|
def test_install_local_subdir
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'gems/a-1.gem'
|
inst = Gem::DependencyInstaller.new :domain => :local
|
||||||
inst.install
|
inst.install 'gems/a-1.gem'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
|
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
|
||||||
|
@ -137,12 +167,11 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'a', nil, :env_shebang => true,
|
inst = Gem::DependencyInstaller.new :env_shebang => true, :wrappers => true
|
||||||
:wrappers => true
|
inst.install 'a'
|
||||||
inst.install
|
|
||||||
end
|
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'))
|
File.read(File.join(@gemhome, 'bin', 'a_bin'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -153,8 +182,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'b', nil, :force => true
|
inst = Gem::DependencyInstaller.new :force => true
|
||||||
inst.install
|
inst.install 'b'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
|
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
|
||||||
|
@ -165,8 +194,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'b', nil, :ignore_dependencies => true
|
inst = Gem::DependencyInstaller.new :ignore_dependencies => true
|
||||||
inst.install
|
inst.install 'b'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
|
assert_equal %w[b-1], inst.installed_gems.map { |s| s.full_name }
|
||||||
|
@ -179,8 +208,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'a', nil, :install_dir => gemhome2
|
inst = Gem::DependencyInstaller.new :install_dir => gemhome2
|
||||||
inst.install
|
inst.install 'a'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
|
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
|
||||||
|
@ -201,8 +230,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'b', nil, :domain => :both
|
inst = Gem::DependencyInstaller.new :domain => :both
|
||||||
inst.install
|
inst.install 'b'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal %w[a-1 b-1], inst.installed_gems.map { |s| s.full_name }
|
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
|
assert_equal b1_expected, b1.loaded_from
|
||||||
end
|
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
|
def test_install_domain_local
|
||||||
FileUtils.mv @b1_gem, @tempdir
|
FileUtils.mv @b1_gem, @tempdir
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
e = assert_raise Gem::InstallError do
|
e = assert_raise Gem::InstallError do
|
||||||
inst = Gem::DependencyInstaller.new 'b', nil, :domain => :local
|
inst = Gem::DependencyInstaller.new :domain => :local
|
||||||
inst.install
|
inst.install 'b'
|
||||||
end
|
end
|
||||||
assert_equal 'b requires a (>= 0)', e.message
|
assert_equal 'b requires a (>= 0)', e.message
|
||||||
end
|
end
|
||||||
|
@ -240,8 +289,43 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
|
|
||||||
@fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
|
@fetcher.data['http://gems.example.com/gems/a-1.gem'] = a1_data
|
||||||
|
|
||||||
inst = Gem::DependencyInstaller.new 'a', nil, :domain => :remote
|
inst = Gem::DependencyInstaller.new :domain => :remote
|
||||||
inst.install
|
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 }
|
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
|
||||||
end
|
end
|
||||||
|
@ -266,8 +350,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
@fetcher.data["http://gems.example.com/gems/#{a2_o.full_name}.gem"] =
|
@fetcher.data["http://gems.example.com/gems/#{a2_o.full_name}.gem"] =
|
||||||
a2_o_data
|
a2_o_data
|
||||||
|
|
||||||
inst = Gem::DependencyInstaller.new 'a', nil, :domain => :remote
|
inst = Gem::DependencyInstaller.new :domain => :remote
|
||||||
inst.install
|
inst.install 'a'
|
||||||
|
|
||||||
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
|
assert_equal %w[a-1], inst.installed_gems.map { |s| s.full_name }
|
||||||
end
|
end
|
||||||
|
@ -278,8 +362,8 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
inst = nil
|
inst = nil
|
||||||
|
|
||||||
Dir.chdir @tempdir do
|
Dir.chdir @tempdir do
|
||||||
inst = Gem::DependencyInstaller.new 'a'
|
inst = Gem::DependencyInstaller.new
|
||||||
inst.install
|
inst.install 'a'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal Gem::SourceIndex.new(@a1.full_name => @a1),
|
assert_equal Gem::SourceIndex.new(@a1.full_name => @a1),
|
||||||
|
@ -290,13 +374,17 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
|
|
||||||
if defined? OpenSSL then
|
if defined? OpenSSL then
|
||||||
def test_install_security_policy
|
def test_install_security_policy
|
||||||
FileUtils.mv @a1_gem, @cache_dir
|
data = File.open(@a1_gem, 'rb') { |f| f.read }
|
||||||
FileUtils.mv @b1_gem, @cache_dir
|
@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
|
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
|
e = assert_raise Gem::Exception do
|
||||||
inst.install
|
inst.install 'b'
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal 'Unsigned gem', e.message
|
assert_equal 'Unsigned gem', e.message
|
||||||
|
@ -305,145 +393,48 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_install_wrappers
|
# Wrappers don't work on mswin
|
||||||
FileUtils.mv @a1_gem, @cache_dir
|
unless win_platform? then
|
||||||
inst = Gem::DependencyInstaller.new 'a', :wrappers => true
|
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.|,
|
assert_no_match(%r|This file was generated by RubyGems.|,
|
||||||
File.read(File.join(@gemhome, 'bin', 'a_bin'))
|
File.read(File.join(@gemhome, 'bin', 'a_bin')))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_install_version
|
def test_install_version
|
||||||
FileUtils.mv @d1_gem, @cache_dir
|
data = File.open(@d2_gem, 'rb') { |f| f.read }
|
||||||
FileUtils.mv @d2_gem, @cache_dir
|
@fetcher.data['http://gems.example.com/gems/d-2.gem'] = data
|
||||||
inst = Gem::DependencyInstaller.new 'd', '= 1'
|
|
||||||
|
|
||||||
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 }
|
assert_equal %w[d-1], inst.installed_gems.map { |s| s.full_name }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_install_version_default
|
def test_install_version_default
|
||||||
FileUtils.mv @d1_gem, @cache_dir
|
data = File.open(@d2_gem, 'rb') { |f| f.read }
|
||||||
FileUtils.mv @d2_gem, @cache_dir
|
@fetcher.data['http://gems.example.com/gems/d-2.gem'] = data
|
||||||
inst = Gem::DependencyInstaller.new 'd'
|
|
||||||
|
|
||||||
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 }
|
assert_equal %w[d-2], inst.installed_gems.map { |s| s.full_name }
|
||||||
end
|
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
|
def test_find_gems_gems_with_sources
|
||||||
inst = Gem::DependencyInstaller.new 'a'
|
inst = Gem::DependencyInstaller.new
|
||||||
dep = Gem::Dependency.new 'b', '>= 0'
|
dep = Gem::Dependency.new 'b', '>= 0'
|
||||||
|
|
||||||
assert_equal [[@b1, 'http://gems.example.com']],
|
assert_equal [[@b1, 'http://gems.example.com']],
|
||||||
|
@ -452,7 +443,7 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
|
|
||||||
def test_find_gems_with_sources_local
|
def test_find_gems_with_sources_local
|
||||||
FileUtils.mv @a1_gem, @tempdir
|
FileUtils.mv @a1_gem, @tempdir
|
||||||
inst = Gem::DependencyInstaller.new 'b'
|
inst = Gem::DependencyInstaller.new
|
||||||
dep = Gem::Dependency.new 'a', '>= 0'
|
dep = Gem::Dependency.new 'a', '>= 0'
|
||||||
gems = nil
|
gems = nil
|
||||||
|
|
||||||
|
@ -462,7 +453,7 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
|
|
||||||
assert_equal 2, gems.length
|
assert_equal 2, gems.length
|
||||||
remote = gems.first
|
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'
|
assert_equal 'http://gems.example.com', remote.last, 'remote path'
|
||||||
|
|
||||||
local = gems.last
|
local = gems.last
|
||||||
|
@ -472,7 +463,9 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_gather_dependencies
|
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 }
|
assert_equal %w[a-1 b-1], inst.gems_to_install.map { |s| s.full_name }
|
||||||
end
|
end
|
||||||
|
@ -488,7 +481,9 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
@fetcher.uri = URI.parse 'http://gems.example.com'
|
@fetcher.uri = URI.parse 'http://gems.example.com'
|
||||||
@fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
|
@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 }
|
assert_equal %w[b-2 c-1], inst.gems_to_install.map { |s| s.full_name }
|
||||||
end
|
end
|
||||||
|
@ -496,14 +491,18 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
def test_gather_dependencies_platform_alternate
|
def test_gather_dependencies_platform_alternate
|
||||||
util_set_arch 'cpu-my_platform1'
|
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],
|
assert_equal %w[x-1-cpu-my_platform-1 w-1],
|
||||||
inst.gems_to_install.map { |s| s.full_name }
|
inst.gems_to_install.map { |s| s.full_name }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_gather_dependencies_platform_bump
|
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 }
|
assert_equal %w[y-1 z-1], inst.gems_to_install.map { |s| s.full_name }
|
||||||
end
|
end
|
||||||
|
@ -518,27 +517,11 @@ class TestGemDependencyInstaller < RubyGemTestCase
|
||||||
@fetcher.uri = URI.parse 'http://gems.example.com'
|
@fetcher.uri = URI.parse 'http://gems.example.com'
|
||||||
@fetcher.data['http://gems.example.com/gems/yaml'] = si.to_yaml
|
@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 }
|
assert_equal %w[d-1 e-1], inst.gems_to_install.map { |s| s.full_name }
|
||||||
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
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -47,16 +47,19 @@ class TestGemExtConfigureBuilder < RubyGemTestCase
|
||||||
end
|
end
|
||||||
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}
|
#{Regexp.escape sh_prefix_configure}#{Regexp.escape @dest_path}
|
||||||
.*?: \./configure: No such file or directory
|
.*?: #{shell_error_msg}
|
||||||
|
|
)
|
||||||
|
|
||||||
assert_match expected, error.message
|
assert_match expected, error.message
|
||||||
|
|
||||||
assert_equal "sh ./configure --prefix=#{@dest_path}", output.shift
|
assert_equal "#{sh_prefix_configure}#{@dest_path}", output.shift
|
||||||
assert_match %r|\./configure: No such file or directory\n|, output.shift
|
assert_match %r(#{shell_error_msg}\n), output.shift
|
||||||
assert_equal true, output.empty?
|
assert_equal true, output.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ class TestGemFormat < RubyGemTestCase
|
||||||
|
|
||||||
gems = Dir[File.join(@gemhome, 'cache', '*.gem')]
|
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
|
spec.original_name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,11 @@ class TestGemIndexer < RubyGemTestCase
|
||||||
assert_indexed quickdir, "index"
|
assert_indexed quickdir, "index"
|
||||||
assert_indexed quickdir, "index.rz"
|
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, "#{@a1.full_name}.gemspec.rz"
|
||||||
assert_indexed quickdir, "#{@a2.full_name}.gemspec.rz"
|
assert_indexed quickdir, "#{@a2.full_name}.gemspec.rz"
|
||||||
assert_indexed quickdir, "#{@b2.full_name}.gemspec.rz"
|
assert_indexed quickdir, "#{@b2.full_name}.gemspec.rz"
|
||||||
|
@ -74,8 +79,8 @@ class TestGemIndexer < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
expected = <<-EOF
|
expected = <<-EOF
|
||||||
Generating index for 5 gems in #{@tempdir}
|
Generating index for 6 gems in #{@tempdir}
|
||||||
.....
|
......
|
||||||
Loaded all gems
|
Loaded all gems
|
||||||
Generating master indexes (this may take a while)
|
Generating master indexes (this may take a while)
|
||||||
EOF
|
EOF
|
||||||
|
|
|
@ -4,63 +4,10 @@
|
||||||
# See LICENSE.txt for permissions.
|
# See LICENSE.txt for permissions.
|
||||||
#++
|
#++
|
||||||
|
|
||||||
require 'test/unit'
|
require File.join(File.expand_path(File.dirname(__FILE__)),
|
||||||
require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
|
'gem_installer_test_case')
|
||||||
require 'rubygems/installer'
|
|
||||||
|
|
||||||
class Gem::Installer
|
class TestGemInstaller < GemInstallerTestCase
|
||||||
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
|
|
||||||
|
|
||||||
def test_app_script_text
|
def test_app_script_text
|
||||||
util_make_exec '2', ''
|
util_make_exec '2', ''
|
||||||
|
@ -162,7 +109,7 @@ load 'my_exec'
|
||||||
@installer.gem_dir = '/nonexistent'
|
@installer.gem_dir = '/nonexistent'
|
||||||
expanded_gem_dir = @installer.send(:expand_and_validate_gem_dir)
|
expanded_gem_dir = @installer.send(:expand_and_validate_gem_dir)
|
||||||
if win_platform?
|
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
|
expanded_gem_dir = expanded_gem_dir.downcase
|
||||||
else
|
else
|
||||||
expected = '/nonexistent'
|
expected = '/nonexistent'
|
||||||
|
@ -768,7 +715,7 @@ load 'my_exec'
|
||||||
@installer.env_shebang = true
|
@installer.env_shebang = true
|
||||||
|
|
||||||
shebang = @installer.shebang 'my_exec'
|
shebang = @installer.shebang 'my_exec'
|
||||||
assert_equal "#!/usr/bin/env ruby", shebang
|
assert_equal "#!/usr/bin/env #{Gem::ConfigMap[:RUBY_INSTALL_NAME]}", shebang
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_shebang_nested
|
def test_shebang_nested
|
||||||
|
@ -855,31 +802,5 @@ load 'my_exec'
|
||||||
File.join @gemhome, 'cache', "#{spec.full_name}.gem"
|
File.join @gemhome, 'cache', "#{spec.full_name}.gem"
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
|
137
test/rubygems/test_gem_package_tar_header.rb
Normal file
137
test/rubygems/test_gem_package_tar_header.rb
Normal file
|
@ -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
|
||||||
|
|
119
test/rubygems/test_gem_package_tar_input.rb
Normal file
119
test/rubygems/test_gem_package_tar_input.rb
Normal file
|
@ -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
|
||||||
|
|
104
test/rubygems/test_gem_package_tar_output.rb
Normal file
104
test/rubygems/test_gem_package_tar_output.rb
Normal file
|
@ -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
|
||||||
|
|
53
test/rubygems/test_gem_package_tar_reader.rb
Normal file
53
test/rubygems/test_gem_package_tar_reader.rb
Normal file
|
@ -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
|
||||||
|
|
116
test/rubygems/test_gem_package_tar_reader_entry.rb
Normal file
116
test/rubygems/test_gem_package_tar_reader_entry.rb
Normal file
|
@ -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
|
||||||
|
|
151
test/rubygems/test_gem_package_tar_writer.rb
Normal file
151
test/rubygems/test_gem_package_tar_writer.rb
Normal file
|
@ -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_uri = base_server_uri + "/yaml"
|
||||||
@server_z_uri = base_server_uri + "/yaml.Z"
|
@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
|
Gem::RemoteFetcher.instance_variable_set :@fetcher, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -156,6 +163,140 @@ gems:
|
||||||
end
|
end
|
||||||
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
|
def test_explicit_proxy
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
fetcher = Gem::RemoteFetcher.new @proxy_uri
|
fetcher = Gem::RemoteFetcher.new @proxy_uri
|
||||||
|
@ -232,22 +373,6 @@ gems:
|
||||||
assert_equal 'EOFError: EOFError reading uri', e.message
|
assert_equal 'EOFError: EOFError reading uri', e.message
|
||||||
end
|
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
|
def test_fetch_path_socket_error
|
||||||
fetcher = Gem::RemoteFetcher.new nil
|
fetcher = Gem::RemoteFetcher.new nil
|
||||||
|
|
||||||
|
@ -324,6 +449,53 @@ gems:
|
||||||
end
|
end
|
||||||
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
|
def test_zip
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
self.class.enable_zip = true
|
self.class.enable_zip = true
|
||||||
|
|
|
@ -36,7 +36,8 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
fetched_index = @source_index.fetch_bulk_index @uri
|
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
|
fetched_index.gems.map { |n,s| n }.sort
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -82,7 +83,8 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
fetched_index = @source_index.fetch_bulk_index @uri
|
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
|
fetched_index.gems.map { |n,s| n }.sort
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -105,7 +107,8 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
fetched_index = @source_index.fetch_bulk_index @uri
|
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
|
fetched_index.gems.map { |n,s| n }.sort
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -123,7 +126,8 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
util_setup_bulk_fetch false
|
util_setup_bulk_fetch false
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
fetched_index = @source_index.fetch_bulk_index @uri
|
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
|
fetched_index.gems.map { |n,s| n }.sort
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -136,11 +140,32 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_fetch_quick_index
|
def test_fetch_quick_index
|
||||||
quick_index = util_zip @gem_names
|
index = util_zip @gem_names
|
||||||
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
|
latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
|
||||||
|
|
||||||
quick_index = @source_index.fetch_quick_index @uri
|
@fetcher.data["#{@gem_repo}/quick/index.rz"] = index
|
||||||
assert_equal [@gem1.full_name, @gem4.full_name, @gem2.full_name].sort,
|
@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
|
quick_index.sort
|
||||||
|
|
||||||
paths = @fetcher.paths
|
paths = @fetcher.paths
|
||||||
|
@ -155,7 +180,7 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
proc { raise Exception }
|
proc { raise Exception }
|
||||||
|
|
||||||
e = assert_raise Gem::OperationNotSupportedError do
|
e = assert_raise Gem::OperationNotSupportedError do
|
||||||
@source_index.fetch_quick_index @uri
|
@source_index.fetch_quick_index @uri, true
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal 'No quick index found: Exception', e.message
|
assert_equal 'No quick index found: Exception', e.message
|
||||||
|
@ -167,41 +192,201 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
assert paths.empty?, paths.join(', ')
|
assert paths.empty?, paths.join(', ')
|
||||||
end
|
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
|
def test_find_missing
|
||||||
missing = @source_index.find_missing [@gem3.full_name]
|
missing = @source_index.find_missing [@b2.full_name]
|
||||||
assert_equal [@gem3.full_name], missing
|
assert_equal [@b2.full_name], missing
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_find_missing_none_missing
|
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
|
assert_equal [], missing
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_latest_specs
|
def test_latest_specs
|
||||||
spec = quick_gem @gem1.name, '1'
|
p1_ruby = quick_gem 'p', '1'
|
||||||
@source_index.add_spec spec
|
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 = [
|
expected = [
|
||||||
@gem1.full_name,
|
@a2.full_name,
|
||||||
@gem2.full_name,
|
a2_platform.full_name,
|
||||||
@gem4.full_name,
|
a3_platform_other.full_name,
|
||||||
|
@c1_2.full_name,
|
||||||
|
@a_evil9.full_name,
|
||||||
|
p1_ruby.full_name,
|
||||||
|
p1_platform.full_name,
|
||||||
].sort
|
].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
|
end
|
||||||
|
|
||||||
def test_outdated
|
def test_outdated
|
||||||
sic = Gem::SourceInfoCache.new
|
util_setup_source_info_cache
|
||||||
Gem::SourceInfoCache.instance_variable_set :@cache, sic
|
|
||||||
|
|
||||||
assert_equal [], @source_index.outdated
|
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
|
util_setup_source_info_cache updated
|
||||||
|
|
||||||
assert_equal [updated.name], @source_index.outdated
|
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'
|
s.platform = Gem::Platform.new 'x86-other_platform1'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -211,28 +396,34 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_remove_extra
|
def test_remove_extra
|
||||||
@source_index.remove_extra [@gem1.full_name]
|
@source_index.add_spec @a1
|
||||||
assert_equal [@gem1.full_name], @source_index.gems.map { |n,s| n }
|
@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
|
end
|
||||||
|
|
||||||
def test_remove_extra_no_changes
|
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
|
@source_index.remove_extra gems
|
||||||
|
|
||||||
assert_equal gems, @source_index.gems.map { |n,s| n }.sort
|
assert_equal gems, @source_index.gems.map { |n,s| n }.sort
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_search
|
def test_search
|
||||||
assert_equal [@gem1, @gem4], @source_index.search("gem_one")
|
assert_equal [@a1, @a2, @a_evil9], @source_index.search('a')
|
||||||
assert_equal [@gem1], @source_index.search("gem_one", "= 2")
|
assert_equal [@a2], @source_index.search('a', '= 2')
|
||||||
|
|
||||||
assert_equal [], @source_index.search("bogusstring")
|
assert_equal [], @source_index.search('bogusstring')
|
||||||
assert_equal [], @source_index.search("gem_one", "= 3.2.1")
|
assert_equal [], @source_index.search('a', '= 3')
|
||||||
|
|
||||||
@a1 = quick_gem 'a', '1'
|
source_index = Gem::SourceIndex.new
|
||||||
@a2 = quick_gem 'a', '2'
|
source_index.add_spec @a1
|
||||||
|
source_index.add_spec @a2
|
||||||
source_index = Gem::SourceIndex.new @a1.full_name => @a1,
|
|
||||||
@a2.full_name => @a2
|
|
||||||
|
|
||||||
assert_equal [@a1], source_index.search(@a1.name, '= 1')
|
assert_equal [@a1], source_index.search(@a1.name, '= 1')
|
||||||
|
|
||||||
|
@ -276,7 +467,7 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_specification
|
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")
|
assert_nil @source_index.specification("foo-1.2.4")
|
||||||
end
|
end
|
||||||
|
@ -298,9 +489,11 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
assert_equal [], @source_index.gems.keys.sort
|
assert_equal [], @source_index.gems.keys.sort
|
||||||
|
|
||||||
use_ui @ui do
|
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
|
end
|
||||||
|
|
||||||
paths = @fetcher.paths
|
paths = @fetcher.paths
|
||||||
|
@ -315,15 +508,42 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
old_gem_conf = Gem.configuration
|
old_gem_conf = Gem.configuration
|
||||||
Gem.configuration = Gem::ConfigFile.new([])
|
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")
|
quick_index = util_zip @all_gem_names.join("\n")
|
||||||
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
|
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
|
||||||
|
|
||||||
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
|
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
|
||||||
"#{@gem3.full_name}.gemspec.rz"
|
"#{@b2.full_name}.gemspec.rz"
|
||||||
@fetcher.data[marshal_uri] = util_zip Marshal.dump(@gem3)
|
@fetcher.data[marshal_uri] = util_zip Marshal.dump(@b2)
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
@source_index.update @uri
|
@source_index.update @uri, true
|
||||||
|
|
||||||
assert_equal @all_gem_names, @source_index.gems.keys.sort
|
assert_equal @all_gem_names, @source_index.gems.keys.sort
|
||||||
end
|
end
|
||||||
|
@ -345,13 +565,13 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
|
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
|
||||||
|
|
||||||
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
|
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"
|
yaml_uri = "#{@gem_repo}/quick/#{@b2.full_name}.gemspec.rz"
|
||||||
@fetcher.data[yaml_uri] = util_zip @gem3.to_yaml
|
@fetcher.data[yaml_uri] = util_zip @b2.to_yaml
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
@source_index.update @uri
|
@source_index.update @uri, true
|
||||||
|
|
||||||
assert_equal @all_gem_names, @source_index.gems.keys.sort
|
assert_equal @all_gem_names, @source_index.gems.keys.sort
|
||||||
end
|
end
|
||||||
|
@ -374,16 +594,16 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
|
@fetcher.data["#{@gem_repo}/quick/index.rz"] = quick_index
|
||||||
|
|
||||||
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
|
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
|
||||||
"#{@gem3.full_name}.gemspec.rz"
|
"#{@b2.full_name}.gemspec.rz"
|
||||||
marshal_data = Marshal.dump(@gem3)
|
marshal_data = Marshal.dump(@b2)
|
||||||
marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr
|
marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr
|
||||||
@fetcher.data[marshal_uri] = util_zip marshal_data
|
@fetcher.data[marshal_uri] = util_zip marshal_data
|
||||||
|
|
||||||
yaml_uri = "#{@gem_repo}/quick/#{@gem3.full_name}.gemspec.rz"
|
yaml_uri = "#{@gem_repo}/quick/#{@b2.full_name}.gemspec.rz"
|
||||||
@fetcher.data[yaml_uri] = util_zip @gem3.to_yaml
|
@fetcher.data[yaml_uri] = util_zip @b2.to_yaml
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
@source_index.update @uri
|
@source_index.update @uri, true
|
||||||
|
|
||||||
assert_equal @all_gem_names, @source_index.gems.keys.sort
|
assert_equal @all_gem_names, @source_index.gems.keys.sort
|
||||||
end
|
end
|
||||||
|
@ -398,22 +618,48 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
Gem.configuration = old_gem_conf
|
Gem.configuration = old_gem_conf
|
||||||
end
|
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
|
def test_update_with_missing
|
||||||
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
|
marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
|
||||||
"#{@gem3.full_name}.gemspec.rz"
|
"#{@c1_2.full_name}.gemspec.rz"
|
||||||
dumped = Marshal.dump @gem3
|
dumped = Marshal.dump @c1_2
|
||||||
@fetcher.data[marshal_uri] = util_zip(dumped)
|
@fetcher.data[marshal_uri] = util_zip(dumped)
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
@source_index.update_with_missing @uri, [@gem3.full_name]
|
@source_index.update_with_missing @uri, [@c1_2.full_name]
|
||||||
end
|
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
|
# We don't care about the equality of undumped attributes
|
||||||
@gem3.files = spec.files
|
@c1_2.files = spec.files
|
||||||
@gem3.loaded_from = spec.loaded_from
|
@c1_2.loaded_from = spec.loaded_from
|
||||||
|
|
||||||
assert_equal @gem3, spec
|
assert_equal @c1_2, spec
|
||||||
end
|
end
|
||||||
|
|
||||||
def util_setup_bulk_fetch(compressed)
|
def util_setup_bulk_fetch(compressed)
|
||||||
|
@ -427,3 +673,4 @@ class TestGemSourceIndex < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,12 @@ class TestGemSourceInfoCache < RubyGemTestCase
|
||||||
@sic = Gem::SourceInfoCache.new
|
@sic = Gem::SourceInfoCache.new
|
||||||
@sic.instance_variable_set :@fetcher, @fetcher
|
@sic.instance_variable_set :@fetcher, @fetcher
|
||||||
|
|
||||||
|
@si_new = Gem::SourceIndex.new
|
||||||
|
@sice_new = Gem::SourceInfoCacheEntry.new @si_new, 0
|
||||||
|
|
||||||
prep_cache_files @sic
|
prep_cache_files @sic
|
||||||
|
|
||||||
|
@sic.reset_cache_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def teardown
|
def teardown
|
||||||
|
@ -35,8 +40,10 @@ class TestGemSourceInfoCache < RubyGemTestCase
|
||||||
|
|
||||||
def test_self_cache_refreshes
|
def test_self_cache_refreshes
|
||||||
Gem.configuration.update_sources = true #true by default
|
Gem.configuration.update_sources = true #true by default
|
||||||
source_index = Gem::SourceIndex.new 'key' => 'sys'
|
si = Gem::SourceIndex.new
|
||||||
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = source_index.dump
|
si.add_spec @a1
|
||||||
|
|
||||||
|
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
|
||||||
|
|
||||||
Gem.sources.replace %W[#{@gem_repo}]
|
Gem.sources.replace %W[#{@gem_repo}]
|
||||||
|
|
||||||
|
@ -51,8 +58,10 @@ class TestGemSourceInfoCache < RubyGemTestCase
|
||||||
|
|
||||||
def test_self_cache_skips_refresh_based_on_configuration
|
def test_self_cache_skips_refresh_based_on_configuration
|
||||||
Gem.configuration.update_sources = false
|
Gem.configuration.update_sources = false
|
||||||
source_index = Gem::SourceIndex.new 'key' => 'sys'
|
si = Gem::SourceIndex.new
|
||||||
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = source_index.dump
|
si.add_spec @a1
|
||||||
|
|
||||||
|
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
|
||||||
|
|
||||||
Gem.sources.replace %w[#{@gem_repo}]
|
Gem.sources.replace %w[#{@gem_repo}]
|
||||||
|
|
||||||
|
@ -66,20 +75,24 @@ class TestGemSourceInfoCache < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_self_cache_data
|
def test_self_cache_data
|
||||||
source_index = Gem::SourceIndex.new 'key' => 'sys'
|
si = Gem::SourceIndex.new
|
||||||
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = source_index.dump
|
si.add_spec @a1
|
||||||
|
|
||||||
|
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
|
||||||
|
|
||||||
Gem::SourceInfoCache.instance_variable_set :@cache, nil
|
Gem::SourceInfoCache.instance_variable_set :@cache, nil
|
||||||
sice = Gem::SourceInfoCacheEntry.new source_index, 0
|
sice = Gem::SourceInfoCacheEntry.new si, 0
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
assert_equal source_index.gems,
|
gems = Gem::SourceInfoCache.cache_data[@gem_repo].source_index.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
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_cache_data
|
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
|
end
|
||||||
|
|
||||||
def test_cache_data_dirty
|
def test_cache_data_dirty
|
||||||
|
@ -97,7 +110,14 @@ class TestGemSourceInfoCache < RubyGemTestCase
|
||||||
|
|
||||||
data = { @gem_repo => { 'totally' => 'borked' } }
|
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)
|
FileUtils.mkdir_p File.dirname(fn)
|
||||||
open(fn, "wb") { |f| f.write Marshal.dump(data) }
|
open(fn, "wb") { |f| f.write Marshal.dump(data) }
|
||||||
end
|
end
|
||||||
|
@ -113,7 +133,9 @@ class TestGemSourceInfoCache < RubyGemTestCase
|
||||||
|
|
||||||
def test_cache_data_none_readable
|
def test_cache_data_none_readable
|
||||||
FileUtils.chmod 0222, @sic.system_cache_file
|
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.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.system_cache_file).mode & 0222) != 0222
|
||||||
return if (File.stat(@sic.user_cache_file).mode & 0222) != 0222
|
return if (File.stat(@sic.user_cache_file).mode & 0222) != 0222
|
||||||
# HACK for systems that don't support chmod
|
# 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
|
assert_equal 'unable to locate a writable cache file', e.message
|
||||||
end
|
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
|
def test_cache_data_repair
|
||||||
data = {
|
data = {
|
||||||
@gem_repo => {
|
@gem_repo => {
|
||||||
|
@ -152,7 +184,8 @@ class TestGemSourceInfoCache < RubyGemTestCase
|
||||||
|
|
||||||
def test_cache_data_user_fallback
|
def test_cache_data_user_fallback
|
||||||
FileUtils.chmod 0444, @sic.system_cache_file
|
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
|
end
|
||||||
|
|
||||||
def test_cache_file
|
def test_cache_file
|
||||||
|
@ -174,60 +207,118 @@ class TestGemSourceInfoCache < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_flush
|
def test_flush
|
||||||
@sic.cache_data['key'] = 'new'
|
@sic.cache_data[@gem_repo] = @sice_new
|
||||||
@sic.update
|
@sic.update
|
||||||
@sic.flush
|
@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
|
end
|
||||||
|
|
||||||
def test_read_system_cache
|
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
|
end
|
||||||
|
|
||||||
def test_read_user_cache
|
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
|
end
|
||||||
|
|
||||||
def test_search
|
def test_search
|
||||||
si = Gem::SourceIndex.new @gem1.full_name => @gem1
|
si = Gem::SourceIndex.new
|
||||||
cache_data = {
|
si.add_spec @a1
|
||||||
@gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
|
cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
|
||||||
}
|
|
||||||
@sic.instance_variable_set :@cache_data, cache_data
|
@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
|
end
|
||||||
|
|
||||||
def test_search_dependency
|
def test_search_dependency
|
||||||
si = Gem::SourceIndex.new @gem1.full_name => @gem1
|
si = Gem::SourceIndex.new
|
||||||
cache_data = {
|
si.add_spec @a1
|
||||||
@gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
|
cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
|
||||||
}
|
|
||||||
@sic.instance_variable_set :@cache_data, cache_data
|
@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
|
end
|
||||||
|
|
||||||
def test_search_no_matches
|
def test_search_no_matches
|
||||||
si = Gem::SourceIndex.new @gem1.full_name => @gem1
|
si = Gem::SourceIndex.new
|
||||||
cache_data = {
|
si.add_spec @a1
|
||||||
@gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
|
cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
|
||||||
}
|
|
||||||
@sic.instance_variable_set :@cache_data, cache_data
|
@sic.instance_variable_set :@cache_data, cache_data
|
||||||
|
|
||||||
assert_equal [], @sic.search(/nonexistent/)
|
assert_equal [], @sic.search(/nonexistent/)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_search_no_matches_in_source
|
def test_search_no_matches_in_source
|
||||||
si = Gem::SourceIndex.new @gem1.full_name => @gem1
|
si = Gem::SourceIndex.new
|
||||||
cache_data = {
|
si.add_spec @a1
|
||||||
@gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
|
cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
|
||||||
}
|
|
||||||
@sic.instance_variable_set :@cache_data, cache_data
|
@sic.instance_variable_set :@cache_data, cache_data
|
||||||
Gem.sources.replace %w[more-gems.example.com]
|
Gem.sources.replace %w[more-gems.example.com]
|
||||||
|
|
||||||
|
@ -235,13 +326,12 @@ class TestGemSourceInfoCache < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_search_with_source
|
def test_search_with_source
|
||||||
si = Gem::SourceIndex.new @gem1.full_name => @gem1
|
si = Gem::SourceIndex.new
|
||||||
cache_data = {
|
si.add_spec @a1
|
||||||
@gem_repo => Gem::SourceInfoCacheEntry.new(si, nil)
|
cache_data = { @gem_repo => Gem::SourceInfoCacheEntry.new(si, nil) }
|
||||||
}
|
|
||||||
@sic.instance_variable_set :@cache_data, cache_data
|
@sic.instance_variable_set :@cache_data, cache_data
|
||||||
|
|
||||||
assert_equal [[@gem1, @gem_repo]],
|
assert_equal [[@a1, @gem_repo]],
|
||||||
@sic.search_with_source(//)
|
@sic.search_with_source(//)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -254,45 +344,81 @@ class TestGemSourceInfoCache < RubyGemTestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_write_cache
|
def test_write_cache
|
||||||
@sic.cache_data['key'] = 'new'
|
@sic.cache_data[@gem_repo] = @sice_new
|
||||||
@sic.write_cache
|
@sic.write_cache
|
||||||
|
|
||||||
assert_equal [['key', 'new']],
|
assert_equal [[@gem_repo, @sice_new]],
|
||||||
read_cache(@sic.system_cache_file).to_a.sort
|
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
|
read_cache(@sic.user_cache_file).to_a.sort
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_write_cache_user
|
def test_write_cache_user
|
||||||
FileUtils.chmod 0444, @sic.system_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.update
|
||||||
@sic.write_cache
|
@sic.write_cache
|
||||||
|
|
||||||
assert_equal [['key', 'sys']], read_cache(@sic.system_cache_file).to_a.sort
|
assert File.exist?(@sic.user_cache_file), 'user_cache_file'
|
||||||
assert_equal [['key', 'new']], read_cache(@sic.user_cache_file).to_a.sort
|
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
|
end
|
||||||
|
|
||||||
def test_write_cache_user_from_scratch
|
def test_write_cache_user_from_scratch
|
||||||
FileUtils.rm_rf @sic.user_cache_file
|
FileUtils.rm_rf @sic.user_cache_file
|
||||||
|
FileUtils.rm_rf @sic.latest_user_cache_file
|
||||||
|
|
||||||
FileUtils.chmod 0444, @sic.system_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.update
|
||||||
@sic.write_cache
|
@sic.write_cache
|
||||||
|
|
||||||
assert_equal [['key', 'sys']], read_cache(@sic.system_cache_file).to_a.sort
|
assert File.exist?(@sic.user_cache_file), 'system_cache_file'
|
||||||
assert_equal [['key', 'new']], read_cache(@sic.user_cache_file).to_a.sort
|
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
|
end
|
||||||
|
|
||||||
def test_write_cache_user_no_directory
|
def test_write_cache_user_no_directory
|
||||||
FileUtils.rm_rf File.dirname(@sic.user_cache_file)
|
FileUtils.rm_rf File.dirname(@sic.user_cache_file)
|
||||||
FileUtils.chmod 0444, @sic.system_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.update
|
||||||
@sic.write_cache
|
@sic.write_cache
|
||||||
|
|
||||||
assert_equal [['key','sys']], read_cache(@sic.system_cache_file).to_a.sort
|
assert_equal [[@gem_repo, @sys_sice]],
|
||||||
assert_equal [['key','new']], read_cache(@sic.user_cache_file).to_a.sort
|
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,37 +9,68 @@ class TestGemSourceInfoCacheEntry < RubyGemTestCase
|
||||||
|
|
||||||
util_setup_fake_fetcher
|
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
|
@sic_e = Gem::SourceInfoCacheEntry.new @si, @si.dump.size
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_refresh
|
def test_refresh
|
||||||
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}.Z"] =
|
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}.Z"] =
|
||||||
proc { raise Exception }
|
proc { raise }
|
||||||
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = @si.dump
|
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = @si.dump
|
||||||
|
|
||||||
assert_nothing_raised do
|
use_ui @ui do
|
||||||
@sic_e.refresh @gem_repo
|
@sic_e.refresh @gem_repo, true
|
||||||
end
|
end
|
||||||
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
|
def test_refresh_bad_uri
|
||||||
assert_raise URI::BadURIError do
|
assert_raise URI::BadURIError do
|
||||||
@sic_e.refresh 'gems.example.com'
|
@sic_e.refresh 'gems.example.com', true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_refresh_update
|
def test_refresh_update
|
||||||
si = Gem::SourceIndex.new @gem1.full_name => @gem1,
|
si = Gem::SourceIndex.new
|
||||||
@gem2.full_name => @gem2
|
si.add_spec @a1
|
||||||
|
si.add_spec @b2
|
||||||
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
|
@fetcher.data["#{@gem_repo}/Marshal.#{@marshal_version}"] = si.dump
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
@sic_e.refresh @gem_repo
|
@sic_e.refresh @gem_repo, true
|
||||||
end
|
end
|
||||||
|
|
||||||
new_gem = @sic_e.source_index.specification(@gem2.full_name)
|
new_gem = @sic_e.source_index.specification(@b2.full_name)
|
||||||
assert_equal @gem2.full_name, new_gem.full_name
|
assert_equal @b2.full_name, new_gem.full_name
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
43
test/rubygems/test_gem_uninstaller.rb
Normal file
43
test/rubygems/test_gem_uninstaller.rb
Normal file
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue