summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-04-17 20:50:00 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-04-17 20:50:00 +0000
commit22d9456b7917fe96fa81fd1d994073312753af8b (patch)
treebe157928ed84f75988ceb82a070797c3482b66a6 /lib
parent22263729af357eb86e8bc2165a9eaa6f25eec8a6 (diff)
* lib/rubygems: Update to RubyGems 1.8.22 plus r33517 and r35337 which
were ported to the rubygems git repository. See https://github.com/rubygems/rubygems/blob/1.8/History.txt for changes since 1.8.11. * test/rubygems: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35370 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/rubygems.rb80
-rw-r--r--lib/rubygems/builder.rb4
-rw-r--r--lib/rubygems/commands/build_command.rb8
-rw-r--r--lib/rubygems/commands/fetch_command.rb13
-rw-r--r--lib/rubygems/commands/pristine_command.rb6
-rw-r--r--lib/rubygems/commands/setup_command.rb19
-rw-r--r--lib/rubygems/commands/specification_command.rb26
-rw-r--r--lib/rubygems/config_file.rb4
-rw-r--r--lib/rubygems/custom_require.rb5
-rw-r--r--lib/rubygems/defaults.rb7
-rw-r--r--lib/rubygems/format.rb2
-rw-r--r--lib/rubygems/installer.rb12
-rw-r--r--lib/rubygems/installer_test_case.rb4
-rw-r--r--lib/rubygems/package/tar_input.rb32
-rw-r--r--lib/rubygems/platform.rb1
-rw-r--r--lib/rubygems/psych_additions.rb9
-rw-r--r--lib/rubygems/psych_tree.rb27
-rw-r--r--lib/rubygems/requirement.rb51
-rw-r--r--lib/rubygems/spec_fetcher.rb8
-rw-r--r--lib/rubygems/specification.rb65
-rw-r--r--lib/rubygems/syck_hack.rb65
-rw-r--r--lib/rubygems/test_case.rb33
-rw-r--r--lib/rubygems/version.rb6
23 files changed, 359 insertions, 128 deletions
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index c8f969224c..6c974fbc3d 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -7,7 +7,9 @@
module Gem
QUICKLOADER_SUCKAGE = RUBY_VERSION =~ /^1\.9\.1/
- GEM_PRELUDE_SUCKAGE = RUBY_VERSION =~ /^1\.9\.2/
+
+ # Only MRI 1.9.2 has the custom prelude.
+ GEM_PRELUDE_SUCKAGE = RUBY_VERSION =~ /^1\.9\.2/ && RUBY_ENGINE == "ruby"
end
if Gem::GEM_PRELUDE_SUCKAGE and defined?(Gem::QuickLoader) then
@@ -118,7 +120,7 @@ require "rubygems/deprecate"
# -The RubyGems Team
module Gem
- VERSION = '1.8.11'
+ VERSION = '1.8.21'
##
# Raised when RubyGems is unable to load or activate a gem. Contains the
@@ -256,7 +258,7 @@ module Gem
Gem.path.each do |gemdir|
each_load_path all_partials(gemdir) do |load_path|
- result << gemdir.add(load_path).expand_path
+ result << load_path
end
end
@@ -442,10 +444,10 @@ module Gem
# problem, then we will silently continue.
def self.ensure_gem_subdirectories dir = Gem.dir
- require 'fileutils'
-
old_umask = File.umask
- File.umask old_umask | 022
+ File.umask old_umask | 002
+
+ require 'fileutils'
%w[cache doc gems specifications].each do |name|
subdir = File.join dir, name
@@ -639,35 +641,54 @@ module Gem
index
end
+ @yaml_loaded = false
+
##
# Loads YAML, preferring Psych
def self.load_yaml
- begin
- gem 'psych', '~> 1.2', '>= 1.2.1' unless ENV['TEST_SYCK']
- rescue Gem::LoadError
- # It's OK if the user does not have the psych gem installed. We will
- # attempt to require the stdlib version
- end
+ return if @yaml_loaded
- begin
- # Try requiring the gem version *or* stdlib version of psych.
- require 'psych' unless ENV['TEST_SYCK']
- rescue ::LoadError
- ensure
- require 'yaml'
- end
+ test_syck = ENV['TEST_SYCK']
- # Hack to handle syck's DefaultKey bug with psych.
- # See the note at the top of lib/rubygems/requirement.rb for
- # why we end up defining DefaultKey more than once.
- if !defined? YAML::Syck
- YAML.module_eval do
- const_set 'Syck', Module.new {
- const_set 'DefaultKey', Class.new
- }
+ unless test_syck
+ begin
+ gem 'psych', '~> 1.2', '>= 1.2.1'
+ rescue Gem::LoadError
+ # It's OK if the user does not have the psych gem installed. We will
+ # attempt to require the stdlib version
+ end
+
+ begin
+ # Try requiring the gem version *or* stdlib version of psych.
+ require 'psych'
+ rescue ::LoadError
+ # If we can't load psych, thats fine, go on.
+ else
+ # If 'yaml' has already been required, then we have to
+ # be sure to switch it over to the newly loaded psych.
+ if defined?(YAML::ENGINE) && YAML::ENGINE.yamler != "psych"
+ YAML::ENGINE.yamler = "psych"
end
+
+ require 'rubygems/psych_additions'
+ require 'rubygems/psych_tree'
+ end
end
+
+ require 'yaml'
+
+ # If we're supposed to be using syck, then we may have to force
+ # activate it via the YAML::ENGINE API.
+ if test_syck and defined?(YAML::ENGINE)
+ YAML::ENGINE.yamler = "syck" unless YAML::ENGINE.syck?
+ end
+
+ # Now that we're sure some kind of yaml library is loaded, pull
+ # in our hack to deal with Syck's DefaultKey ugliness.
+ require 'rubygems/syck_hack'
+
+ @yaml_loaded = true
end
##
@@ -987,9 +1008,8 @@ module Gem
def self.loaded_path? path
# TODO: ruby needs a feature to let us query what's loaded in 1.8 and 1.9
- $LOADED_FEATURES.find { |s|
- s =~ /(^|\/)#{Regexp.escape path}#{Regexp.union(*Gem.suffixes)}$/
- }
+ re = /(^|\/)#{Regexp.escape path}#{Regexp.union(*Gem.suffixes)}$/
+ $LOADED_FEATURES.any? { |s| s =~ re }
end
##
diff --git a/lib/rubygems/builder.rb b/lib/rubygems/builder.rb
index a8e96dd90c..25e8fc8321 100644
--- a/lib/rubygems/builder.rb
+++ b/lib/rubygems/builder.rb
@@ -32,9 +32,9 @@ class Gem::Builder
# Builds the gem from the specification. Returns the name of the file
# written.
- def build
+ def build(skip_validation=false)
@spec.mark_version
- @spec.validate
+ @spec.validate unless skip_validation
@signer = sign
write_package
say success if Gem.configuration.verbose
diff --git a/lib/rubygems/commands/build_command.rb b/lib/rubygems/commands/build_command.rb
index 572a5c36ec..36a6fe48f2 100644
--- a/lib/rubygems/commands/build_command.rb
+++ b/lib/rubygems/commands/build_command.rb
@@ -4,7 +4,11 @@ require 'rubygems/builder'
class Gem::Commands::BuildCommand < Gem::Command
def initialize
- super('build', 'Build a gem from a gemspec')
+ super 'build', 'Build a gem from a gemspec'
+
+ add_option '--force', 'skip validation of the spec' do |value, options|
+ options[:force] = true
+ end
end
def arguments # :nodoc:
@@ -22,7 +26,7 @@ class Gem::Commands::BuildCommand < Gem::Command
spec = load_gemspec gemspec
if spec then
- Gem::Builder.new(spec).build
+ Gem::Builder.new(spec).build options[:force]
else
alert_error "Error loading gemspec. Aborting."
terminate_interaction 1
diff --git a/lib/rubygems/commands/fetch_command.rb b/lib/rubygems/commands/fetch_command.rb
index 666d83e730..e7c9cc9525 100644
--- a/lib/rubygems/commands/fetch_command.rb
+++ b/lib/rubygems/commands/fetch_command.rb
@@ -13,6 +13,7 @@ class Gem::Commands::FetchCommand < Gem::Command
add_bulk_threshold_option
add_proxy_option
add_source_option
+ add_clear_sources_option
add_version_option
add_platform_option
@@ -58,8 +59,16 @@ class Gem::Commands::FetchCommand < Gem::Command
next
end
- path = Gem::RemoteFetcher.fetcher.download spec, source_uri
- FileUtils.mv path, File.basename(spec.cache_file)
+ file = "#{spec.full_name}.gem"
+ remote_path = URI.parse(source_uri) + "gems/#{file}"
+
+ fetch = Gem::RemoteFetcher.fetcher
+
+ gem = fetch.fetch_path remote_path.to_s
+
+ File.open file, "wb" do |f|
+ f.write gem
+ end
say "Downloaded #{spec.full_name}"
end
diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb
index 272a4dd18e..83e6cc7a67 100644
--- a/lib/rubygems/commands/pristine_command.rb
+++ b/lib/rubygems/commands/pristine_command.rb
@@ -94,10 +94,14 @@ extensions.
end
# TODO use installer options
+ install_defaults = Gem::ConfigFile::PLATFORM_DEFAULTS['install']
+ installer_env_shebang = install_defaults.to_s['--env-shebang']
+
installer = Gem::Installer.new(gem,
:wrappers => true,
:force => true,
- :install_dir => spec.base_dir)
+ :install_dir => spec.base_dir,
+ :env_shebang => installer_env_shebang)
installer.install
say "Restored #{spec.full_name}"
diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb
index 52a3b88fe3..0c957393d9 100644
--- a/lib/rubygems/commands/setup_command.rb
+++ b/lib/rubygems/commands/setup_command.rb
@@ -252,9 +252,19 @@ TEXT
end
def make_destination_dirs(install_destdir)
- lib_dir = nil
- bin_dir = nil
+ lib_dir, bin_dir = Gem.default_rubygems_dirs
+ unless lib_dir
+ lib_dir, bin_dir = generate_default_dirs(install_destdir)
+ end
+
+ mkdir_p lib_dir
+ mkdir_p bin_dir
+
+ return lib_dir, bin_dir
+ end
+
+ def generate_default_dirs(install_destdir)
prefix = options[:prefix]
site_or_vendor = options[:site_or_vendor]
@@ -283,10 +293,7 @@ TEXT
bin_dir = File.join install_destdir, bin_dir.gsub(/^[a-zA-Z]:/, '')
end
- mkdir_p lib_dir
- mkdir_p bin_dir
-
- return lib_dir, bin_dir
+ [lib_dir, bin_dir]
end
def remove_old_bin_files(bin_dir)
diff --git a/lib/rubygems/commands/specification_command.rb b/lib/rubygems/commands/specification_command.rb
index 921fd519e9..566a9cc66e 100644
--- a/lib/rubygems/commands/specification_command.rb
+++ b/lib/rubygems/commands/specification_command.rb
@@ -62,7 +62,25 @@ FIELD name of gemspec field to show
"Please specify a gem name or file on the command line"
end
- dep = Gem::Dependency.new gem, options[:version]
+ case options[:version]
+ when String
+ req = Gem::Requirement.parse options[:version]
+ when Gem::Requirement
+ req = options[:version]
+ else
+ raise Gem::CommandLineError, "Unsupported version type: #{options[:version]}"
+ end
+
+ if !req.none? and options[:all]
+ alert_error "Specify --all or -v, not both"
+ terminate_interaction 1
+ end
+
+ if options[:all]
+ dep = Gem::Dependency.new gem
+ else
+ dep = Gem::Dependency.new gem, options[:version]
+ end
field = get_one_optional_argument
@@ -80,7 +98,11 @@ FIELD name of gemspec field to show
end
if remote? then
- found = Gem::SpecFetcher.fetcher.fetch dep
+ found = Gem::SpecFetcher.fetcher.fetch dep, true
+
+ if dep.prerelease? or options[:prerelease]
+ found += Gem::SpecFetcher.fetcher.fetch dep, false, true, true
+ end
specs.push(*found.map { |spec,| spec })
end
diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb
index a4237e143f..d77dbd9235 100644
--- a/lib/rubygems/config_file.rb
+++ b/lib/rubygems/config_file.rb
@@ -25,6 +25,8 @@
# +:sources+:: Sets Gem::sources
# +:verbose+:: See #verbose
+require 'rbconfig'
+
class Gem::ConfigFile
DEFAULT_BACKTRACE = false
@@ -68,7 +70,7 @@ class Gem::ConfigFile
path.strip
rescue LoadError
- "/etc"
+ RbConfig::CONFIG["sysconfdir"] || "/etc"
end
end
diff --git a/lib/rubygems/custom_require.rb b/lib/rubygems/custom_require.rb
index 641db842ac..c813e3aaa2 100644
--- a/lib/rubygems/custom_require.rb
+++ b/lib/rubygems/custom_require.rb
@@ -32,7 +32,7 @@ module Kernel
# that file has already been loaded is preserved.
def require path
- if Gem.unresolved_deps.empty? or Gem.loaded_path? path then
+ if Gem.unresolved_deps.empty? then
gem_original_require path
else
spec = Gem::Specification.find { |s|
@@ -55,7 +55,8 @@ module Kernel
return gem_original_require path
end
rescue LoadError => load_error
- if load_error.message.end_with?(path) and Gem.try_activate(path) then
+ if load_error.message.start_with?("Could not find") or
+ (load_error.message.end_with?(path) and Gem.try_activate(path)) then
return gem_original_require(path)
end
diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb
index 20b4198bfa..d6732adbfa 100644
--- a/lib/rubygems/defaults.rb
+++ b/lib/rubygems/defaults.rb
@@ -44,6 +44,13 @@ module Gem
end
##
+ # Paths where RubyGems' .rb files and bin files are installed
+
+ def self.default_rubygems_dirs
+ nil # default to standard layout
+ end
+
+ ##
# Path for gems in the user's home directory
def self.user_dir
diff --git a/lib/rubygems/format.rb b/lib/rubygems/format.rb
index 246c599316..9644f6ab8e 100644
--- a/lib/rubygems/format.rb
+++ b/lib/rubygems/format.rb
@@ -28,7 +28,7 @@ class Gem::Format
# representing the data in the gem
def self.from_file_by_path(file_path, security_policy = nil)
- unless File.exist?(file_path)
+ unless File.file?(file_path)
raise Gem::Exception, "Cannot load gem at [#{file_path}] in #{Dir.pwd}"
end
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 74d803d7fa..31fb1209c9 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -366,7 +366,7 @@ class Gem::Installer
if /\A#!/ =~ first_line then
# Preserve extra words on shebang line, like "-w". Thanks RPA.
- shebang = first_line.sub(/\A\#!.*?ruby\S*(?=(\s+\S+))/, "#!#{Gem.ruby}")
+ shebang = first_line.sub(/\A\#!.*?ruby\S*((\s+\S+)+)/, "#!#{Gem.ruby}")
opts = $1
shebang.strip! # Avoid nasty ^M issues.
end
@@ -466,9 +466,13 @@ require 'rubygems'
version = "#{Gem::Requirement.default}"
-if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
- version = $1
- ARGV.shift
+if ARGV.first
+ str = ARGV.first
+ str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
+ if str =~ /\\A_(.*)_\\z/
+ version = $1
+ ARGV.shift
+ end
end
gem '#{spec.name}', version
diff --git a/lib/rubygems/installer_test_case.rb b/lib/rubygems/installer_test_case.rb
index 7c7b3b98af..96a5156995 100644
--- a/lib/rubygems/installer_test_case.rb
+++ b/lib/rubygems/installer_test_case.rb
@@ -118,7 +118,9 @@ class Gem::InstallerTestCase < Gem::TestCase
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('bin', 'executable'), 'w' do |f|
+ f.puts "raise 'ran executable'"
+ 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
diff --git a/lib/rubygems/package/tar_input.rb b/lib/rubygems/package/tar_input.rb
index 5ac93ff336..77b4d698da 100644
--- a/lib/rubygems/package/tar_input.rb
+++ b/lib/rubygems/package/tar_input.rb
@@ -210,21 +210,25 @@ class Gem::Package::TarInput
# 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.
-
+ #
+ # Revisited. Here's the beginning of the long story.
+ # http://osdir.com/ml/lang.ruby.gems.devel/2007-06/msg00045.html
+ #
+ # StringIO wraping has never worked as a workaround by definition. Skipping
+ # initial 10 bytes and passing -MAX_WBITS to Zlib::Inflate luckily works as
+ # gzip reader, but it only works if the GZip header is 10 bytes long (see
+ # below) and it does not check inflated stream consistency (CRC value in the
+ # Gzip trailer.)
+ #
+ # RubyGems generated Gzip Header: 10 bytes
+ # magic(2) + method(1) + flag(1) + mtime(4) + exflag(1) + os(1) +
+ # orig_name(0) + comment(0)
+ #
+ # Ideally, it must return a GZipReader without meaningless buffering. We
+ # have lots of CRuby committers around so let's fix windows build when we
+ # received an error.
def zipped_stream(entry)
- if defined? Rubinius or defined? Maglev then
- # these implementations have working Zlib
- 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
+ Zlib::GzipReader.new entry
end
end
diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb
index 4a4e3c1b35..682714a5de 100644
--- a/lib/rubygems/platform.rb
+++ b/lib/rubygems/platform.rb
@@ -68,6 +68,7 @@ class Gem::Platform
when /aix(\d+)/ then [ 'aix', $1 ]
when /cygwin/ then [ 'cygwin', nil ]
when /darwin(\d+)?/ then [ 'darwin', $1 ]
+ when /^macruby$/ then [ 'macruby', nil ]
when /freebsd(\d+)/ then [ 'freebsd', $1 ]
when /hpux(\d+)/ then [ 'hpux', $1 ]
when /^java$/, /^jruby$/ then [ 'java', nil ]
diff --git a/lib/rubygems/psych_additions.rb b/lib/rubygems/psych_additions.rb
new file mode 100644
index 0000000000..08a5cb37ea
--- /dev/null
+++ b/lib/rubygems/psych_additions.rb
@@ -0,0 +1,9 @@
+# This exists just to satify bugs in marshal'd gemspecs that
+# contain a reference to YAML::PrivateType. We prune these out
+# in Specification._load, but if we don't have the constant, Marshal
+# blows up.
+
+module Psych
+ class PrivateType
+ end
+end
diff --git a/lib/rubygems/psych_tree.rb b/lib/rubygems/psych_tree.rb
new file mode 100644
index 0000000000..eca8249383
--- /dev/null
+++ b/lib/rubygems/psych_tree.rb
@@ -0,0 +1,27 @@
+module Gem
+ if defined? ::Psych::Visitors
+ class NoAliasYAMLTree < Psych::Visitors::YAMLTree
+ def visit_String(str)
+ return super unless str == '=' # or whatever you want
+
+ quote = Psych::Nodes::Scalar::SINGLE_QUOTED
+ @emitter.scalar str, nil, nil, false, true, quote
+ end
+
+ # Noop this out so there are no anchors
+ def register(target, obj)
+ end
+
+ # This is ported over from the yaml_tree in 1.9.3
+ def format_time time
+ if time.utc?
+ time.strftime("%Y-%m-%d %H:%M:%S.%9N Z")
+ else
+ time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z")
+ end
+ end
+
+ private :format_time
+ end
+ end
+end
diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb
index ed5cacc237..7abff01c39 100644
--- a/lib/rubygems/requirement.rb
+++ b/lib/rubygems/requirement.rb
@@ -1,35 +1,18 @@
require "rubygems/version"
-# :stopdoc:
-
-# Hack to handle syck's DefaultKey bug with psych
-#
-# Quick note! If/when psych loads in 1.9, it will redefine
-# YAML to point to Psych by removing the YAML constant.
-# Thusly, over in Gem.load_yaml, we define DefaultKey again
-# after proper yaml library has been loaded.
-#
-# All this is so that there is always a YAML::Syck::DefaultKey
-# class no matter if the full yaml library has loaded or not.
-#
-module YAML
- if !defined? Syck
- module Syck
- class DefaultKey
- def to_s
- '='
- end
- end
- end
- end
-end
-
-# :startdoc:
-
##
# A Requirement is a set of one or more version restrictions. It supports a
# few (<tt>=, !=, >, <, >=, <=, ~></tt>) different restriction operators.
+# REFACTOR: The fact that a requirement is singular or plural is kind of
+# awkward. Is Requirement the right name for this? Or should it be one
+# [op, number] pair, and we call the list of requirements something else?
+# Since a Requirement is held by a Dependency, maybe this should be made
+# singular and the list aspect should be pulled up into Dependency?
+
+require "rubygems/version"
+require "rubygems/deprecate"
+
class Gem::Requirement
include Comparable
@@ -147,6 +130,18 @@ class Gem::Requirement
fix_syck_default_key_in_requirements
end
+ def yaml_initialize(tag, vals) # :nodoc:
+ vals.each do |ivar, val|
+ instance_variable_set "@#{ivar}", val
+ end
+
+ fix_syck_default_key_in_requirements
+ end
+
+ def init_with coder # :nodoc:
+ yaml_initialize coder.tag, coder.map
+ end
+
def prerelease?
requirements.any? { |r| r.last.prerelease? }
end
@@ -188,9 +183,11 @@ class Gem::Requirement
private
def fix_syck_default_key_in_requirements
+ Gem.load_yaml
+
# Fixup the Syck DefaultKey bug
@requirements.each do |r|
- if r[0].kind_of? YAML::Syck::DefaultKey
+ if r[0].kind_of? Gem::SyckDefaultKey
r[0] = "="
end
end
diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb
index ad61267cae..7302ad9ffa 100644
--- a/lib/rubygems/spec_fetcher.rb
+++ b/lib/rubygems/spec_fetcher.rb
@@ -255,8 +255,12 @@ class Gem::SpecFetcher
loaded = false
if File.exist? local_file then
- spec_dump =
- @fetcher.fetch_path(spec_path, File.mtime(local_file)) rescue nil
+ begin
+ spec_dump =
+ @fetcher.fetch_path(spec_path, File.mtime(local_file))
+ rescue Gem::RemoteFetcher::FetchError => e
+ alert_warning "Error fetching data: #{e.message}"
+ end
loaded = true if spec_dump
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index 97db19e69a..70a3fd09b4 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -262,18 +262,19 @@ class Gem::Specification
def self._all # :nodoc:
unless defined?(@@all) && @@all then
- specs = []
+ specs = {}
- self.dirs.reverse_each { |dir|
+ self.dirs.each { |dir|
Dir[File.join(dir, "*.gemspec")].each { |path|
spec = Gem::Specification.load path.untaint
# #load returns nil if the spec is bad, so we just ignore
# it at this stage
- specs << spec if spec
+ specs[spec.full_name] ||= spec if spec
}
}
- @@all = specs
+ @@all = specs.values
+
_resort!
end
@@all
@@ -484,6 +485,8 @@ class Gem::Specification
# +input+ can be anything that YAML.load() accepts: String or IO.
def self.from_yaml(input)
+ Gem.load_yaml
+
input = normalize_yaml_input input
spec = YAML.load input
@@ -535,7 +538,7 @@ class Gem::Specification
file = file.dup.untaint
code = if defined? Encoding
- File.read file, :encoding => "UTF-8"
+ File.read file, :mode => 'r:UTF-8:-'
else
File.read file
end
@@ -663,11 +666,16 @@ class Gem::Specification
raise TypeError, "invalid Gem::Specification format #{array.inspect}"
end
+ # Cleanup any YAML::PrivateType. They only show up for an old bug
+ # where nil => null, so just convert them to nil based on the type.
+
+ array.map! { |e| e.kind_of?(YAML::PrivateType) ? nil : e }
+
spec.instance_variable_set :@rubygems_version, array[0]
# spec version
spec.instance_variable_set :@name, array[2]
spec.instance_variable_set :@version, array[3]
- spec.instance_variable_set :@date, array[4]
+ spec.date = array[4]
spec.instance_variable_set :@summary, array[5]
spec.instance_variable_set :@required_ruby_version, array[6]
spec.instance_variable_set :@required_rubygems_version, array[7]
@@ -756,8 +764,16 @@ class Gem::Specification
def activate_dependencies
self.runtime_dependencies.each do |spec_dep|
- # TODO: check for conflicts! not just name!
- next if Gem.loaded_specs.include? spec_dep.name
+ if loaded = Gem.loaded_specs[spec_dep.name]
+ next if spec_dep.matches_spec? loaded
+
+ msg = "can't satisfy '#{spec_dep}', already activated '#{loaded.full_name}'"
+ e = Gem::LoadError.new msg
+ e.name = spec_dep.name
+
+ raise e
+ end
+
specs = spec_dep.to_specs
if specs.size == 1 then
@@ -986,6 +1002,12 @@ class Gem::Specification
when String then
if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
Time.utc($1.to_i, $2.to_i, $3.to_i)
+
+ # Workaround for where the date format output from psych isn't
+ # parsed as a Time object by syck and thus comes through as a
+ # string.
+ elsif /\A(\d{4})-(\d{2})-(\d{2}) \d{2}:\d{2}:\d{2}\.\d+?Z\z/ =~ date then
+ Time.utc($1.to_i, $2.to_i, $3.to_i)
else
raise(Gem::InvalidSpecificationException,
"invalid date format in specification: #{date.inspect}")
@@ -1362,7 +1384,7 @@ class Gem::Specification
val = other_spec.instance_variable_get(name)
if val then
instance_variable_set name, val.dup
- else
+ elsif Gem.configuration.really_verbose
warn "WARNING: #{full_name} has an invalid nil value for #{name}"
end
rescue TypeError
@@ -1912,7 +1934,22 @@ class Gem::Specification
def to_yaml(opts = {}) # :nodoc:
if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck? then
- super.gsub(/ !!null \n/, " \n")
+ # Because the user can switch the YAML engine behind our
+ # back, we have to check again here to make sure that our
+ # psych code was properly loaded, and load it if not.
+ unless Gem.const_defined?(:NoAliasYAMLTree)
+ require 'rubygems/psych_tree'
+ end
+
+ builder = Gem::NoAliasYAMLTree.new({})
+ builder << self
+ ast = builder.tree
+
+ io = StringIO.new
+
+ Psych::Visitors::Emitter.new(io).accept(ast)
+
+ io.string.gsub(/ !!null \n/, " \n")
else
YAML.quick_emit object_id, opts do |out|
out.map taguri, to_yaml_style do |map|
@@ -2097,7 +2134,13 @@ class Gem::Specification
# FIX: have this handle the platform/new_platform/original_platform bullshit
def yaml_initialize(tag, vals) # :nodoc:
vals.each do |ivar, val|
- instance_variable_set "@#{ivar}", val
+ case ivar
+ when "date"
+ # Force Date to go through the extra coerce logic in date=
+ self.date = val.untaint
+ else
+ instance_variable_set "@#{ivar}", val.untaint
+ end
end
@original_platform = @platform # for backwards compatibility
diff --git a/lib/rubygems/syck_hack.rb b/lib/rubygems/syck_hack.rb
new file mode 100644
index 0000000000..154d1d16f1
--- /dev/null
+++ b/lib/rubygems/syck_hack.rb
@@ -0,0 +1,65 @@
+# :stopdoc:
+
+# Hack to handle syck's DefaultKey bug
+#
+# This file is always loaded AFTER either syck or psych are already
+# loaded. It then looks at what constants are available and creates
+# a consistent view on all rubys.
+#
+# All this is so that there is always a YAML::Syck::DefaultKey
+# class no matter if the full yaml library has loaded or not.
+#
+
+module YAML
+ # In newer 1.9.2, there is a Syck toplevel constant instead of it
+ # being underneith YAML. If so, reference it back under YAML as
+ # well.
+ if defined? ::Syck
+ Syck = ::Syck
+
+ # JRuby's "Syck" is called "Yecht"
+ elsif defined? YAML::Yecht
+ Syck = YAML::Yecht
+
+ # Otherwise, if there is no YAML::Syck, then we've got just psych
+ # loaded, so lets define a stub for DefaultKey.
+ elsif !defined? YAML::Syck
+ module Syck
+ class DefaultKey
+ end
+ end
+ end
+
+ # Now that we've got something that is always here, define #to_s
+ # so when code tries to use this, it at least just shows up like it
+ # should.
+ module Syck
+ class DefaultKey
+ def to_s
+ '='
+ end
+ end
+ end
+end
+
+# Sometime in the 1.9 dev cycle, the Syck constant was moved from under YAML
+# to be a toplevel constant. So gemspecs created under these versions of Syck
+# will have references to Syck::DefaultKey.
+#
+# So we need to be sure that we reference Syck at the toplevel too so that
+# we can always load these kind of gemspecs.
+#
+if !defined?(Syck)
+ Syck = YAML::Syck
+end
+
+# Now that we've got Syck setup in all the right places, store
+# a reference to the DefaultKey class inside Gem. We do this so that
+# if later on YAML, etc are redefined, we've still got a consistent
+# place to find the DefaultKey class for comparison.
+
+module Gem
+ SyckDefaultKey = YAML::Syck::DefaultKey
+end
+
+# :startdoc:
diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb
index 6aed3487c6..9fbdfca52e 100644
--- a/lib/rubygems/test_case.rb
+++ b/lib/rubygems/test_case.rb
@@ -243,7 +243,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
##
# Builds and installs the Gem::Specification +spec+
- def install_gem spec
+ def install_gem spec, options = {}
require 'rubygems/installer'
use_ui Gem::MockGemUi.new do
@@ -254,26 +254,14 @@ class Gem::TestCase < MiniTest::Unit::TestCase
gem = File.join(@tempdir, File.basename(spec.cache_file)).untaint
- Gem::Installer.new(gem, :wrappers => true).install
+ Gem::Installer.new(gem, options.merge({:wrappers => true})).install
end
##
# Builds and installs the Gem::Specification +spec+ into the user dir
def install_gem_user spec
- require 'rubygems/installer'
-
- use_ui Gem::MockGemUi.new do
- Dir.chdir @tempdir do
- Gem::Builder.new(spec).build
- end
- end
-
- gem = File.join(@tempdir, File.basename(spec.cache_file)).untaint
-
- i = Gem::Installer.new(gem, :wrappers => true, :user_install => true)
- i.install
- i.spec
+ install_gem spec, :user_install => true
end
##
@@ -499,8 +487,11 @@ class Gem::TestCase < MiniTest::Unit::TestCase
if deps then
block = proc do |s|
- deps.each do |n, req|
- s.add_dependency n, (req || '>= 0')
+ # Since Hash#each is unordered in 1.8, sort
+ # the keys and iterate that way so the tests are
+ # deteriminstic on all implementations.
+ deps.keys.sort.each do |n|
+ s.add_dependency n, (deps[n] || '>= 0')
end
end
end
@@ -520,8 +511,11 @@ class Gem::TestCase < MiniTest::Unit::TestCase
if deps then
block = proc do |s|
- deps.each do |n, req|
- s.add_dependency n, (req || '>= 0')
+ # Since Hash#each is unordered in 1.8, sort
+ # the keys and iterate that way so the tests are
+ # deteriminstic on all implementations.
+ deps.keys.sort.each do |n|
+ s.add_dependency n, (deps[n] || '>= 0')
end
end
end
@@ -874,4 +868,3 @@ Also, a list:
end
end
-
diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb
index 62af34462d..ecf9f2b4ce 100644
--- a/lib/rubygems/version.rb
+++ b/lib/rubygems/version.rb
@@ -238,6 +238,12 @@ class Gem::Version
initialize array[0]
end
+ def yaml_initialize(tag, map)
+ @version = map['version']
+ @segments = nil
+ @hash = nil
+ end
+
##
# A version is considered a prerelease if it contains a letter.