bundler 2.2.7 → 2.2.17

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +132 -5
  3. data/lib/bundler.rb +1 -1
  4. data/lib/bundler/build_metadata.rb +2 -2
  5. data/lib/bundler/cli.rb +4 -2
  6. data/lib/bundler/cli/common.rb +15 -2
  7. data/lib/bundler/cli/gem.rb +43 -17
  8. data/lib/bundler/cli/outdated.rb +1 -1
  9. data/lib/bundler/compact_index_client/updater.rb +10 -6
  10. data/lib/bundler/current_ruby.rb +1 -0
  11. data/lib/bundler/definition.rb +63 -58
  12. data/lib/bundler/dsl.rb +36 -25
  13. data/lib/bundler/feature_flag.rb +0 -1
  14. data/lib/bundler/fetcher.rb +2 -1
  15. data/lib/bundler/fetcher/downloader.rb +8 -4
  16. data/lib/bundler/gem_helper.rb +16 -0
  17. data/lib/bundler/index.rb +6 -5
  18. data/lib/bundler/injector.rb +2 -2
  19. data/lib/bundler/inline.rb +2 -1
  20. data/lib/bundler/installer.rb +2 -0
  21. data/lib/bundler/installer/parallel_installer.rb +36 -15
  22. data/lib/bundler/installer/standalone.rb +2 -1
  23. data/lib/bundler/lazy_specification.rb +14 -18
  24. data/lib/bundler/lockfile_parser.rb +3 -13
  25. data/lib/bundler/man/bundle-add.1 +1 -1
  26. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  27. data/lib/bundler/man/bundle-cache.1 +1 -1
  28. data/lib/bundler/man/bundle-check.1 +1 -1
  29. data/lib/bundler/man/bundle-clean.1 +1 -1
  30. data/lib/bundler/man/bundle-config.1 +25 -8
  31. data/lib/bundler/man/bundle-config.1.ronn +29 -10
  32. data/lib/bundler/man/bundle-doctor.1 +1 -1
  33. data/lib/bundler/man/bundle-exec.1 +1 -1
  34. data/lib/bundler/man/bundle-gem.1 +1 -1
  35. data/lib/bundler/man/bundle-info.1 +1 -1
  36. data/lib/bundler/man/bundle-init.1 +1 -1
  37. data/lib/bundler/man/bundle-inject.1 +1 -1
  38. data/lib/bundler/man/bundle-install.1 +1 -1
  39. data/lib/bundler/man/bundle-list.1 +1 -1
  40. data/lib/bundler/man/bundle-lock.1 +1 -1
  41. data/lib/bundler/man/bundle-open.1 +1 -1
  42. data/lib/bundler/man/bundle-outdated.1 +1 -1
  43. data/lib/bundler/man/bundle-platform.1 +1 -1
  44. data/lib/bundler/man/bundle-pristine.1 +1 -1
  45. data/lib/bundler/man/bundle-remove.1 +1 -1
  46. data/lib/bundler/man/bundle-show.1 +1 -1
  47. data/lib/bundler/man/bundle-update.1 +1 -1
  48. data/lib/bundler/man/bundle-viz.1 +1 -1
  49. data/lib/bundler/man/bundle.1 +1 -1
  50. data/lib/bundler/man/gemfile.5 +1 -1
  51. data/lib/bundler/plugin.rb +3 -2
  52. data/lib/bundler/plugin/api/source.rb +7 -0
  53. data/lib/bundler/plugin/installer.rb +8 -10
  54. data/lib/bundler/plugin/source_list.rb +4 -0
  55. data/lib/bundler/resolver.rb +82 -65
  56. data/lib/bundler/resolver/spec_group.rb +53 -38
  57. data/lib/bundler/retry.rb +1 -1
  58. data/lib/bundler/rubygems_gem_installer.rb +47 -0
  59. data/lib/bundler/settings.rb +60 -10
  60. data/lib/bundler/shared_helpers.rb +2 -2
  61. data/lib/bundler/source.rb +6 -0
  62. data/lib/bundler/source/metadata.rb +0 -4
  63. data/lib/bundler/source/path.rb +3 -1
  64. data/lib/bundler/source/path/installer.rb +1 -1
  65. data/lib/bundler/source/rubygems.rb +22 -6
  66. data/lib/bundler/source_list.rb +29 -24
  67. data/lib/bundler/spec_set.rb +22 -8
  68. data/lib/bundler/stub_specification.rb +8 -0
  69. data/lib/bundler/templates/Gemfile +1 -1
  70. data/lib/bundler/templates/gems.rb +1 -1
  71. data/lib/bundler/templates/newgem/CHANGELOG.md.tt +5 -0
  72. data/lib/bundler/templates/newgem/README.md.tt +5 -3
  73. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +2 -4
  74. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +0 -1
  75. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +11 -5
  76. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +1 -1
  77. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +1 -1
  78. data/lib/bundler/vendor/thor/lib/thor.rb +5 -6
  79. data/lib/bundler/vendor/thor/lib/thor/actions.rb +1 -1
  80. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +4 -2
  81. data/lib/bundler/vendor/thor/lib/thor/error.rb +1 -1
  82. data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +5 -1
  83. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +9 -8
  84. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +5 -2
  85. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +5 -1
  86. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  87. data/lib/bundler/vendor/tmpdir/lib/tmpdir.rb +1 -1
  88. data/lib/bundler/version.rb +1 -1
  89. metadata +4 -3
@@ -140,6 +140,13 @@ module Bundler
140
140
  end
141
141
  end
142
142
 
143
+ # Set internal representation to fetch the gems/specs locally.
144
+ #
145
+ # When this is called, the source should try to fetch the specs and
146
+ # install from the local system.
147
+ def local!
148
+ end
149
+
143
150
  # Set internal representation to fetch the gems/specs from remote.
144
151
  #
145
152
  # When this is called, the source should try to fetch the specs and
@@ -16,15 +16,13 @@ module Bundler
16
16
 
17
17
  version = options[:version] || [">= 0"]
18
18
 
19
- Bundler.settings.temporary(:disable_multisource => false) do
20
- if options[:git]
21
- install_git(names, version, options)
22
- elsif options[:local_git]
23
- install_local_git(names, version, options)
24
- else
25
- sources = options[:source] || Bundler.rubygems.sources
26
- install_rubygems(names, version, sources)
27
- end
19
+ if options[:git]
20
+ install_git(names, version, options)
21
+ elsif options[:local_git]
22
+ install_local_git(names, version, options)
23
+ else
24
+ sources = options[:source] || Bundler.rubygems.sources
25
+ install_rubygems(names, version, sources)
28
26
  end
29
27
  end
30
28
 
@@ -79,7 +77,7 @@ module Bundler
79
77
  source_list = SourceList.new
80
78
 
81
79
  source_list.add_git_source(git_source_options) if git_source_options
82
- source_list.add_rubygems_source("remotes" => rubygems_source) if rubygems_source
80
+ source_list.global_rubygems_source = rubygems_source if rubygems_source
83
81
 
84
82
  deps = names.map {|name| Dependency.new name, version }
85
83
 
@@ -17,6 +17,10 @@ module Bundler
17
17
  path_sources + git_sources + rubygems_sources + [metadata_source]
18
18
  end
19
19
 
20
+ def default_source
21
+ git_sources.first || global_rubygems_source
22
+ end
23
+
20
24
  private
21
25
 
22
26
  def rubygems_aggregate_class
@@ -5,6 +5,8 @@ module Bundler
5
5
  require_relative "vendored_molinillo"
6
6
  require_relative "resolver/spec_group"
7
7
 
8
+ include GemHelpers
9
+
8
10
  # Figures out the best possible configuration of gems that satisfies
9
11
  # the list of passed dependencies and any child dependencies without
10
12
  # causing any gem activation errors.
@@ -15,17 +17,21 @@ module Bundler
15
17
  # ==== Returns
16
18
  # <GemBundle>,nil:: If the list of dependencies can be resolved, a
17
19
  # collection of gemspecs is returned. Otherwise, nil is returned.
18
- def self.resolve(requirements, index, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil)
19
- platforms = Set.new(platforms) if platforms
20
+ def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil)
20
21
  base = SpecSet.new(base) unless base.is_a?(SpecSet)
21
- resolver = new(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
22
+ resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
22
23
  result = resolver.start(requirements)
23
24
  SpecSet.new(result)
24
25
  end
25
26
 
26
- def initialize(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
27
- @index = index
27
+ def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
28
28
  @source_requirements = source_requirements
29
+
30
+ @index_requirements = source_requirements.each_with_object({}) do |source_requirement, index_requirements|
31
+ name, source = source_requirement
32
+ index_requirements[name] = name == :global ? source : source.specs
33
+ end
34
+
29
35
  @base = base
30
36
  @resolver = Molinillo::Resolver.new(self, self)
31
37
  @search_for = {}
@@ -35,10 +41,14 @@ module Bundler
35
41
  @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true)
36
42
  end
37
43
  additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) }
38
- @platforms = platforms
44
+ @platforms = platforms.reject {|p| p != Gem::Platform::RUBY && (platforms - [p]).any? {|pl| generic(pl) == p } }
45
+ @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY]
39
46
  @gem_version_promoter = gem_version_promoter
40
47
  @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major?
41
- @lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.disable_multisource?
48
+ @no_aggregate_global_source = @source_requirements[:global].nil?
49
+
50
+ @variant_specific_names = []
51
+ @generic_names = ["Ruby\0", "RubyGems\0"]
42
52
  end
43
53
 
44
54
  def start(requirements)
@@ -102,16 +112,25 @@ module Bundler
102
112
  include Molinillo::SpecificationProvider
103
113
 
104
114
  def dependencies_for(specification)
105
- specification.dependencies_for_activated_platforms
115
+ all_dependencies = specification.dependencies_for_activated_platforms
116
+
117
+ if @variant_specific_names.include?(specification.name)
118
+ @variant_specific_names |= all_dependencies.map(&:name) - @generic_names
119
+ else
120
+ generic_names, variant_specific_names = specification.partitioned_dependency_names_for_activated_platforms
121
+ @variant_specific_names |= variant_specific_names - @generic_names
122
+ @generic_names |= generic_names
123
+ end
124
+
125
+ all_dependencies
106
126
  end
107
127
 
108
128
  def search_for(dependency_proxy)
109
129
  platform = dependency_proxy.__platform
110
130
  dependency = dependency_proxy.dep
111
- @search_for[dependency_proxy] ||= begin
112
- name = dependency.name
113
- index = index_for(dependency)
114
- results = index.search(dependency, @base[name])
131
+ name = dependency.name
132
+ search_result = @search_for[dependency_proxy] ||= begin
133
+ results = results_for(dependency, @base[name])
115
134
 
116
135
  if vertex = @base_dg.vertex_named(name)
117
136
  locked_requirement = vertex.payload.requirement
@@ -136,56 +155,67 @@ module Bundler
136
155
  end
137
156
  nested.reduce([]) do |groups, (version, specs)|
138
157
  next groups if locked_requirement && !locked_requirement.satisfied_by?(version)
139
- spec_group = SpecGroup.new(specs)
140
- groups << spec_group
158
+
159
+ specs_by_platform = Hash.new do |current_specs, current_platform|
160
+ current_specs[current_platform] = select_best_platform_match(specs, current_platform)
161
+ end
162
+
163
+ spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY)
164
+ groups << spec_group_ruby if spec_group_ruby
165
+
166
+ next groups if @resolving_only_for_ruby
167
+
168
+ spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform)
169
+ groups << spec_group if spec_group
170
+
171
+ groups
141
172
  end
142
173
  else
143
174
  []
144
175
  end
145
176
  # GVP handles major itself, but it's still a bit risky to trust it with it
146
177
  # until we get it settled with new behavior. For 2.x it can take over all cases.
147
- search = if !@use_gvp
178
+ if !@use_gvp
148
179
  spec_groups
149
180
  else
150
181
  @gem_version_promoter.sort_versions(dependency, spec_groups)
151
182
  end
152
- selected_sgs = []
153
- search.each do |sg|
154
- next unless sg.for?(platform)
155
- sg_all_platforms = sg.copy_for(self.class.sort_platforms(@platforms).reverse)
156
- next unless sg_all_platforms
157
-
158
- selected_sgs << sg_all_platforms
183
+ end
159
184
 
160
- next if sg_all_platforms.activated_platforms == [Gem::Platform::RUBY]
161
- # Add a spec group for "non platform specific spec" as the fallback
162
- # spec group.
163
- sg_ruby = sg.copy_for([Gem::Platform::RUBY])
164
- next unless sg_ruby
185
+ unless search_result.empty?
186
+ specific_dependency = @variant_specific_names.include?(name)
187
+ return search_result unless specific_dependency
165
188
 
166
- selected_sgs.insert(-2, sg_ruby)
189
+ search_result.each do |sg|
190
+ if @generic_names.include?(name)
191
+ @variant_specific_names -= [name]
192
+ sg.activate_all_platforms!
193
+ else
194
+ sg.activate_platform!(platform)
195
+ end
167
196
  end
168
- selected_sgs
169
197
  end
198
+
199
+ search_result
170
200
  end
171
201
 
172
202
  def index_for(dependency)
173
- source = @source_requirements[dependency.name]
203
+ source = @index_requirements[dependency.name]
174
204
  if source
175
- source.specs
176
- elsif @lockfile_uses_separate_rubygems_sources
205
+ source
206
+ elsif @no_aggregate_global_source
177
207
  Index.build do |idx|
178
- if dependency.all_sources
179
- dependency.all_sources.each {|s| idx.add_source(s.specs) if s }
180
- else
181
- idx.add_source @source_requirements[:default].specs
182
- end
208
+ dependency.all_sources.each {|s| idx.add_source(s.specs) }
183
209
  end
184
210
  else
185
- @index
211
+ @index_requirements[:global]
186
212
  end
187
213
  end
188
214
 
215
+ def results_for(dependency, base)
216
+ index_for(dependency).search(dependency, base)
217
+ end
218
+
189
219
  def name_for(dependency)
190
220
  dependency.name
191
221
  end
@@ -213,18 +243,20 @@ module Bundler
213
243
  def relevant_sources_for_vertex(vertex)
214
244
  if vertex.root?
215
245
  [@source_requirements[vertex.name]]
216
- elsif @lockfile_uses_separate_rubygems_sources
246
+ elsif @no_aggregate_global_source
217
247
  vertex.recursive_predecessors.map do |v|
218
248
  @source_requirements[v.name]
219
- end << @source_requirements[:default]
249
+ end.compact << @source_requirements[:default]
250
+ else
251
+ []
220
252
  end
221
253
  end
222
254
 
223
255
  def sort_dependencies(dependencies, activated, conflicts)
224
256
  dependencies.sort_by do |dependency|
225
- dependency.all_sources = relevant_sources_for_vertex(activated.vertex_named(dependency.name))
226
257
  name = name_for(dependency)
227
258
  vertex = activated.vertex_named(name)
259
+ dependency.all_sources = relevant_sources_for_vertex(vertex)
228
260
  [
229
261
  @base_dg.vertex_named(name) ? 0 : 1,
230
262
  vertex.payload ? 0 : 1,
@@ -237,13 +269,6 @@ module Bundler
237
269
  end
238
270
  end
239
271
 
240
- # Sort platforms from most general to most specific
241
- def self.sort_platforms(platforms)
242
- platforms.sort_by do |platform|
243
- platform_sort_key(platform)
244
- end
245
- end
246
-
247
272
  def self.platform_sort_key(platform)
248
273
  # Prefer specific platform to not specific platform
249
274
  return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform
@@ -298,7 +323,7 @@ module Bundler
298
323
  "If you are updating multiple gems in your Gemfile at once,\n" \
299
324
  "try passing them all to `bundle update`"
300
325
  elsif source = @source_requirements[name]
301
- specs = source.specs[name]
326
+ specs = source.specs.search(name)
302
327
  versions_with_platforms = specs.map {|s| [s.version, s.platform] }
303
328
  message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n")
304
329
  message << if versions_with_platforms.any?
@@ -307,7 +332,7 @@ module Bundler
307
332
  "The source does not contain any versions of '#{name}'"
308
333
  end
309
334
  else
310
- message = "Could not find gem '#{requirement}' in any of the gem sources " \
335
+ message = "Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in any of the gem sources " \
311
336
  "listed in your Gemfile#{cache_message}."
312
337
  end
313
338
  raise GemNotFound, message
@@ -373,7 +398,7 @@ module Bundler
373
398
  if other_bundler_required
374
399
  o << "\n\n"
375
400
 
376
- candidate_specs = @source_requirements[:default_bundler].specs.search(conflict_dependency)
401
+ candidate_specs = @index_requirements[:default_bundler].search(conflict_dependency)
377
402
  if candidate_specs.any?
378
403
  target_version = candidate_specs.last.version
379
404
  new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ")
@@ -392,14 +417,8 @@ module Bundler
392
417
 
393
418
  relevant_sources = if conflict.requirement.source
394
419
  [conflict.requirement.source]
395
- elsif conflict.requirement.all_sources
396
- conflict.requirement.all_sources
397
- elsif @lockfile_uses_separate_rubygems_sources
398
- # every conflict should have an explicit group of sources when we
399
- # enforce strict pinning
400
- raise "no source set for #{conflict}"
401
420
  else
402
- []
421
+ conflict.requirement.all_sources
403
422
  end.compact.map(&:to_s).uniq.sort
404
423
 
405
424
  metadata_requirement = name.end_with?("\0")
@@ -436,23 +455,21 @@ module Bundler
436
455
  def validate_resolved_specs!(resolved_specs)
437
456
  resolved_specs.each do |v|
438
457
  name = v.name
439
- next unless sources = relevant_sources_for_vertex(v)
440
- sources.compact!
458
+ sources = relevant_sources_for_vertex(v)
459
+ next unless sources.any?
441
460
  if default_index = sources.index(@source_requirements[:default])
442
461
  sources.delete_at(default_index)
443
462
  end
444
- sources.reject! {|s| s.specs[name].empty? }
463
+ sources.reject! {|s| s.specs.search(name).empty? }
445
464
  sources.uniq!
446
465
  next if sources.size <= 1
447
466
 
448
- multisource_disabled = Bundler.feature_flag.disable_multisource?
449
-
450
467
  msg = ["The gem '#{name}' was found in multiple relevant sources."]
451
468
  msg.concat sources.map {|s| " * #{s}" }.sort
452
- msg << "You #{multisource_disabled ? :must : :should} add this gem to the source block for the source you wish it to be installed from."
469
+ msg << "You #{@no_aggregate_global_source ? :must : :should} add this gem to the source block for the source you wish it to be installed from."
453
470
  msg = msg.join("\n")
454
471
 
455
- raise SecurityError, msg if multisource_disabled
472
+ raise SecurityError, msg if @no_aggregate_global_source
456
473
  Bundler.ui.warn "Warning: #{msg}"
457
474
  end
458
475
  end
@@ -3,27 +3,37 @@
3
3
  module Bundler
4
4
  class Resolver
5
5
  class SpecGroup
6
- include GemHelpers
7
-
8
6
  attr_accessor :name, :version, :source
9
7
  attr_accessor :activated_platforms
10
8
 
11
- def initialize(all_specs)
12
- @all_specs = all_specs
13
- raise ArgumentError, "cannot initialize with an empty value" unless exemplary_spec = all_specs.first
9
+ def self.create_for(specs, all_platforms, specific_platform)
10
+ specific_platform_specs = specs[specific_platform]
11
+ return unless specific_platform_specs.any?
12
+
13
+ platforms = all_platforms.select {|p| specs[p].any? }
14
+
15
+ new(specific_platform_specs.first, specs, platforms)
16
+ end
17
+
18
+ def initialize(exemplary_spec, specs, relevant_platforms)
19
+ @exemplary_spec = exemplary_spec
14
20
  @name = exemplary_spec.name
15
21
  @version = exemplary_spec.version
16
22
  @source = exemplary_spec.source
17
23
 
18
- @activated_platforms = []
19
- @dependencies = nil
20
- @specs = Hash.new do |specs, platform|
21
- specs[platform] = select_best_platform_match(all_specs, platform)
24
+ @all_platforms = relevant_platforms
25
+ @activated_platforms = relevant_platforms
26
+ @dependencies = Hash.new do |dependencies, platforms|
27
+ dependencies[platforms] = dependencies_for(platforms)
22
28
  end
29
+ @partitioned_dependency_names = Hash.new do |partitioned_dependency_names, platforms|
30
+ partitioned_dependency_names[platforms] = partitioned_dependency_names_for(platforms)
31
+ end
32
+ @specs = specs
23
33
  end
24
34
 
25
35
  def to_specs
26
- @activated_platforms.map do |p|
36
+ activated_platforms.map do |p|
27
37
  specs = @specs[p]
28
38
  next unless specs.any?
29
39
 
@@ -35,17 +45,12 @@ module Bundler
35
45
  end.flatten.compact.uniq
36
46
  end
37
47
 
38
- def copy_for(platforms)
39
- platforms.select! {|p| for?(p) }
40
- return unless platforms.any?
41
-
42
- copied_sg = self.class.new(@all_specs)
43
- copied_sg.activated_platforms = platforms
44
- copied_sg
48
+ def activate_platform!(platform)
49
+ self.activated_platforms = [platform]
45
50
  end
46
51
 
47
- def for?(platform)
48
- @specs[platform].any?
52
+ def activate_all_platforms!
53
+ self.activated_platforms = @all_platforms
49
54
  end
50
55
 
51
56
  def to_s
@@ -54,11 +59,11 @@ module Bundler
54
59
  end
55
60
 
56
61
  def dependencies_for_activated_platforms
57
- dependencies = @activated_platforms.map {|p| __dependencies[p] }
58
- metadata_dependencies = @activated_platforms.map do |platform|
59
- metadata_dependencies(@specs[platform].first, platform)
60
- end
61
- dependencies.concat(metadata_dependencies).flatten
62
+ @dependencies[activated_platforms]
63
+ end
64
+
65
+ def partitioned_dependency_names_for_activated_platforms
66
+ @partitioned_dependency_names[activated_platforms]
62
67
  end
63
68
 
64
69
  def ==(other)
@@ -84,27 +89,37 @@ module Bundler
84
89
  protected
85
90
 
86
91
  def sorted_activated_platforms
87
- @activated_platforms.sort_by(&:to_s)
92
+ activated_platforms.sort_by(&:to_s)
88
93
  end
89
94
 
90
95
  private
91
96
 
92
- def __dependencies
93
- @dependencies = Hash.new do |dependencies, platform|
94
- dependencies[platform] = []
95
- specs = @specs[platform]
96
- if spec = specs.first
97
- spec.dependencies.each do |dep|
98
- next if dep.type == :development
99
- dependencies[platform] << DepProxy.get_proxy(dep, platform)
100
- end
101
- end
102
- dependencies[platform]
97
+ def dependencies_for(platforms)
98
+ platforms.map do |platform|
99
+ __dependencies(platform) + metadata_dependencies(platform)
100
+ end.flatten
101
+ end
102
+
103
+ def partitioned_dependency_names_for(platforms)
104
+ return @dependencies[platforms].map(&:name), [] if platforms.size == 1
105
+
106
+ @dependencies[platforms].partition do |dep_proxy|
107
+ @dependencies[platforms].count {|dp| dp.dep == dep_proxy.dep } == platforms.size
108
+ end.map {|deps| deps.map(&:name) }
109
+ end
110
+
111
+ def __dependencies(platform)
112
+ dependencies = []
113
+ @specs[platform].first.dependencies.each do |dep|
114
+ next if dep.type == :development
115
+ dependencies << DepProxy.get_proxy(dep, platform)
103
116
  end
117
+ dependencies
104
118
  end
105
119
 
106
- def metadata_dependencies(spec, platform)
107
- return [] unless spec && spec.is_a?(Gem::Specification)
120
+ def metadata_dependencies(platform)
121
+ spec = @specs[platform].first
122
+ return [] unless spec.is_a?(Gem::Specification)
108
123
  dependencies = []
109
124
  if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
110
125
  dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform)