rubygems-update 3.5.11 → 3.5.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/Manifest.txt +1 -0
  4. data/bundler/CHANGELOG.md +28 -0
  5. data/bundler/lib/bundler/build_metadata.rb +2 -2
  6. data/bundler/lib/bundler/cli.rb +5 -8
  7. data/bundler/lib/bundler/compact_index_client/cache.rb +47 -81
  8. data/bundler/lib/bundler/compact_index_client/parser.rb +84 -0
  9. data/bundler/lib/bundler/compact_index_client.rb +51 -80
  10. data/bundler/lib/bundler/definition.rb +13 -3
  11. data/bundler/lib/bundler/endpoint_specification.rb +11 -0
  12. data/bundler/lib/bundler/fetcher/compact_index.rb +15 -24
  13. data/bundler/lib/bundler/installer/gem_installer.rb +0 -1
  14. data/bundler/lib/bundler/man/bundle-config.1 +1 -1
  15. data/bundler/lib/bundler/man/bundle-config.1.ronn +1 -1
  16. data/bundler/lib/bundler/rubygems_gem_installer.rb +4 -1
  17. data/bundler/lib/bundler/rubygems_integration.rb +14 -0
  18. data/bundler/lib/bundler/self_manager.rb +5 -0
  19. data/bundler/lib/bundler/settings.rb +12 -8
  20. data/bundler/lib/bundler/setup.rb +3 -0
  21. data/bundler/lib/bundler/shared_helpers.rb +2 -2
  22. data/bundler/lib/bundler/source/git.rb +14 -0
  23. data/bundler/lib/bundler/source/path.rb +0 -13
  24. data/bundler/lib/bundler/source/rubygems.rb +29 -13
  25. data/bundler/lib/bundler/version.rb +1 -1
  26. data/bundler/lib/bundler/yaml_serializer.rb +1 -8
  27. data/bundler/lib/bundler.rb +6 -1
  28. data/lib/rubygems/basic_specification.rb +27 -0
  29. data/lib/rubygems/commands/pristine_command.rb +3 -3
  30. data/lib/rubygems/specification.rb +11 -2
  31. data/lib/rubygems/specification_record.rb +0 -1
  32. data/lib/rubygems/stub_specification.rb +21 -0
  33. data/lib/rubygems/uninstaller.rb +13 -12
  34. data/lib/rubygems/yaml_serializer.rb +1 -8
  35. data/lib/rubygems.rb +1 -1
  36. data/rubygems-update.gemspec +1 -1
  37. metadata +4 -3
@@ -4,8 +4,6 @@ require_relative "base"
4
4
  require_relative "../worker"
5
5
 
6
6
  module Bundler
7
- autoload :CompactIndexClient, File.expand_path("../compact_index_client", __dir__)
8
-
9
7
  class Fetcher
10
8
  class CompactIndex < Base
11
9
  def self.compact_index_request(method_name)
@@ -36,15 +34,8 @@ module Bundler
36
34
 
37
35
  until remaining_gems.empty?
38
36
  log_specs { "Looking up gems #{remaining_gems.inspect}" }
39
-
40
- deps = begin
41
- parallel_compact_index_client.dependencies(remaining_gems)
42
- rescue TooManyRequestsError
43
- @bundle_worker&.stop
44
- @bundle_worker = nil # reset it. Not sure if necessary
45
- serial_compact_index_client.dependencies(remaining_gems)
46
- end
47
- next_gems = deps.flat_map {|d| d[3].flat_map(&:first) }.uniq
37
+ deps = fetch_gem_infos(remaining_gems).flatten(1)
38
+ next_gems = deps.flat_map {|d| d[CompactIndexClient::INFO_DEPS].flat_map(&:first) }.uniq
48
39
  deps.each {|dep| gem_info << dep }
49
40
  complete_gems.concat(deps.map(&:first)).uniq!
50
41
  remaining_gems = next_gems - complete_gems
@@ -61,7 +52,7 @@ module Bundler
61
52
  return nil
62
53
  end
63
54
  # Read info file checksums out of /versions, so we can know if gems are up to date
64
- compact_index_client.update_and_parse_checksums!
55
+ compact_index_client.available?
65
56
  rescue CompactIndexClient::Updater::MismatchedChecksumError => e
66
57
  Bundler.ui.debug(e.message)
67
58
  nil
@@ -81,20 +72,20 @@ module Bundler
81
72
  end
82
73
  end
83
74
 
84
- def parallel_compact_index_client
85
- compact_index_client.execution_mode = lambda do |inputs, &blk|
86
- func = lambda {|object, _index| blk.call(object) }
87
- worker = bundle_worker(func)
88
- inputs.each {|input| worker.enq(input) }
89
- inputs.map { worker.deq }
90
- end
91
-
92
- compact_index_client
75
+ def fetch_gem_infos(names)
76
+ in_parallel(names) {|name| compact_index_client.info(name) }
77
+ rescue TooManyRequestsError # rubygems.org is rate limiting us, slow down.
78
+ @bundle_worker&.stop
79
+ @bundle_worker = nil # reset it. Not sure if necessary
80
+ compact_index_client.reset!
81
+ names.map {|name| compact_index_client.info(name) }
93
82
  end
94
83
 
95
- def serial_compact_index_client
96
- compact_index_client.sequential_execution_mode!
97
- compact_index_client
84
+ def in_parallel(inputs, &blk)
85
+ func = lambda {|object, _index| blk.call(object) }
86
+ worker = bundle_worker(func)
87
+ inputs.each {|input| worker.enq(input) }
88
+ inputs.map { worker.deq }
98
89
  end
99
90
 
100
91
  def bundle_worker(func = nil)
@@ -54,7 +54,6 @@ module Bundler
54
54
  spec.source.install(
55
55
  spec,
56
56
  force: force,
57
- ensure_builtin_gems_cached: standalone,
58
57
  build_args: Array(spec_settings),
59
58
  previous_spec: previous_spec,
60
59
  )
@@ -307,7 +307,7 @@ Any \fB\.\fR characters in a host name are mapped to a double underscore (\fB__\
307
307
  .P
308
308
  This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you'll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\.
309
309
  .SH "CONFIGURE BUNDLER DIRECTORIES"
310
- Bundler's home, config, cache and plugin directories are able to be configured through environment variables\. The default location for Bundler's home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values
310
+ Bundler's home, cache and plugin directories and config file can be configured through environment variables\. The default location for Bundler's home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values
311
311
  .IP "" 4
312
312
  .nf
313
313
  BUNDLE_USER_HOME : $HOME/\.bundle
@@ -397,7 +397,7 @@ through ENV.
397
397
 
398
398
  ## CONFIGURE BUNDLER DIRECTORIES
399
399
 
400
- Bundler's home, config, cache and plugin directories are able to be configured
400
+ Bundler's home, cache and plugin directories and config file can be configured
401
401
  through environment variables. The default location for Bundler's home directory is
402
402
  `~/.bundle`, which all directories inherit from by default. The following
403
403
  outlines the available environment variables and their default values
@@ -29,7 +29,10 @@ module Bundler
29
29
  write_build_info_file
30
30
  run_post_build_hooks
31
31
 
32
- generate_bin
32
+ SharedHelpers.filesystem_access(bin_dir, :write) do
33
+ generate_bin
34
+ end
35
+
33
36
  generate_plugins
34
37
 
35
38
  write_spec
@@ -469,11 +469,25 @@ module Bundler
469
469
  end
470
470
 
471
471
  def all_specs
472
+ SharedHelpers.major_deprecation 2, "Bundler.rubygems.all_specs has been removed in favor of Bundler.rubygems.installed_specs"
473
+
472
474
  Gem::Specification.stubs.map do |stub|
473
475
  StubSpecification.from_stub(stub)
474
476
  end
475
477
  end
476
478
 
479
+ def installed_specs
480
+ Gem::Specification.stubs.reject(&:default_gem?).map do |stub|
481
+ StubSpecification.from_stub(stub)
482
+ end
483
+ end
484
+
485
+ def default_specs
486
+ Gem::Specification.default_stubs.map do |stub|
487
+ StubSpecification.from_stub(stub)
488
+ end
489
+ end
490
+
477
491
  def find_bundler(version)
478
492
  find_name("bundler").find {|s| s.version.to_s == version }
479
493
  end
@@ -92,6 +92,7 @@ module Bundler
92
92
  def autoswitching_applies?
93
93
  ENV["BUNDLER_VERSION"].nil? &&
94
94
  Bundler.rubygems.supports_bundler_trampolining? &&
95
+ ruby_can_restart_with_same_arguments? &&
95
96
  SharedHelpers.in_bundle? &&
96
97
  lockfile_version
97
98
  end
@@ -151,6 +152,10 @@ module Bundler
151
152
  !version.to_s.end_with?(".dev")
152
153
  end
153
154
 
155
+ def ruby_can_restart_with_same_arguments?
156
+ $PROGRAM_NAME != "-e"
157
+ end
158
+
154
159
  def updating?
155
160
  "update".start_with?(ARGV.first || " ") && ARGV[1..-1].any? {|a| a.start_with?("--bundler") }
156
161
  end
@@ -103,6 +103,7 @@ module Bundler
103
103
  def initialize(root = nil)
104
104
  @root = root
105
105
  @local_config = load_config(local_config_file)
106
+ @local_root = root || Pathname.new(".bundle").expand_path
106
107
 
107
108
  @env_config = ENV.to_h
108
109
  @env_config.select! {|key, _value| key.start_with?("BUNDLE_") }
@@ -142,7 +143,7 @@ module Bundler
142
143
  end
143
144
 
144
145
  def set_local(key, value)
145
- local_config_file || raise(GemfileNotFound, "Could not locate Gemfile")
146
+ local_config_file = @local_root.join("config")
146
147
 
147
148
  set_key(key, value, @local_config, local_config_file)
148
149
  end
@@ -491,6 +492,10 @@ module Bundler
491
492
  valid_file = file.exist? && !file.size.zero?
492
493
  return {} unless valid_file
493
494
  serializer_class.load(file.read).inject({}) do |config, (k, v)|
495
+ k = k.dup
496
+ k << "/" if /https?:/i.match?(k) && !k.end_with?("/", "__#{FALLBACK_TIMEOUT_URI_OPTION.upcase}")
497
+ k.gsub!(".", "__")
498
+
494
499
  unless k.start_with?("#")
495
500
  if k.include?("-")
496
501
  Bundler.ui.warn "Your #{file} config includes `#{k}`, which contains the dash character (`-`).\n" \
@@ -518,26 +523,25 @@ module Bundler
518
523
  YAMLSerializer
519
524
  end
520
525
 
521
- PER_URI_OPTIONS = %w[
522
- fallback_timeout
523
- ].freeze
526
+ FALLBACK_TIMEOUT_URI_OPTION = "fallback_timeout"
524
527
 
525
528
  NORMALIZE_URI_OPTIONS_PATTERN =
526
529
  /
527
530
  \A
528
531
  (\w+\.)? # optional prefix key
529
532
  (https?.*?) # URI
530
- (\.#{Regexp.union(PER_URI_OPTIONS)})? # optional suffix key
533
+ (\.#{FALLBACK_TIMEOUT_URI_OPTION})? # optional suffix key
531
534
  \z
532
535
  /ix
533
536
 
534
537
  def self.key_for(key)
535
- key = normalize_uri(key).to_s if key.is_a?(String) && key.start_with?("http", "mirror.http")
536
- key = key_to_s(key).gsub(".", "__")
538
+ key = key_to_s(key)
539
+ key = normalize_uri(key) if key.start_with?("http", "mirror.http")
540
+ key = key.gsub(".", "__")
537
541
  key.gsub!("-", "___")
538
542
  key.upcase!
539
543
 
540
- key.prepend("BUNDLE_")
544
+ key.gsub(/\A([ #]*)/, '\1BUNDLE_')
541
545
  end
542
546
 
543
547
  # TODO: duplicates Rubygems#normalize_uri
@@ -5,6 +5,9 @@ require_relative "shared_helpers"
5
5
  if Bundler::SharedHelpers.in_bundle?
6
6
  require_relative "../bundler"
7
7
 
8
+ # autoswitch to locked Bundler version if available
9
+ Bundler.auto_switch
10
+
8
11
  # try to auto_install first before we get to the `Bundler.ui.silence`, so user knows what is happening
9
12
  Bundler.auto_install
10
13
 
@@ -4,14 +4,14 @@ require_relative "version"
4
4
  require_relative "rubygems_integration"
5
5
  require_relative "current_ruby"
6
6
 
7
+ autoload :Pathname, "pathname"
8
+
7
9
  module Bundler
8
10
  autoload :WINDOWS, File.expand_path("constants", __dir__)
9
11
  autoload :FREEBSD, File.expand_path("constants", __dir__)
10
12
  autoload :NULL, File.expand_path("constants", __dir__)
11
13
 
12
14
  module SharedHelpers
13
- autoload :Pathname, "pathname"
14
-
15
15
  def root
16
16
  gemfile = find_gemfile
17
17
  raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
@@ -32,6 +32,20 @@ module Bundler
32
32
  @local = false
33
33
  end
34
34
 
35
+ def remote!
36
+ return if @allow_remote
37
+
38
+ @local_specs = nil
39
+ @allow_remote = true
40
+ end
41
+
42
+ def cached!
43
+ return if @allow_cached
44
+
45
+ @local_specs = nil
46
+ @allow_cached = true
47
+ end
48
+
35
49
  def self.from_lock(options)
36
50
  new(options.merge("uri" => options.delete("remote")))
37
51
  end
@@ -18,9 +18,6 @@ module Bundler
18
18
  @options = options.dup
19
19
  @glob = options["glob"] || DEFAULT_GLOB
20
20
 
21
- @allow_cached = false
22
- @allow_remote = false
23
-
24
21
  @root_path = options["root_path"] || root
25
22
 
26
23
  if options["path"]
@@ -41,16 +38,6 @@ module Bundler
41
38
  @original_path = @path
42
39
  end
43
40
 
44
- def remote!
45
- @local_specs = nil
46
- @allow_remote = true
47
- end
48
-
49
- def cached!
50
- @local_specs = nil
51
- @allow_cached = true
52
- end
53
-
54
41
  def self.from_lock(options)
55
42
  new(options.merge("path" => options.delete("remote")))
56
43
  end
@@ -10,7 +10,7 @@ module Bundler
10
10
  # Ask for X gems per API request
11
11
  API_REQUEST_SIZE = 50
12
12
 
13
- attr_accessor :remotes
13
+ attr_reader :remotes
14
14
 
15
15
  def initialize(options = {})
16
16
  @options = options
@@ -20,6 +20,7 @@ module Bundler
20
20
  @allow_cached = false
21
21
  @allow_local = options["allow_local"] || false
22
22
  @checksum_store = Checksum::Store.new
23
+ @original_remotes = nil
23
24
 
24
25
  Array(options["remotes"]).reverse_each {|r| add_remote(r) }
25
26
  end
@@ -94,10 +95,15 @@ module Bundler
94
95
  new(options)
95
96
  end
96
97
 
98
+ def remotes=(new_remotes)
99
+ @original_remotes = @remotes
100
+ @remotes = new_remotes
101
+ end
102
+
97
103
  def to_lock
98
104
  out = String.new("GEM\n")
99
- remotes.reverse_each do |remote|
100
- out << " remote: #{remove_auth remote}\n"
105
+ lockfile_remotes.reverse_each do |remote|
106
+ out << " remote: #{remote}\n"
101
107
  end
102
108
  out << " specs:\n"
103
109
  end
@@ -136,20 +142,17 @@ module Bundler
136
142
  index = @allow_remote ? remote_specs.dup : Index.new
137
143
  index.merge!(cached_specs) if @allow_cached
138
144
  index.merge!(installed_specs) if @allow_local
145
+
146
+ # complete with default specs, only if not already available in the
147
+ # index through remote, cached, or installed specs
148
+ index.use(default_specs) if @allow_local
149
+
139
150
  index
140
151
  end
141
152
  end
142
153
 
143
154
  def install(spec, options = {})
144
- force = options[:force]
145
- ensure_builtin_gems_cached = options[:ensure_builtin_gems_cached]
146
-
147
- if ensure_builtin_gems_cached && spec.default_gem? && !cached_path(spec)
148
- cached_built_in_gem(spec) unless spec.remote
149
- force = true
150
- end
151
-
152
- if installed?(spec) && !force
155
+ if (spec.default_gem? && !cached_built_in_gem(spec)) || (installed?(spec) && !options[:force])
153
156
  print_using_message "Using #{version_message(spec, options[:previous_spec])}"
154
157
  return nil # no post-install message
155
158
  end
@@ -362,7 +365,7 @@ module Bundler
362
365
 
363
366
  def installed_specs
364
367
  @installed_specs ||= Index.build do |idx|
365
- Bundler.rubygems.all_specs.reverse_each do |spec|
368
+ Bundler.rubygems.installed_specs.reverse_each do |spec|
366
369
  spec.source = self
367
370
  if Bundler.rubygems.spec_missing_extensions?(spec, false)
368
371
  Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions"
@@ -373,6 +376,15 @@ module Bundler
373
376
  end
374
377
  end
375
378
 
379
+ def default_specs
380
+ @default_specs ||= Index.build do |idx|
381
+ Bundler.rubygems.default_specs.each do |spec|
382
+ spec.source = self
383
+ idx << spec
384
+ end
385
+ end
386
+ end
387
+
376
388
  def cached_specs
377
389
  @cached_specs ||= begin
378
390
  idx = Index.new
@@ -457,6 +469,10 @@ module Bundler
457
469
 
458
470
  private
459
471
 
472
+ def lockfile_remotes
473
+ @original_remotes || credless_remotes
474
+ end
475
+
460
476
  # Checks if the requested spec exists in the global cache. If it does,
461
477
  # we copy it to the download path, and if it does not, we download it.
462
478
  #
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  module Bundler
4
- VERSION = "2.5.11".freeze
4
+ VERSION = "2.5.13".freeze
5
5
 
6
6
  def self.bundler_major_version
7
7
  @bundler_major_version ||= VERSION.split(".").first.to_i
@@ -60,7 +60,6 @@ module Bundler
60
60
  indent, key, quote, val = match.captures
61
61
  val = strip_comment(val)
62
62
 
63
- convert_to_backward_compatible_key!(key)
64
63
  depth = indent.size / 2
65
64
  if quote.empty? && val.empty?
66
65
  new_hash = {}
@@ -92,14 +91,8 @@ module Bundler
92
91
  end
93
92
  end
94
93
 
95
- # for settings' keys
96
- def convert_to_backward_compatible_key!(key)
97
- key << "/" if /https?:/i.match?(key) && !%r{/\Z}.match?(key)
98
- key.gsub!(".", "__")
99
- end
100
-
101
94
  class << self
102
- private :dump_hash, :convert_to_backward_compatible_key!
95
+ private :dump_hash
103
96
  end
104
97
  end
105
98
  end
@@ -42,6 +42,7 @@ module Bundler
42
42
  autoload :Checksum, File.expand_path("bundler/checksum", __dir__)
43
43
  autoload :CLI, File.expand_path("bundler/cli", __dir__)
44
44
  autoload :CIDetector, File.expand_path("bundler/ci_detector", __dir__)
45
+ autoload :CompactIndexClient, File.expand_path("bundler/compact_index_client", __dir__)
45
46
  autoload :Definition, File.expand_path("bundler/definition", __dir__)
46
47
  autoload :Dependency, File.expand_path("bundler/dependency", __dir__)
47
48
  autoload :Deprecate, File.expand_path("bundler/deprecate", __dir__)
@@ -166,6 +167,10 @@ module Bundler
166
167
  end
167
168
  end
168
169
 
170
+ def auto_switch
171
+ self_manager.restart_with_locked_bundler_if_needed
172
+ end
173
+
169
174
  # Automatically install dependencies if Bundler.settings[:auto_install] exists.
170
175
  # This is set through config cmd `bundle config set --global auto_install 1`.
171
176
  #
@@ -356,7 +361,7 @@ module Bundler
356
361
  def settings
357
362
  @settings ||= Settings.new(app_config_path)
358
363
  rescue GemfileNotFound
359
- @settings = Settings.new(Pathname.new(".bundle").expand_path)
364
+ @settings = Settings.new
360
365
  end
361
366
 
362
367
  # @return [Hash] Environment present before Bundler was activated
@@ -98,6 +98,20 @@ class Gem::BasicSpecification
98
98
  File.dirname(loaded_from) == Gem.default_specifications_dir
99
99
  end
100
100
 
101
+ ##
102
+ # Regular gems take precedence over default gems
103
+
104
+ def default_gem_priority
105
+ default_gem? ? 1 : -1
106
+ end
107
+
108
+ ##
109
+ # Gems higher up in +gem_path+ take precedence
110
+
111
+ def base_dir_priority(gem_path)
112
+ gem_path.index(base_dir) || gem_path.size
113
+ end
114
+
101
115
  ##
102
116
  # Returns full path to the directory where gem's extensions are installed.
103
117
 
@@ -143,6 +157,19 @@ class Gem::BasicSpecification
143
157
  end
144
158
  end
145
159
 
160
+ ##
161
+ # Returns the full name of this Gem (see `Gem::BasicSpecification#full_name`).
162
+ # Information about where the gem is installed is also included if not
163
+ # installed in the default GEM_HOME.
164
+
165
+ def full_name_with_location
166
+ if base_dir != Gem.dir
167
+ "#{full_name} in #{base_dir}"
168
+ else
169
+ full_name
170
+ end
171
+ end
172
+
146
173
  ##
147
174
  # Full paths in the gem to add to <code>$LOAD_PATH</code> when this gem is
148
175
  # activated.
@@ -148,7 +148,7 @@ extensions will be restored.
148
148
  end
149
149
 
150
150
  unless spec.extensions.empty? || options[:extensions] || options[:only_executables] || options[:only_plugins]
151
- say "Skipped #{spec.full_name}, it needs to compile an extension"
151
+ say "Skipped #{spec.full_name_with_location}, it needs to compile an extension"
152
152
  next
153
153
  end
154
154
 
@@ -157,7 +157,7 @@ extensions will be restored.
157
157
  unless File.exist?(gem) || options[:only_executables] || options[:only_plugins]
158
158
  require_relative "../remote_fetcher"
159
159
 
160
- say "Cached gem for #{spec.full_name} not found, attempting to fetch..."
160
+ say "Cached gem for #{spec.full_name_with_location} not found, attempting to fetch..."
161
161
 
162
162
  dep = Gem::Dependency.new spec.name, spec.version
163
163
  found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep
@@ -201,7 +201,7 @@ extensions will be restored.
201
201
  installer.install
202
202
  end
203
203
 
204
- say "Restored #{spec.full_name}"
204
+ say "Restored #{spec.full_name_with_location}"
205
205
  end
206
206
  end
207
207
  end
@@ -771,6 +771,11 @@ class Gem::Specification < Gem::BasicSpecification
771
771
  end
772
772
  private_class_method :clear_load_cache
773
773
 
774
+ def self.gem_path # :nodoc:
775
+ Gem.path
776
+ end
777
+ private_class_method :gem_path
778
+
774
779
  def self.each_gemspec(dirs) # :nodoc:
775
780
  dirs.each do |dir|
776
781
  Gem::Util.glob_files_in_dir("*.gemspec", dir).each do |path|
@@ -830,7 +835,11 @@ class Gem::Specification < Gem::BasicSpecification
830
835
  next names if names.nonzero?
831
836
  versions = b.version <=> a.version
832
837
  next versions if versions.nonzero?
833
- Gem::Platform.sort_priority(b.platform)
838
+ platforms = Gem::Platform.sort_priority(b.platform) <=> Gem::Platform.sort_priority(a.platform)
839
+ next platforms if platforms.nonzero?
840
+ default_gem = a.default_gem_priority <=> b.default_gem_priority
841
+ next default_gem if default_gem.nonzero?
842
+ a.base_dir_priority(gem_path) <=> b.base_dir_priority(gem_path)
834
843
  end
835
844
  end
836
845
 
@@ -906,7 +915,7 @@ class Gem::Specification < Gem::BasicSpecification
906
915
  # Return the directories that Specification uses to find specs.
907
916
 
908
917
  def self.dirs
909
- @@dirs ||= Gem::SpecificationRecord.dirs_from(Gem.path)
918
+ @@dirs ||= Gem::SpecificationRecord.dirs_from(gem_path)
910
919
  end
911
920
 
912
921
  ##
@@ -68,7 +68,6 @@ module Gem
68
68
  installed_stubs = installed_stubs(pattern)
69
69
  installed_stubs.select! {|s| Gem::Platform.match_spec? s } if match_platform
70
70
  stubs = installed_stubs + Gem::Specification.default_stubs(pattern)
71
- stubs = stubs.uniq(&:full_name)
72
71
  Gem::Specification._resort!(stubs)
73
72
  stubs
74
73
  end
@@ -210,4 +210,25 @@ class Gem::StubSpecification < Gem::BasicSpecification
210
210
  def stubbed?
211
211
  data.is_a? StubLine
212
212
  end
213
+
214
+ def ==(other) # :nodoc:
215
+ self.class === other &&
216
+ name == other.name &&
217
+ version == other.version &&
218
+ platform == other.platform
219
+ end
220
+
221
+ alias_method :eql?, :== # :nodoc:
222
+
223
+ def hash # :nodoc:
224
+ name.hash ^ version.hash ^ platform.hash
225
+ end
226
+
227
+ def <=>(other) # :nodoc:
228
+ sort_obj <=> other.sort_obj
229
+ end
230
+
231
+ def sort_obj # :nodoc:
232
+ [name, version, Gem::Platform.sort_priority(platform)]
233
+ end
213
234
  end
@@ -86,11 +86,7 @@ class Gem::Uninstaller
86
86
 
87
87
  list = []
88
88
 
89
- dirs =
90
- Gem::Specification.dirs +
91
- [Gem.default_specifications_dir]
92
-
93
- Gem::Specification.each_spec dirs do |spec|
89
+ specification_record.stubs.each do |spec|
94
90
  next unless dependency.matches_spec? spec
95
91
 
96
92
  list << spec
@@ -102,7 +98,7 @@ class Gem::Uninstaller
102
98
 
103
99
  default_specs, list = list.partition(&:default_gem?)
104
100
  warn_cannot_uninstall_default_gems(default_specs - list)
105
- @default_specs_matching_uninstall_params = default_specs
101
+ @default_specs_matching_uninstall_params = default_specs.map(&:to_spec)
106
102
 
107
103
  list, other_repo_specs = list.partition do |spec|
108
104
  @gem_home == spec.base_dir ||
@@ -126,7 +122,7 @@ class Gem::Uninstaller
126
122
  remove_all list
127
123
 
128
124
  elsif list.size > 1
129
- gem_names = list.map(&:full_name)
125
+ gem_names = list.map(&:full_name_with_location)
130
126
  gem_names << "All versions"
131
127
 
132
128
  say
@@ -147,7 +143,9 @@ class Gem::Uninstaller
147
143
  ##
148
144
  # Uninstalls gem +spec+
149
145
 
150
- def uninstall_gem(spec)
146
+ def uninstall_gem(stub)
147
+ spec = stub.to_spec
148
+
151
149
  @spec = spec
152
150
 
153
151
  unless dependencies_ok? spec
@@ -165,6 +163,8 @@ class Gem::Uninstaller
165
163
  remove_plugins @spec
166
164
  remove @spec
167
165
 
166
+ specification_record.remove_spec(stub)
167
+
168
168
  regenerate_plugins
169
169
 
170
170
  Gem.post_uninstall_hooks.each do |hook|
@@ -178,7 +178,7 @@ class Gem::Uninstaller
178
178
  # Removes installed executables and batch files (windows only) for +spec+.
179
179
 
180
180
  def remove_executables(spec)
181
- return if spec.executables.empty?
181
+ return if spec.executables.empty? || default_spec_matches?(spec)
182
182
 
183
183
  executables = spec.executables.clone
184
184
 
@@ -275,8 +275,6 @@ class Gem::Uninstaller
275
275
 
276
276
  safe_delete { FileUtils.rm_r gemspec }
277
277
  announce_deletion_of(spec)
278
-
279
- Gem::Specification.reset
280
278
  end
281
279
 
282
280
  ##
@@ -292,7 +290,6 @@ class Gem::Uninstaller
292
290
  # Regenerates plugin wrappers after removal.
293
291
 
294
292
  def regenerate_plugins
295
- specification_record = @install_dir ? Gem::SpecificationRecord.from_path(@install_dir) : Gem::Specification.specification_record
296
293
  latest = specification_record.latest_spec_for(@spec.name)
297
294
  return if latest.nil?
298
295
 
@@ -381,6 +378,10 @@ class Gem::Uninstaller
381
378
 
382
379
  private
383
380
 
381
+ def specification_record
382
+ @specification_record ||= @install_dir ? Gem::SpecificationRecord.from_path(@install_dir) : Gem::Specification.specification_record
383
+ end
384
+
384
385
  def announce_deletion_of(spec)
385
386
  name = spec.full_name
386
387
  say "Successfully uninstalled #{name}"