Update to RDoc r56
[rbx.git] / lib / rubygems / old_format.rb
blobef5d621f526330571560490d7840696a03a595a8
1 #--
2 # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
3 # All rights reserved.
4 # See LICENSE.txt for permissions.
5 #++
7 require 'fileutils'
8 require 'yaml'
9 require 'zlib'
11 module Gem
13   ##
14   # The format class knows the guts of the RubyGem .gem file format
15   # and provides the capability to read gem files
16   #
17   class OldFormat
18     attr_accessor :spec, :file_entries, :gem_path
19   
20     ##
21     # Constructs an instance of a Format object, representing the gem's
22     # data structure.
23     #
24     # gem:: [String] The file name of the gem
25     #
26     def initialize(gem_path)
27       @gem_path = gem_path
28     end
29     
30     ##
31     # Reads the named gem file and returns a Format object, representing 
32     # the data from the gem file
33     #
34     # file_path:: [String] Path to the gem file
35     #
36     def self.from_file_by_path(file_path)
37       unless File.exist?(file_path)
38         raise Gem::Exception, "Cannot load gem file [#{file_path}]"
39       end
40       File.open(file_path, 'rb') do |file|
41         from_io(file, file_path)
42       end
43     end
45     ##
46     # Reads a gem from an io stream and returns a Format object, representing
47     # the data from the gem file
48     #
49     # io:: [IO] Stream from which to read the gem
50     #
51     def self.from_io(io, gem_path="(io)")
52       format = self.new(gem_path)
53       skip_ruby(io)
54       format.spec = read_spec(io)
55       format.file_entries = []
56       read_files_from_gem(io) do |entry, file_data|
57         format.file_entries << [entry, file_data]
58       end
59       format
60     end
61     
62     private 
63     ##
64     # Skips the Ruby self-install header.  After calling this method, the
65     # IO index will be set after the Ruby code.
66     #
67     # file:: [IO] The IO to process (skip the Ruby code)
68     #
69     def self.skip_ruby(file)
70       end_seen = false
71       loop {
72         line = file.gets
73         if(line == nil || line.chomp == "__END__") then
74           end_seen = true
75           break
76         end
77       }
78      if(end_seen == false) then
79        raise Gem::Exception.new("Failed to find end of ruby script while reading gem")
80      end
81     end
82      
83     ##
84     # Reads the specification YAML from the supplied IO and constructs
85     # a Gem::Specification from it.  After calling this method, the
86     # IO index will be set after the specification header.
87     #
88     # file:: [IO] The IO to process
89     #
90     def self.read_spec(file)
91       yaml = ''
92       begin
93         read_until_dashes(file) do |line|
94           yaml << line
95         end
96         Specification.from_yaml(yaml)
97       rescue YAML::Error => e
98         raise Gem::Exception.new("Failed to parse gem specification out of gem file")
99       rescue ArgumentError => e
100         raise Gem::Exception.new("Failed to parse gem specification out of gem file")
101       end
102     end
103     
104     ##
105     # Reads lines from the supplied IO until a end-of-yaml (---) is
106     # reached
107     #
108     # file:: [IO] The IO to process
109     # block:: [String] The read line
110     #
111     def self.read_until_dashes(file)
112       while((line = file.gets) && line.chomp.strip != "---") do
113         yield line
114       end
115     end
118     ##
119     # Reads the embedded file data from a gem file, yielding an entry
120     # containing metadata about the file and the file contents themselves
121     # for each file that's archived in the gem.
122     # NOTE: Many of these methods should be extracted into some kind of
123     # Gem file read/writer
124     #
125     # gem_file:: [IO] The IO to process
126     #
127     def self.read_files_from_gem(gem_file)
128       errstr = "Error reading files from gem"
129       header_yaml = ''
130       begin
131         self.read_until_dashes(gem_file) do |line|
132           header_yaml << line
133         end
134         header = YAML.load(header_yaml)
135         raise Gem::Exception.new(errstr) unless header
136         header.each do |entry|
137           file_data = ''
138           self.read_until_dashes(gem_file) do |line|
139             file_data << line
140           end
141           yield [entry, Zlib::Inflate.inflate(file_data.strip.unpack("m")[0])]
142         end
143       rescue Exception,Zlib::DataError => e
144         raise Gem::Exception.new(errstr)
145       end
146     end
147   end