rubygems-update 2.0.17 → 2.1.0.rc.1

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 (154) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -0
  4. data/.autotest +1 -1
  5. data/History.txt +82 -153
  6. data/Manifest.txt +35 -9
  7. data/Rakefile +35 -36
  8. data/lib/rubygems.rb +106 -18
  9. data/lib/rubygems/available_set.rb +68 -0
  10. data/lib/rubygems/basic_specification.rb +139 -0
  11. data/lib/rubygems/command_manager.rb +37 -40
  12. data/lib/rubygems/commands/cert_command.rb +78 -29
  13. data/lib/rubygems/commands/cleanup_command.rb +2 -2
  14. data/lib/rubygems/commands/contents_command.rb +101 -58
  15. data/lib/rubygems/commands/dependency_command.rb +94 -53
  16. data/lib/rubygems/commands/environment_command.rb +70 -53
  17. data/lib/rubygems/commands/fetch_command.rb +1 -2
  18. data/lib/rubygems/commands/help_command.rb +85 -55
  19. data/lib/rubygems/commands/install_command.rb +84 -42
  20. data/lib/rubygems/commands/outdated_command.rb +2 -12
  21. data/lib/rubygems/commands/owner_command.rb +6 -0
  22. data/lib/rubygems/commands/pristine_command.rb +26 -16
  23. data/lib/rubygems/commands/sources_command.rb +85 -70
  24. data/lib/rubygems/commands/uninstall_command.rb +32 -2
  25. data/lib/rubygems/commands/update_command.rb +111 -75
  26. data/lib/rubygems/config_file.rb +15 -3
  27. data/lib/rubygems/core_ext/kernel_require.rb +9 -31
  28. data/lib/rubygems/defaults.rb +8 -0
  29. data/lib/rubygems/dependency.rb +4 -2
  30. data/lib/rubygems/dependency_installer.rb +180 -170
  31. data/lib/rubygems/dependency_resolver.rb +191 -526
  32. data/lib/rubygems/dependency_resolver/activation_request.rb +109 -0
  33. data/lib/rubygems/dependency_resolver/api_set.rb +65 -0
  34. data/lib/rubygems/dependency_resolver/api_specification.rb +36 -0
  35. data/lib/rubygems/dependency_resolver/composed_set.rb +18 -0
  36. data/lib/rubygems/dependency_resolver/current_set.rb +16 -0
  37. data/lib/rubygems/dependency_resolver/dependency_conflict.rb +85 -0
  38. data/lib/rubygems/dependency_resolver/dependency_request.rb +51 -0
  39. data/lib/rubygems/dependency_resolver/index_set.rb +59 -0
  40. data/lib/rubygems/dependency_resolver/index_specification.rb +53 -0
  41. data/lib/rubygems/dependency_resolver/installed_specification.rb +38 -0
  42. data/lib/rubygems/dependency_resolver/installer_set.rb +130 -0
  43. data/lib/rubygems/exceptions.rb +88 -1
  44. data/lib/rubygems/ext/builder.rb +1 -1
  45. data/lib/rubygems/gem_runner.rb +17 -9
  46. data/lib/rubygems/gemcutter_utilities.rb +72 -42
  47. data/lib/rubygems/install_default_message.rb +12 -0
  48. data/lib/rubygems/install_update_options.rb +3 -0
  49. data/lib/rubygems/installer.rb +55 -30
  50. data/lib/rubygems/name_tuple.rb +18 -7
  51. data/lib/rubygems/package.rb +50 -25
  52. data/lib/rubygems/package/tar_test_case.rb +9 -9
  53. data/lib/rubygems/package/tar_writer.rb +35 -12
  54. data/lib/rubygems/package_task.rb +2 -5
  55. data/lib/rubygems/path_support.rb +10 -0
  56. data/lib/rubygems/platform.rb +9 -3
  57. data/lib/rubygems/psych_additions.rb +1 -1
  58. data/lib/rubygems/remote_fetcher.rb +9 -276
  59. data/lib/rubygems/request.rb +267 -0
  60. data/lib/rubygems/request_set.rb +123 -125
  61. data/lib/rubygems/request_set/gem_dependency_api.rb +39 -0
  62. data/lib/rubygems/security.rb +32 -23
  63. data/lib/rubygems/security/policy.rb +35 -9
  64. data/lib/rubygems/security/signer.rb +2 -2
  65. data/lib/rubygems/server.rb +8 -16
  66. data/lib/rubygems/source.rb +25 -14
  67. data/lib/rubygems/source/installed.rb +28 -0
  68. data/lib/rubygems/source/local.rb +122 -0
  69. data/lib/rubygems/source/specific_file.rb +28 -0
  70. data/lib/rubygems/source_local.rb +2 -89
  71. data/lib/rubygems/source_specific_file.rb +2 -26
  72. data/lib/rubygems/spec_fetcher.rb +11 -11
  73. data/lib/rubygems/specification.rb +186 -198
  74. data/lib/rubygems/ssl_certs/AddTrustExternalCARoot.pem +88 -30
  75. data/lib/rubygems/ssl_certs/Entrust_net-Secure-Server-Certification-Authority.pem +90 -0
  76. data/lib/rubygems/ssl_certs/{GeoTrustGlobalCA.pem → GeoTrust_Global_CA.pem} +20 -20
  77. data/lib/rubygems/ssl_certs/VerisignClass3PublicPrimaryCertificationAuthority-G2.pem +57 -0
  78. data/lib/rubygems/stub_specification.rb +119 -0
  79. data/lib/rubygems/test_case.rb +117 -49
  80. data/lib/rubygems/uninstaller.rb +14 -9
  81. data/lib/rubygems/uri_formatter.rb +39 -0
  82. data/lib/rubygems/util/list.rb +44 -0
  83. data/lib/rubygems/version.rb +15 -5
  84. data/lib/rubygems/version_option.rb +8 -2
  85. data/test/rubygems/ca_cert.pem +23 -0
  86. data/test/rubygems/client.pem +49 -0
  87. data/test/rubygems/encrypted_private_key.pem +30 -0
  88. data/test/rubygems/invalid_client.pem +49 -0
  89. data/test/rubygems/specifications/bar-0.0.2.gemspec +9 -0
  90. data/test/rubygems/specifications/foo-0.0.1.gemspec +0 -0
  91. data/test/rubygems/test_gem.rb +76 -454
  92. data/test/rubygems/test_gem_command_manager.rb +23 -21
  93. data/test/rubygems/test_gem_commands_cert_command.rb +154 -14
  94. data/test/rubygems/test_gem_commands_cleanup_command.rb +15 -0
  95. data/test/rubygems/test_gem_commands_contents_command.rb +32 -4
  96. data/test/rubygems/test_gem_commands_environment_command.rb +9 -1
  97. data/test/rubygems/test_gem_commands_fetch_command.rb +2 -28
  98. data/test/rubygems/test_gem_commands_help_command.rb +6 -3
  99. data/test/rubygems/test_gem_commands_install_command.rb +2 -65
  100. data/test/rubygems/test_gem_commands_owner_command.rb +49 -0
  101. data/test/rubygems/test_gem_commands_pristine_command.rb +30 -0
  102. data/test/rubygems/test_gem_commands_sources_command.rb +1 -1
  103. data/test/rubygems/test_gem_commands_uninstall_command.rb +33 -0
  104. data/test/rubygems/test_gem_commands_update_command.rb +2 -1
  105. data/test/rubygems/test_gem_config_file.rb +12 -0
  106. data/test/rubygems/test_gem_dependency_installer.rb +58 -65
  107. data/test/rubygems/test_gem_dependency_resolver.rb +6 -3
  108. data/test/rubygems/test_gem_dependency_resolver_dependency_conflict.rb +36 -0
  109. data/test/rubygems/test_gem_ext_builder.rb +2 -4
  110. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +7 -2
  111. data/test/rubygems/test_gem_gem_runner.rb +17 -13
  112. data/test/rubygems/test_gem_gemcutter_utilities.rb +6 -19
  113. data/test/rubygems/test_gem_impossible_dependencies_error.rb +41 -0
  114. data/test/rubygems/test_gem_install_update_options.rb +4 -1
  115. data/test/rubygems/test_gem_installer.rb +31 -2
  116. data/test/rubygems/test_gem_name_tuple.rb +22 -0
  117. data/test/rubygems/test_gem_package.rb +122 -11
  118. data/test/rubygems/test_gem_package_old.rb +8 -0
  119. data/test/rubygems/test_gem_package_tar_reader.rb +9 -8
  120. data/test/rubygems/test_gem_package_tar_reader_entry.rb +1 -1
  121. data/test/rubygems/test_gem_package_tar_writer.rb +78 -56
  122. data/test/rubygems/test_gem_package_task.rb +2 -23
  123. data/test/rubygems/test_gem_path_support.rb +17 -0
  124. data/test/rubygems/test_gem_platform.rb +18 -0
  125. data/test/rubygems/test_gem_remote_fetcher.rb +106 -385
  126. data/test/rubygems/test_gem_request.rb +239 -0
  127. data/test/rubygems/test_gem_requirement.rb +9 -11
  128. data/test/rubygems/test_gem_security.rb +58 -2
  129. data/test/rubygems/test_gem_security_policy.rb +42 -1
  130. data/test/rubygems/test_gem_security_signer.rb +13 -1
  131. data/test/rubygems/test_gem_security_trust_dir.rb +5 -1
  132. data/test/rubygems/test_gem_server.rb +1 -105
  133. data/test/rubygems/test_gem_source.rb +4 -14
  134. data/test/rubygems/test_gem_source_local.rb +4 -4
  135. data/test/rubygems/test_gem_source_specific_file.rb +1 -1
  136. data/test/rubygems/test_gem_spec_fetcher.rb +0 -12
  137. data/test/rubygems/test_gem_specification.rb +452 -28
  138. data/test/rubygems/test_gem_stub_specification.rb +30 -0
  139. data/test/rubygems/test_gem_uninstaller.rb +14 -0
  140. data/test/rubygems/test_gem_uri_formatter.rb +20 -0
  141. data/test/rubygems/test_gem_version.rb +23 -13
  142. data/test/rubygems/test_gem_version_option.rb +63 -1
  143. data/test/rubygems/test_require.rb +0 -12
  144. data/util/create_encrypted_key.rb +16 -0
  145. metadata +161 -23
  146. metadata.gz.sig +0 -0
  147. data/CVE-2013-4287.txt +0 -36
  148. data/CVE-2013-4363.txt +0 -45
  149. data/lib/rubygems/ssl_certs/AddTrustExternalCARoot-2048.pem +0 -25
  150. data/lib/rubygems/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +0 -14
  151. data/lib/rubygems/ssl_certs/DigiCertHighAssuranceEVRootCA.pem +0 -23
  152. data/lib/rubygems/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +0 -28
  153. data/test/rubygems/test_bundled_ca.rb +0 -59
  154. data/util/update_bundled_ca_certificates.rb +0 -103
@@ -1,575 +1,240 @@
1
1
  require 'rubygems'
2
2
  require 'rubygems/dependency'
3
3
  require 'rubygems/exceptions'
4
+ require 'rubygems/util/list'
4
5
 
5
6
  require 'uri'
6
7
  require 'net/http'
7
8
 
8
- module Gem
9
+ ##
10
+ # Given a set of Gem::Dependency objects as +needed+ and a way to query the
11
+ # set of available specs via +set+, calculates a set of ActivationRequest
12
+ # objects which indicate all the specs that should be activated to meet the
13
+ # all the requirements.
9
14
 
10
- # Raised when a DependencyConflict reaches the toplevel.
11
- # Indicates which dependencies were incompatible.
12
- #
13
- class DependencyResolutionError < Gem::Exception
14
- def initialize(conflict)
15
- @conflict = conflict
16
- a, b = conflicting_dependencies
15
+ class Gem::DependencyResolver
17
16
 
18
- super "unable to resolve conflicting dependencies '#{a}' and '#{b}'"
19
- end
17
+ ##
18
+ # Contains all the conflicts encountered while doing resolution
20
19
 
21
- attr_reader :conflict
20
+ attr_reader :conflicts
22
21
 
23
- def conflicting_dependencies
24
- @conflict.conflicting_dependencies
25
- end
26
- end
22
+ attr_accessor :development
27
23
 
28
- # Raised when a dependency requests a gem for which there is
29
- # no spec.
30
- #
31
- class UnsatisfiableDepedencyError < Gem::Exception
32
- def initialize(dep)
33
- super "unable to find any gem matching dependency '#{dep}'"
24
+ attr_reader :missing
34
25
 
35
- @dependency = dep
36
- end
26
+ ##
27
+ # When a missing dependency, don't stop. Just go on and record what was
28
+ # missing.
37
29
 
38
- attr_reader :dependency
39
- end
30
+ attr_accessor :soft_missing
40
31
 
41
- # Raised when dependencies conflict and create the inability to
42
- # find a valid possible spec for a request.
43
- #
44
- class ImpossibleDependenciesError < Gem::Exception
45
- def initialize(request, conflicts)
46
- s = conflicts.size == 1 ? "" : "s"
47
- super "detected #{conflicts.size} conflict#{s} with dependency '#{request.dependency}'"
48
- @request = request
49
- @conflicts = conflicts
50
- end
32
+ def self.compose_sets *sets
33
+ Gem::DependencyResolver::ComposedSet.new(*sets)
34
+ end
51
35
 
52
- def dependency
53
- @request.dependency
54
- end
36
+ ##
37
+ # Provide a DependencyResolver that queries only against the already
38
+ # installed gems.
55
39
 
56
- attr_reader :conflicts
40
+ def self.for_current_gems needed
41
+ new needed, Gem::DependencyResolver::CurrentSet.new
57
42
  end
58
43
 
59
- # Given a set of Gem::Dependency objects as +needed+ and a way
60
- # to query the set of available specs via +set+, calculates
61
- # a set of ActivationRequest objects which indicate all the specs
62
- # that should be activated to meet the all the requirements.
44
+ ##
45
+ # Create DependencyResolver object which will resolve the tree starting
46
+ # with +needed+ Depedency objects.
63
47
  #
64
- class DependencyResolver
65
-
66
- # Represents a specification retrieved via the rubygems.org
67
- # API. This is used to avoid having to load the full
68
- # Specification object when all we need is the name, version,
69
- # and dependencies.
70
- #
71
- class APISpecification
72
- attr_reader :set # :nodoc:
73
-
74
- def initialize(set, api_data)
75
- @set = set
76
- @name = api_data[:name]
77
- @version = Gem::Version.new api_data[:number]
78
- @dependencies = api_data[:dependencies].map do |name, ver|
79
- Gem::Dependency.new name, ver.split(/\s*,\s*/)
80
- end
81
- end
82
-
83
- attr_reader :name, :version, :dependencies
84
-
85
- def == other # :nodoc:
86
- self.class === other and
87
- @set == other.set and
88
- @name == other.name and
89
- @version == other.version and
90
- @dependencies == other.dependencies
91
- end
92
-
93
- def full_name
94
- "#{@name}-#{@version}"
95
- end
96
- end
97
-
98
- # The global rubygems pool, available via the rubygems.org API.
99
- # Returns instances of APISpecification.
100
- #
101
- class APISet
102
- def initialize
103
- @data = Hash.new { |h,k| h[k] = [] }
104
- @dep_uri = URI 'https://rubygems.org/api/v1/dependencies'
105
- end
106
-
107
- # Return data for all versions of the gem +name+.
108
- #
109
- def versions(name)
110
- if @data.key?(name)
111
- return @data[name]
112
- end
113
-
114
- uri = @dep_uri + "?gems=#{name}"
115
- str = Gem::RemoteFetcher.fetcher.fetch_path uri
116
-
117
- Marshal.load(str).each do |ver|
118
- @data[ver[:name]] << ver
119
- end
120
-
121
- @data[name]
122
- end
123
-
124
- # Return an array of APISpecification objects matching
125
- # DependencyRequest +req+.
126
- #
127
- def find_all(req)
128
- res = []
129
-
130
- versions(req.name).each do |ver|
131
- if req.dependency.match? req.name, ver[:number]
132
- res << APISpecification.new(self, ver)
133
- end
134
- end
135
-
136
- res
137
- end
138
-
139
- # A hint run by the resolver to allow the Set to fetch
140
- # data for DependencyRequests +reqs+.
141
- #
142
- def prefetch(reqs)
143
- names = reqs.map { |r| r.dependency.name }
144
- needed = names.find_all { |d| !@data.key?(d) }
145
-
146
- return if needed.empty?
147
-
148
- uri = @dep_uri + "?gems=#{needed.sort.join ','}"
149
- str = Gem::RemoteFetcher.fetcher.fetch_path uri
150
-
151
- Marshal.load(str).each do |ver|
152
- @data[ver[:name]] << ver
153
- end
154
- end
155
- end
156
-
157
- # Represents a possible Specification object returned
158
- # from IndexSet. Used to delay needed to download full
159
- # Specification objects when only the +name+ and +version+
160
- # are needed.
161
- #
162
- class IndexSpecification
163
- def initialize(set, name, version, source, plat)
164
- @set = set
165
- @name = name
166
- @version = version
167
- @source = source
168
- @platform = plat
169
-
170
- @spec = nil
171
- end
172
-
173
- attr_reader :name, :version, :source
174
-
175
- def full_name
176
- "#{@name}-#{@version}"
177
- end
178
-
179
- def spec
180
- @spec ||= @set.load_spec(@name, @version, @source)
181
- end
182
-
183
- def dependencies
184
- spec.dependencies
185
- end
186
- end
187
-
188
- # The global rubygems pool represented via the traditional
189
- # source index.
190
- #
191
- class IndexSet
192
- def initialize
193
- @f = Gem::SpecFetcher.fetcher
194
-
195
- @all = Hash.new { |h,k| h[k] = [] }
196
-
197
- list, _ = @f.available_specs(:released)
198
- list.each do |uri, specs|
199
- specs.each do |n|
200
- @all[n.name] << [uri, n]
201
- end
202
- end
203
-
204
- @specs = {}
205
- end
206
-
207
- # Return an array of IndexSpecification objects matching
208
- # DependencyRequest +req+.
209
- #
210
- def find_all(req)
211
- res = []
212
-
213
- name = req.dependency.name
214
-
215
- @all[name].each do |uri, n|
216
- if req.dependency.match? n
217
- res << IndexSpecification.new(self, n.name, n.version,
218
- uri, n.platform)
219
- end
220
- end
221
-
222
- res
223
- end
224
-
225
- # No prefetching needed since we load the whole index in
226
- # initially.
227
- #
228
- def prefetch(gems)
229
- end
230
-
231
- # Called from IndexSpecification to get a true Specification
232
- # object.
233
- #
234
- def load_spec(name, ver, source)
235
- key = "#{name}-#{ver}"
236
- @specs[key] ||= source.fetch_spec(Gem::NameTuple.new(name, ver))
237
- end
238
- end
239
-
240
- # A set which represents the installed gems. Respects
241
- # all the normal settings that control where to look
242
- # for installed gems.
243
- #
244
- class CurrentSet
245
- def find_all(req)
246
- req.dependency.matching_specs
247
- end
248
-
249
- def prefetch(gems)
250
- end
251
- end
252
-
253
- # Create DependencyResolver object which will resolve
254
- # the tree starting with +needed+ Depedency objects.
255
- #
256
- # +set+ is an object that provides where to look for
257
- # specifications to satisify the Dependencies. This
258
- # defaults to IndexSet, which will query rubygems.org.
259
- #
260
- def initialize(needed, set=IndexSet.new)
261
- @set = set || IndexSet.new # Allow nil to mean IndexSet
262
- @needed = needed
263
-
264
- @conflicts = nil
265
- end
266
-
267
- # Provide a DependencyResolver that queries only against
268
- # the already installed gems.
269
- #
270
- def self.for_current_gems(needed)
271
- new needed, CurrentSet.new
272
- end
273
-
274
- # Contains all the conflicts encountered while doing resolution
275
- #
276
- attr_reader :conflicts
277
-
278
- # Proceed with resolution! Returns an array of ActivationRequest
279
- # objects.
280
- #
281
- def resolve
282
- @conflicts = []
283
-
284
- needed = @needed.map { |n| DependencyRequest.new(n, nil) }
285
-
286
- res = resolve_for needed, []
287
-
288
- if res.kind_of? DependencyConflict
289
- raise DependencyResolutionError.new(res)
290
- end
291
-
292
- res
293
- end
294
-
295
- # Used internally to indicate that a dependency conflicted
296
- # with a spec that would be activated.
297
- #
298
- class DependencyConflict
299
- def initialize(dependency, activated, failed_dep=dependency)
300
- @dependency = dependency
301
- @activated = activated
302
- @failed_dep = failed_dep
303
- end
304
-
305
- attr_reader :dependency, :activated
306
-
307
- # Return the Specification that listed the dependency
308
- #
309
- def requester
310
- @failed_dep.requester
311
- end
312
-
313
- def for_spec?(spec)
314
- @dependency.name == spec.name
315
- end
48
+ # +set+ is an object that provides where to look for specifications to
49
+ # satisify the Dependencies. This defaults to IndexSet, which will query
50
+ # rubygems.org.
51
+
52
+ def initialize needed, set = nil
53
+ @set = set || Gem::DependencyResolver::IndexSet.new
54
+ @needed = needed
55
+
56
+ @conflicts = nil
57
+ @development = false
58
+ @missing = []
59
+ @soft_missing = false
60
+ end
316
61
 
317
- # Return the 2 dependency objects that conflicted
318
- #
319
- def conflicting_dependencies
320
- [@failed_dep.dependency, @activated.request.dependency]
321
- end
62
+ def requests s, act, reqs=nil
63
+ s.dependencies.reverse_each do |d|
64
+ next if d.type == :development and not @development
65
+ reqs = Gem::List.new Gem::DependencyResolver::DependencyRequest.new(d, act), reqs
322
66
  end
323
67
 
324
- # Used Internally. Wraps a Depedency object to also track
325
- # which spec contained the Dependency.
326
- #
327
- class DependencyRequest
328
- def initialize(dep, act)
329
- @dependency = dep
330
- @requester = act
331
- end
68
+ @set.prefetch reqs
332
69
 
333
- attr_reader :dependency, :requester
70
+ reqs
71
+ end
334
72
 
335
- def name
336
- @dependency.name
337
- end
73
+ ##
74
+ # Proceed with resolution! Returns an array of ActivationRequest objects.
338
75
 
339
- def matches_spec?(spec)
340
- @dependency.matches_spec? spec
341
- end
76
+ def resolve
77
+ @conflicts = []
342
78
 
343
- def to_s
344
- @dependency.to_s
345
- end
79
+ needed = nil
346
80
 
347
- def ==(other)
348
- case other
349
- when Dependency
350
- @dependency == other
351
- when DependencyRequest
352
- @dependency == other.dependency && @requester == other.requester
353
- else
354
- false
355
- end
356
- end
81
+ @needed.reverse_each do |n|
82
+ needed = Gem::List.new(Gem::DependencyResolver::DependencyRequest.new(n, nil), needed)
357
83
  end
358
84
 
359
- # Specifies a Specification object that should be activated.
360
- # Also contains a dependency that was used to introduce this
361
- # activation.
362
- #
363
- class ActivationRequest
364
- def initialize(spec, req, others_possible=true)
365
- @spec = spec
366
- @request = req
367
- @others_possible = others_possible
368
- end
369
-
370
- attr_reader :spec, :request
85
+ res = resolve_for needed, nil
371
86
 
372
- # Indicate if this activation is one of a set of possible
373
- # requests for the same Dependency request.
374
- #
375
- def others_possible?
376
- @others_possible
377
- end
87
+ raise Gem::DependencyResolutionError, res if
88
+ res.kind_of? Gem::DependencyResolver::DependencyConflict
378
89
 
379
- # Return the ActivationRequest that contained the dependency
380
- # that we were activated for.
381
- #
382
- def parent
383
- @request.requester
384
- end
385
-
386
- def name
387
- @spec.name
388
- end
389
-
390
- def full_name
391
- @spec.full_name
392
- end
393
-
394
- def version
395
- @spec.version
396
- end
397
-
398
- def full_spec
399
- Gem::Specification === @spec ? @spec : @spec.spec
400
- end
90
+ res.to_a
91
+ end
401
92
 
402
- def download(path)
403
- if @spec.respond_to? :source
404
- source = @spec.source
93
+ ##
94
+ # The meat of the algorithm. Given +needed+ DependencyRequest objects and
95
+ # +specs+ being a list to ActivationRequest, calculate a new list of
96
+ # ActivationRequest objects.
97
+
98
+ def resolve_for needed, specs
99
+ while needed
100
+ dep = needed.value
101
+ needed = needed.tail
102
+
103
+ # If there is already a spec activated for the requested name...
104
+ if specs && existing = specs.find { |s| dep.name == s.name }
105
+
106
+ # then we're done since this new dep matches the
107
+ # existing spec.
108
+ next if dep.matches_spec? existing
109
+
110
+ # There is a conflict! We return the conflict
111
+ # object which will be seen by the caller and be
112
+ # handled at the right level.
113
+
114
+ # If the existing activation indicates that there
115
+ # are other possibles for it, then issue the conflict
116
+ # on the dep for the activation itself. Otherwise, issue
117
+ # it on the requester's request itself.
118
+ #
119
+ if existing.others_possible?
120
+ conflict =
121
+ Gem::DependencyResolver::DependencyConflict.new dep, existing
405
122
  else
406
- source = Gem.sources.first
123
+ depreq = existing.request.requester.request
124
+ conflict =
125
+ Gem::DependencyResolver::DependencyConflict.new depreq, existing, dep
407
126
  end
127
+ @conflicts << conflict
408
128
 
409
- Gem.ensure_gem_subdirectories path
410
-
411
- source.download full_spec, path
412
- end
413
-
414
- def ==(other)
415
- case other
416
- when Gem::Specification
417
- @spec == other
418
- when ActivationRequest
419
- @spec == other.spec && @request == other.request
420
- else
421
- false
422
- end
129
+ return conflict
423
130
  end
424
131
 
425
- ##
426
- # Indicates if the requested gem has already been installed.
132
+ # Get a list of all specs that satisfy dep
133
+ possible = @set.find_all dep
427
134
 
428
- def installed?
429
- this_spec = full_spec
135
+ case possible.size
136
+ when 0
137
+ @missing << dep
430
138
 
431
- Gem::Specification.any? do |s|
432
- s == this_spec
139
+ unless @soft_missing
140
+ # If there are none, then our work here is done.
141
+ raise Gem::UnsatisfiableDependencyError, dep
433
142
  end
434
- end
435
- end
436
-
437
- def requests(s, act)
438
- reqs = []
439
- s.dependencies.each do |d|
440
- next unless d.type == :runtime
441
- reqs << DependencyRequest.new(d, act)
442
- end
443
-
444
- @set.prefetch(reqs)
445
-
446
- reqs
447
- end
448
-
449
- # The meat of the algorithm. Given +needed+ DependencyRequest objects
450
- # and +specs+ being a list to ActivationRequest, calculate a new list
451
- # of ActivationRequest objects.
452
- #
453
- def resolve_for(needed, specs)
454
- until needed.empty?
455
- dep = needed.shift
456
-
457
- # If there is already a spec activated for the requested name...
458
- if existing = specs.find { |s| dep.name == s.name }
459
-
460
- # then we're done since this new dep matches the
461
- # existing spec.
462
- next if dep.matches_spec? existing
463
-
464
- # There is a conflict! We return the conflict
465
- # object which will be seen by the caller and be
466
- # handled at the right level.
467
-
468
- # If the existing activation indicates that there
469
- # are other possibles for it, then issue the conflict
470
- # on the dep for the activation itself. Otherwise, issue
471
- # it on the requester's request itself.
472
- #
473
- if existing.others_possible?
474
- conflict = DependencyConflict.new(dep, existing)
143
+ when 1
144
+ # If there is one, then we just add it to specs
145
+ # and process the specs dependencies by adding
146
+ # them to needed.
147
+
148
+ spec = possible.first
149
+ act = Gem::DependencyResolver::ActivationRequest.new spec, dep, false
150
+
151
+ specs = Gem::List.prepend specs, act
152
+
153
+ # Put the deps for at the beginning of needed
154
+ # rather than the end to match the depth first
155
+ # searching done by the multiple case code below.
156
+ #
157
+ # This keeps the error messages consistent.
158
+ needed = requests(spec, act, needed)
159
+ else
160
+ # There are multiple specs for this dep. This is
161
+ # the case that this class is built to handle.
162
+
163
+ # Sort them so that we try the highest versions
164
+ # first.
165
+ possible = possible.sort_by { |s| [s.source, s.version] }
166
+
167
+ # We track the conflicts seen so that we can report them
168
+ # to help the user figure out how to fix the situation.
169
+ conflicts = []
170
+
171
+ # To figure out which to pick, we keep resolving
172
+ # given each one being activated and if there isn't
173
+ # a conflict, we know we've found a full set.
174
+ #
175
+ # We use an until loop rather than #reverse_each
176
+ # to keep the stack short since we're using a recursive
177
+ # algorithm.
178
+ #
179
+ until possible.empty?
180
+ s = possible.pop
181
+
182
+ # Recursively call #resolve_for with this spec
183
+ # and add it's dependencies into the picture...
184
+
185
+ act = Gem::DependencyResolver::ActivationRequest.new s, dep
186
+
187
+ try = requests(s, act, needed)
188
+
189
+ res = resolve_for try, Gem::List.prepend(specs, act)
190
+
191
+ # While trying to resolve these dependencies, there may
192
+ # be a conflict!
193
+
194
+ if res.kind_of? Gem::DependencyResolver::DependencyConflict
195
+ # The conflict might be created not by this invocation
196
+ # but rather one up the stack, so if we can't attempt
197
+ # to resolve this conflict (conflict isn't with the spec +s+)
198
+ # then just return it so the caller can try to sort it out.
199
+ return res unless res.for_spec? s
200
+
201
+ # Otherwise, this is a conflict that we can attempt to fix
202
+ conflicts << [s, res]
203
+
204
+ # Optimization:
205
+ #
206
+ # Because the conflict indicates the dependency that trigger
207
+ # it, we can prune possible based on this new information.
208
+ #
209
+ # This cuts down on the number of iterations needed.
210
+ possible.delete_if { |x| !res.dependency.matches_spec? x }
475
211
  else
476
- depreq = existing.request.requester.request
477
- conflict = DependencyConflict.new(depreq, existing, dep)
212
+ # No conflict, return the specs
213
+ return res
478
214
  end
479
- @conflicts << conflict
480
-
481
- return conflict
482
215
  end
483
216
 
484
- # Get a list of all specs that satisfy dep
485
- possible = @set.find_all(dep)
486
-
487
- case possible.size
488
- when 0
489
- # If there are none, then our work here is done.
490
- raise UnsatisfiableDepedencyError.new(dep)
491
- when 1
492
- # If there is one, then we just add it to specs
493
- # and process the specs dependencies by adding
494
- # them to needed.
495
-
496
- spec = possible.first
497
- act = ActivationRequest.new(spec, dep, false)
498
-
499
- specs << act
500
-
501
- # Put the deps for at the beginning of needed
502
- # rather than the end to match the depth first
503
- # searching done by the multiple case code below.
504
- #
505
- # This keeps the error messages consistent.
506
- needed = requests(spec, act) + needed
507
- else
508
- # There are multiple specs for this dep. This is
509
- # the case that this class is built to handle.
510
-
511
- # Sort them so that we try the highest versions
512
- # first.
513
- possible = possible.sort_by { |s| s.version }
514
-
515
- # We track the conflicts seen so that we can report them
516
- # to help the user figure out how to fix the situation.
517
- conflicts = []
518
-
519
- # To figure out which to pick, we keep resolving
520
- # given each one being activated and if there isn't
521
- # a conflict, we know we've found a full set.
522
- #
523
- # We use an until loop rather than #reverse_each
524
- # to keep the stack short since we're using a recursive
525
- # algorithm.
526
- #
527
- until possible.empty?
528
- s = possible.pop
529
-
530
- # Recursively call #resolve_for with this spec
531
- # and add it's dependencies into the picture...
532
-
533
- act = ActivationRequest.new(s, dep)
534
-
535
- try = requests(s, act) + needed
536
-
537
- res = resolve_for(try, specs + [act])
538
-
539
- # While trying to resolve these dependencies, there may
540
- # be a conflict!
541
-
542
- if res.kind_of? DependencyConflict
543
- # The conflict might be created not by this invocation
544
- # but rather one up the stack, so if we can't attempt
545
- # to resolve this conflict (conflict isn't with the spec +s+)
546
- # then just return it so the caller can try to sort it out.
547
- return res unless res.for_spec? s
548
-
549
- # Otherwise, this is a conflict that we can attempt to fix
550
- conflicts << [s, res]
551
-
552
- # Optimization:
553
- #
554
- # Because the conflict indicates the dependency that trigger
555
- # it, we can prune possible based on this new information.
556
- #
557
- # This cuts down on the number of iterations needed.
558
- possible.delete_if { |x| !res.dependency.matches_spec? x }
559
- else
560
- # No conflict, return the specs
561
- return res
562
- end
563
- end
564
-
565
- # We tried all possibles and nothing worked, so we let the user
566
- # know and include as much information about the problem since
567
- # the user is going to have to take action to fix this.
568
- raise ImpossibleDependenciesError.new(dep, conflicts)
569
- end
217
+ # We tried all possibles and nothing worked, so we let the user
218
+ # know and include as much information about the problem since
219
+ # the user is going to have to take action to fix this.
220
+ raise Gem::ImpossibleDependenciesError.new(dep, conflicts)
570
221
  end
571
-
572
- specs
573
222
  end
223
+
224
+ specs
574
225
  end
226
+
575
227
  end
228
+
229
+ require 'rubygems/dependency_resolver/api_set'
230
+ require 'rubygems/dependency_resolver/api_specification'
231
+ require 'rubygems/dependency_resolver/activation_request'
232
+ require 'rubygems/dependency_resolver/composed_set'
233
+ require 'rubygems/dependency_resolver/current_set'
234
+ require 'rubygems/dependency_resolver/dependency_conflict'
235
+ require 'rubygems/dependency_resolver/dependency_request'
236
+ require 'rubygems/dependency_resolver/index_set'
237
+ require 'rubygems/dependency_resolver/index_specification'
238
+ require 'rubygems/dependency_resolver/installed_specification'
239
+ require 'rubygems/dependency_resolver/installer_set'
240
+