rubygems-update 2.1.11 → 2.2.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 (190) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.autotest +37 -12
  5. data/History.txt +99 -2
  6. data/MIT.txt +1 -0
  7. data/Manifest.txt +59 -19
  8. data/Rakefile +4 -6
  9. data/lib/gauntlet_rubygems.rb +1 -1
  10. data/lib/rubygems.rb +102 -80
  11. data/lib/rubygems/available_set.rb +2 -2
  12. data/lib/rubygems/basic_specification.rb +97 -8
  13. data/lib/rubygems/commands/install_command.rb +58 -15
  14. data/lib/rubygems/commands/list_command.rb +1 -7
  15. data/lib/rubygems/commands/outdated_command.rb +1 -1
  16. data/lib/rubygems/commands/pristine_command.rb +14 -1
  17. data/lib/rubygems/commands/push_command.rb +9 -4
  18. data/lib/rubygems/commands/query_command.rb +33 -17
  19. data/lib/rubygems/commands/search_command.rb +0 -6
  20. data/lib/rubygems/commands/specification_command.rb +1 -1
  21. data/lib/rubygems/commands/unpack_command.rb +1 -1
  22. data/lib/rubygems/commands/update_command.rb +4 -1
  23. data/lib/rubygems/commands/which_command.rb +5 -8
  24. data/lib/rubygems/compatibility.rb +3 -0
  25. data/lib/rubygems/core_ext/kernel_gem.rb +6 -0
  26. data/lib/rubygems/defaults.rb +19 -0
  27. data/lib/rubygems/dependency_installer.rb +28 -9
  28. data/lib/rubygems/doctor.rb +17 -11
  29. data/lib/rubygems/errors.rb +16 -3
  30. data/lib/rubygems/exceptions.rb +52 -5
  31. data/lib/rubygems/ext.rb +1 -2
  32. data/lib/rubygems/ext/build_error.rb +6 -0
  33. data/lib/rubygems/ext/builder.rb +50 -17
  34. data/lib/rubygems/ext/cmake_builder.rb +1 -1
  35. data/lib/rubygems/ext/configure_builder.rb +1 -3
  36. data/lib/rubygems/ext/ext_conf_builder.rb +9 -3
  37. data/lib/rubygems/ext/rake_builder.rb +2 -5
  38. data/lib/rubygems/gemcutter_utilities.rb +8 -1
  39. data/lib/rubygems/installer.rb +14 -4
  40. data/lib/rubygems/installer_test_case.rb +0 -5
  41. data/lib/rubygems/package.rb +11 -2
  42. data/lib/rubygems/psych_additions.rb +1 -1
  43. data/lib/rubygems/rdoc.rb +1 -1
  44. data/lib/rubygems/remote_fetcher.rb +3 -3
  45. data/lib/rubygems/request.rb +16 -8
  46. data/lib/rubygems/request_set.rb +133 -42
  47. data/lib/rubygems/request_set/gem_dependency_api.rb +493 -11
  48. data/lib/rubygems/request_set/lockfile.rb +579 -0
  49. data/lib/rubygems/requirement.rb +58 -30
  50. data/lib/rubygems/resolver.rb +471 -0
  51. data/lib/rubygems/resolver/activation_request.rb +165 -0
  52. data/lib/rubygems/resolver/api_set.rb +110 -0
  53. data/lib/rubygems/resolver/api_specification.rb +79 -0
  54. data/lib/rubygems/resolver/best_set.rb +31 -0
  55. data/lib/rubygems/resolver/composed_set.rb +39 -0
  56. data/lib/rubygems/resolver/conflict.rb +122 -0
  57. data/lib/rubygems/{dependency_resolver → resolver}/current_set.rb +1 -4
  58. data/lib/rubygems/{dependency_resolver → resolver}/dependency_request.rb +37 -7
  59. data/lib/rubygems/resolver/git_set.rb +119 -0
  60. data/lib/rubygems/resolver/git_specification.rb +35 -0
  61. data/lib/rubygems/resolver/index_set.rb +74 -0
  62. data/lib/rubygems/resolver/index_specification.rb +69 -0
  63. data/lib/rubygems/resolver/installed_specification.rb +40 -0
  64. data/lib/rubygems/{dependency_resolver → resolver}/installer_set.rb +18 -17
  65. data/lib/rubygems/resolver/local_specification.rb +16 -0
  66. data/lib/rubygems/resolver/lock_set.rb +78 -0
  67. data/lib/rubygems/resolver/lock_specification.rb +58 -0
  68. data/lib/rubygems/resolver/requirement_list.rb +81 -0
  69. data/lib/rubygems/resolver/set.rb +27 -0
  70. data/lib/rubygems/resolver/spec_specification.rb +58 -0
  71. data/lib/rubygems/resolver/specification.rb +89 -0
  72. data/lib/rubygems/resolver/stats.rb +44 -0
  73. data/lib/rubygems/resolver/vendor_set.rb +83 -0
  74. data/lib/rubygems/resolver/vendor_specification.rb +24 -0
  75. data/lib/rubygems/security/trust_dir.rb +16 -2
  76. data/lib/rubygems/source.rb +71 -18
  77. data/lib/rubygems/source/git.rb +218 -0
  78. data/lib/rubygems/source/installed.rb +8 -1
  79. data/lib/rubygems/source/local.rb +14 -8
  80. data/lib/rubygems/source/lock.rb +48 -0
  81. data/lib/rubygems/source/specific_file.rb +14 -3
  82. data/lib/rubygems/source/vendor.rb +27 -0
  83. data/lib/rubygems/source_list.rb +74 -12
  84. data/lib/rubygems/spec_fetcher.rb +36 -4
  85. data/lib/rubygems/specification.rb +214 -65
  86. data/lib/rubygems/stub_specification.rb +57 -1
  87. data/lib/rubygems/syck_hack.rb +3 -3
  88. data/lib/rubygems/test_case.rb +226 -59
  89. data/lib/rubygems/test_utilities.rb +198 -0
  90. data/lib/rubygems/uninstaller.rb +22 -10
  91. data/lib/rubygems/uri_formatter.rb +20 -0
  92. data/lib/rubygems/user_interaction.rb +193 -71
  93. data/lib/rubygems/util.rb +121 -0
  94. data/lib/rubygems/util/list.rb +4 -0
  95. data/lib/rubygems/util/stringio.rb +34 -0
  96. data/lib/rubygems/validator.rb +6 -2
  97. data/lib/rubygems/version.rb +4 -8
  98. data/test/rubygems/test_bundled_ca.rb +1 -1
  99. data/test/rubygems/test_gem.rb +137 -29
  100. data/test/rubygems/test_gem_available_set.rb +19 -0
  101. data/test/rubygems/test_gem_commands_build_command.rb +1 -1
  102. data/test/rubygems/test_gem_commands_cert_command.rb +2 -2
  103. data/test/rubygems/test_gem_commands_cleanup_command.rb +13 -13
  104. data/test/rubygems/test_gem_commands_dependency_command.rb +24 -34
  105. data/test/rubygems/test_gem_commands_fetch_command.rb +43 -48
  106. data/test/rubygems/test_gem_commands_install_command.rb +244 -279
  107. data/test/rubygems/test_gem_commands_list_command.rb +3 -3
  108. data/test/rubygems/test_gem_commands_outdated_command.rb +7 -12
  109. data/test/rubygems/test_gem_commands_pristine_command.rb +73 -27
  110. data/test/rubygems/test_gem_commands_push_command.rb +76 -8
  111. data/test/rubygems/test_gem_commands_query_command.rb +239 -49
  112. data/test/rubygems/test_gem_commands_sources_command.rb +10 -43
  113. data/test/rubygems/test_gem_commands_specification_command.rb +24 -47
  114. data/test/rubygems/test_gem_commands_stale_command.rb +2 -2
  115. data/test/rubygems/test_gem_commands_uninstall_command.rb +3 -3
  116. data/test/rubygems/test_gem_commands_unpack_command.rb +16 -30
  117. data/test/rubygems/test_gem_commands_update_command.rb +149 -134
  118. data/test/rubygems/test_gem_commands_which_command.rb +4 -2
  119. data/test/rubygems/test_gem_dependency_installer.rb +68 -0
  120. data/test/rubygems/test_gem_dependency_list.rb +17 -17
  121. data/test/rubygems/test_gem_dependency_resolution_error.rb +28 -0
  122. data/test/rubygems/test_gem_doctor.rb +1 -1
  123. data/test/rubygems/test_gem_ext_builder.rb +178 -8
  124. data/test/rubygems/test_gem_ext_cmake_builder.rb +1 -7
  125. data/test/rubygems/test_gem_ext_configure_builder.rb +8 -10
  126. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +18 -21
  127. data/test/rubygems/test_gem_ext_rake_builder.rb +1 -3
  128. data/test/rubygems/test_gem_impossible_dependencies_error.rb +10 -6
  129. data/test/rubygems/test_gem_indexer.rb +6 -6
  130. data/test/rubygems/test_gem_installer.rb +29 -10
  131. data/test/rubygems/test_gem_local_remote_options.rb +1 -1
  132. data/test/rubygems/test_gem_package.rb +18 -0
  133. data/test/rubygems/test_gem_rdoc.rb +1 -1
  134. data/test/rubygems/test_gem_remote_fetcher.rb +1 -1
  135. data/test/rubygems/test_gem_request.rb +37 -10
  136. data/test/rubygems/test_gem_request_set.rb +271 -9
  137. data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +684 -0
  138. data/test/rubygems/test_gem_request_set_lockfile.rb +849 -0
  139. data/test/rubygems/test_gem_requirement.rb +21 -0
  140. data/test/rubygems/{test_gem_dependency_resolver.rb → test_gem_resolver.rb} +231 -70
  141. data/test/rubygems/test_gem_resolver_activation_request.rb +63 -0
  142. data/test/rubygems/test_gem_resolver_api_set.rb +167 -0
  143. data/test/rubygems/test_gem_resolver_api_specification.rb +104 -0
  144. data/test/rubygems/test_gem_resolver_best_set.rb +30 -0
  145. data/test/rubygems/test_gem_resolver_conflict.rb +75 -0
  146. data/test/rubygems/test_gem_resolver_dependency_request.rb +20 -0
  147. data/test/rubygems/test_gem_resolver_git_set.rb +148 -0
  148. data/test/rubygems/test_gem_resolver_git_specification.rb +100 -0
  149. data/test/rubygems/test_gem_resolver_index_set.rb +28 -0
  150. data/test/rubygems/test_gem_resolver_index_specification.rb +89 -0
  151. data/test/rubygems/test_gem_resolver_installed_specification.rb +49 -0
  152. data/test/rubygems/test_gem_resolver_installer_set.rb +22 -0
  153. data/test/rubygems/test_gem_resolver_local_specification.rb +45 -0
  154. data/test/rubygems/test_gem_resolver_lock_set.rb +57 -0
  155. data/test/rubygems/test_gem_resolver_lock_specification.rb +87 -0
  156. data/test/rubygems/test_gem_resolver_requirement_list.rb +20 -0
  157. data/test/rubygems/test_gem_resolver_specification.rb +32 -0
  158. data/test/rubygems/test_gem_resolver_vendor_set.rb +67 -0
  159. data/test/rubygems/test_gem_resolver_vendor_specification.rb +83 -0
  160. data/test/rubygems/test_gem_server.rb +4 -4
  161. data/test/rubygems/test_gem_source.rb +54 -64
  162. data/test/rubygems/test_gem_source_git.rb +231 -0
  163. data/test/rubygems/test_gem_source_list.rb +24 -0
  164. data/test/rubygems/test_gem_source_local.rb +1 -1
  165. data/test/rubygems/test_gem_source_lock.rb +114 -0
  166. data/test/rubygems/test_gem_source_vendor.rb +27 -0
  167. data/test/rubygems/test_gem_spec_fetcher.rb +116 -61
  168. data/test/rubygems/test_gem_specification.rb +526 -94
  169. data/test/rubygems/test_gem_stub_specification.rb +123 -10
  170. data/test/rubygems/test_gem_uninstaller.rb +28 -2
  171. data/test/rubygems/test_gem_util.rb +31 -0
  172. data/test/rubygems/test_gem_validator.rb +9 -0
  173. data/util/update_bundled_ca_certificates.rb +8 -1
  174. metadata +89 -29
  175. metadata.gz.sig +2 -4
  176. data/lib/rubygems/dependency_resolver.rb +0 -254
  177. data/lib/rubygems/dependency_resolver/activation_request.rb +0 -109
  178. data/lib/rubygems/dependency_resolver/api_set.rb +0 -65
  179. data/lib/rubygems/dependency_resolver/api_specification.rb +0 -39
  180. data/lib/rubygems/dependency_resolver/composed_set.rb +0 -18
  181. data/lib/rubygems/dependency_resolver/dependency_conflict.rb +0 -85
  182. data/lib/rubygems/dependency_resolver/index_set.rb +0 -64
  183. data/lib/rubygems/dependency_resolver/index_specification.rb +0 -60
  184. data/lib/rubygems/dependency_resolver/installed_specification.rb +0 -52
  185. data/test/rubygems/test_gem_dependency_resolver_api_specification.rb +0 -33
  186. data/test/rubygems/test_gem_dependency_resolver_dependency_conflict.rb +0 -36
  187. data/test/rubygems/test_gem_dependency_resolver_index_set.rb +0 -53
  188. data/test/rubygems/test_gem_dependency_resolver_index_specification.rb +0 -73
  189. data/test/rubygems/test_gem_dependency_resolver_installed_specification.rb +0 -19
  190. data/test/rubygems/test_gem_dependency_resolver_installer_set.rb +0 -28
@@ -1,13 +1,3 @@
1
- ##
2
- # A Requirement is a set of one or more version restrictions. It supports a
3
- # few (<tt>=, !=, >, <, >=, <=, ~></tt>) different restriction operators.
4
-
5
- # REFACTOR: The fact that a requirement is singular or plural is kind of
6
- # awkward. Is Requirement the right name for this? Or should it be one
7
- # [op, number] pair, and we call the list of requirements something else?
8
- # Since a Requirement is held by a Dependency, maybe this should be made
9
- # singular and the list aspect should be pulled up into Dependency?
10
-
11
1
  require "rubygems/version"
12
2
  require "rubygems/deprecate"
13
3
 
@@ -15,6 +5,10 @@ require "rubygems/deprecate"
15
5
  # load our yaml + workarounds now.
16
6
  Gem.load_yaml if defined? ::YAML
17
7
 
8
+ ##
9
+ # A Requirement is a set of one or more version restrictions. It supports a
10
+ # few (<tt>=, !=, >, <, >=, <=, ~></tt>) different restriction operators.
11
+
18
12
  class Gem::Requirement
19
13
  OPS = { #:nodoc:
20
14
  "=" => lambda { |v, r| v == r },
@@ -27,11 +21,21 @@ class Gem::Requirement
27
21
  }
28
22
 
29
23
  quoted = OPS.keys.map { |k| Regexp.quote k }.join "|"
30
- PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*"
24
+ PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*" # :nodoc:
25
+
26
+ ##
27
+ # A regular expression that matches a requirement
28
+
31
29
  PATTERN = /\A#{PATTERN_RAW}\z/
32
30
 
31
+ ##
32
+ # The default requirement matches any version
33
+
33
34
  DefaultRequirement = [">=", Gem::Version.new(0)]
34
35
 
36
+ ##
37
+ # Raised when a bad requirement is encountered
38
+
35
39
  class BadRequirementError < ArgumentError; end
36
40
 
37
41
  ##
@@ -41,9 +45,6 @@ class Gem::Requirement
41
45
  # If the input is "weird", the default version requirement is
42
46
  # returned.
43
47
 
44
- # REFACTOR: There's no reason that this can't be unified with .new.
45
- # .new is the standard Ruby factory method.
46
-
47
48
  def self.create input
48
49
  case input
49
50
  when Gem::Requirement then
@@ -78,11 +79,6 @@ class Gem::Requirement
78
79
  # parse("1.0") # => ["=", "1.0"]
79
80
  # parse(Gem::Version.new("1.0")) # => ["=, "1.0"]
80
81
 
81
- # REFACTOR: Little two element arrays like this have no real semantic
82
- # value. I'd love to see something like this:
83
- # Constraint = Struct.new(:operator, :version); (or similar)
84
- # and have a Requirement be a list of Constraints.
85
-
86
82
  def self.parse obj
87
83
  return ["=", obj] if Gem::Version === obj
88
84
 
@@ -121,10 +117,36 @@ class Gem::Requirement
121
117
  end
122
118
  end
123
119
 
120
+ ##
121
+ # Concatenates the +new+ requirements onto this requirement.
122
+
123
+ def concat new
124
+ new = new.flatten
125
+ new.compact!
126
+ new.uniq!
127
+ new = new.map { |r| self.class.parse r }
128
+
129
+ @requirements.concat new
130
+ end
131
+
132
+ ##
133
+ # Formats this requirement for use in a Gem::RequestSet::Lockfile.
134
+
135
+ def for_lockfile # :nodoc:
136
+ return if [DefaultRequirement] == @requirements
137
+
138
+ list = requirements.sort_by { |_, version|
139
+ version
140
+ }.map { |op, version|
141
+ "#{op} #{version}"
142
+ }.uniq
143
+
144
+ " (#{list.join ', '})"
145
+ end
146
+
124
147
  ##
125
148
  # true if this gem has no requirements.
126
149
 
127
- # FIX: maybe this should be using #default ?
128
150
  def none?
129
151
  if @requirements.size == 1
130
152
  @requirements[0] == DefaultRequirement
@@ -133,6 +155,14 @@ class Gem::Requirement
133
155
  end
134
156
  end
135
157
 
158
+ ##
159
+ # true if the requirement is for only an exact version
160
+
161
+ def exact?
162
+ return false unless @requirements.size == 1
163
+ @requirements[0][0] == "="
164
+ end
165
+
136
166
  def as_list # :nodoc:
137
167
  requirements.map { |op, version| "#{op} #{version}" }.sort
138
168
  end
@@ -166,11 +196,11 @@ class Gem::Requirement
166
196
  yaml_initialize coder.tag, coder.map
167
197
  end
168
198
 
169
- def to_yaml_properties
199
+ def to_yaml_properties # :nodoc:
170
200
  ["@requirements"]
171
201
  end
172
202
 
173
- def encode_with(coder)
203
+ def encode_with coder # :nodoc:
174
204
  coder.add 'requirements', @requirements
175
205
  end
176
206
 
@@ -214,15 +244,13 @@ class Gem::Requirement
214
244
  as_list.join ", "
215
245
  end
216
246
 
217
- # DOC: this should probably be :nodoc'd
218
- def == other
247
+ def == other # :nodoc:
219
248
  Gem::Requirement === other and to_s == other.to_s
220
249
  end
221
250
 
222
251
  private
223
252
 
224
- # DOC: this should probably be :nodoc'd
225
- def fix_syck_default_key_in_requirements
253
+ def fix_syck_default_key_in_requirements # :nodoc:
226
254
  Gem.load_yaml
227
255
 
228
256
  # Fixup the Syck DefaultKey bug
@@ -234,9 +262,9 @@ class Gem::Requirement
234
262
  end
235
263
  end
236
264
 
237
- # This is needed for compatibility with older yaml
238
- # gemspecs.
239
-
240
265
  class Gem::Version
241
- Requirement = Gem::Requirement
266
+ # This is needed for compatibility with older yaml
267
+ # gemspecs.
268
+
269
+ Requirement = Gem::Requirement # :nodoc:
242
270
  end
@@ -0,0 +1,471 @@
1
+ require 'rubygems'
2
+ require 'rubygems/dependency'
3
+ require 'rubygems/exceptions'
4
+ require 'rubygems/util/list'
5
+
6
+ require 'uri'
7
+ require 'net/http'
8
+
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.
14
+
15
+ class Gem::Resolver
16
+
17
+ ##
18
+ # If the DEBUG_RESOLVER environment variable is set then debugging mode is
19
+ # enabled for the resolver. This will display information about the state
20
+ # of the resolver while a set of dependencies is being resolved.
21
+
22
+ DEBUG_RESOLVER = !ENV['DEBUG_RESOLVER'].nil?
23
+
24
+ ##
25
+ # Contains all the conflicts encountered while doing resolution
26
+
27
+ attr_reader :conflicts
28
+
29
+ ##
30
+ # Set to true if development dependencies should be considered.
31
+
32
+ attr_accessor :development
33
+
34
+ ##
35
+ # When true, no dependencies are looked up for requested gems.
36
+
37
+ attr_accessor :ignore_dependencies
38
+
39
+ ##
40
+ # List of dependencies that could not be found in the configured sources.
41
+
42
+ attr_reader :missing
43
+
44
+ attr_reader :stats
45
+
46
+ ##
47
+ # When a missing dependency, don't stop. Just go on and record what was
48
+ # missing.
49
+
50
+ attr_accessor :soft_missing
51
+
52
+ ##
53
+ # Combines +sets+ into a ComposedSet that allows specification lookup in a
54
+ # uniform manner. If one of the +sets+ is itself a ComposedSet its sets are
55
+ # flattened into the result ComposedSet.
56
+
57
+ def self.compose_sets *sets
58
+ sets.compact!
59
+
60
+ sets = sets.map do |set|
61
+ case set
62
+ when Gem::Resolver::ComposedSet then
63
+ set.sets
64
+ else
65
+ set
66
+ end
67
+ end.flatten
68
+
69
+ case sets.length
70
+ when 0 then
71
+ raise ArgumentError, 'one set in the composition must be non-nil'
72
+ when 1 then
73
+ sets.first
74
+ else
75
+ Gem::Resolver::ComposedSet.new(*sets)
76
+ end
77
+ end
78
+
79
+ ##
80
+ # Creates a Resolver that queries only against the already installed gems
81
+ # for the +needed+ dependencies.
82
+
83
+ def self.for_current_gems needed
84
+ new needed, Gem::Resolver::CurrentSet.new
85
+ end
86
+
87
+ ##
88
+ # Create Resolver object which will resolve the tree starting
89
+ # with +needed+ Dependency objects.
90
+ #
91
+ # +set+ is an object that provides where to look for specifications to
92
+ # satisfy the Dependencies. This defaults to IndexSet, which will query
93
+ # rubygems.org.
94
+
95
+ def initialize needed, set = nil
96
+ @set = set || Gem::Resolver::IndexSet.new
97
+ @needed = needed
98
+
99
+ @conflicts = []
100
+ @development = false
101
+ @ignore_dependencies = false
102
+ @missing = []
103
+ @soft_missing = false
104
+ @stats = Gem::Resolver::Stats.new
105
+ end
106
+
107
+ def explain stage, *data # :nodoc:
108
+ if DEBUG_RESOLVER
109
+ d = data.map { |x| x.inspect }.join(", ")
110
+ STDOUT.printf "%20s %s\n", stage.to_s.upcase, d
111
+ end
112
+ end
113
+
114
+ def explain_list stage, data # :nodoc:
115
+ if DEBUG_RESOLVER
116
+ STDOUT.printf "%20s (%d entries)\n", stage.to_s.upcase, data.size
117
+ data.each do |d|
118
+ STDOUT.printf "%20s %s\n", "", d
119
+ end
120
+ end
121
+ end
122
+
123
+ ##
124
+ # Creates an ActivationRequest for the given +dep+ and the last +possible+
125
+ # specification.
126
+ #
127
+ # Returns the Specification and the ActivationRequest
128
+
129
+ def activation_request dep, possible # :nodoc:
130
+ spec = possible.pop
131
+
132
+ explain :activate, [spec.full_name, possible.size]
133
+
134
+ activation_request =
135
+ Gem::Resolver::ActivationRequest.new spec, dep, possible
136
+
137
+ return spec, activation_request
138
+ end
139
+
140
+ def requests s, act, reqs=nil # :nodoc:
141
+ return reqs if @ignore_dependencies
142
+
143
+ s.dependencies.reverse_each do |d|
144
+ next if d.type == :development and not @development
145
+ reqs.add Gem::Resolver::DependencyRequest.new(d, act)
146
+ @stats.requirement!
147
+ end
148
+
149
+ @set.prefetch reqs
150
+
151
+ @stats.record_requirements reqs
152
+
153
+ reqs
154
+ end
155
+
156
+ ##
157
+ # Proceed with resolution! Returns an array of ActivationRequest objects.
158
+
159
+ def resolve
160
+ @conflicts = []
161
+
162
+ needed = Gem::Resolver::RequirementList.new
163
+
164
+ @needed.reverse_each do |n|
165
+ request = Gem::Resolver::DependencyRequest.new n, nil
166
+
167
+ needed.add request
168
+ @stats.requirement!
169
+ end
170
+
171
+ @stats.record_requirements needed
172
+
173
+ res = resolve_for needed, nil
174
+
175
+ raise Gem::DependencyResolutionError, res if
176
+ res.kind_of? Gem::Resolver::Conflict
177
+
178
+ res.to_a
179
+ end
180
+
181
+ ##
182
+ # Finds the State in +states+ that matches the +conflict+ so that we can try
183
+ # other possible sets.
184
+ #
185
+ # If no good candidate is found, the first state is tried.
186
+
187
+ def find_conflict_state conflict, states # :nodoc:
188
+ until states.empty? do
189
+ state = states.pop
190
+
191
+ explain :consider, state.dep, conflict.failed_dep
192
+
193
+ if conflict.for_spec? state.spec
194
+ state.conflicts << [state.spec, conflict]
195
+ return state
196
+ end
197
+ end
198
+
199
+ nil
200
+ end
201
+
202
+ ##
203
+ # Extracts the specifications that may be able to fulfill +dependency+ and
204
+ # returns those that match the local platform and all those that match.
205
+
206
+ def find_possible dependency # :nodoc:
207
+ all = @set.find_all dependency
208
+ matching_platform = select_local_platforms all
209
+
210
+ return matching_platform, all
211
+ end
212
+
213
+ def handle_conflict(dep, existing) # :nodoc:
214
+ # There is a conflict! We return the conflict object which will be seen by
215
+ # the caller and be handled at the right level.
216
+
217
+ # If the existing activation indicates that there are other possibles for
218
+ # it, then issue the conflict on the dependency for the activation itself.
219
+ # Otherwise, if there was a requester, issue it on the requester's
220
+ # request itself.
221
+ # Finally, if the existing request has no requester (toplevel) unwind to
222
+ # it anyway.
223
+
224
+ if existing.others_possible?
225
+ conflict =
226
+ Gem::Resolver::Conflict.new dep, existing
227
+ elsif dep.requester
228
+ depreq = dep.requester.request
229
+ conflict =
230
+ Gem::Resolver::Conflict.new depreq, existing, dep
231
+ elsif existing.request.requester.nil?
232
+ conflict =
233
+ Gem::Resolver::Conflict.new dep, existing
234
+ else
235
+ raise Gem::DependencyError, "Unable to figure out how to unwind conflict"
236
+ end
237
+
238
+ @conflicts << conflict unless @conflicts.include? conflict
239
+
240
+ return conflict
241
+ end
242
+
243
+ # Contains the state for attempting activation of a set of possible specs.
244
+ # +needed+ is a Gem::List of DependencyRequest objects that, well, need
245
+ # to be satisfied.
246
+ # +specs+ is the List of ActivationRequest that are being tested.
247
+ # +dep+ is the DependencyRequest that was used to generate this state.
248
+ # +spec+ is the Specification for this state.
249
+ # +possible+ is List of DependencyRequest objects that can be tried to
250
+ # find a complete set.
251
+ # +conflicts+ is a [DependencyRequest, Conflict] hit tried to
252
+ # activate the state.
253
+ #
254
+ State = Struct.new(:needed, :specs, :dep, :spec, :possibles, :conflicts) do
255
+ def summary # :nodoc:
256
+ nd = needed.map { |s| s.to_s }.sort if nd
257
+
258
+ if specs then
259
+ ss = specs.map { |s| s.full_name }.sort
260
+ ss.unshift ss.length
261
+ end
262
+
263
+ d = dep.to_s
264
+ d << " from #{dep.requester.full_name}" if dep.requester
265
+
266
+ ps = possibles.map { |p| p.full_name }.sort
267
+ ps.unshift ps.length
268
+
269
+ cs = conflicts.map do |(s, c)|
270
+ [s.full_name, c.conflicting_dependencies.map { |cd| cd.to_s }]
271
+ end
272
+
273
+ { :needed => nd, :specs => ss, :dep => d, :spec => spec.full_name,
274
+ :possibles => ps, :conflicts => cs }
275
+ end
276
+ end
277
+
278
+ ##
279
+ # The meat of the algorithm. Given +needed+ DependencyRequest objects and
280
+ # +specs+ being a list to ActivationRequest, calculate a new list of
281
+ # ActivationRequest objects.
282
+
283
+ def resolve_for needed, specs # :nodoc:
284
+ # The State objects that are used to attempt the activation tree.
285
+ states = []
286
+
287
+ while !needed.empty?
288
+ @stats.iteration!
289
+
290
+ dep = needed.remove
291
+ explain :try, [dep, dep.requester ? dep.requester.request : :toplevel]
292
+ explain_list :next5, needed.next5
293
+ explain_list :specs, Array(specs).map { |x| x.full_name }.sort
294
+
295
+ # If there is already a spec activated for the requested name...
296
+ if specs && existing = specs.find { |s| dep.name == s.name }
297
+ # then we're done since this new dep matches the existing spec.
298
+ next if dep.matches_spec? existing
299
+
300
+ conflict = handle_conflict dep, existing
301
+
302
+ return conflict unless dep.requester
303
+
304
+ explain :conflict, dep, :existing, existing.full_name
305
+
306
+ depreq = dep.requester.request
307
+
308
+ state = nil
309
+ until states.empty?
310
+ x = states.pop
311
+
312
+ i = existing.request.requester
313
+ explain :consider, x.spec.full_name, [depreq.name, dep.name, i ? i.name : :top]
314
+
315
+ if x.spec.name == depreq.name or
316
+ x.spec.name == dep.name or
317
+ (i && (i.name == x.spec.name))
318
+ explain :found, x.spec.full_name
319
+ state = x
320
+ break
321
+ end
322
+ end
323
+
324
+ return conflict unless state
325
+
326
+ @stats.backtracking!
327
+
328
+ needed, specs = resolve_for_conflict needed, specs, state
329
+
330
+ states << state unless state.possibles.empty?
331
+
332
+ next
333
+ end
334
+
335
+ matching, all = find_possible dep
336
+
337
+ case matching.size
338
+ when 0
339
+ resolve_for_zero dep, all
340
+ when 1
341
+ needed, specs =
342
+ resolve_for_single needed, specs, dep, matching
343
+ else
344
+ needed, specs =
345
+ resolve_for_multiple needed, specs, states, dep, matching
346
+ end
347
+ end
348
+
349
+ specs
350
+ end
351
+
352
+ ##
353
+ # Rewinds +needed+ and +specs+ to a previous state in +state+ for a conflict
354
+ # between +dep+ and +existing+.
355
+
356
+ def resolve_for_conflict needed, specs, state # :nodoc:
357
+ # We exhausted the possibles so it's definitely not going to work out,
358
+ # bail out.
359
+ raise Gem::ImpossibleDependenciesError.new state.dep, state.conflicts if
360
+ state.possibles.empty?
361
+
362
+ # Retry resolution with this spec and add it's dependencies
363
+ spec, act = activation_request state.dep, state.possibles
364
+
365
+ needed = requests spec, act, state.needed.dup
366
+ specs = Gem::List.prepend state.specs, act
367
+
368
+ return needed, specs
369
+ end
370
+
371
+ ##
372
+ # There are multiple +possible+ specifications for this +dep+. Updates
373
+ # +needed+, +specs+ and +states+ for further resolution of the +possible+
374
+ # choices.
375
+
376
+ def resolve_for_multiple needed, specs, states, dep, possible # :nodoc:
377
+ # Sort them so that we try the highest versions first.
378
+ possible = possible.sort_by do |s|
379
+ [s.source, s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
380
+ end
381
+
382
+ spec, act = activation_request dep, possible
383
+
384
+ # We may need to try all of +possible+, so we setup state to unwind back
385
+ # to current +needed+ and +specs+ so we can try another. This is code is
386
+ # what makes conflict resolution possible.
387
+ states << State.new(needed.dup, specs, dep, spec, possible, [])
388
+
389
+ @stats.record_depth states
390
+
391
+ explain :states, states.map { |s| s.dep }
392
+
393
+ needed = requests spec, act, needed
394
+ specs = Gem::List.prepend specs, act
395
+
396
+ return needed, specs
397
+ end
398
+
399
+ ##
400
+ # Add the spec from the +possible+ list to +specs+ and process the spec's
401
+ # dependencies by adding them to +needed+.
402
+
403
+ def resolve_for_single needed, specs, dep, possible # :nodoc:
404
+ spec, act = activation_request dep, possible
405
+
406
+ specs = Gem::List.prepend specs, act
407
+
408
+ # Put the deps for at the beginning of needed
409
+ # rather than the end to match the depth first
410
+ # searching done by the multiple case code below.
411
+ #
412
+ # This keeps the error messages consistent.
413
+ needed = requests spec, act, needed
414
+
415
+ return needed, specs
416
+ end
417
+
418
+ ##
419
+ # When there are no possible specifications for +dep+ our work is done.
420
+
421
+ def resolve_for_zero dep, platform_mismatch # :nodoc:
422
+ @missing << dep
423
+
424
+ unless @soft_missing
425
+ raise Gem::UnsatisfiableDependencyError.new(dep, platform_mismatch)
426
+ end
427
+ end
428
+
429
+ ##
430
+ # Returns the gems in +specs+ that match the local platform.
431
+
432
+ def select_local_platforms specs # :nodoc:
433
+ specs.select do |spec|
434
+ Gem::Platform.installable? spec
435
+ end
436
+ end
437
+
438
+ end
439
+
440
+ ##
441
+ # TODO remove in RubyGems 3
442
+
443
+ Gem::DependencyResolver = Gem::Resolver # :nodoc:
444
+
445
+ require 'rubygems/resolver/activation_request'
446
+ require 'rubygems/resolver/conflict'
447
+ require 'rubygems/resolver/dependency_request'
448
+ require 'rubygems/resolver/requirement_list'
449
+ require 'rubygems/resolver/stats'
450
+
451
+ require 'rubygems/resolver/set'
452
+ require 'rubygems/resolver/api_set'
453
+ require 'rubygems/resolver/composed_set'
454
+ require 'rubygems/resolver/best_set'
455
+ require 'rubygems/resolver/current_set'
456
+ require 'rubygems/resolver/git_set'
457
+ require 'rubygems/resolver/index_set'
458
+ require 'rubygems/resolver/installer_set'
459
+ require 'rubygems/resolver/lock_set'
460
+ require 'rubygems/resolver/vendor_set'
461
+
462
+ require 'rubygems/resolver/specification'
463
+ require 'rubygems/resolver/spec_specification'
464
+ require 'rubygems/resolver/api_specification'
465
+ require 'rubygems/resolver/git_specification'
466
+ require 'rubygems/resolver/index_specification'
467
+ require 'rubygems/resolver/installed_specification'
468
+ require 'rubygems/resolver/local_specification'
469
+ require 'rubygems/resolver/lock_specification'
470
+ require 'rubygems/resolver/vendor_specification'
471
+