rubygems-update 3.2.2 → 3.2.3

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