rubygems-update 1.8.30 → 2.0.0.preview2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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'