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
@@ -1,8 +1,8 @@
1
1
  module Gem
2
-
3
- # TODO: move this whole file back into rubygems.rb
2
+ DEFAULT_HOST = "https://rubygems.org"
4
3
 
5
4
  @post_install_hooks ||= []
5
+ @done_installing_hooks ||= []
6
6
  @post_uninstall_hooks ||= []
7
7
  @pre_uninstall_hooks ||= []
8
8
  @pre_install_hooks ||= []
@@ -57,11 +57,18 @@ module Gem
57
57
  File.join Gem.user_home, '.gem', ruby_engine, ConfigMap[:ruby_version]
58
58
  end
59
59
 
60
+ ##
61
+ # How String Gem paths should be split. Overridable for esoteric platforms.
62
+
63
+ def self.path_separator
64
+ File::PATH_SEPARATOR
65
+ end
66
+
60
67
  ##
61
68
  # Default gem load path
62
69
 
63
70
  def self.default_path
64
- if File.exist? Gem.user_home then
71
+ if Gem.user_home && File.exist?(Gem.user_home) then
65
72
  [user_dir, default_dir]
66
73
  else
67
74
  [default_dir]
@@ -93,24 +100,6 @@ module Gem
93
100
  end
94
101
  end
95
102
 
96
- ##
97
- # The default system-wide source info cache directory
98
-
99
- def self.default_system_source_cache_dir
100
- File.join(Gem.dir, 'source_cache')
101
- end
102
-
103
- ##
104
- # The default user-specific source info cache directory
105
-
106
- def self.default_user_source_cache_dir
107
- #
108
- # NOTE Probably an argument for moving this to per-ruby supported dirs like
109
- # user_dir
110
- #
111
- File.join(Gem.user_home, '.gem', 'source_cache')
112
- end
113
-
114
103
  ##
115
104
  # A wrapper around RUBY_ENGINE const that may not be defined
116
105
 
@@ -1,8 +1,8 @@
1
- require "rubygems/requirement"
2
-
3
1
  ##
4
2
  # The Dependency class holds a Gem name and a Gem::Requirement.
5
3
 
4
+ require "rubygems/requirement"
5
+
6
6
  class Gem::Dependency
7
7
 
8
8
  ##
@@ -11,6 +11,9 @@ class Gem::Dependency
11
11
  # When this list is updated, be sure to change
12
12
  # Gem::Specification::CURRENT_SPECIFICATION_VERSION as well.
13
13
 
14
+ # REFACTOR: This type of constant, TYPES, indicates we might want
15
+ # two classes, used via inheretance or duck typing.
16
+
14
17
  TYPES = [
15
18
  :development,
16
19
  :runtime,
@@ -32,18 +35,23 @@ class Gem::Dependency
32
35
  # <tt>:runtime</tt>.
33
36
 
34
37
  def initialize name, *requirements
35
- if Regexp === name then
38
+ case name
39
+ when String then # ok
40
+ when Regexp then
36
41
  msg = ["NOTE: Dependency.new w/ a regexp is deprecated.",
37
42
  "Dependency.new called from #{Gem.location_of_caller.join(":")}"]
38
43
  warn msg.join("\n") unless Gem::Deprecate.skip
44
+ else
45
+ raise ArgumentError,
46
+ "dependency name must be a String, was #{name.inspect}"
39
47
  end
40
48
 
41
49
  type = Symbol === requirements.last ? requirements.pop : :runtime
42
50
  requirements = requirements.first if 1 == requirements.length # unpack
43
51
 
44
52
  unless TYPES.include? type
45
- raise ArgumentError, "Valid types are #{TYPES.inspect}, "
46
- + "not #{type.inspect}"
53
+ raise ArgumentError, "Valid types are #{TYPES.inspect}, " +
54
+ "not #{type.inspect}"
47
55
  end
48
56
 
49
57
  @name = name
@@ -66,8 +74,13 @@ class Gem::Dependency
66
74
  end
67
75
 
68
76
  def inspect # :nodoc:
69
- "<%s type=%p name=%p requirements=%p>" %
70
- [self.class, self.type, self.name, requirement.to_s]
77
+ if @prerelease
78
+ "<%s type=%p name=%p requirements=%p prerelease=ok>" %
79
+ [self.class, self.type, self.name, requirement.to_s]
80
+ else
81
+ "<%s type=%p name=%p requirements=%p>" %
82
+ [self.class, self.type, self.name, requirement.to_s]
83
+ end
71
84
  end
72
85
 
73
86
  ##
@@ -77,6 +90,14 @@ class Gem::Dependency
77
90
  @prerelease || requirement.prerelease?
78
91
  end
79
92
 
93
+ ##
94
+ # Is this dependency simply asking for the latest version
95
+ # of a gem?
96
+
97
+ def latest_version?
98
+ @requirement.none?
99
+ end
100
+
80
101
  def pretty_print q # :nodoc:
81
102
  q.group 1, 'Gem::Dependency.new(', ')' do
82
103
  q.pp name
@@ -113,6 +134,8 @@ class Gem::Dependency
113
134
  # Children, define explicit marshal and unmarshal behavior for
114
135
  # public classes. Marshal formats are part of your public API.
115
136
 
137
+ # REFACTOR: See above
138
+
116
139
  if defined?(@version_requirement) && @version_requirement
117
140
  version = @version_requirement.instance_variable_get :@version
118
141
  @version_requirement = nil
@@ -122,6 +145,7 @@ class Gem::Dependency
122
145
  @requirement = @version_requirements if defined?(@version_requirements)
123
146
  end
124
147
 
148
+ # DOC: this method needs documentation or :nodoc''d
125
149
  def requirements_list
126
150
  requirement.as_list
127
151
  end
@@ -179,13 +203,24 @@ class Gem::Dependency
179
203
  requirement.satisfied_by? version
180
204
  end
181
205
 
182
- def match? name, version
206
+ # DOC: this method needs either documented or :nodoc'd
207
+
208
+ def match? obj, version=nil
209
+ if !version
210
+ name = obj.name
211
+ version = obj.version
212
+ else
213
+ name = obj
214
+ end
215
+
183
216
  return false unless self.name === name
184
217
  return true if requirement.none?
185
218
 
186
219
  requirement.satisfied_by? Gem::Version.new(version)
187
220
  end
188
221
 
222
+ # DOC: this method needs either documented or :nodoc'd
223
+
189
224
  def matches_spec? spec
190
225
  return false unless name === spec.name
191
226
  return true if requirement.none?
@@ -212,6 +247,8 @@ class Gem::Dependency
212
247
  self.class.new name, self_req.as_list.concat(other_req.as_list)
213
248
  end
214
249
 
250
+ # DOC: this method needs either documented or :nodoc'd
251
+
215
252
  def matching_specs platform_only = false
216
253
  matches = Gem::Specification.find_all { |spec|
217
254
  self.name === spec.name and # TODO: == instead of ===
@@ -234,14 +271,26 @@ class Gem::Dependency
234
271
  @requirement.specific?
235
272
  end
236
273
 
274
+ # DOC: this method needs either documented or :nodoc'd
275
+
237
276
  def to_specs
238
277
  matches = matching_specs true
239
278
 
240
279
  # TODO: check Gem.activated_spec[self.name] in case matches falls outside
241
280
 
242
281
  if matches.empty? then
243
- specs = Gem::Specification.all_names.join ", "
244
- error = Gem::LoadError.new "Could not find #{name} (#{requirement}) amongst [#{specs}]"
282
+ specs = Gem::Specification.find_all { |s|
283
+ s.name == name
284
+ }.map { |x| x.full_name }
285
+
286
+ if specs.empty?
287
+ total = Gem::Specification.to_a.size
288
+ error = Gem::LoadError.new \
289
+ "Could not find '#{name}' (#{requirement}) among #{total} total gem(s)"
290
+ else
291
+ error = Gem::LoadError.new \
292
+ "Could not find '#{name}' (#{requirement}) - did find: [#{specs.join ','}]"
293
+ end
245
294
  error.name = self.name
246
295
  error.requirement = self.requirement
247
296
  raise error
@@ -252,6 +301,8 @@ class Gem::Dependency
252
301
  matches
253
302
  end
254
303
 
304
+ # DOC: this method needs either documented or :nodoc'd
305
+
255
306
  def to_spec
256
307
  matches = self.to_specs
257
308
 
@@ -1,8 +1,12 @@
1
1
  require 'rubygems'
2
2
  require 'rubygems/dependency_list'
3
+ require 'rubygems/package'
3
4
  require 'rubygems/installer'
4
5
  require 'rubygems/spec_fetcher'
5
6
  require 'rubygems/user_interaction'
7
+ require 'rubygems/source_local'
8
+ require 'rubygems/source_specific_file'
9
+ require 'rubygems/available_set'
6
10
 
7
11
  ##
8
12
  # Installs a gem along with all its dependencies from local and remote gems.
@@ -14,8 +18,14 @@ class Gem::DependencyInstaller
14
18
  attr_reader :gems_to_install
15
19
  attr_reader :installed_gems
16
20
 
21
+ ##
22
+ # Documentation types. For use by the Gem.done_installing hook
23
+
24
+ attr_reader :document
25
+
17
26
  DEFAULT_OPTIONS = {
18
27
  :env_shebang => false,
28
+ :document => %w[ri],
19
29
  :domain => :both, # HACK dup
20
30
  :force => false,
21
31
  :format_executable => false, # HACK dup
@@ -23,7 +33,8 @@ class Gem::DependencyInstaller
23
33
  :prerelease => false,
24
34
  :security_policy => nil, # HACK NoSecurity requires OpenSSL. AlmostNo? Low?
25
35
  :wrappers => true,
26
- }
36
+ :build_docs_in_background => false,
37
+ }.freeze
27
38
 
28
39
  ##
29
40
  # Creates a new installer instance.
@@ -47,6 +58,7 @@ class Gem::DependencyInstaller
47
58
  if options[:install_dir] then
48
59
  @gem_home = options[:install_dir]
49
60
 
61
+ # HACK shouldn't change the global settings
50
62
  Gem::Specification.dirs = @gem_home
51
63
  Gem.ensure_gem_subdirectories @gem_home
52
64
  options[:install_dir] = @gem_home # FIX: because we suck and reuse below
@@ -55,7 +67,9 @@ class Gem::DependencyInstaller
55
67
  options = DEFAULT_OPTIONS.merge options
56
68
 
57
69
  @bin_dir = options[:bin_dir]
70
+ @dev_shallow = options[:dev_shallow]
58
71
  @development = options[:development]
72
+ @document = options[:document]
59
73
  @domain = options[:domain]
60
74
  @env_shebang = options[:env_shebang]
61
75
  @force = options[:force]
@@ -65,8 +79,14 @@ class Gem::DependencyInstaller
65
79
  @security_policy = options[:security_policy]
66
80
  @user_install = options[:user_install]
67
81
  @wrappers = options[:wrappers]
82
+ @build_docs_in_background = options[:build_docs_in_background]
83
+
84
+ # Indicates that we should not try to update any deps unless
85
+ # we absolutely must.
86
+ @minimal_deps = options[:minimal_deps]
68
87
 
69
88
  @installed_gems = []
89
+ @toplevel_specs = nil
70
90
 
71
91
  @install_dir = options[:install_dir] || Gem.dir
72
92
  @cache_dir = options[:cache_dir] || @install_dir
@@ -76,6 +96,24 @@ class Gem::DependencyInstaller
76
96
  @errors = nil
77
97
  end
78
98
 
99
+ attr_reader :errors
100
+
101
+ ##
102
+ # Indicated, based on the requested domain, if local
103
+ # gems should be considered.
104
+
105
+ def consider_local?
106
+ @domain == :both or @domain == :local
107
+ end
108
+
109
+ ##
110
+ # Indicated, based on the requested domain, if remote
111
+ # gems should be considered.
112
+
113
+ def consider_remote?
114
+ @domain == :both or @domain == :remote
115
+ end
116
+
79
117
  ##
80
118
  # Returns a list of pairs of gemspecs and source_uris that match
81
119
  # Gem::Dependency +dep+ from both local (Dir.pwd) and remote (Gem.sources)
@@ -83,35 +121,34 @@ class Gem::DependencyInstaller
83
121
  # local gems preferred over remote gems.
84
122
 
85
123
  def find_gems_with_sources(dep)
86
- # Reset the errors
87
- @errors = nil
88
- gems_and_sources = []
124
+ set = Gem::AvailableSet.new
125
+
126
+ if consider_local?
127
+ sl = Gem::Source::Local.new
89
128
 
90
- if @domain == :both or @domain == :local then
91
- Dir[File.join(Dir.pwd, "#{dep.name}-[0-9]*.gem")].each do |gem_file|
92
- spec = Gem::Format.from_file_by_path(gem_file).spec
93
- gems_and_sources << [spec, gem_file] if spec.name == dep.name
129
+ if spec = sl.find_gem(dep.name)
130
+ if dep.matches_spec? spec
131
+ set.add spec, sl
132
+ end
94
133
  end
95
134
  end
96
135
 
97
- if @domain == :both or @domain == :remote then
136
+ if consider_remote?
98
137
  begin
99
- # REFACTOR: all = dep.requirement.needs_all?
100
- requirements = dep.requirement.requirements.map do |req, ver|
101
- req
102
- end
103
-
104
- all = !dep.prerelease? &&
105
- # we only need latest if there's one requirement and it is
106
- # guaranteed to match the newest specs
107
- (requirements.length > 1 or
108
- (requirements.first != ">=" and requirements.first != ">"))
138
+ found, errors = Gem::SpecFetcher.fetcher.spec_for_dependency dep
109
139
 
110
- found, @errors = Gem::SpecFetcher.fetcher.fetch_with_errors dep, all, true, dep.prerelease?
140
+ if @errors
141
+ @errors += errors
142
+ else
143
+ @errors = errors
144
+ end
111
145
 
112
- gems_and_sources.push(*found)
146
+ set << found
113
147
 
114
148
  rescue Gem::RemoteFetcher::FetchError => e
149
+ # FIX if there is a problem talking to the network, we either need to always tell
150
+ # the user (no really_verbose) or fail hard, not silently tell them that we just
151
+ # couldn't find their requested gem.
115
152
  if Gem.configuration.really_verbose then
116
153
  say "Error fetching remote data:\t\t#{e.message}"
117
154
  say "Falling back to local-only install"
@@ -120,9 +157,7 @@ class Gem::DependencyInstaller
120
157
  end
121
158
  end
122
159
 
123
- gems_and_sources.sort_by do |gem, source|
124
- [gem, source =~ /^http:\/\// ? 0 : 1] # local gems win
125
- end
160
+ set
126
161
  end
127
162
 
128
163
  ##
@@ -130,17 +165,22 @@ class Gem::DependencyInstaller
130
165
  # remote sources unless the ignore_dependencies was given.
131
166
 
132
167
  def gather_dependencies
133
- specs = @specs_and_sources.map { |spec,_| spec }
168
+ specs = @available.all_specs
134
169
 
135
170
  # these gems were listed by the user, always install them
136
171
  keep_names = specs.map { |spec| spec.full_name }
137
172
 
173
+ if @dev_shallow
174
+ @toplevel_specs = keep_names
175
+ end
176
+
138
177
  dependency_list = Gem::DependencyList.new @development
139
178
  dependency_list.add(*specs)
140
179
  to_do = specs.dup
141
-
142
180
  add_found_dependencies to_do, dependency_list unless @ignore_dependencies
143
181
 
182
+ # REFACTOR maybe abstract away using Gem::Specification.include? so
183
+ # that this isn't dependent only on the currently installed gems
144
184
  dependency_list.specs.reject! { |spec|
145
185
  not keep_names.include?(spec.full_name) and
146
186
  Gem::Specification.include?(spec)
@@ -162,32 +202,43 @@ class Gem::DependencyInstaller
162
202
 
163
203
  until to_do.empty? do
164
204
  spec = to_do.shift
205
+
206
+ # HACK why is spec nil?
165
207
  next if spec.nil? or seen[spec.name]
166
208
  seen[spec.name] = true
167
209
 
168
210
  deps = spec.runtime_dependencies
169
- deps |= spec.development_dependencies if @development
211
+
212
+ if @development
213
+ if @dev_shallow
214
+ if @toplevel_specs.include? spec.full_name
215
+ deps |= spec.development_dependencies
216
+ end
217
+ else
218
+ deps |= spec.development_dependencies
219
+ end
220
+ end
170
221
 
171
222
  deps.each do |dep|
172
223
  dependencies[dep.name] = dependencies[dep.name].merge dep
173
224
 
174
- results = find_gems_with_sources(dep).reverse
225
+ if @minimal_deps
226
+ next if Gem::Specification.any? do |installed_spec|
227
+ dep.name == installed_spec.name and
228
+ dep.requirement.satisfied_by? installed_spec.version
229
+ end
230
+ end
175
231
 
176
- results.reject! do |dep_spec,|
177
- to_do.push dep_spec
232
+ results = find_gems_with_sources(dep)
178
233
 
179
- # already locally installed
180
- Gem::Specification.any? do |installed_spec|
181
- dep.name == installed_spec.name and
182
- dep.requirement.satisfied_by? installed_spec.version
183
- end
234
+ results.sorted.each do |t|
235
+ to_do.push t.spec
184
236
  end
185
237
 
186
- results.each do |dep_spec, source_uri|
187
- @specs_and_sources << [dep_spec, source_uri]
238
+ results.remove_installed! dep
188
239
 
189
- dependency_list.add dep_spec
190
- end
240
+ @available << results
241
+ results.inject_into_list dependency_list
191
242
  end
192
243
  end
193
244
 
@@ -202,42 +253,36 @@ class Gem::DependencyInstaller
202
253
  def find_spec_by_name_and_version(gem_name,
203
254
  version = Gem::Requirement.default,
204
255
  prerelease = false)
205
- spec_and_source = nil
206
256
 
207
- glob = if File::ALT_SEPARATOR then
208
- gem_name.gsub File::ALT_SEPARATOR, File::SEPARATOR
209
- else
210
- gem_name
211
- end
257
+ set = Gem::AvailableSet.new
212
258
 
213
- local_gems = Dir["#{glob}*"].sort.reverse
259
+ if consider_local?
260
+ if File.exists? gem_name
261
+ src = Gem::Source::SpecificFile.new(gem_name)
262
+ set.add src.spec, src
263
+ else
264
+ local = Gem::Source::Local.new
214
265
 
215
- local_gems.each do |gem_file|
216
- next unless gem_file =~ /gem$/
217
- begin
218
- spec = Gem::Format.from_file_by_path(gem_file).spec
219
- spec_and_source = [spec, gem_file]
220
- break
221
- rescue SystemCallError, Gem::Package::FormatError
266
+ if s = local.find_gem(gem_name, version)
267
+ set.add s, local
268
+ end
222
269
  end
223
270
  end
224
271
 
225
- unless spec_and_source then
272
+ if set.empty?
226
273
  dep = Gem::Dependency.new gem_name, version
274
+ # HACK Dependency objects should be immutable
227
275
  dep.prerelease = true if prerelease
228
- spec_and_sources = find_gems_with_sources(dep).reverse
229
- spec_and_source = spec_and_sources.find { |spec, source|
230
- Gem::Platform.match spec.platform
231
- }
276
+
277
+ set = find_gems_with_sources(dep)
278
+ set.match_platform!
232
279
  end
233
280
 
234
- if spec_and_source.nil? then
235
- raise Gem::GemNotFoundException.new(
236
- "Could not find a valid gem '#{gem_name}' (#{version}) locally or in a repository",
237
- gem_name, version, @errors)
281
+ if set.empty?
282
+ raise Gem::SpecificGemNotFoundException.new(gem_name, version, @errors)
238
283
  end
239
284
 
240
- @specs_and_sources = [spec_and_source]
285
+ @available = set
241
286
  end
242
287
 
243
288
  ##
@@ -258,33 +303,49 @@ class Gem::DependencyInstaller
258
303
  if String === dep_or_name then
259
304
  find_spec_by_name_and_version dep_or_name, version, @prerelease
260
305
  else
261
- dep_or_name.prerelease = @prerelease
262
- @specs_and_sources = [find_gems_with_sources(dep_or_name).last]
306
+ dep = dep_or_name.dup
307
+ dep.prerelease = @prerelease
308
+ @available = find_gems_with_sources(dep).pick_best!
263
309
  end
264
310
 
265
311
  @installed_gems = []
266
312
 
267
313
  gather_dependencies
268
314
 
315
+ # REFACTOR is the last gem always the one that the user requested?
316
+ # This code assumes that but is that actually validated by the code?
317
+
269
318
  last = @gems_to_install.size - 1
270
319
  @gems_to_install.each_with_index do |spec, index|
320
+ # REFACTOR more current spec set hardcoding, should be abstracted?
271
321
  next if Gem::Specification.include?(spec) and index != last
272
322
 
273
323
  # TODO: make this sorta_verbose so other users can benefit from it
274
324
  say "Installing gem #{spec.full_name}" if Gem.configuration.really_verbose
275
325
 
276
- _, source_uri = @specs_and_sources.assoc spec
326
+ source = @available.source_for spec
327
+
277
328
  begin
278
- local_gem_path = Gem::RemoteFetcher.fetcher.download spec, source_uri,
279
- @cache_dir
329
+ # REFACTOR make the fetcher to use configurable
330
+ local_gem_path = source.download spec, @cache_dir
280
331
  rescue Gem::RemoteFetcher::FetchError
332
+ # TODO I doubt all fetch errors are recoverable, we should at least
333
+ # report the errors probably.
281
334
  next if @force
282
335
  raise
283
336
  end
284
337
 
338
+ if @development
339
+ if @dev_shallow
340
+ is_dev = @toplevel_specs.include? spec.full_name
341
+ else
342
+ is_dev = true
343
+ end
344
+ end
345
+
285
346
  inst = Gem::Installer.new local_gem_path,
286
347
  :bin_dir => @bin_dir,
287
- :development => @development,
348
+ :development => is_dev,
288
349
  :env_shebang => @env_shebang,
289
350
  :force => @force,
290
351
  :format_executable => @format_executable,
@@ -299,6 +360,33 @@ class Gem::DependencyInstaller
299
360
  @installed_gems << spec
300
361
  end
301
362
 
363
+ # Since this is currently only called for docs, we can be lazy and just say
364
+ # it's documentation. Ideally the hook adder could decide whether to be in
365
+ # the background or not, and what to call it.
366
+ in_background "Installing documentation" do
367
+ start = Time.now
368
+ Gem.done_installing_hooks.each do |hook|
369
+ hook.call self, @installed_gems
370
+ end
371
+ finish = Time.now
372
+ say "Done installing documentation for #{@installed_gems.map(&:name).join(', ')} (#{(finish-start).to_i} sec)."
373
+ end unless Gem.done_installing_hooks.empty?
374
+
302
375
  @installed_gems
303
376
  end
377
+
378
+ def in_background what
379
+ fork_happened = false
380
+ if @build_docs_in_background and Process.respond_to?(:fork)
381
+ begin
382
+ Process.fork do
383
+ yield
384
+ end
385
+ fork_happened = true
386
+ say "#{what} in a background process."
387
+ rescue NotImplementedError
388
+ end
389
+ end
390
+ yield unless fork_happened
391
+ end
304
392
  end