Commit graph

96 commits

Author SHA1 Message Date
David Rodríguez
746e0d3ef4 [rubygems/rubygems] Deprecate unused Bundler#SpecSet methods
380c95ce05
2025-06-23 11:06:59 +09:00
Samuel Giddins
c0a1e877b3
Move most of Bundler::GemHelpers to Gem::Platform
This will help centralize wheel platform selection logic eventually

Signed-off-by: Samuel Giddins <segiddins@segiddins.me>
2025-06-06 10:22:18 +09:00
David Rodríguez
b8b4c15695 [rubygems/rubygems] Let bundle lock --normalize-platforms remove invalid platforms
c39d2f84fd
2025-04-15 16:47:22 +09:00
David Rodríguez
1929e73a36 [rubygems/rubygems] Raise an error if bundle lock target platform is incompatible
282e4a8593
2025-04-15 16:47:21 +09:00
David Rodríguez
ce2640dde8 [rubygems/rubygems] Fix edge case making bundle update behave incorrectly
If both a native and a generic version are locked, but the native
version is incompatible with the running Ruby, Bundler will still keep
the native version in the lockfile, since it could be potentially useful
when using other rubies.

However, when `bundle update` is run, this was not the case because the
locked native gems were not using the right source when materializing.
They were using the lockfile source instead of the Gemfile source, and
that meant they could not be found when materializing, because the
lockfile source always uses local mode so does not see them.

The effect of this was normally that they were incorrectly removed from
the lockfile and a strange "this spec has been possibly yanked" was
printed in verbose mode. However, in certain situations (i.e., when the
generic gem would bring extra dependencies), it could also make `bundle
update` crash.

The solution is, when adding this extra locked specs to the result after
resolving, maybe sure they inherit the source from the resolved specs,
so they can be found when materializing.

`bundle install` did not have the issue because it passes locked specs
to the resolver, and assigns the right source to them in
`Definition#converge_locked_specs`.

91ce881fda
2025-04-14 16:17:50 +09:00
David Rodríguez
c4a2f72b1b [rubygems/rubygems] Fix bundle lock --normalize-platforms regression
458fa5dc4c
2025-04-14 16:17:48 +09:00
David Rodríguez
b2bcd36044
[rubygems/rubygems] Remove edge cases for not removing invalid platforms
Instead, remove them anytime we find dependencies don't match the
lockfile for a platform, and then add them back after resolution if
they ended up being valid.

220bd77887
2025-03-31 09:39:22 +09:00
David Rodríguez
f72d5effb7
[rubygems/rubygems] SpecSet#add_extra_platforms! doesn't need to return anything
9fd92ade54
2025-03-31 09:39:22 +09:00
David Rodríguez
a55a2fc6e8
[rubygems/rubygems] Reset existing specs when using Bundler::SpecSet#[]=
We have a flaky failure where to equal Bundler specs sneak into the same
SpecSet. This seems like a vector where that could happen so trying this
in case it fixes the flaky.

a33aeb3c4d
2025-02-14 16:13:27 +09:00
David Rodríguez
a64c697b22
[rubygems/rubygems] Refactor SpecSet to not need reset
55af558124
2025-02-14 16:13:27 +09:00
David Rodríguez
c94cec27f7
[rubygems/rubygems] Simplify SpecSet#sorted
a3f365bbaa
2025-02-14 16:13:27 +09:00
David Rodríguez
5adbad731b
[rubygems/rubygems] Move logic to materialize gems for cache to a new method
And make the current `materialize_strictly` private.

3fc2129147
2025-02-13 09:37:50 +09:00
David Rodríguez
0603c1c68f [rubygems/rubygems] Define Bundler::SpecSet#to_s
For better debuggability.

21d252fa7a
2025-01-28 15:31:51 +09:00
David Rodríguez
0b1b8bc3ec [rubygems/rubygems] Don't remove platform specific variants from the lockfile unless necessary
Even if they don't match the current Ruby version, they could still work
in other rubies. So it's better to keep them.

9a3e583b0c
2025-01-14 12:24:37 +09:00
David Rodríguez
5c83d09ec8 [rubygems/rubygems] Tiny parameter rename
Just for consistency, since all the other methods in this class that
receive an array of dependencies use `deps`.

eca1341950
2025-01-14 12:24:37 +09:00
David Rodríguez
ae75c8877a [rubygems/rubygems] Extract SpecSet#version_for
a76fd6d3bf
2025-01-14 12:24:37 +09:00
David Rodríguez
2b91a56d40 [rubygems/rubygems] Remove no longer necessary code
9ea1539b08
2024-11-26 15:11:05 +09:00
David Rodríguez
10de74b75b [rubygems/rubygems] Avoid needing a second pass to ignore unlocked gems
When converging locked specifications to select the ones that should be
preserved while resolving, we can avoid having to do a second pass to
ignore the ones that have been explicitly unlocked.

411742703e
2024-11-26 15:11:05 +09:00
David Rodríguez
44ad2e3f38 [rubygems/rubygems] Allow some materialized specs to be missing
As long as some spec in the materialization is complete.

9a673b0bbb
2024-11-26 15:11:05 +09:00
David Rodríguez
36fb7994fe [rubygems/rubygems] Deprecate check parameter to Bundler::SpecSet#for
3041b3d784
2024-11-26 15:11:05 +09:00
David Rodríguez
c76b1ea2a6 [rubygems/rubygems] Keep track of materializations in the original resolve
This gives more flexibility to allow further improvements.

f11a890f5e
2024-11-26 15:11:05 +09:00
David Rodríguez
e15921c694 [rubygems/rubygems] Create LazySpecifications directly with most_specific_locked_platform
So there's no need to pass it around in so many places.

784ab7481b
2024-11-26 15:11:05 +09:00
David Rodríguez
7c93460331 [rubygems/rubygems] Simplify more
a2bb68a29b
2024-11-26 15:11:05 +09:00
David Rodríguez
83ce2351ff [rubygems/rubygems] Remove no longer necessary code
e1caeecdf8
2024-11-26 15:11:05 +09:00
David Rodríguez
631908d9a8 [rubygems/rubygems] Use platform local variable
6a6041d073
2024-11-26 15:11:05 +09:00
David Rodríguez
10d694a1ff [rubygems/rubygems] Warn on insecure materialization
bc2537de71
2024-11-08 12:06:32 +00:00
David Rodríguez
4d83f37ff7 [rubygems/rubygems] Reduce global state
43c0c41c6b
2024-11-08 12:06:30 +00:00
David Rodríguez
5fa491b405 Normalize lockfile platforms 2024-10-26 18:44:15 +09:00
David Rodríguez
7285e76493
Fix truffleruby removing gems from lockfile
When resolving on truffleruby, and multiple platforms are included in
the lockfile, Bundler will not respect existing platforms, but always
force ruby variants. That means removal of existing version specific
variants, introducing lockfile churn between implementations.

To prevent this, we introduce the distinction between
`Dependency#force_ruby_platform`, only settable via Gemfile, and
`Dependency#default_force_ruby_platform`, which is always true on
truffleruby for certain dependency names. This way, when resolving
lockfile gems for other platforms on truffleruby, we keep platform
specific variants in the lockfile.

However, that introduces the problem that if only platform specific
variants are locked in the lockfile, Bundler won't be able to
materialize on truffleruby because the generic variant will be missing.
To fix this additional problem, we make sure the generic "ruby" platform
is always added when resolving on truffleruby.
2024-08-05 11:58:07 +09:00
David Rodríguez
e7610582ad [rubygems/rubygems] Fix bundle exec gem uninstall
* `bundle exec` assigns `Gem::Specification.all` to the set of specs
  known to Bundler (a `Bundler::SpecSet`).

* `gem uninstall` recently started calling `#delete` on the set of specs
  stored in `Gem::Specification#all`. This, in RubyGems, is just an
  array of specs, so has a `#delete` method that receives a single
  element.

* However, at some point I added a `SpecSet#delete` method that takes an
  array of specs, breaking the "Array-like" contract and making `gem
  uninstall` break when run in a `bundle exec` context.

The fix is to make `Bundler::SpecSet#delete` handle being given a single
spec.

e3acb7b01d
2024-07-23 19:43:26 +00:00
David Rodríguez
e6c7a309d0 [rubygems/rubygems] Refactor selecting specs from a SpecSet
bcbbff5149
2024-07-09 16:34:09 +00:00
David Rodríguez
dd05191bc3 [rubygems/rubygems] Resolve all platforms directly
Instead of having to do a complete pass after resolve.

To do this, we add to the ruby group all the platform specs with the
same dependencies as the ruby specs.

e50415f2a6
2024-07-09 16:34:08 +00:00
David Rodríguez
744dd5a362 [rubygems/rubygems] Fix performance regression on applications with a local cache
Even if all gems are properly installed and no resolve is needed, we
recently started always reading all packages in `vendor/cache` and
extracting specifications from them.

This commit fixes the problem by longer making considering cached specs
the default and only enable them when a resolve is actually needed.

edeb2c42bf
2024-05-24 15:02:30 +00:00
David Rodriguez
7857061ecd [rubygems/rubygems] Fix regression when caching gems from secondary sources
If `cache_all_platforms` setting is enabled, the secondary source was
no longer considering cached gems.

That means that if the remote secondary source has removed its gems,
then this was now resulting in an error while before the previously
cached gem from the source would still be used.

This commit restores previous behavior.

2d2cd00255
2024-05-16 09:21:32 +00:00
Mike Dalessio
98c84ef42c [rubygems/rubygems] Excluding local platform from lockfile should not affect musl vs gnu case
This case is for not locking things like `arm-darwin-23` when the
lockfile already includes `arm-darwin`, so that we don't infinitely keep
redundant versioned platforms in the lockfile when not necessary.

We detect this with `Gem::Platform#===`. For example,
`Gem::Platform.new("arm-darwin-23") === Gem::Platform.new("arm-darwin")`
but they're not `==`.

However, in the case of `-musl` vs `-gnu`, those act as the platform
"version", but `===` is not commutative for them. This is explained in
`===` docs.

We only want to exclude the local platform in situations when
`Gem::Platform#===` is actually commutative.

8099c4face
2024-04-17 18:17:12 +00:00
David Rodriguez
95c9711d6e [rubygems/rubygems] Fix musl platform not being added to the lockfile
235f7b4266
2024-01-31 19:07:39 +00:00
David Rodríguez
b8f859f0bf Complete missing specs for platforms after resolution
If two platform specific variants have different dependencies, then
resolution may fallback to the non platform specific variant. However,
the platform specific variants that have the same dependencies as the
non specific one can still be kept.

Do a pass to complete those after resolution.
2024-01-11 13:51:52 +09:00
David Rodríguez
7f0dbfc9c8 [rubygems/rubygems] Move resetting the spec set to where it becomes necessary
a8b547c6b1
2024-01-11 13:51:52 +09:00
David Rodríguez
51d2a8e983 [rubygems/rubygems] Extract a couple of helper methods
880a4eae7f
2024-01-11 13:51:52 +09:00
David Rodríguez
ab1936faf9 [rubygems/rubygems] Remove methods to clarify what they do
1d15d8a8ff
2024-01-11 13:51:52 +09:00
David Rodríguez
76916217b6 [rubygems/rubygems] Extract SpecSet#reset! helper
41f9b4d940
2024-01-11 13:51:52 +09:00
Hiroshi SHIBATA
82496f2b38 Merge RubyGems-3.5.2 and Bundler-2.5.2 2023-12-22 07:24:04 +09:00
David Rodriguez
c05495530e [rubygems/rubygems] Fix universal lockfiles regression
If a platform specific variant would not match the current Ruby, we would still be
considering it compatible with the initial resolution and adding its
platform to the lockfile, but we would later fail to materialize it for
installation due to not really being compatible.

Fix is to only add platforms for variants that are also compatible with
current Ruby and RubyGems versions.

75d1290843
2023-11-22 13:17:12 +00:00
David Rodríguez
435eb56f61 [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.

5f24f06bc5
2023-11-13 11:06:10 +09:00
David Rodríguez
bd6aaa78c3 [rubygems/rubygems] Remove unused SpecSet#merge
53e0490b55
2023-11-13 11:06:10 +09:00
David Rodríguez
9f67118d7b
[rubygems/rubygems] Simplify selecting specs with force_ruby_platform set
5f90a43635

Co-authored-by: Martin Emde <martin.emde@gmail.com>
2023-11-08 09:04:28 +09:00
David Rodríguez
73ba4b76c2 [rubygems/rubygems] Automatically remove invalid platforms before re-resolving
40989271dd
2023-10-16 13:52:56 +09:00
Samuel Giddins
83f929316e [rubygems/rubygems] Fix force_ruby_platform: when the lockfile only locks the ruby platform
7c50064c3c
2023-10-15 04:46:32 +00:00
David Rodríguez
f3d69bed62
[rubygems/rubygems] Fix resolver hangs when dealing with an incomplete lockfile
While working on locking multiple platforms by default, I got an
infinite resolution loop in one of our resolver specs.

The culprit ended up being that when dealing with lockfile specs with
incomplete dependencies (spec appears in lockfile, but its dependencies
don't), those specs were not being properly expired and that tripped up
resolution.

The issue for some reason only manifests when dealing with multiple
lockfile platforms, that's why it only manifested when working on
locking multiple platforms by default.

4ca72913bb
2023-04-06 13:07:16 +09:00
David Rodríguez
c257380965
Revert "Refactor incomplete specs handling"
This reverts commit 69580f8b72f41c58cae57d1ada4db909922b3891.
2023-04-06 13:07:16 +09:00