/tools/Ruby/lib/ruby/site_ruby/1.8/rubygems/old_format.rb

http://github.com/agross/netopenspace · Ruby · 153 lines · 78 code · 27 blank · 48 comment · 9 complexity · 3a09372146a1a0eaa91369bc64f83fe3 MD5 · raw file

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