rubygems-update 1.8.30 → 2.0.0.preview2

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 (241) hide show
  1. checksums.yaml +6 -6
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +3 -0
  4. data/.autotest +6 -3
  5. data/History.txt +137 -63
  6. data/LICENSE.txt +1 -5
  7. data/Manifest.txt +69 -32
  8. data/README.rdoc +11 -9
  9. data/Rakefile +24 -38
  10. data/bin/gem +0 -9
  11. data/bin/update_rubygems +1 -0
  12. data/lib/rubygems.rb +193 -405
  13. data/lib/rubygems/available_set.rb +95 -0
  14. data/lib/rubygems/command.rb +88 -45
  15. data/lib/rubygems/command_manager.rb +67 -40
  16. data/lib/rubygems/commands/build_command.rb +5 -23
  17. data/lib/rubygems/commands/cert_command.rb +199 -57
  18. data/lib/rubygems/commands/check_command.rb +14 -39
  19. data/lib/rubygems/commands/cleanup_command.rb +9 -1
  20. data/lib/rubygems/commands/contents_command.rb +30 -12
  21. data/lib/rubygems/commands/dependency_command.rb +3 -8
  22. data/lib/rubygems/commands/environment_command.rb +13 -8
  23. data/lib/rubygems/commands/fetch_command.rb +3 -16
  24. data/lib/rubygems/commands/generate_index_command.rb +7 -47
  25. data/lib/rubygems/commands/help_command.rb +1 -1
  26. data/lib/rubygems/commands/install_command.rb +69 -36
  27. data/lib/rubygems/commands/list_command.rb +6 -4
  28. data/lib/rubygems/commands/lock_command.rb +1 -1
  29. data/lib/rubygems/commands/mirror_command.rb +17 -0
  30. data/lib/rubygems/commands/outdated_command.rb +6 -3
  31. data/lib/rubygems/commands/owner_command.rb +13 -5
  32. data/lib/rubygems/commands/pristine_command.rb +19 -4
  33. data/lib/rubygems/commands/push_command.rb +12 -1
  34. data/lib/rubygems/commands/query_command.rb +43 -27
  35. data/lib/rubygems/commands/rdoc_command.rb +23 -28
  36. data/lib/rubygems/commands/search_command.rb +4 -18
  37. data/lib/rubygems/commands/server_command.rb +1 -1
  38. data/lib/rubygems/commands/setup_command.rb +124 -38
  39. data/lib/rubygems/commands/sources_command.rb +16 -16
  40. data/lib/rubygems/commands/specification_command.rb +11 -13
  41. data/lib/rubygems/commands/uninstall_command.rb +24 -7
  42. data/lib/rubygems/commands/unpack_command.rb +7 -3
  43. data/lib/rubygems/commands/update_command.rb +22 -36
  44. data/lib/rubygems/commands/yank_command.rb +98 -0
  45. data/lib/rubygems/compatibility.rb +51 -0
  46. data/lib/rubygems/config_file.rb +82 -54
  47. data/lib/rubygems/core_ext/kernel_gem.rb +53 -0
  48. data/lib/rubygems/core_ext/kernel_require.rb +119 -0
  49. data/lib/rubygems/defaults.rb +10 -21
  50. data/lib/rubygems/dependency.rb +61 -10
  51. data/lib/rubygems/dependency_installer.rb +157 -69
  52. data/lib/rubygems/dependency_list.rb +11 -19
  53. data/lib/rubygems/dependency_resolver.rb +562 -0
  54. data/lib/rubygems/deprecate.rb +40 -40
  55. data/lib/rubygems/errors.rb +77 -24
  56. data/lib/rubygems/exceptions.rb +25 -7
  57. data/lib/rubygems/ext/builder.rb +20 -23
  58. data/lib/rubygems/ext/configure_builder.rb +2 -2
  59. data/lib/rubygems/ext/ext_conf_builder.rb +5 -45
  60. data/lib/rubygems/ext/rake_builder.rb +2 -2
  61. data/lib/rubygems/gem_runner.rb +3 -16
  62. data/lib/rubygems/gemcutter_utilities.rb +22 -7
  63. data/lib/rubygems/indexer.rb +6 -159
  64. data/lib/rubygems/install_message.rb +12 -0
  65. data/lib/rubygems/install_update_options.rb +56 -18
  66. data/lib/rubygems/installer.rb +244 -134
  67. data/lib/rubygems/installer_test_case.rb +71 -19
  68. data/lib/rubygems/mock_gem_ui.rb +17 -0
  69. data/lib/rubygems/name_tuple.rb +110 -0
  70. data/lib/rubygems/package.rb +514 -43
  71. data/lib/rubygems/package/digest_io.rb +64 -0
  72. data/lib/rubygems/package/old.rb +147 -0
  73. data/lib/rubygems/package/tar_header.rb +18 -55
  74. data/lib/rubygems/package/tar_reader.rb +20 -3
  75. data/lib/rubygems/package/tar_writer.rb +63 -7
  76. data/lib/rubygems/package_task.rb +3 -4
  77. data/lib/rubygems/path_support.rb +14 -7
  78. data/lib/rubygems/platform.rb +19 -26
  79. data/lib/rubygems/rdoc.rb +316 -0
  80. data/lib/rubygems/remote_fetcher.rb +117 -54
  81. data/lib/rubygems/request_set.rb +182 -0
  82. data/lib/rubygems/requirement.rb +63 -26
  83. data/lib/rubygems/security.rb +295 -555
  84. data/lib/rubygems/security/policies.rb +115 -0
  85. data/lib/rubygems/security/policy.rb +227 -0
  86. data/lib/rubygems/security/signer.rb +136 -0
  87. data/lib/rubygems/security/trust_dir.rb +104 -0
  88. data/lib/rubygems/server.rb +45 -55
  89. data/lib/rubygems/source.rb +144 -0
  90. data/lib/rubygems/source_list.rb +87 -0
  91. data/lib/rubygems/source_local.rb +92 -0
  92. data/lib/rubygems/source_specific_file.rb +28 -0
  93. data/lib/rubygems/spec_fetcher.rb +116 -184
  94. data/lib/rubygems/specification.rb +731 -335
  95. data/lib/rubygems/ssl_certs/AddTrustExternalCARoot.pem +88 -30
  96. data/lib/rubygems/ssl_certs/Entrust_net-Secure-Server-Certification-Authority.pem +90 -0
  97. data/lib/rubygems/ssl_certs/VerisignClass3PublicPrimaryCertificationAuthority-G2.pem +57 -0
  98. data/lib/rubygems/syck_hack.rb +2 -0
  99. data/lib/rubygems/test_case.rb +199 -109
  100. data/lib/rubygems/test_utilities.rb +25 -5
  101. data/lib/rubygems/uninstaller.rb +62 -20
  102. data/lib/rubygems/user_interaction.rb +10 -0
  103. data/lib/rubygems/validator.rb +33 -40
  104. data/lib/rubygems/version.rb +19 -8
  105. data/setup.rb +8 -1
  106. data/test/rubygems/alternate_cert.pem +9 -0
  107. data/test/rubygems/alternate_cert_32.pem +9 -0
  108. data/test/rubygems/alternate_key.pem +9 -0
  109. data/test/rubygems/bad_rake.rb +1 -0
  110. data/test/rubygems/child_cert.pem +9 -0
  111. data/test/rubygems/child_cert_32.pem +9 -0
  112. data/test/rubygems/child_key.pem +9 -0
  113. data/test/rubygems/data/null-type.gemspec.rz +0 -0
  114. data/test/rubygems/expired_cert.pem +9 -0
  115. data/test/rubygems/future_cert.pem +9 -0
  116. data/test/rubygems/future_cert_32.pem +9 -0
  117. data/test/rubygems/good_rake.rb +1 -0
  118. data/test/rubygems/grandchild_cert.pem +9 -0
  119. data/test/rubygems/grandchild_cert_32.pem +9 -0
  120. data/test/rubygems/grandchild_key.pem +9 -0
  121. data/test/rubygems/invalid_issuer_cert.pem +9 -0
  122. data/test/rubygems/invalid_issuer_cert_32.pem +9 -0
  123. data/test/rubygems/invalid_key.pem +9 -0
  124. data/test/rubygems/invalid_signer_cert.pem +9 -0
  125. data/test/rubygems/invalid_signer_cert_32.pem +9 -0
  126. data/test/rubygems/invalidchild_cert.pem +9 -0
  127. data/test/rubygems/invalidchild_cert_32.pem +9 -0
  128. data/test/rubygems/invalidchild_key.pem +9 -0
  129. data/test/rubygems/plugin/exception/rubygems_plugin.rb +1 -1
  130. data/test/rubygems/plugin/standarderror/rubygems_plugin.rb +1 -1
  131. data/test/rubygems/private_key.pem +7 -25
  132. data/test/rubygems/public_cert.pem +8 -18
  133. data/test/rubygems/public_cert_32.pem +10 -0
  134. data/test/rubygems/public_key.pem +4 -0
  135. data/test/rubygems/rubygems/commands/crash_command.rb +1 -1
  136. data/test/rubygems/test_config.rb +4 -6
  137. data/test/rubygems/test_deprecate.rb +76 -0
  138. data/test/rubygems/test_gem.rb +318 -83
  139. data/test/rubygems/test_gem_available_set.rb +106 -0
  140. data/test/rubygems/test_gem_command.rb +10 -0
  141. data/test/rubygems/test_gem_command_manager.rb +55 -9
  142. data/test/rubygems/test_gem_commands_build_command.rb +11 -19
  143. data/test/rubygems/test_gem_commands_cert_command.rb +441 -42
  144. data/test/rubygems/test_gem_commands_cleanup_command.rb +29 -1
  145. data/test/rubygems/test_gem_commands_contents_command.rb +23 -0
  146. data/test/rubygems/test_gem_commands_dependency_command.rb +5 -0
  147. data/test/rubygems/test_gem_commands_fetch_command.rb +19 -20
  148. data/test/rubygems/test_gem_commands_generate_index_command.rb +2 -83
  149. data/test/rubygems/test_gem_commands_help_command.rb +2 -1
  150. data/test/rubygems/test_gem_commands_install_command.rb +647 -48
  151. data/test/rubygems/test_gem_commands_mirror.rb +32 -0
  152. data/test/rubygems/test_gem_commands_owner_command.rb +4 -8
  153. data/test/rubygems/test_gem_commands_pristine_command.rb +99 -4
  154. data/test/rubygems/test_gem_commands_push_command.rb +62 -8
  155. data/test/rubygems/test_gem_commands_query_command.rb +51 -0
  156. data/test/rubygems/test_gem_commands_search_command.rb +25 -0
  157. data/test/rubygems/test_gem_commands_setup_command.rb +45 -0
  158. data/test/rubygems/test_gem_commands_sources_command.rb +21 -6
  159. data/test/rubygems/test_gem_commands_specification_command.rb +33 -1
  160. data/test/rubygems/test_gem_commands_uninstall_command.rb +91 -31
  161. data/test/rubygems/test_gem_commands_unpack_command.rb +3 -3
  162. data/test/rubygems/test_gem_commands_update_command.rb +56 -38
  163. data/test/rubygems/test_gem_commands_which_command.rb +4 -4
  164. data/test/rubygems/test_gem_commands_yank_command.rb +97 -0
  165. data/test/rubygems/test_gem_config_file.rb +66 -21
  166. data/test/rubygems/test_gem_dependency.rb +46 -0
  167. data/test/rubygems/test_gem_dependency_installer.rb +228 -18
  168. data/test/rubygems/test_gem_dependency_list.rb +0 -9
  169. data/test/rubygems/test_gem_dependency_resolver.rb +327 -0
  170. data/test/rubygems/test_gem_ext_configure_builder.rb +4 -4
  171. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +21 -49
  172. data/test/rubygems/test_gem_ext_rake_builder.rb +13 -13
  173. data/test/rubygems/test_gem_gem_runner.rb +27 -5
  174. data/test/rubygems/test_gem_gemcutter_utilities.rb +19 -0
  175. data/test/rubygems/test_gem_indexer.rb +14 -227
  176. data/test/rubygems/test_gem_install_update_options.rb +83 -3
  177. data/test/rubygems/test_gem_installer.rb +211 -236
  178. data/test/rubygems/test_gem_local_remote_options.rb +8 -2
  179. data/test/rubygems/test_gem_name_tuple.rb +15 -0
  180. data/test/rubygems/test_gem_package.rb +547 -0
  181. data/test/rubygems/test_gem_package_old.rb +37 -0
  182. data/test/rubygems/test_gem_package_tar_reader.rb +32 -0
  183. data/test/rubygems/test_gem_package_tar_writer.rb +84 -1
  184. data/test/rubygems/test_gem_path_support.rb +4 -30
  185. data/test/rubygems/test_gem_platform.rb +3 -6
  186. data/test/rubygems/test_gem_rdoc.rb +245 -0
  187. data/test/rubygems/test_gem_remote_fetcher.rb +51 -5
  188. data/test/rubygems/test_gem_request_set.rb +70 -0
  189. data/test/rubygems/test_gem_requirement.rb +53 -24
  190. data/test/rubygems/test_gem_security.rb +189 -43
  191. data/test/rubygems/test_gem_security_policy.rb +376 -0
  192. data/test/rubygems/test_gem_security_signer.rb +184 -0
  193. data/test/rubygems/test_gem_security_trust_dir.rb +94 -0
  194. data/test/rubygems/test_gem_server.rb +31 -36
  195. data/test/rubygems/test_gem_silent_ui.rb +2 -2
  196. data/test/rubygems/test_gem_source.rb +188 -0
  197. data/test/rubygems/test_gem_source_list.rb +87 -0
  198. data/test/rubygems/test_gem_source_local.rb +83 -0
  199. data/test/rubygems/test_gem_source_specific_file.rb +33 -0
  200. data/test/rubygems/test_gem_spec_fetcher.rb +91 -255
  201. data/test/rubygems/test_gem_specification.rb +293 -39
  202. data/test/rubygems/test_gem_uninstaller.rb +136 -13
  203. data/test/rubygems/test_gem_validator.rb +14 -41
  204. data/test/rubygems/test_gem_version.rb +15 -21
  205. data/test/rubygems/test_require.rb +193 -0
  206. data/test/rubygems/wrong_key_cert.pem +9 -0
  207. data/test/rubygems/wrong_key_cert_32.pem +9 -0
  208. metadata +171 -83
  209. metadata.gz.sig +1 -0
  210. data/CVE-2013-4287.txt +0 -36
  211. data/CVE-2013-4363.txt +0 -45
  212. data/ci_build.sh +0 -27
  213. data/cruise_config.rb +0 -32
  214. data/lib/rbconfig/datadir.rb +0 -13
  215. data/lib/rubygems/builder.rb +0 -99
  216. data/lib/rubygems/custom_require.rb +0 -69
  217. data/lib/rubygems/doc_manager.rb +0 -243
  218. data/lib/rubygems/format.rb +0 -82
  219. data/lib/rubygems/gem_openssl.rb +0 -90
  220. data/lib/rubygems/gem_path_searcher.rb +0 -172
  221. data/lib/rubygems/old_format.rb +0 -153
  222. data/lib/rubygems/package/f_sync_dir.rb +0 -23
  223. data/lib/rubygems/package/tar_input.rb +0 -234
  224. data/lib/rubygems/package/tar_output.rb +0 -146
  225. data/lib/rubygems/require_paths_builder.rb +0 -18
  226. data/lib/rubygems/source_index.rb +0 -406
  227. data/lib/rubygems/ssl_certs/AddTrustExternalCARoot-2048.pem +0 -25
  228. data/lib/rubygems/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +0 -14
  229. data/lib/rubygems/ssl_certs/DigiCertHighAssuranceEVRootCA.pem +0 -23
  230. data/lib/rubygems/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +0 -28
  231. data/lib/rubygems/ssl_certs/GeoTrustGlobalCA.pem +0 -20
  232. data/test/rubygems/test_bundled_ca.rb +0 -59
  233. data/test/rubygems/test_gem_builder.rb +0 -44
  234. data/test/rubygems/test_gem_doc_manager.rb +0 -32
  235. data/test/rubygems/test_gem_ext_builder.rb +0 -58
  236. data/test/rubygems/test_gem_format.rb +0 -88
  237. data/test/rubygems/test_gem_gem_path_searcher.rb +0 -94
  238. data/test/rubygems/test_gem_package_tar_input.rb +0 -129
  239. data/test/rubygems/test_gem_package_tar_output.rb +0 -101
  240. data/test/rubygems/test_gem_source_index.rb +0 -250
  241. data/util/update_bundled_ca_certificates.rb +0 -103
@@ -6,11 +6,26 @@ class Gem::Installer
6
6
  ##
7
7
  # Available through requiring rubygems/installer_test_case
8
8
 
9
+ attr_writer :bin_dir
10
+
11
+ ##
12
+ # Available through requiring rubygems/installer_test_case
13
+
14
+ attr_writer :build_args
15
+
16
+ ##
17
+ # Available through requiring rubygems/installer_test_case
18
+
9
19
  attr_writer :gem_dir
10
20
 
11
21
  ##
12
22
  # Available through requiring rubygems/installer_test_case
13
23
 
24
+ attr_writer :force
25
+
26
+ ##
27
+ # Available through requiring rubygems/installer_test_case
28
+
14
29
  attr_writer :format
15
30
 
16
31
  ##
@@ -54,47 +69,68 @@ end
54
69
 
55
70
  class Gem::InstallerTestCase < Gem::TestCase
56
71
 
72
+ ##
73
+ # Creates the following instance variables:
74
+ #
75
+ # @spec::
76
+ # a spec named 'a', intended for regular installs
77
+ # @user_spec::
78
+ # a spec named 'b', intended for user installs
79
+
80
+ # @gem::
81
+ # the path to a built gem from @spec
82
+ # @user_spec::
83
+ # the path to a built gem from @user_spec
84
+ #
85
+ # @installer::
86
+ # a Gem::Installer for the @spec that installs into @gemhome
87
+ # @user_installer::
88
+ # a Gem::Installer for the @user_spec that installs into Gem.user_dir
89
+
57
90
  def setup
58
91
  super
59
92
 
60
- @installer_tmp = File.join @tempdir, 'installer'
61
- FileUtils.mkdir_p @installer_tmp
93
+ @spec = quick_gem 'a' do |spec|
94
+ util_make_exec spec
95
+ end
62
96
 
63
- Gem.use_paths @installer_tmp
64
- Gem.ensure_gem_subdirectories @installer_tmp
97
+ @user_spec = quick_gem 'b' do |spec|
98
+ util_make_exec spec
99
+ end
65
100
 
66
- @spec = quick_gem 'a'
67
- util_make_exec @spec
68
101
  util_build_gem @spec
69
- @gem = @spec.cache_file
70
-
71
- @user_spec = quick_gem 'b'
72
- util_make_exec @user_spec
73
102
  util_build_gem @user_spec
74
- @user_gem = @user_spec.cache_file
75
103
 
76
- Gem.use_paths @gemhome
104
+ @gem = @spec.cache_file
105
+ @user_gem = @user_spec.cache_file
77
106
 
78
107
  @installer = util_installer @spec, @gemhome
79
108
  @user_installer = util_installer @user_spec, Gem.user_dir, :user
80
-
81
- Gem.use_paths @gemhome
82
109
  end
83
110
 
84
- def util_gem_bindir spec = @spec
111
+ def util_gem_bindir spec = @spec # :nodoc:
85
112
  # TODO: deprecate
86
113
  spec.bin_dir
87
114
  end
88
115
 
89
- def util_gem_dir spec = @spec
116
+ def util_gem_dir spec = @spec # :nodoc:
90
117
  # TODO: deprecate
91
118
  spec.gem_dir
92
119
  end
93
120
 
121
+ ##
122
+ # The path where installed executables live
123
+
94
124
  def util_inst_bindir
95
125
  File.join @gemhome, "bin"
96
126
  end
97
127
 
128
+ ##
129
+ # Adds an executable named "executable" to +spec+ with the given +shebang+.
130
+ #
131
+ # The executable is also written to the bin dir in @tmpdir and the installed
132
+ # gem directory for +spec+.
133
+
98
134
  def util_make_exec(spec = @spec, shebang = "#!/usr/bin/ruby")
99
135
  spec.executables = %w[executable]
100
136
  spec.files << 'bin/executable'
@@ -110,6 +146,14 @@ class Gem::InstallerTestCase < Gem::TestCase
110
146
  end
111
147
  end
112
148
 
149
+ ##
150
+ # Builds the @spec gem and returns an installer for it. The built gem
151
+ # includes:
152
+ #
153
+ # bin/executable
154
+ # lib/code.rb
155
+ # ext/a/mkrf_conf.rb
156
+
113
157
  def util_setup_gem(ui = @ui) # HACK fix use_ui to make this automatic
114
158
  @spec.files << File.join('lib', 'code.rb')
115
159
  @spec.extensions << File.join('ext', 'a', 'mkrf_conf.rb')
@@ -129,16 +173,24 @@ class Gem::InstallerTestCase < Gem::TestCase
129
173
  end
130
174
 
131
175
  use_ui ui do
132
- FileUtils.rm @gem
176
+ FileUtils.rm_f @gem
133
177
 
134
- @gem = Gem::Builder.new(@spec).build
178
+ @gem = Gem::Package.build @spec
135
179
  end
136
180
  end
137
181
 
138
182
  @installer = Gem::Installer.new @gem
139
183
  end
140
184
 
185
+ ##
186
+ # Creates an installer for +spec+ that will install into +gem_home+. If
187
+ # +user+ is true a user-install will be performed.
188
+
141
189
  def util_installer(spec, gem_home, user=false)
142
- Gem::Installer.new spec.cache_file, :user_install => user
190
+ Gem::Installer.new(spec.cache_file,
191
+ :install_dir => gem_home,
192
+ :user_install => user)
143
193
  end
194
+
144
195
  end
196
+
@@ -6,6 +6,17 @@ require 'rubygems/user_interaction'
6
6
  # retrieval during tests.
7
7
 
8
8
  class Gem::MockGemUi < Gem::StreamUI
9
+ ##
10
+ # Raised when you haven't provided enough input to your MockGemUi
11
+
12
+ class InputEOFError < RuntimeError
13
+
14
+ def initialize question
15
+ super "Out of input for MockGemUi on #{question.inspect}"
16
+ end
17
+
18
+ end
19
+
9
20
  class TermError < RuntimeError
10
21
  attr_reader :exit_code
11
22
 
@@ -44,6 +55,12 @@ class Gem::MockGemUi < Gem::StreamUI
44
55
  @terminated = false
45
56
  end
46
57
 
58
+ def ask question
59
+ raise InputEOFError, question if @ins.eof?
60
+
61
+ super
62
+ end
63
+
47
64
  def input
48
65
  @ins.string
49
66
  end
@@ -0,0 +1,110 @@
1
+ ##
2
+ #
3
+ # Represents a gem of name +name+ at +version+ of +platform+. These
4
+ # wrap the data returned from the indexes.
5
+
6
+ require 'rubygems/platform'
7
+
8
+ class Gem::NameTuple
9
+ def initialize(name, version, platform="ruby")
10
+ @name = name
11
+ @version = version
12
+
13
+ unless platform.kind_of? Gem::Platform
14
+ platform = "ruby" if !platform or platform.empty?
15
+ end
16
+
17
+ @platform = platform
18
+ end
19
+
20
+ attr_reader :name, :version, :platform
21
+
22
+ ##
23
+ # Turn an array of [name, version, platform] into an array of
24
+ # NameTuple objects.
25
+
26
+ def self.from_list list
27
+ list.map { |t| new(*t) }
28
+ end
29
+
30
+ ##
31
+ # Turn an array of NameTuple objects back into an array of
32
+ # [name, version, platform] tuples.
33
+
34
+ def self.to_basic list
35
+ list.map { |t| t.to_a }
36
+ end
37
+
38
+ ##
39
+ # A null NameTuple, ie name=nil, version=0
40
+
41
+ def self.null
42
+ new nil, Gem::Version.new(0), nil
43
+ end
44
+
45
+ ##
46
+ # Indicate if this NameTuple matches the current platform.
47
+
48
+ def match_platform?
49
+ Gem::Platform.match @platform
50
+ end
51
+
52
+ ##
53
+ # Indicate if this NameTuple is for a prerelease version.
54
+ def prerelease?
55
+ @version.prerelease?
56
+ end
57
+
58
+ ##
59
+ # Return the name that the gemspec file would be
60
+
61
+ def spec_name
62
+ case @platform
63
+ when nil, 'ruby', ''
64
+ "#{@name}-#{@version}.gemspec"
65
+ else
66
+ "#{@name}-#{@version}-#{@platform}.gemspec"
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Convert back to the [name, version, platform] tuple
72
+
73
+ def to_a
74
+ [@name, @version, @platform]
75
+ end
76
+
77
+ def to_s
78
+ "#<Gem::NameTuple #{@name}, #{@version}, #{@platform}>"
79
+ end
80
+
81
+ def <=> other
82
+ to_a <=> other.to_a
83
+ end
84
+
85
+ include Comparable
86
+
87
+ ##
88
+ # Compare with +other+. Supports another NameTuple or an Array
89
+ # in the [name, version, platform] format.
90
+
91
+ def == other
92
+ case other
93
+ when self.class
94
+ @name == other.name and
95
+ @version == other.version and
96
+ @platform == other.platform
97
+ when Array
98
+ to_a == other
99
+ else
100
+ false
101
+ end
102
+ end
103
+
104
+ alias_method :eql?, :==
105
+
106
+ def hash
107
+ to_a.hash
108
+ end
109
+
110
+ end
@@ -3,16 +3,54 @@
3
3
  # Copyright (C) 2004 Mauricio Julio Fernández Pradier
4
4
  # See LICENSE.txt for additional licensing information.
5
5
  #++
6
+ #
7
+ # Example using a Gem::Package
8
+ #
9
+ # Builds a .gem file given a Gem::Specification. A .gem file is a tarball
10
+ # which contains a data.tar.gz and metadata.gz, and possibly signatures.
11
+ #
12
+ # require 'rubygems'
13
+ # require 'rubygems/package'
14
+ #
15
+ # spec = Gem::Specification.new do |s|
16
+ # s.summary = "Ruby based make-like utility."
17
+ # s.name = 'rake'
18
+ # s.version = PKG_VERSION
19
+ # s.requirements << 'none'
20
+ # s.files = PKG_FILES
21
+ # s.description = <<-EOF
22
+ # Rake is a Make-like program implemented in Ruby. Tasks
23
+ # and dependencies are specified in standard Ruby syntax.
24
+ # EOF
25
+ # end
26
+ #
27
+ # Gem::Package.build spec
28
+ #
29
+ # Reads a .gem file.
30
+ #
31
+ # require 'rubygems'
32
+ # require 'rubygems/package'
33
+ #
34
+ # the_gem = Gem::Package.new(path_to_dot_gem)
35
+ # the_gem.contents # get the files in the gem
36
+ # the_gem.extract_files destination_directory # extract the gem into a directory
37
+ # the_gem.spec # get the spec out of the gem
38
+ # the_gem.verify # check the gem is OK (contains valid gem specification, contains a not corrupt contents archive)
39
+ #
40
+ # #files are the files in the .gem tar file, not the ruby files in the gem
41
+ # #extract_files and #contents automatically call #verify
6
42
 
43
+ require 'rubygems/security'
7
44
  require 'rubygems/specification'
45
+ require 'rubygems/user_interaction'
46
+ require 'zlib'
8
47
 
9
- module Gem::Package
48
+ class Gem::Package
49
+
50
+ include Gem::UserInteraction
51
+
52
+ class Error < Gem::Exception; end
10
53
 
11
- class Error < StandardError; end
12
- class NonSeekableIO < Error; end
13
- class ClosedIO < Error; end
14
- class BadCheckSum < Error; end
15
- class TooLongFileName < Error; end
16
54
  class FormatError < Error
17
55
  attr_reader :path
18
56
 
@@ -26,57 +64,490 @@ module Gem::Package
26
64
 
27
65
  end
28
66
 
67
+ class PathError < Error
68
+ def initialize destination, destination_dir
69
+ super "installing into parent path %s of %s is not allowed" %
70
+ [destination, destination_dir]
71
+ end
72
+ end
73
+
74
+ class NonSeekableIO < Error; end
75
+
76
+ class TooLongFileName < Error; end
77
+
29
78
  ##
30
79
  # Raised when a tar file is corrupt
31
80
 
32
81
  class TarInvalidError < Error; end
33
82
 
34
- # FIX: zenspider said: does it really take an IO?
35
- # passed to a method called open?!? that seems stupid.
36
- def self.open(io, mode = "r", signer = nil, &block)
37
- tar_type = case mode
38
- when 'r' then TarInput
39
- when 'w' then TarOutput
40
- else
41
- raise "Unknown Package open mode"
42
- end
43
-
44
- tar_type.open(io, signer, &block)
45
- end
46
-
47
- def self.pack(src, destname, signer = nil)
48
- TarOutput.open(destname, signer) do |outp|
49
- dir_class.chdir(src) do
50
- outp.metadata = (file_class.read("RPA/metadata") rescue nil)
51
- find_class.find('.') do |entry|
52
- case
53
- when file_class.file?(entry)
54
- entry.sub!(%r{\./}, "")
55
- next if entry =~ /\ARPA\//
56
- stat = File.stat(entry)
57
- outp.add_file_simple(entry, stat.mode, stat.size) do |os|
58
- file_class.open(entry, "rb") do |f|
59
- os.write(f.read(4096)) until f.eof?
60
- end
61
- end
62
- when file_class.dir?(entry)
63
- entry.sub!(%r{\./}, "")
64
- next if entry == "RPA"
65
- outp.mkdir(entry, file_class.stat(entry).mode)
66
- else
67
- raise "Don't know how to pack this yet!"
83
+ attr_accessor :build_time # :nodoc:
84
+
85
+ ##
86
+ # Checksums for the contents of the package
87
+
88
+ attr_reader :checksums
89
+
90
+ ##
91
+ # The files in this package. This is not the contents of the gem, just the
92
+ # files in the top-level container.
93
+
94
+ attr_reader :files
95
+
96
+ ##
97
+ # The security policy used for verifying the contents of this package.
98
+
99
+ attr_accessor :security_policy
100
+
101
+ ##
102
+ # Sets the Gem::Specification to use to build this package.
103
+
104
+ attr_writer :spec
105
+
106
+ def self.build spec, skip_validation=false
107
+ gem_file = spec.file_name
108
+
109
+ package = new gem_file
110
+ package.spec = spec
111
+ package.build skip_validation
112
+
113
+ gem_file
114
+ end
115
+
116
+ ##
117
+ # Creates a new Gem::Package for the file at +gem+.
118
+ #
119
+ # If +gem+ is an existing file in the old format a Gem::Package::Old will be
120
+ # returned.
121
+
122
+ def self.new gem
123
+ return super unless Gem::Package == self
124
+ return super unless File.exist? gem
125
+
126
+ start = File.read gem, 20
127
+
128
+ return super unless start
129
+ return super unless start.include? 'MD5SUM ='
130
+
131
+ Gem::Package::Old.new gem
132
+ end
133
+
134
+ ##
135
+ # Creates a new package that will read or write to the file +gem+.
136
+
137
+ def initialize gem # :notnew:
138
+ @gem = gem
139
+
140
+ @build_time = Time.now
141
+ @checksums = {}
142
+ @contents = nil
143
+ @digests = Hash.new { |h, algorithm| h[algorithm] = {} }
144
+ @files = nil
145
+ @security_policy = nil
146
+ @signatures = {}
147
+ @signer = nil
148
+ @spec = nil
149
+ end
150
+
151
+ ##
152
+ # Adds a checksum for each entry in the gem to checksums.yaml.gz.
153
+
154
+ def add_checksums tar
155
+ Gem.load_yaml
156
+
157
+ checksums_by_algorithm = Hash.new { |h, algorithm| h[algorithm] = {} }
158
+
159
+ @checksums.each do |name, digests|
160
+ digests.each do |algorithm, digest|
161
+ checksums_by_algorithm[algorithm][name] = digest.hexdigest
162
+ end
163
+ end
164
+
165
+ tar.add_file_signed 'checksums.yaml.gz', 0444, @signer do |io|
166
+ gzip_to io do |gz_io|
167
+ YAML.dump checksums_by_algorithm, gz_io
168
+ end
169
+ end
170
+ end
171
+
172
+ ##
173
+ # Adds the files listed in the packages's Gem::Specification to data.tar.gz
174
+ # and adds this file to the +tar+.
175
+
176
+ def add_contents tar # :nodoc:
177
+ digests = tar.add_file_signed 'data.tar.gz', 0444, @signer do |io|
178
+ gzip_to io do |gz_io|
179
+ Gem::Package::TarWriter.new gz_io do |data_tar|
180
+ add_files data_tar
181
+ end
182
+ end
183
+ end
184
+
185
+ @checksums['data.tar.gz'] = digests
186
+ end
187
+
188
+ ##
189
+ # Adds files included the package's Gem::Specification to the +tar+ file
190
+
191
+ def add_files tar # :nodoc:
192
+ @spec.files.each do |file|
193
+ stat = File.stat file
194
+
195
+ tar.add_file_simple file, stat.mode, stat.size do |dst_io|
196
+ open file, 'rb' do |src_io|
197
+ dst_io.write src_io.read 16384 until src_io.eof?
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ ##
204
+ # Adds the package's Gem::Specification to the +tar+ file
205
+
206
+ def add_metadata tar # :nodoc:
207
+ digests = tar.add_file_signed 'metadata.gz', 0444, @signer do |io|
208
+ gzip_to io do |gz_io|
209
+ gz_io.write @spec.to_yaml
210
+ end
211
+ end
212
+
213
+ @checksums['metadata.gz'] = digests
214
+ end
215
+
216
+ ##
217
+ # Builds this package based on the specification set by #spec=
218
+
219
+ def build skip_validation = false
220
+ Gem.load_yaml
221
+ require 'rubygems/security'
222
+
223
+ @spec.validate unless skip_validation
224
+ @spec.mark_version
225
+
226
+ setup_signer
227
+
228
+ open @gem, 'wb' do |gem_io|
229
+ Gem::Package::TarWriter.new gem_io do |gem|
230
+ add_metadata gem
231
+ add_contents gem
232
+ add_checksums gem
233
+ end
234
+ end
235
+
236
+ say <<-EOM
237
+ Successfully built RubyGem
238
+ Name: #{@spec.name}
239
+ Version: #{@spec.version}
240
+ File: #{File.basename @spec.cache_file}
241
+ EOM
242
+ ensure
243
+ @signer = nil
244
+ end
245
+
246
+ ##
247
+ # A list of file names contained in this gem
248
+
249
+ def contents
250
+ return @contents if @contents
251
+
252
+ verify unless @spec
253
+
254
+ @contents = []
255
+
256
+ open @gem, 'rb' do |io|
257
+ gem_tar = Gem::Package::TarReader.new io
258
+
259
+ gem_tar.each do |entry|
260
+ next unless entry.full_name == 'data.tar.gz'
261
+
262
+ open_tar_gz entry do |pkg_tar|
263
+ pkg_tar.each do |contents_entry|
264
+ @contents << contents_entry.full_name
68
265
  end
69
266
  end
267
+
268
+ return @contents
269
+ end
270
+ end
271
+ end
272
+
273
+ ##
274
+ # Creates a digest of the TarEntry +entry+ from the digest algorithm set by
275
+ # the security policy.
276
+
277
+ def digest entry # :nodoc:
278
+ return unless @checksums
279
+
280
+ @checksums.each_key do |algorithm|
281
+ digester = OpenSSL::Digest.new algorithm
282
+
283
+ digester << entry.read(16384) until entry.eof?
284
+
285
+ entry.rewind
286
+
287
+ @digests[algorithm][entry.full_name] = digester
288
+ end
289
+
290
+ @digests
291
+ end
292
+
293
+ ##
294
+ # Extracts the files in this package into +destination_dir+
295
+
296
+ def extract_files destination_dir
297
+ verify unless @spec
298
+
299
+ FileUtils.mkdir_p destination_dir
300
+
301
+ open @gem, 'rb' do |io|
302
+ reader = Gem::Package::TarReader.new io
303
+
304
+ reader.each do |entry|
305
+ next unless entry.full_name == 'data.tar.gz'
306
+
307
+ extract_tar_gz entry, destination_dir
308
+
309
+ return # ignore further entries
310
+ end
311
+ end
312
+ end
313
+
314
+ ##
315
+ # Extracts all the files in the gzipped tar archive +io+ into
316
+ # +destination_dir+.
317
+ #
318
+ # If an entry in the archive contains a relative path above
319
+ # +destination_dir+ or an absolute path is encountered an exception is
320
+ # raised.
321
+
322
+ def extract_tar_gz io, destination_dir # :nodoc:
323
+ open_tar_gz io do |tar|
324
+ tar.each do |entry|
325
+ destination = install_location entry.full_name, destination_dir
326
+
327
+ FileUtils.rm_rf destination
328
+
329
+ FileUtils.mkdir_p File.dirname destination
330
+
331
+ open destination, 'wb', entry.header.mode do |out|
332
+ out.write entry.read
333
+ out.fsync rescue nil # for filesystems without fsync(2)
334
+ end
335
+
336
+ say destination if Gem.configuration.really_verbose
337
+ end
338
+ end
339
+ end
340
+
341
+ ##
342
+ # Gzips content written to +gz_io+ to +io+.
343
+ #--
344
+ # Also sets the gzip modification time to the package build time to ease
345
+ # testing.
346
+
347
+ def gzip_to io # :yields: gz_io
348
+ gz_io = Zlib::GzipWriter.new io, Zlib::BEST_COMPRESSION
349
+ gz_io.mtime = @build_time
350
+
351
+ yield gz_io
352
+ ensure
353
+ gz_io.close
354
+ end
355
+
356
+ ##
357
+ # Returns the full path for installing +filename+.
358
+ #
359
+ # If +filename+ is not inside +destination_dir+ an exception is raised.
360
+
361
+ def install_location filename, destination_dir # :nodoc:
362
+ raise Gem::Package::PathError.new(filename, destination_dir) if
363
+ filename.start_with? '/'
364
+
365
+ destination = File.join destination_dir, filename
366
+ destination = File.expand_path destination
367
+
368
+ raise Gem::Package::PathError.new(destination, destination_dir) unless
369
+ destination.start_with? destination_dir
370
+
371
+ destination.untaint
372
+ destination
373
+ end
374
+
375
+ ##
376
+ # Loads a Gem::Specification from the TarEntry +entry+
377
+
378
+ def load_spec entry # :nodoc:
379
+ case entry.full_name
380
+ when 'metadata' then
381
+ @spec = Gem::Specification.from_yaml entry.read
382
+ when 'metadata.gz' then
383
+ args = [entry]
384
+ args << { :external_encoding => Encoding::UTF_8 } if
385
+ Object.const_defined? :Encoding
386
+
387
+ Zlib::GzipReader.wrap(*args) do |gzio|
388
+ @spec = Gem::Specification.from_yaml gzio.read
389
+ end
390
+ end
391
+ end
392
+
393
+ ##
394
+ # Opens +io+ as a gzipped tar archive
395
+
396
+ def open_tar_gz io # :nodoc:
397
+ Zlib::GzipReader.wrap io do |gzio|
398
+ tar = Gem::Package::TarReader.new gzio
399
+
400
+ yield tar
401
+ end
402
+ end
403
+
404
+ ##
405
+ # Reads and loads checksums.yaml.gz from the tar file +gem+
406
+
407
+ def read_checksums gem
408
+ Gem.load_yaml
409
+
410
+ @checksums = gem.seek 'checksums.yaml.gz' do |entry|
411
+ Zlib::GzipReader.wrap entry do |gz_io|
412
+ YAML.load gz_io.read
413
+ end
414
+ end
415
+ end
416
+
417
+ ##
418
+ # Prepares the gem for signing and checksum generation. If a signing
419
+ # certificate and key are not present only checksum generation is set up.
420
+
421
+ def setup_signer
422
+ if @spec.signing_key then
423
+ @signer = Gem::Security::Signer.new @spec.signing_key, @spec.cert_chain
424
+ @spec.signing_key = nil
425
+ @spec.cert_chain = @signer.cert_chain.map { |cert| cert.to_s }
426
+ else
427
+ @signer = Gem::Security::Signer.new nil, nil
428
+ @spec.cert_chain = @signer.cert_chain.map { |cert| cert.to_pem } if
429
+ @signer.cert_chain
430
+ end
431
+ end
432
+
433
+ ##
434
+ # The spec for this gem.
435
+ #
436
+ # If this is a package for a built gem the spec is loaded from the
437
+ # gem and returned. If this is a package for a gem being built the provided
438
+ # spec is returned.
439
+
440
+ def spec
441
+ verify unless @spec
442
+
443
+ @spec
444
+ end
445
+
446
+ ##
447
+ # Verifies that this gem:
448
+ #
449
+ # * Contains a valid gem specification
450
+ # * Contains a contents archive
451
+ # * The contents archive is not corrupt
452
+ #
453
+ # After verification the gem specification from the gem is available from
454
+ # #spec
455
+
456
+ def verify
457
+ @files = []
458
+ @spec = nil
459
+
460
+ open @gem, 'rb' do |io|
461
+ Gem::Package::TarReader.new io do |reader|
462
+ read_checksums reader
463
+
464
+ verify_files reader
465
+ end
466
+ end
467
+
468
+ verify_checksums @digests, @checksums
469
+
470
+ @security_policy.verify_signatures @spec, @digests, @signatures if
471
+ @security_policy
472
+
473
+ true
474
+ rescue Errno::ENOENT => e
475
+ raise Gem::Package::FormatError.new e.message
476
+ rescue Gem::Package::TarInvalidError => e
477
+ raise Gem::Package::FormatError.new e.message, @gem
478
+ end
479
+
480
+ ##
481
+ # Verifies the +checksums+ against the +digests+. This check is not
482
+ # cryptographically secure. Missing checksums are ignored.
483
+
484
+ def verify_checksums digests, checksums # :nodoc:
485
+ return unless checksums
486
+
487
+ checksums.sort.each do |algorithm, gem_digests|
488
+ gem_digests.sort.each do |file_name, gem_hexdigest|
489
+ computed_digest = digests[algorithm][file_name]
490
+
491
+ unless computed_digest.hexdigest == gem_hexdigest then
492
+ raise Gem::Package::FormatError.new \
493
+ "#{algorithm} checksum mismatch for #{file_name}", @gem
494
+ end
70
495
  end
71
496
  end
72
497
  end
73
498
 
499
+ ##
500
+ # Verifies the files of the +gem+
501
+
502
+ def verify_files gem
503
+ gem.each do |entry|
504
+ file_name = entry.full_name
505
+ @files << file_name
506
+
507
+ case file_name
508
+ when /\.sig$/ then
509
+ @signatures[$`] = entry.read if @security_policy
510
+ next
511
+ when 'checksums.yaml.gz' then
512
+ next # already handled
513
+ else
514
+ digest entry
515
+ end
516
+
517
+ case file_name
518
+ when /^metadata(.gz)?$/ then
519
+ load_spec entry
520
+ when 'data.tar.gz' then
521
+ verify_gz entry
522
+ end
523
+ end
524
+
525
+ unless @spec then
526
+ raise Gem::Package::FormatError.new 'package metadata is missing', @gem
527
+ end
528
+
529
+ unless @files.include? 'data.tar.gz' then
530
+ raise Gem::Package::FormatError.new \
531
+ 'package content (data.tar.gz) is missing', @gem
532
+ end
533
+ end
534
+
535
+ ##
536
+ # Verifies that +entry+ is a valid gzipped file.
537
+
538
+ def verify_gz entry # :nodoc:
539
+ Zlib::GzipReader.wrap entry do |gzio|
540
+ gzio.read 16384 until gzio.eof? # gzip checksum verification
541
+ end
542
+ rescue Zlib::GzipFile::Error => e
543
+ raise Gem::Package::FormatError.new(e.message, entry.full_name)
544
+ end
545
+
74
546
  end
75
547
 
76
- require 'rubygems/package/f_sync_dir'
548
+ require 'rubygems/package/digest_io'
549
+ require 'rubygems/package/old'
77
550
  require 'rubygems/package/tar_header'
78
- require 'rubygems/package/tar_input'
79
- require 'rubygems/package/tar_output'
80
551
  require 'rubygems/package/tar_reader'
81
552
  require 'rubygems/package/tar_reader/entry'
82
553
  require 'rubygems/package/tar_writer'