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
@@ -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