bundler 2.5.11 → 2.5.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +84 -0
  3. data/lib/bundler/build_metadata.rb +2 -2
  4. data/lib/bundler/cli/check.rb +1 -1
  5. data/lib/bundler/cli/fund.rb +1 -1
  6. data/lib/bundler/cli/gem.rb +8 -15
  7. data/lib/bundler/cli.rb +26 -26
  8. data/lib/bundler/compact_index_client/cache.rb +47 -81
  9. data/lib/bundler/compact_index_client/parser.rb +84 -0
  10. data/lib/bundler/compact_index_client.rb +51 -80
  11. data/lib/bundler/definition.rb +50 -24
  12. data/lib/bundler/endpoint_specification.rb +11 -0
  13. data/lib/bundler/env.rb +1 -1
  14. data/lib/bundler/fetcher/compact_index.rb +15 -24
  15. data/lib/bundler/force_platform.rb +0 -2
  16. data/lib/bundler/gem_helpers.rb +14 -7
  17. data/lib/bundler/injector.rb +1 -4
  18. data/lib/bundler/installer/gem_installer.rb +0 -1
  19. data/lib/bundler/installer/standalone.rb +0 -3
  20. data/lib/bundler/installer.rb +1 -3
  21. data/lib/bundler/lazy_specification.rb +1 -0
  22. data/lib/bundler/man/bundle-add.1 +1 -1
  23. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  24. data/lib/bundler/man/bundle-cache.1 +1 -1
  25. data/lib/bundler/man/bundle-check.1 +1 -1
  26. data/lib/bundler/man/bundle-clean.1 +1 -1
  27. data/lib/bundler/man/bundle-config.1 +2 -2
  28. data/lib/bundler/man/bundle-config.1.ronn +1 -1
  29. data/lib/bundler/man/bundle-console.1 +1 -1
  30. data/lib/bundler/man/bundle-doctor.1 +1 -1
  31. data/lib/bundler/man/bundle-exec.1 +1 -1
  32. data/lib/bundler/man/bundle-gem.1 +7 -1
  33. data/lib/bundler/man/bundle-gem.1.ronn +11 -0
  34. data/lib/bundler/man/bundle-help.1 +1 -1
  35. data/lib/bundler/man/bundle-info.1 +1 -1
  36. data/lib/bundler/man/bundle-init.1 +1 -1
  37. data/lib/bundler/man/bundle-inject.1 +1 -1
  38. data/lib/bundler/man/bundle-install.1 +1 -1
  39. data/lib/bundler/man/bundle-list.1 +1 -1
  40. data/lib/bundler/man/bundle-lock.1 +1 -1
  41. data/lib/bundler/man/bundle-open.1 +1 -1
  42. data/lib/bundler/man/bundle-outdated.1 +1 -1
  43. data/lib/bundler/man/bundle-platform.1 +1 -1
  44. data/lib/bundler/man/bundle-plugin.1 +1 -1
  45. data/lib/bundler/man/bundle-pristine.1 +1 -1
  46. data/lib/bundler/man/bundle-remove.1 +1 -1
  47. data/lib/bundler/man/bundle-show.1 +1 -1
  48. data/lib/bundler/man/bundle-update.1 +1 -1
  49. data/lib/bundler/man/bundle-version.1 +1 -1
  50. data/lib/bundler/man/bundle-viz.1 +1 -1
  51. data/lib/bundler/man/bundle.1 +1 -1
  52. data/lib/bundler/man/gemfile.5 +1 -1
  53. data/lib/bundler/plugin/api/source.rb +1 -0
  54. data/lib/bundler/resolver/base.rb +4 -0
  55. data/lib/bundler/resolver/candidate.rb +4 -16
  56. data/lib/bundler/resolver/package.rb +4 -0
  57. data/lib/bundler/resolver/spec_group.rb +20 -2
  58. data/lib/bundler/resolver.rb +18 -9
  59. data/lib/bundler/rubygems_ext.rb +76 -14
  60. data/lib/bundler/rubygems_gem_installer.rb +35 -2
  61. data/lib/bundler/rubygems_integration.rb +16 -2
  62. data/lib/bundler/runtime.rb +1 -6
  63. data/lib/bundler/self_manager.rb +22 -2
  64. data/lib/bundler/settings.rb +12 -8
  65. data/lib/bundler/setup.rb +3 -0
  66. data/lib/bundler/shared_helpers.rb +2 -2
  67. data/lib/bundler/source/git.rb +43 -16
  68. data/lib/bundler/source/path.rb +0 -13
  69. data/lib/bundler/source/rubygems.rb +26 -13
  70. data/lib/bundler/spec_set.rb +15 -13
  71. data/lib/bundler/stub_specification.rb +8 -0
  72. data/lib/bundler/vendored_net_http.rb +17 -6
  73. data/lib/bundler/version.rb +1 -1
  74. data/lib/bundler/yaml_serializer.rb +2 -9
  75. data/lib/bundler.rb +6 -1
  76. metadata +4 -3
@@ -4,6 +4,29 @@ require "pathname"
4
4
  require "set"
5
5
 
6
6
  module Bundler
7
+ # The CompactIndexClient is responsible for fetching and parsing the compact index.
8
+ #
9
+ # The compact index is a set of caching optimized files that are used to fetch gem information.
10
+ # The files are:
11
+ # - names: a list of all gem names
12
+ # - versions: a list of all gem versions
13
+ # - info/[gem]: a list of all versions of a gem
14
+ #
15
+ # The client is instantiated with:
16
+ # - `directory`: the root directory where the cache files are stored.
17
+ # - `fetcher`: (optional) an object that responds to #call(uri_path, headers) and returns an http response.
18
+ # If the `fetcher` is not provided, the client will only read cached files from disk.
19
+ #
20
+ # The client is organized into:
21
+ # - `Updater`: updates the cached files on disk using the fetcher.
22
+ # - `Cache`: calls the updater, caches files, read and return them from disk
23
+ # - `Parser`: parses the compact index file data
24
+ # - `CacheFile`: a concurrency safe file reader/writer that verifies checksums
25
+ #
26
+ # The client is intended to optimize memory usage and performance.
27
+ # It is called 100s or 1000s of times, parsing files with hundreds of thousands of lines.
28
+ # It may be called concurrently without global interpreter lock in some Rubies.
29
+ # As a result, some methods may look more complex than necessary to save memory or time.
7
30
  class CompactIndexClient
8
31
  # NOTE: MD5 is here not because we expect a server to respond with it, but
9
32
  # because we use it to generate the etag on first request during the upgrade
@@ -12,6 +35,13 @@ module Bundler
12
35
  SUPPORTED_DIGESTS = { "sha-256" => :SHA256, "md5" => :MD5 }.freeze
13
36
  DEBUG_MUTEX = Thread::Mutex.new
14
37
 
38
+ # info returns an Array of INFO Arrays. Each INFO Array has the following indices:
39
+ INFO_NAME = 0
40
+ INFO_VERSION = 1
41
+ INFO_PLATFORM = 2
42
+ INFO_DEPS = 3
43
+ INFO_REQS = 4
44
+
15
45
  def self.debug
16
46
  return unless ENV["DEBUG_COMPACT_INDEX"]
17
47
  DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") }
@@ -21,106 +51,47 @@ module Bundler
21
51
 
22
52
  require_relative "compact_index_client/cache"
23
53
  require_relative "compact_index_client/cache_file"
54
+ require_relative "compact_index_client/parser"
24
55
  require_relative "compact_index_client/updater"
25
56
 
26
- attr_reader :directory
27
-
28
- def initialize(directory, fetcher)
29
- @directory = Pathname.new(directory)
30
- @updater = Updater.new(fetcher)
31
- @cache = Cache.new(@directory)
32
- @endpoints = Set.new
33
- @info_checksums_by_name = {}
34
- @parsed_checksums = false
35
- @mutex = Thread::Mutex.new
36
- end
37
-
38
- def execution_mode=(block)
39
- Bundler::CompactIndexClient.debug { "execution_mode=" }
40
- @endpoints = Set.new
41
-
42
- @execution_mode = block
43
- end
44
-
45
- # @return [Lambda] A lambda that takes an array of inputs and a block, and
46
- # maps the inputs with the block in parallel.
47
- #
48
- def execution_mode
49
- @execution_mode || sequentially
50
- end
51
-
52
- def sequential_execution_mode!
53
- self.execution_mode = sequentially
54
- end
55
-
56
- def sequentially
57
- @sequentially ||= lambda do |inputs, &blk|
58
- inputs.map(&blk)
59
- end
57
+ def initialize(directory, fetcher = nil)
58
+ @cache = Cache.new(directory, fetcher)
59
+ @parser = Parser.new(@cache)
60
60
  end
61
61
 
62
62
  def names
63
- Bundler::CompactIndexClient.debug { "/names" }
64
- update("names", @cache.names_path, @cache.names_etag_path)
65
- @cache.names
63
+ Bundler::CompactIndexClient.debug { "names" }
64
+ @parser.names
66
65
  end
67
66
 
68
67
  def versions
69
- Bundler::CompactIndexClient.debug { "/versions" }
70
- update("versions", @cache.versions_path, @cache.versions_etag_path)
71
- versions, @info_checksums_by_name = @cache.versions
72
- versions
68
+ Bundler::CompactIndexClient.debug { "versions" }
69
+ @parser.versions
73
70
  end
74
71
 
75
72
  def dependencies(names)
76
73
  Bundler::CompactIndexClient.debug { "dependencies(#{names})" }
77
- execution_mode.call(names) do |name|
78
- update_info(name)
79
- @cache.dependencies(name).map {|d| d.unshift(name) }
80
- end.flatten(1)
74
+ names.map {|name| info(name) }
81
75
  end
82
76
 
83
- def update_and_parse_checksums!
84
- Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" }
85
- return @info_checksums_by_name if @parsed_checksums
86
- update("versions", @cache.versions_path, @cache.versions_etag_path)
87
- @info_checksums_by_name = @cache.checksums
88
- @parsed_checksums = true
89
- end
90
-
91
- private
92
-
93
- def update(remote_path, local_path, local_etag_path)
94
- Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" }
95
- unless synchronize { @endpoints.add?(remote_path) }
96
- Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" }
97
- return
98
- end
99
- @updater.update(url(remote_path), local_path, local_etag_path)
77
+ def info(name)
78
+ Bundler::CompactIndexClient.debug { "info(#{name})" }
79
+ @parser.info(name)
100
80
  end
101
81
 
102
- def update_info(name)
103
- Bundler::CompactIndexClient.debug { "update_info(#{name})" }
104
- path = @cache.info_path(name)
105
- unless existing = @info_checksums_by_name[name]
106
- Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" }
107
- return
108
- end
109
- checksum = SharedHelpers.checksum_for_file(path, :MD5)
110
- if checksum == existing
111
- Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" }
112
- return
113
- end
114
- Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" }
115
- update("info/#{name}", path, @cache.info_etag_path(name))
82
+ def latest_version(name)
83
+ Bundler::CompactIndexClient.debug { "latest_version(#{name})" }
84
+ @parser.info(name).map {|d| Gem::Version.new(d[INFO_VERSION]) }.max
116
85
  end
117
86
 
118
- def url(path)
119
- path
87
+ def available?
88
+ Bundler::CompactIndexClient.debug { "available?" }
89
+ @parser.available?
120
90
  end
121
91
 
122
- def synchronize
123
- @mutex.synchronize { yield }
92
+ def reset!
93
+ Bundler::CompactIndexClient.debug { "reset!" }
94
+ @cache.reset!
124
95
  end
125
96
  end
126
97
  end
@@ -81,7 +81,7 @@ module Bundler
81
81
  @resolved_bundler_version = nil
82
82
 
83
83
  @locked_ruby_version = nil
84
- @new_platform = nil
84
+ @new_platforms = []
85
85
  @removed_platform = nil
86
86
 
87
87
  if lockfile_exists?
@@ -115,7 +115,7 @@ module Bundler
115
115
  @originally_locked_specs = @locked_specs
116
116
  @locked_sources = []
117
117
  @locked_platforms = []
118
- @locked_checksums = nil
118
+ @locked_checksums = Bundler.feature_flag.bundler_3_mode?
119
119
  end
120
120
 
121
121
  locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
@@ -137,7 +137,7 @@ module Bundler
137
137
  end
138
138
  @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
139
139
 
140
- add_current_platform unless Bundler.frozen_bundle?
140
+ @current_platform_missing = add_current_platform unless Bundler.frozen_bundle?
141
141
 
142
142
  converge_path_sources_to_gemspec_sources
143
143
  @path_changes = converge_paths
@@ -367,6 +367,10 @@ module Bundler
367
367
  end
368
368
 
369
369
  def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
370
+ return unless Bundler.frozen_bundle?
371
+
372
+ raise ProductionError, "Frozen mode is set, but there's no lockfile" unless lockfile_exists?
373
+
370
374
  added = []
371
375
  deleted = []
372
376
  changed = []
@@ -395,7 +399,7 @@ module Bundler
395
399
  changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`"
396
400
  end
397
401
 
398
- reason = change_reason
402
+ reason = nothing_changed? ? "some dependencies were deleted from your gemfile" : change_reason
399
403
  msg = String.new
400
404
  msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because frozen mode is set"
401
405
  msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
@@ -453,8 +457,10 @@ module Bundler
453
457
  end
454
458
 
455
459
  def add_platform(platform)
456
- @new_platform ||= !@platforms.include?(platform)
457
- @platforms |= [platform]
460
+ return if @platforms.include?(platform)
461
+
462
+ @new_platforms << platform
463
+ @platforms << platform
458
464
  end
459
465
 
460
466
  def remove_platform(platform)
@@ -478,7 +484,8 @@ module Bundler
478
484
 
479
485
  !@source_changes &&
480
486
  !@dependency_changes &&
481
- !@new_platform &&
487
+ !@current_platform_missing &&
488
+ @new_platforms.empty? &&
482
489
  !@path_changes &&
483
490
  !@local_changes &&
484
491
  !@missing_lockfile_dep &&
@@ -561,7 +568,7 @@ module Bundler
561
568
  def resolution_packages
562
569
  @resolution_packages ||= begin
563
570
  last_resolve = converge_locked_specs
564
- remove_invalid_platforms!(current_dependencies)
571
+ remove_invalid_platforms!
565
572
  packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @gems_to_unlock, prerelease: gem_version_promoter.pre?)
566
573
  packages = additional_base_requirements_to_prevent_downgrades(packages, last_resolve)
567
574
  packages = additional_base_requirements_to_force_updates(packages)
@@ -621,12 +628,23 @@ module Bundler
621
628
  end
622
629
 
623
630
  def start_resolution
631
+ local_platform_needed_for_resolvability = @most_specific_non_local_locked_ruby_platform && !@platforms.include?(local_platform)
632
+ @platforms << local_platform if local_platform_needed_for_resolvability
633
+ add_platform(Gem::Platform::RUBY) if RUBY_ENGINE == "truffleruby"
634
+
624
635
  result = SpecSet.new(resolver.start)
625
636
 
626
637
  @resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version
627
- @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
628
638
 
629
- result.complete_platforms!(platforms)
639
+ if @most_specific_non_local_locked_ruby_platform
640
+ if spec_set_incomplete_for_platform?(result, @most_specific_non_local_locked_ruby_platform)
641
+ @platforms.delete(@most_specific_non_local_locked_ruby_platform)
642
+ elsif local_platform_needed_for_resolvability
643
+ @platforms.delete(local_platform)
644
+ end
645
+ end
646
+
647
+ @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
630
648
 
631
649
  SpecSet.new(result.for(dependencies, false, @platforms))
632
650
  end
@@ -648,13 +666,6 @@ module Bundler
648
666
  end
649
667
  end
650
668
 
651
- def current_ruby_platform_locked?
652
- return false unless generic_local_platform_is_ruby?
653
- return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY)
654
-
655
- current_platform_locked?
656
- end
657
-
658
669
  def current_platform_locked?
659
670
  @platforms.any? do |bundle_platform|
660
671
  MatchPlatform.platforms_match?(bundle_platform, local_platform)
@@ -662,9 +673,19 @@ module Bundler
662
673
  end
663
674
 
664
675
  def add_current_platform
665
- return if current_ruby_platform_locked?
676
+ return if @platforms.include?(local_platform)
677
+
678
+ @most_specific_non_local_locked_ruby_platform = find_most_specific_locked_ruby_platform
679
+ return if @most_specific_non_local_locked_ruby_platform
666
680
 
667
- add_platform(local_platform)
681
+ @platforms << local_platform
682
+ true
683
+ end
684
+
685
+ def find_most_specific_locked_ruby_platform
686
+ return unless generic_local_platform_is_ruby? && current_platform_locked?
687
+
688
+ most_specific_locked_platform
668
689
  end
669
690
 
670
691
  def change_reason
@@ -686,7 +707,8 @@ module Bundler
686
707
  [
687
708
  [@source_changes, "the list of sources changed"],
688
709
  [@dependency_changes, "the dependencies in your gemfile changed"],
689
- [@new_platform, "you added a new platform to your gemfile"],
710
+ [@current_platform_missing, "your lockfile does not include the current platform"],
711
+ [@new_platforms.any?, "you added a new platform to your gemfile"],
690
712
  [@path_changes, "the gemspecs for path gems changed"],
691
713
  [@local_changes, "the gemspecs for git local gems changed"],
692
714
  [@missing_lockfile_dep, "your lock file is missing \"#{@missing_lockfile_dep}\""],
@@ -1039,21 +1061,25 @@ module Bundler
1039
1061
  unlocked_definition
1040
1062
  end
1041
1063
 
1042
- def remove_invalid_platforms!(dependencies)
1064
+ def remove_invalid_platforms!
1043
1065
  return if Bundler.frozen_bundle?
1044
1066
 
1045
1067
  platforms.reverse_each do |platform|
1046
1068
  next if local_platform == platform ||
1047
- (@new_platform && platforms.last == platform) ||
1069
+ @new_platforms.include?(platform) ||
1048
1070
  @path_changes ||
1049
1071
  @dependency_changes ||
1050
- !@originally_locked_specs.incomplete_for_platform?(dependencies, platform)
1072
+ @locked_spec_with_invalid_deps ||
1073
+ !spec_set_incomplete_for_platform?(@originally_locked_specs, platform)
1051
1074
 
1052
1075
  remove_platform(platform)
1053
- add_current_platform if platform == Gem::Platform::RUBY
1054
1076
  end
1055
1077
  end
1056
1078
 
1079
+ def spec_set_incomplete_for_platform?(spec_set, platform)
1080
+ spec_set.incomplete_for_platform?(current_dependencies, platform)
1081
+ end
1082
+
1057
1083
  def source_map
1058
1084
  @source_map ||= SourceMap.new(sources, dependencies, @locked_specs)
1059
1085
  end
@@ -92,6 +92,17 @@ module Bundler
92
92
  end
93
93
  end
94
94
 
95
+ # needed for `bundle fund`
96
+ def metadata
97
+ if @remote_specification
98
+ @remote_specification.metadata
99
+ elsif _local_specification
100
+ _local_specification.metadata
101
+ else
102
+ super
103
+ end
104
+ end
105
+
95
106
  def _local_specification
96
107
  return unless @loaded_from && File.exist?(local_specification_path)
97
108
  eval(File.read(local_specification_path), nil, local_specification_path).tap do |spec|
data/lib/bundler/env.rb CHANGED
@@ -120,7 +120,7 @@ module Bundler
120
120
  specs = Bundler.rubygems.find_name(name)
121
121
  out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty?
122
122
  end
123
- if (exe = caller.last.split(":").first)&.match? %r{(exe|bin)/bundler?\z}
123
+ if (exe = caller_locations.last.absolute_path)&.match? %r{(exe|bin)/bundler?\z}
124
124
  shebang = File.read(exe).lines.first
125
125
  shebang.sub!(/^#!\s*/, "")
126
126
  unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby")
@@ -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)
@@ -2,8 +2,6 @@
2
2
 
3
3
  module Bundler
4
4
  module ForcePlatform
5
- private
6
-
7
5
  # The `:force_ruby_platform` value used by dependencies for resolution, and
8
6
  # by locked specifications for materialization is `false` by default, except
9
7
  # for TruffleRuby. TruffleRuby generally needs to force the RUBY platform
@@ -46,19 +46,26 @@ module Bundler
46
46
  end
47
47
  module_function :platform_specificity_match
48
48
 
49
- def select_best_platform_match(specs, platform)
50
- matching = specs.select {|spec| spec.match_platform(platform) }
49
+ def select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
50
+ matching = if force_ruby
51
+ specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! }
52
+ else
53
+ specs.select {|spec| spec.match_platform(platform) }
54
+ end
55
+
56
+ if prefer_locked
57
+ locked_originally = matching.select {|spec| spec.is_a?(LazySpecification) }
58
+ return locked_originally if locked_originally.any?
59
+ end
51
60
 
52
61
  sort_best_platform_match(matching, platform)
53
62
  end
54
63
  module_function :select_best_platform_match
55
64
 
56
- def force_ruby_platform(specs)
57
- matching = specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! }
58
-
59
- sort_best_platform_match(matching, Gem::Platform::RUBY)
65
+ def select_best_local_platform_match(specs, force_ruby: false)
66
+ select_best_platform_match(specs, local_platform, force_ruby: force_ruby).map(&:materialize_for_installation).compact
60
67
  end
61
- module_function :force_ruby_platform
68
+ module_function :select_best_local_platform_match
62
69
 
63
70
  def sort_best_platform_match(matching, platform)
64
71
  exact = matching.select {|spec| spec.platform == platform }
@@ -23,10 +23,7 @@ module Bundler
23
23
  # @param [Pathname] lockfile_path The lockfile in which to inject the new dependency.
24
24
  # @return [Array]
25
25
  def inject(gemfile_path, lockfile_path)
26
- if Bundler.frozen_bundle?
27
- # ensure the lock and Gemfile are synced
28
- Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true)
29
- end
26
+ Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true)
30
27
 
31
28
  # temporarily unfreeze
32
29
  Bundler.settings.temporary(deployment: false, frozen: false) do
@@ -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
  )
@@ -58,9 +58,6 @@ module Bundler
58
58
  else
59
59
  SharedHelpers.relative_path_to(full_path, from: Bundler.root.join(bundler_path))
60
60
  end
61
- rescue TypeError
62
- error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
63
- raise Gem::InvalidSpecificationException.new(error_message)
64
61
  end
65
62
 
66
63
  def prevent_gem_activation
@@ -69,9 +69,7 @@ module Bundler
69
69
  Bundler.create_bundle_path
70
70
 
71
71
  ProcessLock.lock do
72
- if Bundler.frozen_bundle?
73
- @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])
74
- end
72
+ @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])
75
73
 
76
74
  if @definition.dependencies.empty?
77
75
  Bundler.ui.warn "The Gemfile specifies no dependencies"
@@ -4,6 +4,7 @@ require_relative "force_platform"
4
4
 
5
5
  module Bundler
6
6
  class LazySpecification
7
+ include MatchMetadata
7
8
  include MatchPlatform
8
9
  include ForcePlatform
9
10
 
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-ADD" "1" "May 2024" ""
3
+ .TH "BUNDLE\-ADD" "1" "June 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-BINSTUBS" "1" "May 2024" ""
3
+ .TH "BUNDLE\-BINSTUBS" "1" "June 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-CACHE" "1" "May 2024" ""
3
+ .TH "BUNDLE\-CACHE" "1" "June 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-CHECK" "1" "May 2024" ""
3
+ .TH "BUNDLE\-CHECK" "1" "June 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-CLEAN" "1" "May 2024" ""
3
+ .TH "BUNDLE\-CLEAN" "1" "June 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-CONFIG" "1" "May 2024" ""
3
+ .TH "BUNDLE\-CONFIG" "1" "June 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-config\fR \- Set bundler configuration options
6
6
  .SH "SYNOPSIS"
@@ -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
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-CONSOLE" "1" "May 2024" ""
3
+ .TH "BUNDLE\-CONSOLE" "1" "June 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-console\fR \- Deprecated way to open an IRB session with the bundle pre\-loaded
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-DOCTOR" "1" "May 2024" ""
3
+ .TH "BUNDLE\-DOCTOR" "1" "June 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-doctor\fR \- Checks the bundle for common problems
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with nRonn/v0.11.1
2
2
  .\" https://github.com/n-ronn/nronn/tree/0.11.1
3
- .TH "BUNDLE\-EXEC" "1" "May 2024" ""
3
+ .TH "BUNDLE\-EXEC" "1" "June 2024" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-exec\fR \- Execute a command in the context of the bundle
6
6
  .SH "SYNOPSIS"