rubygems-update 3.5.10 → 3.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -1
  3. data/CODE_OF_CONDUCT.md +79 -28
  4. data/CONTRIBUTING.md +2 -2
  5. data/Manifest.txt +1 -0
  6. data/bundler/CHANGELOG.md +28 -0
  7. data/bundler/lib/bundler/build_metadata.rb +2 -2
  8. data/bundler/lib/bundler/cli/install.rb +1 -1
  9. data/bundler/lib/bundler/compact_index_client/cache.rb +16 -7
  10. data/bundler/lib/bundler/constants.rb +8 -1
  11. data/bundler/lib/bundler/definition.rb +15 -24
  12. data/bundler/lib/bundler/errors.rb +14 -0
  13. data/bundler/lib/bundler/gem_helper.rb +1 -1
  14. data/bundler/lib/bundler/installer.rb +8 -8
  15. data/bundler/lib/bundler/man/bundle-add.1 +1 -1
  16. data/bundler/lib/bundler/man/bundle-binstubs.1 +1 -1
  17. data/bundler/lib/bundler/man/bundle-cache.1 +1 -1
  18. data/bundler/lib/bundler/man/bundle-check.1 +1 -1
  19. data/bundler/lib/bundler/man/bundle-clean.1 +1 -1
  20. data/bundler/lib/bundler/man/bundle-config.1 +1 -1
  21. data/bundler/lib/bundler/man/bundle-console.1 +1 -1
  22. data/bundler/lib/bundler/man/bundle-doctor.1 +1 -1
  23. data/bundler/lib/bundler/man/bundle-exec.1 +1 -1
  24. data/bundler/lib/bundler/man/bundle-gem.1 +1 -1
  25. data/bundler/lib/bundler/man/bundle-help.1 +1 -1
  26. data/bundler/lib/bundler/man/bundle-info.1 +1 -1
  27. data/bundler/lib/bundler/man/bundle-init.1 +1 -1
  28. data/bundler/lib/bundler/man/bundle-inject.1 +1 -1
  29. data/bundler/lib/bundler/man/bundle-install.1 +1 -1
  30. data/bundler/lib/bundler/man/bundle-list.1 +1 -1
  31. data/bundler/lib/bundler/man/bundle-lock.1 +1 -1
  32. data/bundler/lib/bundler/man/bundle-open.1 +1 -1
  33. data/bundler/lib/bundler/man/bundle-outdated.1 +1 -1
  34. data/bundler/lib/bundler/man/bundle-platform.1 +1 -1
  35. data/bundler/lib/bundler/man/bundle-plugin.1 +1 -1
  36. data/bundler/lib/bundler/man/bundle-pristine.1 +1 -1
  37. data/bundler/lib/bundler/man/bundle-remove.1 +1 -1
  38. data/bundler/lib/bundler/man/bundle-show.1 +1 -1
  39. data/bundler/lib/bundler/man/bundle-update.1 +1 -1
  40. data/bundler/lib/bundler/man/bundle-version.1 +1 -1
  41. data/bundler/lib/bundler/man/bundle-viz.1 +1 -1
  42. data/bundler/lib/bundler/man/bundle.1 +1 -1
  43. data/bundler/lib/bundler/man/gemfile.5 +1 -1
  44. data/bundler/lib/bundler/rubygems_ext.rb +20 -12
  45. data/bundler/lib/bundler/self_manager.rb +1 -1
  46. data/bundler/lib/bundler/shared_helpers.rb +6 -4
  47. data/bundler/lib/bundler/source/git/git_proxy.rb +8 -0
  48. data/bundler/lib/bundler/source/metadata.rb +2 -0
  49. data/bundler/lib/bundler/source/rubygems.rb +3 -2
  50. data/bundler/lib/bundler/source_list.rb +13 -2
  51. data/bundler/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +77 -29
  52. data/bundler/lib/bundler/version.rb +1 -1
  53. data/exe/update_rubygems +1 -1
  54. data/lib/rubygems/commands/pristine_command.rb +9 -6
  55. data/lib/rubygems/commands/setup_command.rb +2 -0
  56. data/lib/rubygems/commands/uninstall_command.rb +1 -1
  57. data/lib/rubygems/dependency.rb +1 -13
  58. data/lib/rubygems/ext/cargo_builder.rb +1 -16
  59. data/lib/rubygems/installer.rb +1 -1
  60. data/lib/rubygems/package/tar_header.rb +20 -4
  61. data/lib/rubygems/package.rb +0 -1
  62. data/lib/rubygems/platform.rb +1 -0
  63. data/lib/rubygems/specification.rb +35 -117
  64. data/lib/rubygems/specification_policy.rb +3 -1
  65. data/lib/rubygems/specification_record.rb +213 -0
  66. data/lib/rubygems/uninstaller.rb +15 -9
  67. data/lib/rubygems/util/licenses.rb +25 -0
  68. data/lib/rubygems.rb +8 -1
  69. data/rubygems-update.gemspec +1 -1
  70. metadata +4 -3
@@ -185,6 +185,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
185
185
  end
186
186
 
187
187
  def cargo_dylib_path(dest_path, crate_name)
188
+ so_ext = RbConfig::CONFIG["SOEXT"]
188
189
  prefix = so_ext == "dll" ? "" : "lib"
189
190
  path_parts = [dest_path]
190
191
  path_parts << ENV["CARGO_BUILD_TARGET"] if ENV["CARGO_BUILD_TARGET"]
@@ -313,22 +314,6 @@ EOF
313
314
  deffile_path
314
315
  end
315
316
 
316
- # We have to basically reimplement <code>RbConfig::CONFIG['SOEXT']</code> here to support
317
- # Ruby < 2.5
318
- #
319
- # @see https://github.com/ruby/ruby/blob/c87c027f18c005460746a74c07cd80ee355b16e4/configure.ac#L3185
320
- def so_ext
321
- return RbConfig::CONFIG["SOEXT"] if RbConfig::CONFIG.key?("SOEXT")
322
-
323
- if win_target?
324
- "dll"
325
- elsif darwin_target?
326
- "dylib"
327
- else
328
- "so"
329
- end
330
- end
331
-
332
317
  # Corresponds to $(LIBPATH) in mkmf
333
318
  def mkmf_libpath
334
319
  ["-L", "native=#{makefile_config("libdir")}"]
@@ -344,7 +344,7 @@ class Gem::Installer
344
344
 
345
345
  say spec.post_install_message if options[:post_install_message] && !spec.post_install_message.nil?
346
346
 
347
- Gem::Specification.add_spec(spec)
347
+ Gem::Specification.add_spec(spec) unless @install_dir
348
348
 
349
349
  load_plugin
350
350
 
@@ -95,14 +95,14 @@ class Gem::Package::TarHeader
95
95
 
96
96
  attr_reader(*FIELDS)
97
97
 
98
- EMPTY_HEADER = ("\0" * 512).freeze # :nodoc:
98
+ EMPTY_HEADER = ("\0" * 512).b.freeze # :nodoc:
99
99
 
100
100
  ##
101
101
  # Creates a tar header from IO +stream+
102
102
 
103
103
  def self.from(stream)
104
104
  header = stream.read 512
105
- empty = (header == EMPTY_HEADER)
105
+ return EMPTY if header == EMPTY_HEADER
106
106
 
107
107
  fields = header.unpack UNPACK_FORMAT
108
108
 
@@ -123,7 +123,7 @@ class Gem::Package::TarHeader
123
123
  devminor: strict_oct(fields.shift),
124
124
  prefix: fields.shift,
125
125
 
126
- empty: empty
126
+ empty: false
127
127
  end
128
128
 
129
129
  def self.strict_oct(str)
@@ -172,6 +172,22 @@ class Gem::Package::TarHeader
172
172
  @empty = vals[:empty]
173
173
  end
174
174
 
175
+ EMPTY = new({ # :nodoc:
176
+ checksum: 0,
177
+ gname: "",
178
+ linkname: "",
179
+ magic: "",
180
+ mode: 0,
181
+ name: "",
182
+ prefix: "",
183
+ size: 0,
184
+ uname: "",
185
+ version: 0,
186
+
187
+ empty: true,
188
+ }).freeze
189
+ private_constant :EMPTY
190
+
175
191
  ##
176
192
  # Is the tar entry empty?
177
193
 
@@ -241,7 +257,7 @@ class Gem::Package::TarHeader
241
257
 
242
258
  header = header.pack PACK_FORMAT
243
259
 
244
- header << ("\0" * ((512 - header.size) % 512))
260
+ header.ljust 512, "\0"
245
261
  end
246
262
 
247
263
  def oct(num, len)
@@ -294,7 +294,6 @@ class Gem::Package
294
294
 
295
295
  Gem.load_yaml
296
296
 
297
- @spec.mark_version
298
297
  @spec.validate true, strict_validation unless skip_validation
299
298
 
300
299
  setup_signer(
@@ -134,6 +134,7 @@ class Gem::Platform
134
134
  when /netbsdelf/ then ["netbsdelf", nil]
135
135
  when /openbsd(\d+\.\d+)?/ then ["openbsd", $1]
136
136
  when /solaris(\d+\.\d+)?/ then ["solaris", $1]
137
+ when /wasi/ then ["wasi", nil]
137
138
  # test
138
139
  when /^(\w+_platform)(\d+)?/ then [$1, $2]
139
140
  else ["unknown", nil]
@@ -11,6 +11,7 @@ require_relative "deprecate"
11
11
  require_relative "basic_specification"
12
12
  require_relative "stub_specification"
13
13
  require_relative "platform"
14
+ require_relative "specification_record"
14
15
  require_relative "util/list"
15
16
 
16
17
  require "rbconfig"
@@ -179,22 +180,12 @@ class Gem::Specification < Gem::BasicSpecification
179
180
  @@default_value[k].nil?
180
181
  end
181
182
 
182
- def self.clear_specs # :nodoc:
183
- @@all = nil
184
- @@stubs = nil
185
- @@stubs_by_name = {}
186
- @@spec_with_requirable_file = {}
187
- @@active_stub_with_requirable_file = {}
188
- end
189
- private_class_method :clear_specs
190
-
191
- clear_specs
192
-
193
183
  # Sentinel object to represent "not found" stubs
194
184
  NOT_FOUND = Struct.new(:to_spec, :this).new # :nodoc:
185
+ deprecate_constant :NOT_FOUND
195
186
 
196
187
  # Tracking removed method calls to warn users during build time.
197
- REMOVED_METHODS = [:rubyforge_project=].freeze # :nodoc:
188
+ REMOVED_METHODS = [:rubyforge_project=, :mark_version].freeze # :nodoc:
198
189
  def removed_method_calls
199
190
  @removed_method_calls ||= []
200
191
  end
@@ -770,7 +761,7 @@ class Gem::Specification < Gem::BasicSpecification
770
761
  attr_accessor :specification_version
771
762
 
772
763
  def self._all # :nodoc:
773
- @@all ||= Gem.loaded_specs.values | stubs.map(&:to_spec)
764
+ specification_record.all
774
765
  end
775
766
 
776
767
  def self.clear_load_cache # :nodoc:
@@ -788,26 +779,9 @@ class Gem::Specification < Gem::BasicSpecification
788
779
  end
789
780
  end
790
781
 
791
- def self.gemspec_stubs_in(dir, pattern)
782
+ def self.gemspec_stubs_in(dir, pattern) # :nodoc:
792
783
  Gem::Util.glob_files_in_dir(pattern, dir).map {|path| yield path }.select(&:valid?)
793
784
  end
794
- private_class_method :gemspec_stubs_in
795
-
796
- def self.installed_stubs(dirs, pattern)
797
- map_stubs(dirs, pattern) do |path, base_dir, gems_dir|
798
- Gem::StubSpecification.gemspec_stub(path, base_dir, gems_dir)
799
- end
800
- end
801
- private_class_method :installed_stubs
802
-
803
- def self.map_stubs(dirs, pattern) # :nodoc:
804
- dirs.flat_map do |dir|
805
- base_dir = File.dirname dir
806
- gems_dir = File.join base_dir, "gems"
807
- gemspec_stubs_in(dir, pattern) {|path| yield path, base_dir, gems_dir }
808
- end
809
- end
810
- private_class_method :map_stubs
811
785
 
812
786
  def self.each_spec(dirs) # :nodoc:
813
787
  each_gemspec(dirs) do |path|
@@ -820,13 +794,7 @@ class Gem::Specification < Gem::BasicSpecification
820
794
  # Returns a Gem::StubSpecification for every installed gem
821
795
 
822
796
  def self.stubs
823
- @@stubs ||= begin
824
- pattern = "*.gemspec"
825
- stubs = stubs_for_pattern(pattern, false)
826
-
827
- @@stubs_by_name = stubs.select {|s| Gem::Platform.match_spec? s }.group_by(&:name)
828
- stubs
829
- end
797
+ specification_record.stubs
830
798
  end
831
799
 
832
800
  ##
@@ -845,13 +813,7 @@ class Gem::Specification < Gem::BasicSpecification
845
813
  # only returns stubs that match Gem.platforms
846
814
 
847
815
  def self.stubs_for(name)
848
- if @@stubs
849
- @@stubs_by_name[name] || []
850
- else
851
- @@stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec").select do |s|
852
- s.name == name
853
- end
854
- end
816
+ specification_record.stubs_for(name)
855
817
  end
856
818
 
857
819
  ##
@@ -859,12 +821,7 @@ class Gem::Specification < Gem::BasicSpecification
859
821
  # optionally filtering out specs not matching the current platform
860
822
  #
861
823
  def self.stubs_for_pattern(pattern, match_platform = true) # :nodoc:
862
- installed_stubs = installed_stubs(Gem::Specification.dirs, pattern)
863
- installed_stubs.select! {|s| Gem::Platform.match_spec? s } if match_platform
864
- stubs = installed_stubs + default_stubs(pattern)
865
- stubs = stubs.uniq(&:full_name)
866
- _resort!(stubs)
867
- stubs
824
+ specification_record.stubs_for_pattern(pattern, match_platform)
868
825
  end
869
826
 
870
827
  def self._resort!(specs) # :nodoc:
@@ -893,23 +850,14 @@ class Gem::Specification < Gem::BasicSpecification
893
850
  # properly sorted.
894
851
 
895
852
  def self.add_spec(spec)
896
- return if _all.include? spec
897
-
898
- _all << spec
899
- stubs << spec
900
- (@@stubs_by_name[spec.name] ||= []) << spec
901
-
902
- _resort!(@@stubs_by_name[spec.name])
903
- _resort!(stubs)
853
+ specification_record.add_spec(spec)
904
854
  end
905
855
 
906
856
  ##
907
857
  # Removes +spec+ from the known specs.
908
858
 
909
859
  def self.remove_spec(spec)
910
- _all.delete spec.to_spec
911
- stubs.delete spec
912
- (@@stubs_by_name[spec.name] || []).delete spec
860
+ specification_record.remove_spec(spec)
913
861
  end
914
862
 
915
863
  ##
@@ -923,27 +871,17 @@ class Gem::Specification < Gem::BasicSpecification
923
871
  end
924
872
 
925
873
  ##
926
- # Sets the known specs to +specs+. Not guaranteed to work for you in
927
- # the future. Use at your own risk. Caveat emptor. Doomy doom doom.
928
- # Etc etc.
929
- #
930
- #--
931
- # Makes +specs+ the known specs
932
- # Listen, time is a river
933
- # Winter comes, code breaks
934
- #
935
- # -- wilsonb
874
+ # Sets the known specs to +specs+.
936
875
 
937
876
  def self.all=(specs)
938
- @@stubs_by_name = specs.group_by(&:name)
939
- @@all = @@stubs = specs
877
+ specification_record.all = specs
940
878
  end
941
879
 
942
880
  ##
943
881
  # Return full names of all specs in sorted order.
944
882
 
945
883
  def self.all_names
946
- _all.map(&:full_name)
884
+ specification_record.all_names
947
885
  end
948
886
 
949
887
  ##
@@ -968,9 +906,7 @@ class Gem::Specification < Gem::BasicSpecification
968
906
  # Return the directories that Specification uses to find specs.
969
907
 
970
908
  def self.dirs
971
- @@dirs ||= Gem.path.collect do |dir|
972
- File.join dir, "specifications"
973
- end
909
+ @@dirs ||= Gem::SpecificationRecord.dirs_from(Gem.path)
974
910
  end
975
911
 
976
912
  ##
@@ -980,7 +916,7 @@ class Gem::Specification < Gem::BasicSpecification
980
916
  def self.dirs=(dirs)
981
917
  reset
982
918
 
983
- @@dirs = Array(dirs).map {|dir| File.join dir, "specifications" }
919
+ @@dirs = Gem::SpecificationRecord.dirs_from(Array(dirs))
984
920
  end
985
921
 
986
922
  extend Enumerable
@@ -989,21 +925,15 @@ class Gem::Specification < Gem::BasicSpecification
989
925
  # Enumerate every known spec. See ::dirs= and ::add_spec to set the list of
990
926
  # specs.
991
927
 
992
- def self.each
993
- return enum_for(:each) unless block_given?
994
-
995
- _all.each do |x|
996
- yield x
997
- end
928
+ def self.each(&block)
929
+ specification_record.each(&block)
998
930
  end
999
931
 
1000
932
  ##
1001
933
  # Returns every spec that matches +name+ and optional +requirements+.
1002
934
 
1003
935
  def self.find_all_by_name(name, *requirements)
1004
- requirements = Gem::Requirement.default if requirements.empty?
1005
-
1006
- Gem::Dependency.new(name, *requirements).matching_specs
936
+ specification_record.find_all_by_name(name, *requirements)
1007
937
  end
1008
938
 
1009
939
  ##
@@ -1033,12 +963,7 @@ class Gem::Specification < Gem::BasicSpecification
1033
963
  # Return the best specification that contains the file matching +path+.
1034
964
 
1035
965
  def self.find_by_path(path)
1036
- path = path.dup.freeze
1037
- spec = @@spec_with_requirable_file[path] ||= stubs.find do |s|
1038
- s.contains_requirable_file? path
1039
- end || NOT_FOUND
1040
-
1041
- spec.to_spec
966
+ specification_record.find_by_path(path)
1042
967
  end
1043
968
 
1044
969
  ##
@@ -1046,19 +971,15 @@ class Gem::Specification < Gem::BasicSpecification
1046
971
  # amongst the specs that are not activated.
1047
972
 
1048
973
  def self.find_inactive_by_path(path)
1049
- stub = stubs.find do |s|
1050
- next if s.activated?
1051
- s.contains_requirable_file? path
1052
- end
1053
- stub&.to_spec
974
+ specification_record.find_inactive_by_path(path)
1054
975
  end
1055
976
 
1056
- def self.find_active_stub_by_path(path)
1057
- stub = @@active_stub_with_requirable_file[path] ||= stubs.find do |s|
1058
- s.activated? && s.contains_requirable_file?(path)
1059
- end || NOT_FOUND
977
+ ##
978
+ # Return the best specification that contains the file matching +path+, among
979
+ # those already activated.
1060
980
 
1061
- stub.this
981
+ def self.find_active_stub_by_path(path)
982
+ specification_record.find_active_stub_by_path(path)
1062
983
  end
1063
984
 
1064
985
  ##
@@ -1125,14 +1046,14 @@ class Gem::Specification < Gem::BasicSpecification
1125
1046
  # +prerelease+ is true.
1126
1047
 
1127
1048
  def self.latest_specs(prerelease = false)
1128
- _latest_specs Gem::Specification.stubs, prerelease
1049
+ specification_record.latest_specs(prerelease)
1129
1050
  end
1130
1051
 
1131
1052
  ##
1132
1053
  # Return the latest installed spec for gem +name+.
1133
1054
 
1134
1055
  def self.latest_spec_for(name)
1135
- latest_specs(true).find {|installed_spec| installed_spec.name == name }
1056
+ specification_record.latest_spec_for(name)
1136
1057
  end
1137
1058
 
1138
1059
  def self._latest_specs(specs, prerelease = false) # :nodoc:
@@ -1270,7 +1191,7 @@ class Gem::Specification < Gem::BasicSpecification
1270
1191
  def self.reset
1271
1192
  @@dirs = nil
1272
1193
  Gem.pre_reset_hooks.each(&:call)
1273
- clear_specs
1194
+ @specification_record = nil
1274
1195
  clear_load_cache
1275
1196
  unresolved = unresolved_deps
1276
1197
  unless unresolved.empty?
@@ -1291,6 +1212,13 @@ class Gem::Specification < Gem::BasicSpecification
1291
1212
  Gem.post_reset_hooks.each(&:call)
1292
1213
  end
1293
1214
 
1215
+ ##
1216
+ # Keeps track of all currently known specifications
1217
+
1218
+ def self.specification_record
1219
+ @specification_record ||= Gem::SpecificationRecord.new(dirs)
1220
+ end
1221
+
1294
1222
  # DOC: This method needs documented or nodoc'd
1295
1223
  def self.unresolved_deps
1296
1224
  @unresolved_deps ||= Hash.new {|h, n| h[n] = Gem::Dependency.new n }
@@ -1874,8 +1802,6 @@ class Gem::Specification < Gem::BasicSpecification
1874
1802
  end
1875
1803
 
1876
1804
  def encode_with(coder) # :nodoc:
1877
- mark_version
1878
-
1879
1805
  coder.add "name", @name
1880
1806
  coder.add "version", @version
1881
1807
  platform = case @original_platform
@@ -2169,13 +2095,6 @@ class Gem::Specification < Gem::BasicSpecification
2169
2095
  @spec_file = nil
2170
2096
  end
2171
2097
 
2172
- ##
2173
- # Sets the rubygems_version to the current RubyGems version.
2174
-
2175
- def mark_version
2176
- @rubygems_version = Gem::VERSION
2177
- end
2178
-
2179
2098
  ##
2180
2099
  # Track removed method calls to warn about during build time.
2181
2100
  # Warn about unknown attributes while loading a spec.
@@ -2493,7 +2412,6 @@ class Gem::Specification < Gem::BasicSpecification
2493
2412
  # still have their default values are omitted.
2494
2413
 
2495
2414
  def to_ruby
2496
- mark_version
2497
2415
  result = []
2498
2416
  result << "# -*- encoding: utf-8 -*-"
2499
2417
  result << "#{Gem::StubSpecification::PREFIX}#{name} #{version} #{platform} #{raw_require_paths.join("\0")}"
@@ -274,7 +274,9 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
274
274
 
275
275
  return if rubygems_version == Gem::VERSION
276
276
 
277
- error "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}"
277
+ warning "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}"
278
+
279
+ @specification.rubygems_version = Gem::VERSION
278
280
  end
279
281
 
280
282
  def validate_required_attributes
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gem
4
+ class SpecificationRecord
5
+ def self.dirs_from(paths)
6
+ paths.map do |path|
7
+ File.join(path, "specifications")
8
+ end
9
+ end
10
+
11
+ def self.from_path(path)
12
+ new(dirs_from([path]))
13
+ end
14
+
15
+ def initialize(dirs)
16
+ @all = nil
17
+ @stubs = nil
18
+ @stubs_by_name = {}
19
+ @spec_with_requirable_file = {}
20
+ @active_stub_with_requirable_file = {}
21
+
22
+ @dirs = dirs
23
+ end
24
+
25
+ # Sentinel object to represent "not found" stubs
26
+ NOT_FOUND = Struct.new(:to_spec, :this).new
27
+ private_constant :NOT_FOUND
28
+
29
+ ##
30
+ # Returns the list of all specifications in the record
31
+
32
+ def all
33
+ @all ||= Gem.loaded_specs.values | stubs.map(&:to_spec)
34
+ end
35
+
36
+ ##
37
+ # Returns a Gem::StubSpecification for every specification in the record
38
+
39
+ def stubs
40
+ @stubs ||= begin
41
+ pattern = "*.gemspec"
42
+ stubs = stubs_for_pattern(pattern, false)
43
+
44
+ @stubs_by_name = stubs.select {|s| Gem::Platform.match_spec? s }.group_by(&:name)
45
+ stubs
46
+ end
47
+ end
48
+
49
+ ##
50
+ # Returns a Gem::StubSpecification for every specification in the record
51
+ # named +name+ only returns stubs that match Gem.platforms
52
+
53
+ def stubs_for(name)
54
+ if @stubs
55
+ @stubs_by_name[name] || []
56
+ else
57
+ @stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec").select do |s|
58
+ s.name == name
59
+ end
60
+ end
61
+ end
62
+
63
+ ##
64
+ # Finds stub specifications matching a pattern in the record, optionally
65
+ # filtering out specs not matching the current platform
66
+
67
+ def stubs_for_pattern(pattern, match_platform = true)
68
+ installed_stubs = installed_stubs(pattern)
69
+ installed_stubs.select! {|s| Gem::Platform.match_spec? s } if match_platform
70
+ stubs = installed_stubs + Gem::Specification.default_stubs(pattern)
71
+ stubs = stubs.uniq(&:full_name)
72
+ Gem::Specification._resort!(stubs)
73
+ stubs
74
+ end
75
+
76
+ ##
77
+ # Adds +spec+ to the the record, keeping the collection properly sorted.
78
+
79
+ def add_spec(spec)
80
+ return if all.include? spec
81
+
82
+ all << spec
83
+ stubs << spec
84
+ (@stubs_by_name[spec.name] ||= []) << spec
85
+
86
+ Gem::Specification._resort!(@stubs_by_name[spec.name])
87
+ Gem::Specification._resort!(stubs)
88
+ end
89
+
90
+ ##
91
+ # Removes +spec+ from the record.
92
+
93
+ def remove_spec(spec)
94
+ all.delete spec.to_spec
95
+ stubs.delete spec
96
+ (@stubs_by_name[spec.name] || []).delete spec
97
+ end
98
+
99
+ ##
100
+ # Sets the specs known by the record to +specs+.
101
+
102
+ def all=(specs)
103
+ @stubs_by_name = specs.group_by(&:name)
104
+ @all = @stubs = specs
105
+ end
106
+
107
+ ##
108
+ # Return full names of all specs in the record in sorted order.
109
+
110
+ def all_names
111
+ all.map(&:full_name)
112
+ end
113
+
114
+ include Enumerable
115
+
116
+ ##
117
+ # Enumerate every known spec.
118
+
119
+ def each
120
+ return enum_for(:each) unless block_given?
121
+
122
+ all.each do |x|
123
+ yield x
124
+ end
125
+ end
126
+
127
+ ##
128
+ # Returns every spec in the record that matches +name+ and optional +requirements+.
129
+
130
+ def find_all_by_name(name, *requirements)
131
+ req = Gem::Requirement.create(*requirements)
132
+ env_req = Gem.env_requirement(name)
133
+
134
+ matches = stubs_for(name).find_all do |spec|
135
+ req.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
136
+ end.map(&:to_spec)
137
+
138
+ if name == "bundler" && !req.specific?
139
+ require_relative "bundler_version_finder"
140
+ Gem::BundlerVersionFinder.prioritize!(matches)
141
+ end
142
+
143
+ matches
144
+ end
145
+
146
+ ##
147
+ # Return the best specification in the record that contains the file matching +path+.
148
+
149
+ def find_by_path(path)
150
+ path = path.dup.freeze
151
+ spec = @spec_with_requirable_file[path] ||= stubs.find do |s|
152
+ s.contains_requirable_file? path
153
+ end || NOT_FOUND
154
+
155
+ spec.to_spec
156
+ end
157
+
158
+ ##
159
+ # Return the best specification in the record that contains the file
160
+ # matching +path+ amongst the specs that are not activated.
161
+
162
+ def find_inactive_by_path(path)
163
+ stub = stubs.find do |s|
164
+ next if s.activated?
165
+ s.contains_requirable_file? path
166
+ end
167
+ stub&.to_spec
168
+ end
169
+
170
+ ##
171
+ # Return the best specification in the record that contains the file
172
+ # matching +path+, among those already activated.
173
+
174
+ def find_active_stub_by_path(path)
175
+ stub = @active_stub_with_requirable_file[path] ||= stubs.find do |s|
176
+ s.activated? && s.contains_requirable_file?(path)
177
+ end || NOT_FOUND
178
+
179
+ stub.this
180
+ end
181
+
182
+ ##
183
+ # Return the latest specs in the record, optionally including prerelease
184
+ # specs if +prerelease+ is true.
185
+
186
+ def latest_specs(prerelease)
187
+ Gem::Specification._latest_specs stubs, prerelease
188
+ end
189
+
190
+ ##
191
+ # Return the latest installed spec in the record for gem +name+.
192
+
193
+ def latest_spec_for(name)
194
+ latest_specs(true).find {|installed_spec| installed_spec.name == name }
195
+ end
196
+
197
+ private
198
+
199
+ def installed_stubs(pattern)
200
+ map_stubs(pattern) do |path, base_dir, gems_dir|
201
+ Gem::StubSpecification.gemspec_stub(path, base_dir, gems_dir)
202
+ end
203
+ end
204
+
205
+ def map_stubs(pattern)
206
+ @dirs.flat_map do |dir|
207
+ base_dir = File.dirname dir
208
+ gems_dir = File.join base_dir, "gems"
209
+ Gem::Specification.gemspec_stubs_in(dir, pattern) {|path| yield path, base_dir, gems_dir }
210
+ end
211
+ end
212
+ end
213
+ end