Permalink
Browse files

Port the Psych/Syck YAML fix from Rubygems 1.8.24

The existing Psych/Syck fix wasn't working in certain circumstances
(gem fetch XXXXX, for example), so the broader solution from
Rubygems 1.8.24 was used instead. This resolved the problem without
breaking existing tests.
  • Loading branch information...
mckern committed May 4, 2012
1 parent 39c38dc commit e7aa0c2eff691bee5106210b8b8fc92ddf055da0
Showing with 173 additions and 22 deletions.
  1. +45 −15 lib/rubygems.rb
  2. +9 −0 lib/rubygems/psych_additions.rb
  3. +27 −0 lib/rubygems/psych_tree.rb
  4. +18 −7 lib/rubygems/requirement.rb
  5. +74 −0 lib/rubygems/syck_hack.rb
View
@@ -106,7 +106,7 @@
module Gem
NAME = 'SlimGems'
GEM_NAME = 'slimgems'
- VERSION = '1.3.9.4'
+ VERSION = '1.3.9.5'
SlimGemsVersion = RubyGemsVersion = VERSION
##
@@ -633,24 +633,54 @@ def self.remove_prelude_paths
##
# Loads YAML, preferring Psych
+@yaml_loaded = false
+
+ ##
+ # Loads YAML, preferring Psych
+
def self.load_yaml
- begin
- require 'psych' unless ENV['TEST_SYCK']
- rescue ::LoadError
- ensure
- require 'yaml'
- end
+ return if @yaml_loaded
+
+ test_syck = ENV['TEST_SYCK']
+
+ 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
- # 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
- }
+ 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
##
@@ -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
View
@@ -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
@@ -129,18 +129,15 @@ def hash # :nodoc:
end
def marshal_dump # :nodoc:
+ fix_syck_default_key_in_requirements
+
[@requirements]
end
def marshal_load array # :nodoc:
@requirements = array[0]
- # Fixup the Syck DefaultKey bug
- @requirements.each do |r|
- if r[0].kind_of? YAML::Syck::DefaultKey
- r[0] = "="
- end
- end
+ fix_syck_default_key_in_requirements
end
def prerelease?
@@ -157,7 +154,7 @@ def pretty_print q # :nodoc:
# True if +version+ satisfies this Requirement.
def satisfied_by? version
- requirements.all? { |op, rv| OPS[op].call version, rv }
+ requirements.all? { |op, rv| (OPS[op] || OPS["="]).call version, rv }
end
def to_s # :nodoc:
@@ -167,6 +164,20 @@ def to_s # :nodoc:
def <=> other # :nodoc:
to_s <=> other.to_s
end
+
+ 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? Gem::SyckDefaultKey
+ r[0] = "="
+ end
+ end
+ end
+
end
# :stopdoc:
View
@@ -0,0 +1,74 @@
+# :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
+ # for tests that change YAML::ENGINE
+ # 1.8 does not support the second argument to const_defined?
+ remove_const :Syck rescue nil
+
+ 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
+ remove_method :to_s rescue nil
+
+ 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
+ # for tests that change YAML::ENGINE
+ remove_const :SyckDefaultKey if const_defined? :SyckDefaultKey
+
+ SyckDefaultKey = YAML::Syck::DefaultKey
+end
+
+# :startdoc:

0 comments on commit e7aa0c2

Please sign in to comment.