rubygems-update 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

Files changed (172) hide show
  1. data.tar.gz.sig +0 -0
  2. data/ChangeLog +248 -0
  3. data/README +2 -0
  4. data/Rakefile +47 -23
  5. data/bin/gem +9 -4
  6. data/bin/update_rubygems +15 -1
  7. data/examples/application/bin/myapp +0 -0
  8. data/lib/rubygems.rb +506 -373
  9. data/lib/rubygems/builder.rb +14 -7
  10. data/lib/rubygems/command.rb +9 -9
  11. data/lib/rubygems/command_manager.rb +1 -0
  12. data/lib/rubygems/commands/cleanup_command.rb +67 -69
  13. data/lib/rubygems/commands/environment_command.rb +16 -10
  14. data/lib/rubygems/commands/fetch_command.rb +7 -9
  15. data/lib/rubygems/commands/install_command.rb +9 -3
  16. data/lib/rubygems/commands/list_command.rb +2 -4
  17. data/lib/rubygems/commands/mirror_command.rb +1 -1
  18. data/lib/rubygems/commands/query_command.rb +52 -5
  19. data/lib/rubygems/commands/sources_command.rb +19 -10
  20. data/lib/rubygems/commands/specification_command.rb +10 -6
  21. data/lib/rubygems/commands/uninstall_command.rb +23 -6
  22. data/lib/rubygems/commands/unpack_command.rb +15 -3
  23. data/lib/rubygems/commands/update_command.rb +27 -25
  24. data/lib/rubygems/custom_require.rb +1 -1
  25. data/lib/rubygems/defaults.rb +8 -1
  26. data/lib/rubygems/dependency_installer.rb +72 -104
  27. data/lib/rubygems/digest/digest_adapter.rb +0 -0
  28. data/lib/rubygems/digest/md5.rb +0 -0
  29. data/lib/rubygems/digest/sha1.rb +0 -0
  30. data/lib/rubygems/digest/sha2.rb +0 -0
  31. data/lib/rubygems/exceptions.rb +22 -1
  32. data/lib/rubygems/format.rb +16 -10
  33. data/lib/rubygems/indexer.rb +46 -33
  34. data/lib/rubygems/indexer/abstract_index_builder.rb +10 -2
  35. data/lib/rubygems/indexer/latest_index_builder.rb +35 -0
  36. data/lib/rubygems/indexer/master_index_builder.rb +9 -8
  37. data/lib/rubygems/indexer/quick_index_builder.rb +5 -3
  38. data/lib/rubygems/install_update_options.rb +7 -1
  39. data/lib/rubygems/installer.rb +8 -5
  40. data/lib/rubygems/package.rb +17 -774
  41. data/lib/rubygems/package/f_sync_dir.rb +24 -0
  42. data/lib/rubygems/package/tar_header.rb +245 -0
  43. data/lib/rubygems/package/tar_input.rb +219 -0
  44. data/lib/rubygems/package/tar_output.rb +143 -0
  45. data/lib/rubygems/package/tar_reader.rb +86 -0
  46. data/lib/rubygems/package/tar_reader/entry.rb +99 -0
  47. data/lib/rubygems/package/tar_writer.rb +180 -0
  48. data/lib/rubygems/remote_fetcher.rb +131 -16
  49. data/lib/rubygems/requirement.rb +2 -0
  50. data/lib/rubygems/rubygems_version.rb +1 -1
  51. data/lib/rubygems/security.rb +1 -0
  52. data/lib/rubygems/server.rb +85 -104
  53. data/lib/rubygems/source_index.rb +412 -329
  54. data/lib/rubygems/source_info_cache.rb +232 -99
  55. data/lib/rubygems/source_info_cache_entry.rb +14 -4
  56. data/lib/rubygems/specification.rb +9 -10
  57. data/lib/rubygems/timer.rb +0 -0
  58. data/lib/rubygems/uninstaller.rb +56 -32
  59. data/lib/rubygems/user_interaction.rb +4 -10
  60. data/lib/rubygems/validator.rb +0 -0
  61. data/scripts/gemdoc.rb +0 -0
  62. data/scripts/specdoc.rb +0 -0
  63. data/setup.rb +56 -19
  64. data/test/gem_installer_test_case.rb +86 -0
  65. data/test/gem_installer_test_case.rbc +0 -0
  66. data/test/gem_package_tar_test_case.rb +146 -0
  67. data/test/gem_package_tar_test_case.rbc +0 -0
  68. data/test/gemutilities.rb +123 -38
  69. data/test/gemutilities.rbc +0 -0
  70. data/test/mockgemui.rb +5 -13
  71. data/test/mockgemui.rbc +0 -0
  72. data/test/private_key.pem +27 -0
  73. data/test/public_cert.pem +20 -0
  74. data/test/simple_gem.rbc +0 -0
  75. data/test/test_config.rbc +0 -0
  76. data/test/test_gem.rb +46 -4
  77. data/test/test_gem.rbc +0 -0
  78. data/test/test_gem_builder.rbc +0 -0
  79. data/test/test_gem_command.rbc +0 -0
  80. data/test/test_gem_command_manager.rb +4 -2
  81. data/test/test_gem_command_manager.rbc +0 -0
  82. data/test/test_gem_commands_build_command.rbc +0 -0
  83. data/test/test_gem_commands_cert_command.rb +5 -1
  84. data/test/test_gem_commands_cert_command.rbc +0 -0
  85. data/test/test_gem_commands_check_command.rbc +0 -0
  86. data/test/test_gem_commands_contents_command.rbc +0 -0
  87. data/test/test_gem_commands_dependency_command.rbc +0 -0
  88. data/test/test_gem_commands_environment_command.rb +17 -1
  89. data/test/test_gem_commands_environment_command.rbc +0 -0
  90. data/test/test_gem_commands_fetch_command.rb +6 -5
  91. data/test/test_gem_commands_fetch_command.rbc +0 -0
  92. data/test/test_gem_commands_generate_index_command.rbc +0 -0
  93. data/test/test_gem_commands_install_command.rb +36 -28
  94. data/test/test_gem_commands_install_command.rbc +0 -0
  95. data/test/test_gem_commands_mirror_command.rbc +0 -0
  96. data/test/test_gem_commands_pristine_command.rbc +0 -0
  97. data/test/test_gem_commands_query_command.rb +143 -19
  98. data/test/test_gem_commands_query_command.rbc +0 -0
  99. data/test/test_gem_commands_server_command.rb +1 -1
  100. data/test/test_gem_commands_server_command.rbc +0 -0
  101. data/test/test_gem_commands_sources_command.rb +67 -9
  102. data/test/test_gem_commands_sources_command.rbc +0 -0
  103. data/test/test_gem_commands_specification_command.rb +3 -2
  104. data/test/test_gem_commands_specification_command.rbc +0 -0
  105. data/test/test_gem_commands_unpack_command.rb +46 -4
  106. data/test/test_gem_commands_unpack_command.rbc +0 -0
  107. data/test/test_gem_commands_update_command.rb +174 -0
  108. data/test/test_gem_commands_update_command.rbc +0 -0
  109. data/test/test_gem_config_file.rbc +0 -0
  110. data/test/test_gem_dependency.rbc +0 -0
  111. data/test/test_gem_dependency_installer.rb +172 -187
  112. data/test/test_gem_dependency_installer.rbc +0 -0
  113. data/test/test_gem_dependency_list.rbc +0 -0
  114. data/test/test_gem_digest.rb +0 -0
  115. data/test/test_gem_digest.rbc +0 -0
  116. data/test/test_gem_doc_manager.rbc +0 -0
  117. data/test/test_gem_ext_configure_builder.rb +9 -6
  118. data/test/test_gem_ext_configure_builder.rbc +0 -0
  119. data/test/test_gem_ext_ext_conf_builder.rbc +0 -0
  120. data/test/test_gem_ext_rake_builder.rbc +0 -0
  121. data/test/test_gem_format.rb +1 -1
  122. data/test/test_gem_format.rbc +0 -0
  123. data/test/test_gem_gem_path_searcher.rbc +0 -0
  124. data/test/test_gem_gem_runner.rbc +0 -0
  125. data/test/test_gem_indexer.rb +7 -2
  126. data/test/test_gem_indexer.rbc +0 -0
  127. data/test/test_gem_install_update_options.rbc +0 -0
  128. data/test/test_gem_installer.rb +5 -84
  129. data/test/test_gem_installer.rbc +0 -0
  130. data/test/test_gem_local_remote_options.rbc +0 -0
  131. data/test/test_gem_outdated_command.rbc +0 -0
  132. data/test/test_gem_package_tar_header.rb +137 -0
  133. data/test/test_gem_package_tar_header.rbc +0 -0
  134. data/test/test_gem_package_tar_input.rb +119 -0
  135. data/test/test_gem_package_tar_input.rbc +0 -0
  136. data/test/test_gem_package_tar_output.rb +104 -0
  137. data/test/test_gem_package_tar_output.rbc +0 -0
  138. data/test/test_gem_package_tar_reader.rb +53 -0
  139. data/test/test_gem_package_tar_reader.rbc +0 -0
  140. data/test/test_gem_package_tar_reader_entry.rb +116 -0
  141. data/test/test_gem_package_tar_reader_entry.rbc +0 -0
  142. data/test/test_gem_package_tar_writer.rb +151 -0
  143. data/test/test_gem_package_tar_writer.rbc +0 -0
  144. data/test/test_gem_platform.rbc +0 -0
  145. data/test/test_gem_remote_fetcher.rb +189 -17
  146. data/test/test_gem_remote_fetcher.rbc +0 -0
  147. data/test/test_gem_requirement.rbc +0 -0
  148. data/test/test_gem_server.rb +13 -12
  149. data/test/test_gem_server.rbc +0 -0
  150. data/test/test_gem_source_index.rb +305 -56
  151. data/test/test_gem_source_index.rbc +0 -0
  152. data/test/test_gem_source_info_cache.rb +179 -53
  153. data/test/test_gem_source_info_cache.rbc +0 -0
  154. data/test/test_gem_source_info_cache_entry.rb +41 -10
  155. data/test/test_gem_source_info_cache_entry.rbc +0 -0
  156. data/test/test_gem_specification.rb +7 -7
  157. data/test/test_gem_specification.rbc +0 -0
  158. data/test/test_gem_stream_ui.rbc +0 -0
  159. data/test/test_gem_uninstaller.rb +43 -0
  160. data/test/test_gem_uninstaller.rbc +0 -0
  161. data/test/test_gem_validator.rbc +0 -0
  162. data/test/test_gem_version.rb +1 -1
  163. data/test/test_gem_version.rbc +0 -0
  164. data/test/test_gem_version_option.rbc +0 -0
  165. data/test/test_kernel.rb +1 -0
  166. data/test/test_kernel.rbc +0 -0
  167. metadata +85 -8
  168. metadata.gz.sig +0 -0
  169. data/lib/rubygems/gem_open_uri.rb +0 -7
  170. data/lib/rubygems/open-uri.rb +0 -773
  171. data/test/test_open_uri.rb +0 -13
  172. data/test/test_package.rb +0 -608
@@ -0,0 +1,24 @@
1
+ #++
2
+ # Copyright (C) 2004 Mauricio Julio Fern�ndez Pradier
3
+ # See LICENSE.txt for additional licensing information.
4
+ #--
5
+
6
+ require 'rubygems/package'
7
+
8
+ module Gem::Package::FSyncDir
9
+
10
+ private
11
+
12
+ ##
13
+ # make sure this hits the disc
14
+
15
+ def fsync_dir(dirname)
16
+ dir = open dirname, 'r'
17
+ dir.fsync
18
+ rescue # ignore IOError if it's an unpatched (old) Ruby
19
+ ensure
20
+ dir.close if dir rescue nil
21
+ end
22
+
23
+ end
24
+
@@ -0,0 +1,245 @@
1
+ #++
2
+ # Copyright (C) 2004 Mauricio Julio Fern�ndez Pradier
3
+ # See LICENSE.txt for additional licensing information.
4
+ #--
5
+
6
+ require 'rubygems/package'
7
+
8
+ ##
9
+ #--
10
+ # struct tarfile_entry_posix {
11
+ # char name[100]; # ASCII + (Z unless filled)
12
+ # char mode[8]; # 0 padded, octal, null
13
+ # char uid[8]; # ditto
14
+ # char gid[8]; # ditto
15
+ # char size[12]; # 0 padded, octal, null
16
+ # char mtime[12]; # 0 padded, octal, null
17
+ # char checksum[8]; # 0 padded, octal, null, space
18
+ # char typeflag[1]; # file: "0" dir: "5"
19
+ # char linkname[100]; # ASCII + (Z unless filled)
20
+ # char magic[6]; # "ustar\0"
21
+ # char version[2]; # "00"
22
+ # char uname[32]; # ASCIIZ
23
+ # char gname[32]; # ASCIIZ
24
+ # char devmajor[8]; # 0 padded, octal, null
25
+ # char devminor[8]; # o padded, octal, null
26
+ # char prefix[155]; # ASCII + (Z unless filled)
27
+ # };
28
+ #++
29
+
30
+ class Gem::Package::TarHeader
31
+
32
+ FIELDS = [
33
+ :checksum,
34
+ :devmajor,
35
+ :devminor,
36
+ :gid,
37
+ :gname,
38
+ :linkname,
39
+ :magic,
40
+ :mode,
41
+ :mtime,
42
+ :name,
43
+ :prefix,
44
+ :size,
45
+ :typeflag,
46
+ :uid,
47
+ :uname,
48
+ :version,
49
+ ]
50
+
51
+ PACK_FORMAT = 'a100' + # name
52
+ 'a8' + # mode
53
+ 'a8' + # uid
54
+ 'a8' + # gid
55
+ 'a12' + # size
56
+ 'a12' + # mtime
57
+ 'a7a' + # chksum
58
+ 'a' + # typeflag
59
+ 'a100' + # linkname
60
+ 'a6' + # magic
61
+ 'a2' + # version
62
+ 'a32' + # uname
63
+ 'a32' + # gname
64
+ 'a8' + # devmajor
65
+ 'a8' + # devminor
66
+ 'a155' # prefix
67
+
68
+ UNPACK_FORMAT = 'A100' + # name
69
+ 'A8' + # mode
70
+ 'A8' + # uid
71
+ 'A8' + # gid
72
+ 'A12' + # size
73
+ 'A12' + # mtime
74
+ 'A8' + # checksum
75
+ 'A' + # typeflag
76
+ 'A100' + # linkname
77
+ 'A6' + # magic
78
+ 'A2' + # version
79
+ 'A32' + # uname
80
+ 'A32' + # gname
81
+ 'A8' + # devmajor
82
+ 'A8' + # devminor
83
+ 'A155' # prefix
84
+
85
+ attr_reader(*FIELDS)
86
+
87
+ def self.from(stream)
88
+ header = stream.read 512
89
+ empty = (header == "\0" * 512)
90
+
91
+ fields = header.unpack UNPACK_FORMAT
92
+
93
+ name = fields.shift
94
+ mode = fields.shift.oct
95
+ uid = fields.shift.oct
96
+ gid = fields.shift.oct
97
+ size = fields.shift.oct
98
+ mtime = fields.shift.oct
99
+ checksum = fields.shift.oct
100
+ typeflag = fields.shift
101
+ linkname = fields.shift
102
+ magic = fields.shift
103
+ version = fields.shift.oct
104
+ uname = fields.shift
105
+ gname = fields.shift
106
+ devmajor = fields.shift.oct
107
+ devminor = fields.shift.oct
108
+ prefix = fields.shift
109
+
110
+ new :name => name,
111
+ :mode => mode,
112
+ :uid => uid,
113
+ :gid => gid,
114
+ :size => size,
115
+ :mtime => mtime,
116
+ :checksum => checksum,
117
+ :typeflag => typeflag,
118
+ :linkname => linkname,
119
+ :magic => magic,
120
+ :version => version,
121
+ :uname => uname,
122
+ :gname => gname,
123
+ :devmajor => devmajor,
124
+ :devminor => devminor,
125
+ :prefix => prefix,
126
+
127
+ :empty => empty
128
+
129
+ # HACK unfactor for Rubinius
130
+ #new :name => fields.shift,
131
+ # :mode => fields.shift.oct,
132
+ # :uid => fields.shift.oct,
133
+ # :gid => fields.shift.oct,
134
+ # :size => fields.shift.oct,
135
+ # :mtime => fields.shift.oct,
136
+ # :checksum => fields.shift.oct,
137
+ # :typeflag => fields.shift,
138
+ # :linkname => fields.shift,
139
+ # :magic => fields.shift,
140
+ # :version => fields.shift.oct,
141
+ # :uname => fields.shift,
142
+ # :gname => fields.shift,
143
+ # :devmajor => fields.shift.oct,
144
+ # :devminor => fields.shift.oct,
145
+ # :prefix => fields.shift,
146
+
147
+ # :empty => empty
148
+ end
149
+
150
+ def initialize(vals)
151
+ unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] then
152
+ raise ArgumentError, ":name, :size, :prefix and :mode required"
153
+ end
154
+
155
+ vals[:uid] ||= 0
156
+ vals[:gid] ||= 0
157
+ vals[:mtime] ||= 0
158
+ vals[:checksum] ||= ""
159
+ vals[:typeflag] ||= "0"
160
+ vals[:magic] ||= "ustar"
161
+ vals[:version] ||= "00"
162
+ vals[:uname] ||= "wheel"
163
+ vals[:gname] ||= "wheel"
164
+ vals[:devmajor] ||= 0
165
+ vals[:devminor] ||= 0
166
+
167
+ FIELDS.each do |name|
168
+ instance_variable_set "@#{name}", vals[name]
169
+ end
170
+
171
+ @empty = vals[:empty]
172
+ end
173
+
174
+ def empty?
175
+ @empty
176
+ end
177
+
178
+ def ==(other)
179
+ self.class === other and
180
+ @checksum == other.checksum and
181
+ @devmajor == other.devmajor and
182
+ @devminor == other.devminor and
183
+ @gid == other.gid and
184
+ @gname == other.gname and
185
+ @linkname == other.linkname and
186
+ @magic == other.magic and
187
+ @mode == other.mode and
188
+ @mtime == other.mtime and
189
+ @name == other.name and
190
+ @prefix == other.prefix and
191
+ @size == other.size and
192
+ @typeflag == other.typeflag and
193
+ @uid == other.uid and
194
+ @uname == other.uname and
195
+ @version == other.version
196
+ end
197
+
198
+ def to_s
199
+ update_checksum
200
+ header
201
+ end
202
+
203
+ def update_checksum
204
+ header = header " " * 8
205
+ @checksum = oct calculate_checksum(header), 6
206
+ end
207
+
208
+ private
209
+
210
+ def calculate_checksum(header)
211
+ header.unpack("C*").inject { |a, b| a + b }
212
+ end
213
+
214
+ def header(checksum = @checksum)
215
+ header = [
216
+ name,
217
+ oct(mode, 7),
218
+ oct(uid, 7),
219
+ oct(gid, 7),
220
+ oct(size, 11),
221
+ oct(mtime, 11),
222
+ checksum,
223
+ " ",
224
+ typeflag,
225
+ linkname,
226
+ magic,
227
+ oct(version, 2),
228
+ uname,
229
+ gname,
230
+ oct(devmajor, 7),
231
+ oct(devminor, 7),
232
+ prefix
233
+ ]
234
+
235
+ header = header.pack PACK_FORMAT
236
+
237
+ header << ("\0" * ((512 - header.size) % 512))
238
+ end
239
+
240
+ def oct(num, len)
241
+ "%0#{len}o" % num
242
+ end
243
+
244
+ end
245
+
@@ -0,0 +1,219 @@
1
+ #++
2
+ # Copyright (C) 2004 Mauricio Julio Fern�ndez Pradier
3
+ # See LICENSE.txt for additional licensing information.
4
+ #--
5
+
6
+ require 'rubygems/package'
7
+
8
+ class Gem::Package::TarInput
9
+
10
+ include Gem::Package::FSyncDir
11
+ include Enumerable
12
+
13
+ attr_reader :metadata
14
+
15
+ private_class_method :new
16
+
17
+ def self.open(io, security_policy = nil, &block)
18
+ is = new io, security_policy
19
+
20
+ yield is
21
+ ensure
22
+ is.close if is
23
+ end
24
+
25
+ def initialize(io, security_policy = nil)
26
+ @io = io
27
+ @tarreader = Gem::Package::TarReader.new @io
28
+ has_meta = false
29
+
30
+ data_sig, meta_sig, data_dgst, meta_dgst = nil, nil, nil, nil
31
+ dgst_algo = security_policy ? Gem::Security::OPT[:dgst_algo] : nil
32
+
33
+ @tarreader.each do |entry|
34
+ case entry.full_name
35
+ when "metadata"
36
+ @metadata = load_gemspec entry.read
37
+ has_meta = true
38
+ when "metadata.gz"
39
+ begin
40
+ # if we have a security_policy, then pre-read the metadata file
41
+ # and calculate it's digest
42
+ sio = nil
43
+ if security_policy
44
+ Gem.ensure_ssl_available
45
+ sio = StringIO.new(entry.read)
46
+ meta_dgst = dgst_algo.digest(sio.string)
47
+ sio.rewind
48
+ end
49
+
50
+ gzis = Zlib::GzipReader.new(sio || entry)
51
+ # YAML wants an instance of IO
52
+ @metadata = load_gemspec(gzis)
53
+ has_meta = true
54
+ ensure
55
+ gzis.close unless gzis.nil?
56
+ end
57
+ when 'metadata.gz.sig'
58
+ meta_sig = entry.read
59
+ when 'data.tar.gz.sig'
60
+ data_sig = entry.read
61
+ when 'data.tar.gz'
62
+ if security_policy
63
+ Gem.ensure_ssl_available
64
+ data_dgst = dgst_algo.digest(entry.read)
65
+ end
66
+ end
67
+ end
68
+
69
+ if security_policy then
70
+ Gem.ensure_ssl_available
71
+
72
+ # map trust policy from string to actual class (or a serialized YAML
73
+ # file, if that exists)
74
+ if String === security_policy then
75
+ if Gem::Security::Policy.key? security_policy then
76
+ # load one of the pre-defined security policies
77
+ security_policy = Gem::Security::Policy[security_policy]
78
+ elsif File.exist? security_policy then
79
+ # FIXME: this doesn't work yet
80
+ security_policy = YAML.load File.read(security_policy)
81
+ else
82
+ raise Gem::Exception, "Unknown trust policy '#{security_policy}'"
83
+ end
84
+ end
85
+
86
+ if data_sig && data_dgst && meta_sig && meta_dgst then
87
+ # the user has a trust policy, and we have a signed gem
88
+ # file, so use the trust policy to verify the gem signature
89
+
90
+ begin
91
+ security_policy.verify_gem(data_sig, data_dgst, @metadata.cert_chain)
92
+ rescue Exception => e
93
+ raise "Couldn't verify data signature: #{e}"
94
+ end
95
+
96
+ begin
97
+ security_policy.verify_gem(meta_sig, meta_dgst, @metadata.cert_chain)
98
+ rescue Exception => e
99
+ raise "Couldn't verify metadata signature: #{e}"
100
+ end
101
+ elsif security_policy.only_signed
102
+ raise Gem::Exception, "Unsigned gem"
103
+ else
104
+ # FIXME: should display warning here (trust policy, but
105
+ # either unsigned or badly signed gem file)
106
+ end
107
+ end
108
+
109
+ @tarreader.rewind
110
+ @fileops = Gem::FileOperations.new
111
+
112
+ raise Gem::Package::FormatError, "No metadata found!" unless has_meta
113
+ end
114
+
115
+ def close
116
+ @io.close
117
+ @tarreader.close
118
+ end
119
+
120
+ def each(&block)
121
+ @tarreader.each do |entry|
122
+ next unless entry.full_name == "data.tar.gz"
123
+ is = zipped_stream entry
124
+
125
+ begin
126
+ Gem::Package::TarReader.new is do |inner|
127
+ inner.each(&block)
128
+ end
129
+ ensure
130
+ is.close if is
131
+ end
132
+ end
133
+
134
+ @tarreader.rewind
135
+ end
136
+
137
+ def extract_entry(destdir, entry, expected_md5sum = nil)
138
+ if entry.directory? then
139
+ dest = File.join(destdir, entry.full_name)
140
+
141
+ if File.dir? dest then
142
+ @fileops.chmod entry.header.mode, dest, :verbose=>false
143
+ else
144
+ @fileops.mkdir_p dest, :mode => entry.header.mode, :verbose => false
145
+ end
146
+
147
+ fsync_dir dest
148
+ fsync_dir File.join(dest, "..")
149
+
150
+ return
151
+ end
152
+
153
+ # it's a file
154
+ md5 = Digest::MD5.new if expected_md5sum
155
+ destdir = File.join destdir, File.dirname(entry.full_name)
156
+ @fileops.mkdir_p destdir, :mode => 0755, :verbose => false
157
+ destfile = File.join destdir, File.basename(entry.full_name)
158
+ @fileops.chmod 0600, destfile, :verbose => false rescue nil # Errno::ENOENT
159
+
160
+ open destfile, "wb", entry.header.mode do |os|
161
+ loop do
162
+ data = entry.read 4096
163
+ break unless data
164
+ # HACK shouldn't we check the MD5 before writing to disk?
165
+ md5 << data if expected_md5sum
166
+ os.write(data)
167
+ end
168
+
169
+ os.fsync
170
+ end
171
+
172
+ @fileops.chmod entry.header.mode, destfile, :verbose => false
173
+ fsync_dir File.dirname(destfile)
174
+ fsync_dir File.join(File.dirname(destfile), "..")
175
+
176
+ if expected_md5sum && expected_md5sum != md5.hexdigest then
177
+ raise Gem::Package::BadCheckSum
178
+ end
179
+ end
180
+
181
+ # Attempt to YAML-load a gemspec from the given _io_ parameter. Return
182
+ # nil if it fails.
183
+ def load_gemspec(io)
184
+ Gem::Specification.from_yaml io
185
+ rescue Gem::Exception
186
+ nil
187
+ end
188
+
189
+ ##
190
+ # Return an IO stream for the zipped entry.
191
+ #
192
+ # NOTE: Originally this method used two approaches, Return a GZipReader
193
+ # directly, or read the GZipReader into a string and return a StringIO on
194
+ # the string. The string IO approach was used for versions of ZLib before
195
+ # 1.2.1 to avoid buffer errors on windows machines. Then we found that
196
+ # errors happened with 1.2.1 as well, so we changed the condition. Then
197
+ # we discovered errors occurred with versions as late as 1.2.3. At this
198
+ # point (after some benchmarking to show we weren't seriously crippling
199
+ # the unpacking speed) we threw our hands in the air and declared that
200
+ # this method would use the String IO approach on all platforms at all
201
+ # times. And that's the way it is.
202
+
203
+ def zipped_stream(entry)
204
+ if defined? Rubinius then
205
+ zis = Zlib::GzipReader.new entry
206
+ dis = zis.read
207
+ is = StringIO.new(dis)
208
+ else
209
+ # This is Jamis Buck's Zlib workaround for some unknown issue
210
+ entry.read(10) # skip the gzip header
211
+ zis = Zlib::Inflate.new(-Zlib::MAX_WBITS)
212
+ is = StringIO.new(zis.inflate(entry.read))
213
+ end
214
+ ensure
215
+ zis.finish if zis
216
+ end
217
+
218
+ end
219
+