diff options
author | David RodrÃguez <deivid.rodriguez@riseup.net> | 2023-03-17 14:18:30 +0100 |
---|---|---|
committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2023-11-13 11:06:10 +0900 |
commit | 435eb56f6175b7c9a16121ec8441f7492fa9aec5 (patch) | |
tree | 086201ded65f06c9f09d057287ce92778fe9abaf /lib | |
parent | 59b361aaca0194bd526e32b7053948a49da4e39d (diff) | |
download | ruby-435eb56f6175b7c9a16121ec8441f7492fa9aec5.tar.gz |
[rubygems/rubygems] Automatically lock extra ruby platforms
Since we started locking the specific platform in the lockfile, that has
created an annoying situation for users that don't develop on Linux.
They will create a lockfile on their machines, locking their local
platform, for example, darwin. But then that lockfile won't work
automatically when deploying to Heroku for example, because the lockfile
is frozen and the Linux platform is not included.
There's the chance though that resolving against two platforms (Linux +
the local platform) won't succeed while resolving for just the current
platform will. So, instead, we check other platform specific variants
available for the resolution we initially found, and lock those
platforms and specs too if they satisfy the resolution.
This is only done when generating new lockfiles from scratch, existing
lockfiles should keep working as before, and it's only done for "ruby
platforms", i.e., not Java or Windows which have their own complexities,
and so are excluded.
With this change, we expect that MacOS users can bundle locally and
deploy to Heroku without needing to do anything special.
https://github.com/rubygems/rubygems/commit/5f24f06bc5
Diffstat (limited to 'lib')
-rw-r--r-- | lib/bundler/definition.rb | 15 | ||||
-rw-r--r-- | lib/bundler/spec_set.rb | 38 |
2 files changed, 50 insertions, 3 deletions
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 72fbae1984..9ef0abed93 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -84,7 +84,7 @@ module Bundler @new_platform = nil @removed_platform = nil - if lockfile && File.exist?(lockfile) + if lockfile_exists? @lockfile_contents = Bundler.read_file(lockfile) @locked_gems = LockfileParser.new(@lockfile_contents) @locked_platforms = @locked_gems.platforms @@ -302,6 +302,10 @@ module Bundler end end + def should_complete_platforms? + !lockfile_exists? && generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform] + end + def spec_git_paths sources.git_sources.map {|s| File.realpath(s.path) if File.exist?(s.path) }.compact end @@ -491,6 +495,10 @@ module Bundler private + def lockfile_exists? + lockfile && File.exist?(lockfile) + end + def resolver @resolver ||= Resolver.new(resolution_packages, gem_version_promoter) end @@ -567,11 +575,12 @@ module Bundler end def start_resolution - result = resolver.start + result = SpecSet.new(resolver.start) @resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version + @platforms = result.complete_platforms!(platforms) if should_complete_platforms? - SpecSet.new(SpecSet.new(result).for(dependencies, false, @platforms)) + SpecSet.new(result.for(dependencies, false, @platforms)) end def precompute_source_requirements_for_indirect_dependencies? diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 277824c34f..f4fc005ef2 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -52,6 +52,44 @@ module Bundler specs.uniq end + def complete_platforms!(platforms) + return platforms.concat([Gem::Platform::RUBY]).uniq if @specs.empty? + + new_platforms = @specs.flat_map {|spec| spec.source.specs.search([spec.name, spec.version]).map(&:platform) }.uniq.select do |platform| + next if platforms.include?(platform) + next unless GemHelpers.generic(platform) == Gem::Platform::RUBY + + new_specs = [] + + valid_platform = lookup.all? do |_, specs| + spec = specs.first + matching_specs = spec.source.specs.search([spec.name, spec.version]) + platform_spec = GemHelpers.select_best_platform_match(matching_specs, platform).first + + if platform_spec + new_specs << LazySpecification.from_spec(platform_spec) + true + else + false + end + end + next unless valid_platform + + @specs.concat(new_specs.uniq) + end + return platforms if new_platforms.empty? + + platforms.concat(new_platforms) + + less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && platform === Bundler.local_platform } + platforms.delete(Bundler.local_platform) if less_specific_platform + + @sorted = nil + @lookup = nil + + platforms + end + def [](key) key = key.name if key.respond_to?(:name) lookup[key].reverse |