rubygems-update 3.2.2 → 3.2.3

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +12 -0
  3. data/Manifest.txt +2 -0
  4. data/bundler/CHANGELOG.md +9 -0
  5. data/bundler/lib/bundler.rb +3 -6
  6. data/bundler/lib/bundler/build_metadata.rb +2 -2
  7. data/bundler/lib/bundler/cli/update.rb +1 -1
  8. data/bundler/lib/bundler/compact_index_client/cache.rb +5 -13
  9. data/bundler/lib/bundler/compact_index_client/gem_parser.rb +28 -0
  10. data/bundler/lib/bundler/definition.rb +26 -14
  11. data/bundler/lib/bundler/gem_helpers.rb +30 -24
  12. data/bundler/lib/bundler/lazy_specification.rb +10 -11
  13. data/bundler/lib/bundler/resolver/spec_group.rb +14 -16
  14. data/bundler/lib/bundler/rubygems_integration.rb +0 -5
  15. data/bundler/lib/bundler/spec_set.rb +5 -8
  16. data/bundler/lib/bundler/version.rb +1 -1
  17. data/lib/rubygems.rb +1 -1
  18. data/lib/rubygems/dependency_installer.rb +1 -0
  19. data/lib/rubygems/gemcutter_utilities.rb +2 -2
  20. data/lib/rubygems/installer.rb +0 -23
  21. data/lib/rubygems/remote_fetcher.rb +1 -1
  22. data/lib/rubygems/request_set.rb +2 -13
  23. data/lib/rubygems/resolver.rb +6 -1
  24. data/lib/rubygems/resolver/api_set.rb +28 -19
  25. data/lib/rubygems/resolver/api_set/gem_parser.rb +20 -0
  26. data/lib/rubygems/resolver/api_specification.rb +4 -3
  27. data/lib/rubygems/resolver/best_set.rb +1 -1
  28. data/lib/rubygems/resolver/index_specification.rb +15 -0
  29. data/lib/rubygems/resolver/installer_set.rb +57 -7
  30. data/lib/rubygems/resolver/spec_specification.rb +14 -0
  31. data/lib/rubygems/resolver/specification.rb +12 -0
  32. data/lib/rubygems/source.rb +10 -6
  33. data/rubygems-update.gemspec +1 -1
  34. data/test/rubygems/test_gem_commands_install_command.rb +131 -0
  35. data/test/rubygems/test_gem_installer.rb +6 -60
  36. data/test/rubygems/test_gem_resolver_api_set.rb +26 -52
  37. data/test/rubygems/test_gem_resolver_api_specification.rb +3 -3
  38. data/test/rubygems/test_gem_resolver_best_set.rb +3 -3
  39. data/test/rubygems/test_gem_source.rb +2 -2
  40. data/test/rubygems/test_gem_source_subpath_problem.rb +2 -2
  41. metadata +5 -3
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  module Bundler
4
- VERSION = "2.2.2".freeze
4
+ VERSION = "2.2.3".freeze
5
5
 
6
6
  def self.bundler_major_version
7
7
  @bundler_major_version ||= VERSION.split(".").first.to_i
@@ -8,7 +8,7 @@
8
8
  require 'rbconfig'
9
9
 
10
10
  module Gem
11
- VERSION = "3.2.2".freeze
11
+ VERSION = "3.2.3".freeze
12
12
  end
13
13
 
14
14
  # Must be first since it unloads the prelude from 1.9.2
@@ -286,6 +286,7 @@ class Gem::DependencyInstaller
286
286
 
287
287
  installer_set = Gem::Resolver::InstallerSet.new @domain
288
288
  installer_set.ignore_installed = (@minimal_deps == false) || @only_install_dir
289
+ installer_set.force = @force
289
290
 
290
291
  if consider_local?
291
292
  if dep_or_name =~ /\.gem$/ and File.file? dep_or_name
@@ -260,8 +260,8 @@ module Gem::GemcutterUtilities
260
260
  end
261
261
 
262
262
  def get_key_name(scope)
263
- hostname = Socket.gethostname || "unkown-host"
264
- user = ENV["USER"] || ENV["USERNAME"] || "unkown-user"
263
+ hostname = Socket.gethostname || "unknown-host"
264
+ user = ENV["USER"] || ENV["USERNAME"] || "unknown-user"
265
265
  ts = Time.now.strftime("%Y%m%d%H%M%S")
266
266
  default_key_name = "#{hostname}-#{user}-#{ts}"
267
267
 
@@ -638,27 +638,6 @@ class Gem::Installer
638
638
  end
639
639
  end
640
640
 
641
- def ensure_required_ruby_version_met # :nodoc:
642
- if rrv = spec.required_ruby_version
643
- ruby_version = Gem.ruby_version
644
- unless rrv.satisfied_by? ruby_version
645
- raise Gem::RuntimeRequirementNotMetError,
646
- "#{spec.name} requires Ruby version #{rrv}. The current ruby version is #{ruby_version}."
647
- end
648
- end
649
- end
650
-
651
- def ensure_required_rubygems_version_met # :nodoc:
652
- if rrgv = spec.required_rubygems_version
653
- unless rrgv.satisfied_by? Gem.rubygems_version
654
- rg_version = Gem::VERSION
655
- raise Gem::RuntimeRequirementNotMetError,
656
- "#{spec.name} requires RubyGems version #{rrgv}. The current RubyGems version is #{rg_version}. " +
657
- "Try 'gem update --system' to update RubyGems itself."
658
- end
659
- end
660
- end
661
-
662
641
  def ensure_dependencies_met # :nodoc:
663
642
  deps = spec.runtime_dependencies
664
643
  deps |= spec.development_dependencies if @development
@@ -914,8 +893,6 @@ TEXT
914
893
 
915
894
  return true if @force
916
895
 
917
- ensure_required_ruby_version_met
918
- ensure_required_rubygems_version_met
919
896
  ensure_dependencies_met unless @ignore_dependencies
920
897
 
921
898
  true
@@ -215,7 +215,7 @@ class Gem::RemoteFetcher
215
215
 
216
216
  case response
217
217
  when Net::HTTPOK, Net::HTTPNotModified then
218
- response.uri = uri if response.respond_to? :uri
218
+ response.uri = uri
219
219
  head ? response : response.body
220
220
  when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther,
221
221
  Net::HTTPTemporaryRedirect then
@@ -195,19 +195,8 @@ class Gem::RequestSet
195
195
  yield req, installer if block_given?
196
196
  end
197
197
  rescue Gem::RuntimeRequirementNotMetError => e
198
- recent_match = req.spec.set.find_all(req.request).sort_by(&:version).reverse_each.find do |s|
199
- s = s.spec
200
- s.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
201
- s.required_rubygems_version.satisfied_by?(Gem.rubygems_version) &&
202
- Gem::Platform.installable?(s)
203
- end
204
- if recent_match
205
- suggestion = "The last version of #{req.request} to support your Ruby & RubyGems was #{recent_match.version}. Try installing it with `gem install #{recent_match.name} -v #{recent_match.version}`"
206
- suggestion += " and then running the current command again" unless @always_install.include?(req.spec.spec)
207
- else
208
- suggestion = "There are no versions of #{req.request} compatible with your Ruby & RubyGems"
209
- suggestion += ". Maybe try installing an older version of the gem you're looking for?" unless @always_install.include?(req.spec.spec)
210
- end
198
+ suggestion = "There are no versions of #{req.request} compatible with your Ruby & RubyGems"
199
+ suggestion += ". Maybe try installing an older version of the gem you're looking for?" unless @always_install.include?(req.spec.spec)
211
200
  e.suggestion = suggestion
212
201
  raise
213
202
  end
@@ -261,7 +261,12 @@ class Gem::Resolver
261
261
  end
262
262
 
263
263
  def requirement_satisfied_by?(requirement, activated, spec)
264
- requirement.matches_spec? spec
264
+ matches_spec = requirement.matches_spec? spec
265
+ return matches_spec if @soft_missing
266
+
267
+ matches_spec &&
268
+ spec.spec.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
269
+ spec.spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version)
265
270
  end
266
271
 
267
272
  def name_for(dependency)
@@ -4,6 +4,8 @@
4
4
  # Returns instances of APISpecification.
5
5
 
6
6
  class Gem::Resolver::APISet < Gem::Resolver::Set
7
+ autoload :GemParser, File.expand_path("api_set/gem_parser", __dir__)
8
+
7
9
  ##
8
10
  # The URI for the dependency API this APISet uses.
9
11
 
@@ -24,13 +26,13 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
24
26
  # API URL +dep_uri+ which is described at
25
27
  # https://guides.rubygems.org/rubygems-org-api
26
28
 
27
- def initialize(dep_uri = 'https://rubygems.org/api/v1/dependencies')
29
+ def initialize(dep_uri = 'https://index.rubygems.org/info/')
28
30
  super()
29
31
 
30
32
  dep_uri = URI dep_uri unless URI === dep_uri
31
33
 
32
34
  @dep_uri = dep_uri
33
- @uri = dep_uri + '../..'
35
+ @uri = dep_uri + '..'
34
36
 
35
37
  @data = Hash.new {|h,k| h[k] = [] }
36
38
  @source = Gem::Source.new @uri
@@ -75,20 +77,8 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
75
77
  def prefetch_now # :nodoc:
76
78
  needed, @to_fetch = @to_fetch, []
77
79
 
78
- uri = @dep_uri + "?gems=#{needed.sort.join ','}"
79
- str = Gem::RemoteFetcher.fetcher.fetch_path uri
80
-
81
- loaded = []
82
-
83
- Marshal.load(str).each do |ver|
84
- name = ver[:name]
85
-
86
- @data[name] << ver
87
- loaded << name
88
- end
89
-
90
- (needed - loaded).each do |missing|
91
- @data[missing] = []
80
+ needed.sort.each do |name|
81
+ versions(name)
92
82
  end
93
83
  end
94
84
 
@@ -111,13 +101,32 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
111
101
  return @data[name]
112
102
  end
113
103
 
114
- uri = @dep_uri + "?gems=#{name}"
104
+ uri = @dep_uri + name
115
105
  str = Gem::RemoteFetcher.fetcher.fetch_path uri
116
106
 
117
- Marshal.load(str).each do |ver|
118
- @data[ver[:name]] << ver
107
+ lines(str).each do |ver|
108
+ number, platform, dependencies, requirements = parse_gem(ver)
109
+
110
+ platform ||= "ruby"
111
+ dependencies = dependencies.map {|dep_name, reqs| [dep_name, reqs.join(", ")] }
112
+ requirements = requirements.map {|req_name, reqs| [req_name.to_sym, reqs] }.to_h
113
+
114
+ @data[name] << { name: name, number: number, platform: platform, dependencies: dependencies, requirements: requirements }
119
115
  end
120
116
 
121
117
  @data[name]
122
118
  end
119
+
120
+ private
121
+
122
+ def lines(str)
123
+ lines = str.split("\n")
124
+ header = lines.index("---")
125
+ header ? lines[header + 1..-1] : lines
126
+ end
127
+
128
+ def parse_gem(string)
129
+ @gem_parser ||= GemParser.new
130
+ @gem_parser.parse(string)
131
+ end
123
132
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gem::Resolver::APISet::GemParser
4
+ def parse(line)
5
+ version_and_platform, rest = line.split(" ", 2)
6
+ version, platform = version_and_platform.split("-", 2)
7
+ dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
8
+ dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
9
+ requirements = requirements ? requirements.map {|d| parse_dependency(d) } : []
10
+ [version, platform, dependencies, requirements]
11
+ end
12
+
13
+ private
14
+
15
+ def parse_dependency(string)
16
+ dependency = string.split(":")
17
+ dependency[-1] = dependency[-1].split("&") if dependency.size > 1
18
+ dependency
19
+ end
20
+ end
@@ -35,6 +35,8 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
35
35
  @dependencies = api_data[:dependencies].map do |name, ver|
36
36
  Gem::Dependency.new(name, ver.split(/\s*,\s*/)).freeze
37
37
  end.freeze
38
+ @required_ruby_version = Gem::Requirement.new(api_data.dig(:requirements, :ruby)).freeze
39
+ @required_rubygems_version = Gem::Requirement.new(api_data.dig(:requirements, :rubygems)).freeze
38
40
  end
39
41
 
40
42
  def ==(other) # :nodoc:
@@ -42,12 +44,11 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
42
44
  @set == other.set and
43
45
  @name == other.name and
44
46
  @version == other.version and
45
- @platform == other.platform and
46
- @dependencies == other.dependencies
47
+ @platform == other.platform
47
48
  end
48
49
 
49
50
  def hash
50
- @set.hash ^ @name.hash ^ @version.hash ^ @platform.hash ^ @dependencies.hash
51
+ @set.hash ^ @name.hash ^ @version.hash ^ @platform.hash
51
52
  end
52
53
 
53
54
  def fetch_development_dependencies # :nodoc:
@@ -60,7 +60,7 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
60
60
  def replace_failed_api_set(error) # :nodoc:
61
61
  uri = error.uri
62
62
  uri = URI uri unless URI === uri
63
- uri.query = nil
63
+ uri = uri + "."
64
64
 
65
65
  raise error unless api_set = @sets.find do |set|
66
66
  Gem::Resolver::APISet === set and set.dep_uri == uri
@@ -33,6 +33,21 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification
33
33
  spec.dependencies
34
34
  end
35
35
 
36
+ ##
37
+ # The required_ruby_version constraint for this specification
38
+
39
+ def required_ruby_version
40
+ spec.required_ruby_version
41
+ end
42
+
43
+ ##
44
+ # The required_rubygems_version constraint for this specification
45
+ #
46
+
47
+ def required_rubygems_version
48
+ spec.required_rubygems_version
49
+ end
50
+
36
51
  def ==(other)
37
52
  self.class === other &&
38
53
  @name == other.name &&
@@ -25,6 +25,12 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
25
25
 
26
26
  attr_reader :remote_set # :nodoc:
27
27
 
28
+ ##
29
+ # Ignore ruby & rubygems specification constraints.
30
+ #
31
+
32
+ attr_accessor :force # :nodoc:
33
+
28
34
  ##
29
35
  # Creates a new InstallerSet that will look for gems in +domain+.
30
36
 
@@ -41,6 +47,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
41
47
  @local = {}
42
48
  @local_source = Gem::Source::Local.new
43
49
  @remote_set = Gem::Resolver::BestSet.new
50
+ @force = false
44
51
  @specs = {}
45
52
  end
46
53
 
@@ -63,15 +70,30 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
63
70
  Gem::Platform.local === s.platform
64
71
  end
65
72
 
66
- if found.empty?
67
- exc = Gem::UnsatisfiableDependencyError.new request
68
- exc.errors = errors
69
-
70
- raise exc
73
+ found = found.sort_by do |s|
74
+ [s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
71
75
  end
72
76
 
73
- newest = found.max_by do |s|
74
- [s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
77
+ newest = found.last
78
+
79
+ unless @force
80
+ found_matching_metadata = found.select do |spec|
81
+ metadata_satisfied?(spec)
82
+ end
83
+
84
+ if found_matching_metadata.empty?
85
+ if newest
86
+ ensure_required_ruby_version_met(newest.spec)
87
+ ensure_required_rubygems_version_met(newest.spec)
88
+ else
89
+ exc = Gem::UnsatisfiableDependencyError.new request
90
+ exc.errors = errors
91
+
92
+ raise exc
93
+ end
94
+ else
95
+ newest = found_matching_metadata.last
96
+ end
75
97
  end
76
98
 
77
99
  @always_install << newest.spec
@@ -221,4 +243,32 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
221
243
  @domain = :local unless remote
222
244
  end
223
245
  end
246
+
247
+ private
248
+
249
+ def metadata_satisfied?(spec)
250
+ spec.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
251
+ spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version)
252
+ end
253
+
254
+ def ensure_required_ruby_version_met(spec) # :nodoc:
255
+ if rrv = spec.required_ruby_version
256
+ ruby_version = Gem.ruby_version
257
+ unless rrv.satisfied_by? ruby_version
258
+ raise Gem::RuntimeRequirementNotMetError,
259
+ "#{spec.full_name} requires Ruby version #{rrv}. The current ruby version is #{ruby_version}."
260
+ end
261
+ end
262
+ end
263
+
264
+ def ensure_required_rubygems_version_met(spec) # :nodoc:
265
+ if rrgv = spec.required_rubygems_version
266
+ unless rrgv.satisfied_by? Gem.rubygems_version
267
+ rg_version = Gem::VERSION
268
+ raise Gem::RuntimeRequirementNotMetError,
269
+ "#{spec.full_name} requires RubyGems version #{rrgv}. The current RubyGems version is #{rg_version}. " +
270
+ "Try 'gem update --system' to update RubyGems itself."
271
+ end
272
+ end
273
+ end
224
274
  end
@@ -22,6 +22,20 @@ class Gem::Resolver::SpecSpecification < Gem::Resolver::Specification
22
22
  spec.dependencies
23
23
  end
24
24
 
25
+ ##
26
+ # The required_ruby_version constraint for this specification
27
+
28
+ def required_ruby_version
29
+ spec.required_ruby_version
30
+ end
31
+
32
+ ##
33
+ # The required_rubygems_version constraint for this specification
34
+
35
+ def required_rubygems_version
36
+ spec.required_rubygems_version
37
+ end
38
+
25
39
  ##
26
40
  # The name and version of the specification.
27
41
  #
@@ -43,6 +43,16 @@ class Gem::Resolver::Specification
43
43
 
44
44
  attr_reader :version
45
45
 
46
+ ##
47
+ # The required_ruby_version constraint for this specification.
48
+
49
+ attr_reader :required_ruby_version
50
+
51
+ ##
52
+ # The required_ruby_version constraint for this specification.
53
+
54
+ attr_reader :required_rubygems_version
55
+
46
56
  ##
47
57
  # Sets default instance variables for the specification.
48
58
 
@@ -53,6 +63,8 @@ class Gem::Resolver::Specification
53
63
  @set = nil
54
64
  @source = nil
55
65
  @version = nil
66
+ @required_ruby_version = Gem::Requirement.default
67
+ @required_rubygems_version = Gem::Requirement.default
56
68
  end
57
69
 
58
70
  ##
@@ -79,7 +79,15 @@ class Gem::Source
79
79
  def dependency_resolver_set # :nodoc:
80
80
  return Gem::Resolver::IndexSet.new self if 'file' == uri.scheme
81
81
 
82
- bundler_api_uri = enforce_trailing_slash(uri) + './api/v1/dependencies'
82
+ fetch_uri = if uri.host == "rubygems.org"
83
+ index_uri = uri.dup
84
+ index_uri.host = "index.rubygems.org"
85
+ index_uri
86
+ else
87
+ uri
88
+ end
89
+
90
+ bundler_api_uri = enforce_trailing_slash(fetch_uri)
83
91
 
84
92
  begin
85
93
  fetcher = Gem::RemoteFetcher.fetcher
@@ -87,11 +95,7 @@ class Gem::Source
87
95
  rescue Gem::RemoteFetcher::FetchError
88
96
  Gem::Resolver::IndexSet.new self
89
97
  else
90
- if response.respond_to? :uri
91
- Gem::Resolver::APISet.new response.uri
92
- else
93
- Gem::Resolver::APISet.new bundler_api_uri
94
- end
98
+ Gem::Resolver::APISet.new response.uri + "./info/"
95
99
  end
96
100
  end
97
101