rubygems-update 3.5.10 → 3.5.11

Sign up to get free protection for your applications and to get access to all the features.
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