diff options
Diffstat (limited to 'lib/rubygems/package/old.rb')
-rw-r--r-- | lib/rubygems/package/old.rb | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/lib/rubygems/package/old.rb b/lib/rubygems/package/old.rb new file mode 100644 index 0000000000..552a5f3591 --- /dev/null +++ b/lib/rubygems/package/old.rb @@ -0,0 +1,147 @@ +#-- +# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. +# All rights reserved. +# See LICENSE.txt for permissions. +#++ + +## +# The format class knows the guts of the ancient .gem file format and provides +# the capability to read such ancient gems. +# +# Please pretend this doesn't exist. + +class Gem::Package::Old < Gem::Package + + undef_method :spec= + + ## + # Creates a new old-format package reader for +gem+. Old-format packages + # cannot be written. + + def initialize gem + require 'fileutils' + require 'zlib' + Gem.load_yaml + + @gem = gem + @contents = nil + @spec = nil + end + + ## + # A list of file names contained in this gem + + def contents + return @contents if @contents + + open @gem, 'rb' do |io| + read_until_dashes io # spec + header = file_list io + + @contents = header.map { |file| file['path'] } + end + end + + ## + # Extracts the files in this package into +destination_dir+ + + def extract_files destination_dir + errstr = "Error reading files from gem" + + open @gem, 'rb' do |io| + read_until_dashes io # spec + header = file_list io + raise Gem::Exception, errstr unless header + + header.each do |entry| + full_name = entry['path'] + + destination = install_location full_name, destination_dir + + file_data = '' + + read_until_dashes io do |line| + file_data << line + end + + file_data = file_data.strip.unpack("m")[0] + file_data = Zlib::Inflate.inflate file_data + + raise Gem::Package::FormatError, "#{full_name} in #{@gem} is corrupt" if + file_data.length != entry['size'].to_i + + FileUtils.rm_rf destination + + FileUtils.mkdir_p File.dirname destination + + open destination, 'wb', entry['mode'] do |out| + out.write file_data + end + + say destination if Gem.configuration.really_verbose + end + end + rescue Zlib::DataError + raise Gem::Exception, errstr + end + + ## + # Reads the file list section from the old-format gem +io+ + + def file_list io # :nodoc: + header = '' + + read_until_dashes io do |line| + header << line + end + + YAML.load header + end + + ## + # Reads lines until a "---" separator is found + + def read_until_dashes io # :nodoc: + while (line = io.gets) && line.chomp.strip != "---" do + yield line if block_given? + end + end + + ## + # Skips the Ruby self-install header in +io+. + + def skip_ruby io # :nodoc: + loop do + line = io.gets + + return if line.chomp == '__END__' + break unless line + end + + raise Gem::Exception, "Failed to find end of ruby script while reading gem" + end + + ## + # The specification for this gem + + def spec + return @spec if @spec + + yaml = '' + + open @gem, 'rb' do |io| + skip_ruby io + read_until_dashes io do |line| + yaml << line + end + end + + @spec = Gem::Specification.from_yaml yaml + rescue YAML::SyntaxError => e + raise Gem::Exception, "Failed to parse gem specification out of gem file" + rescue ArgumentError => e + raise Gem::Exception, "Failed to parse gem specification out of gem file" + end + +end + |