Index: setup.rb =================================================================== --- setup.rb (revision 1423) +++ setup.rb (working copy) @@ -7,6 +7,7 @@ $:.unshift 'lib' require 'rubygems' +require 'rubygems/source_info_cache' require 'fileutils' require 'rbconfig' @@ -100,6 +101,20 @@ end end +# remove source_cache +source_cache_path = File.join Gem.dir, 'source_cache' +if File.writable? source_cache_path then + puts "Removing system-wide source cache" + rm source_cache_path +end + +user_cache_path = Gem::SourceInfoCache.user_cache_file +if File.writable? user_cache_path then + puts "Removing user source cache" + rm user_cache_path +end + +# # install RDoc gem_doc_dir = File.join Gem.dir, 'doc' Index: lib/rubygems/specification.rb =================================================================== --- lib/rubygems/specification.rb (revision 1423) +++ lib/rubygems/specification.rb (working copy) @@ -58,6 +58,8 @@ 'Now forward-compatible with future versions', ], } + + MARSHAL_FIELDS = { 1 => 16, 2 => 16 } # ------------------------- Class variables. @@ -208,21 +210,36 @@ # Dump only crucial instance variables def marshal_dump - [@rubygems_version, @specification_version, @name, @version, @date, + date = @date.respond_to?(:ctime) ? @date.ctime : @date.to_s + [@rubygems_version, @specification_version, @name, @version, date, @summary, @required_ruby_version, @required_rubygems_version, @platform, @dependencies, @rubyforge_project, @email, @authors, @description, @homepage, @has_rdoc] end # Load custom marshal format, re-initializing defaults as needed def marshal_load(array) + if $MARSHAL_DEBUG + STDERR.puts "Loading Specification: #{array.inspect}" + $MARSHAL_DEBUG = false + end + + unless array.is_a?(Array) then + raise TypeError, "Outdated Gem::Specification marshal format" + end + spec_version = array[1] current_version = CURRENT_SPECIFICATION_VERSION - unless spec_version == current_version - raise TypeError, "Outdated Gem::Specification marshal format: #{spec_version} - instead of #{current_version}" + field_count = MARSHAL_FIELDS[current_version] + if field_count.nil? or array.size < field_count then + #raise TypeError, "Outdated Gem::Specification marshal format: #{spec_version} \ + # instead of #{current_version}" + $MARSHAL_DEBUG = true + STDERR.puts "Enabling debug after breaking on: #{array.inspect}" + STDERR.puts "last 'good' spec was: #{$LAST_SPEC.inspect}" end assign_defaults # Set defaults for anything we didn't dump + $LAST_SPEC = array.dup @rubygems_version = array[0] @specification_version = array[1] @name = array[2] Index: lib/rubygems/version.rb =================================================================== --- lib/rubygems/version.rb (revision 1423) +++ lib/rubygems/version.rb (working copy) @@ -9,6 +9,7 @@ ## # The Version class processes string versions into comparable values class Gem::Version + MARSHAL_FIELDS = { 1 => 1, 2 => 1 } include Comparable @@ -59,18 +60,25 @@ # Dump only the raw version string, not the complete object def marshal_dump - [Gem::Specification::CURRENT_SPECIFICATION_VERSION, @version] + [@version] end # Load custom marshal format def marshal_load(array) - spec_version = array[0] + if $MARSHAL_DEBUG + STDERR.puts "Loading Version: #{array.inspect}" + end + unless array.is_a?(Array) then + raise TypeError, "Outdated Gem::Version marshal format" + end + current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION - unless spec_version == current_version - raise TypeError, "Outdated Gem::Version marshal format: #{spec_version} - instead of #{current_version}" + field_count = MARSHAL_FIELDS[current_version] + if field_count.nil? or array.size < field_count then + raise TypeError, "Outdated Gem::Version marshal format: expected + #{field_count} fields, got: #{array}" end - @version = array[1] + @version = array[0] end ## Index: lib/rubygems/source_info_cache.rb =================================================================== --- lib/rubygems/source_info_cache.rb (revision 1423) +++ lib/rubygems/source_info_cache.rb (working copy) @@ -74,24 +74,39 @@ @cache_data = Marshal.load data @cache_data.each do |url, sice| - next unless Hash === sice + next unless sice.is_a?(Hash) @dirty = true - if sice.key? 'cache' and sice.key? 'size' and - Gem::SourceIndex === sice['cache'] and Numeric === sice['size'] then - new_sice = Gem::SourceInfoCacheEntry.new sice['cache'], sice['size'] + 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. - sice = Gem::SourceInfoCacheEntry.new Gem::SourceIndex.new, 0 - sice.refresh url # HACK may be unnecessary, see ::cache and #refresh - @cache_data[url] = sice + reset_cache_for(url) end end @cache_data - rescue - {} + rescue => ex + if Gem.configuration.really_verbose + say "Exception during cache_data handling: #{ex.class} - #{ex}" + say "Cache file was: #{cache_file}" + say ex.backtrace.join("\n") + end + reset_cache_data end end + def reset_cache_for(url) + sice = Gem::SourceInfoCacheEntry.new Gem::SourceIndex.new, 0 + sice.refresh url # HACK may be unnecessary, see ::cache and #refresh + @cache_data[url] = sice + @cache_data + end + + def reset_cache_data + @cache_data = {} + end + # The name of the cache file to be read def cache_file return @cache_file if @cache_file @@ -176,6 +191,7 @@ # Write data to the proper cache. def write_cache open cache_file, "wb" do |f| + STDERR.puts "writing cache data" f.write Marshal.dump(cache_data) end end Index: lib/rubygems/requirement.rb =================================================================== --- lib/rubygems/requirement.rb (revision 1423) +++ lib/rubygems/requirement.rb (working copy) @@ -28,6 +28,8 @@ OP_RE = /#{OPS.keys.map{ |k| Regexp.quote k }.join '|'}/o + MARSHAL_FIELDS = { 1 => 2, 2 => 2 } + ## # Factory method to create a Gem::Requirement object. Input may be a # Version, a String, or nil. Intended to simplify client code. @@ -82,11 +84,23 @@ # Load custom marshal format def marshal_load(array) + if $MARSHAL_DEBUG + STDERR.puts "loading Requirement: #{array.inspect}" + end + unless array.is_a?(Array) then + raise TypeError, "Outdated Gem::Requirement marshal format" + end spec_version = array[0] current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION - unless spec_version == current_version + field_count = MARSHAL_FIELDS[current_version] + if field_count.nil? or array.size < field_count then + if $MARSHAL_DEBUG + STDERR.puts "ignoring invalid requirement due to debug mode" + return + else raise TypeError, "Outdated Gem::Requirement marshal format: #{spec_version} instead of #{current_version}" + end end @requirements = array[1] @version = nil