-
Notifications
You must be signed in to change notification settings - Fork 207
Correct Bundler 2.x Gem path on war/jar load #575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Currently warbler is unusable from jruby 9.2 during to this require failing (not sure to which extent though, but at least one spec is failing and there's an open issue about this). If we stop monkeypatching bundler, we don't need to require it, and thus the error disappears. Since doing that doesn't make any tests fail, I will assume the problems caused by not monkeypatching bundler are less important than the problems caused by doing it. So, I'm removing the code to fix the issue and get specs green.
0935fa3
to
572be95
Compare
🎉 LGTM, haven't investigated in detail
if that turns out problematic, we could just refactor the actually thought it was refactored at some point already, |
Good idea, I'll take a look at both. (edit: done at jruby/jruby-rack#358 however couldn't find a place to move the capture stuff later, as it is at the last possible moment before initializing rack and calling the init method above). |
…nt state As noted at jruby/warbler#575 for warbler, it is similarly possible for jruby-rack to leave ENV['GEM_PATH'] and Gem.path in an inconsistent state after it updates them. This would make any later Gem.clear_paths or Bundler usage (driven from the ENV vars) unpredictable. This happens because jruby-rack alters `ENV['GEM_PATH']``, in some cases but does not force Rubygems to recalculate Gem.paths. Normally this is fine, however if Gem.paths had already been used and cached prior to this mangling `Gem.path` will contain a "stale" value with respect to ENV. (e.g possibly missing the `GEM_HOME`/`Gem.default_dir` value, or retaining values from an old `GEM_PATH`. Clearing the paths is the only way to ensure things are consistent for later usage. In particular this currently can happen on JRuby 9.4+ because often `Gem.path` is already initialized by the time we boot, due to the use of default gems such as `stringio`. Rather than assume a given state, it would be better to ensure it is consistent by clearing paths whenever we touch `ENV['GEM_PATH']`.
…nt state As noted at jruby/warbler#575 for warbler, it is similarly possible for jruby-rack to leave ENV['GEM_PATH'] and Gem.path in an inconsistent state after it updates them. This would make any later Gem.clear_paths or Bundler usage (driven from the ENV vars) unpredictable. This happens because jruby-rack alters `ENV['GEM_PATH']``, in some cases but does not force Rubygems to recalculate Gem.paths. Normally this is fine, however if Gem.paths had already been used and cached prior to this mangling `Gem.path` will contain a "stale" value with respect to ENV. (e.g possibly missing the `GEM_HOME`/`Gem.default_dir` value, or retaining values from an old `GEM_PATH`. Clearing the paths is the only way to ensure things are consistent for later usage. In particular this currently can happen on JRuby 9.4+ because often `Gem.path` is already initialized by the time we boot, due to the use of default gems such as `stringio`. Rather than assume a given state, it would be better to ensure it is consistent by clearing paths whenever we touch `ENV['GEM_PATH']`.
…lse init parameter option Changes the `false` value to behave the same way as empty, and not touch ENV['GEM_PATH'] or Gem.path at all. Previously this allowed you to alter Gem.path without touching the ENV['GEM_PATH']'. This was unsafe with Bundler 1.6+ (so for a long time), because many things may cause Gem.path to be recalculated from env, including bundler initialisations, restarts and later changes within an application's boot hooks. Furthermore the behaviour varied wildly depending on whether Rubygems was initialised prior to the Rack booter, or afterwards, even without bundler causing indeterminism and issues similar to jruby/warbler#575 I cannot find any reference to use of this value on GitHub, or discussion, and it would not work at all with modern JRuby/bundler so removing it, because it helps avoid further issues. Note that it was added in jruby@2fd826b and then the default changed back in jruby@d3ee8f0 shortly after when issues were discovered, so given it's undocumented/unsupported, it is unlikely to be relied upon by anyone.
On JRuby 9.4 this causes Rubygems initialisation which means realisation of init values. This screws with jruby-rack's own guarantees about env implied by its config values and can cause issues in boot hooks such as jruby/warbler#575 due to Rubygems being in a different state to what they expect.
…nt state As noted at jruby/warbler#575 for warbler, it is similarly possible for jruby-rack to leave ENV['GEM_PATH'] and Gem.path in an inconsistent state after it updates them. This would make any later Gem.clear_paths or Bundler usage (driven from the ENV vars) unpredictable. This happens because jruby-rack alters `ENV['GEM_PATH']``, in some cases but does not force Rubygems to recalculate Gem.paths. Normally this is fine, however if Gem.paths had already been used and cached prior to this mangling `Gem.path` will contain a "stale" value with respect to ENV. (e.g possibly missing the `GEM_HOME`/`Gem.default_dir` value, or retaining values from an old `GEM_PATH`. Clearing the paths is the only way to ensure things are consistent for later usage. In particular this currently can happen on JRuby 9.4+ because often `Gem.path` is already initialized by the time we boot, due to the use of default gems such as `stringio`. Rather than assume a given state, it would be better to ensure it is consistent by clearing paths whenever we touch `ENV['GEM_PATH']`.
…lse init parameter option Changes the `false` value to behave the same way as empty, and not touch ENV['GEM_PATH'] or Gem.path at all. Previously this allowed you to alter Gem.path without touching the ENV['GEM_PATH']'. This was unsafe with Bundler 1.6+ (so for a long time), because many things may cause Gem.path to be recalculated from env, including bundler initialisations, restarts and later changes within an application's boot hooks. Furthermore the behaviour varied wildly depending on whether Rubygems was initialised prior to the Rack booter, or afterwards, even without bundler causing indeterminism and issues similar to jruby/warbler#575 I cannot find any reference to use of this value on GitHub, or discussion, and it would not work at all with modern JRuby/bundler so removing it, because it helps avoid further issues. Note that it was added in jruby@2fd826b and then the default changed back in jruby@d3ee8f0 shortly after when issues were discovered, so given it's undocumented/unsupported, it is unlikely to be relied upon by anyone.
On JRuby 9.4 this causes Rubygems initialisation which means realisation of init values. This screws with jruby-rack's own guarantees about env implied by its config values and can cause issues in boot hooks such as jruby/warbler#575 due to Rubygems being in a different state to what they expect.
…nt state As noted at jruby/warbler#575 for warbler, it is similarly possible for jruby-rack to leave ENV['GEM_PATH'] and Gem.path in an inconsistent state after it updates them. This would make any later Gem.clear_paths or Bundler usage (driven from the ENV vars) unpredictable. This happens because jruby-rack alters `ENV['GEM_PATH']``, in some cases but does not force Rubygems to recalculate Gem.paths. Normally this is fine, however if Gem.paths had already been used and cached prior to this mangling `Gem.path` will contain a "stale" value with respect to ENV. (e.g possibly missing the `GEM_HOME`/`Gem.default_dir` value, or retaining values from an old `GEM_PATH`. Clearing the paths is the only way to ensure things are consistent for later usage. In particular this currently can happen on JRuby 9.4+ because often `Gem.path` is already initialized by the time we boot, due to the use of default gems such as `stringio`. Rather than assume a given state, it would be better to ensure it is consistent by clearing paths whenever we touch `ENV['GEM_PATH']`.
…lse init parameter option Changes the `false` value to behave the same way as empty, and not touch ENV['GEM_PATH'] or Gem.path at all. Previously this allowed you to alter Gem.path without touching the ENV['GEM_PATH']'. This was unsafe with Bundler 1.6+ (so for a long time), because many things may cause Gem.path to be recalculated from env, including bundler initialisations, restarts and later changes within an application's boot hooks. Furthermore the behaviour varied wildly depending on whether Rubygems was initialised prior to the Rack booter, or afterwards, even without bundler causing indeterminism and issues similar to jruby/warbler#575 I cannot find any reference to use of this value on GitHub, or discussion, and it would not work at all with modern JRuby/bundler so removing it, because it helps avoid further issues. Note that it was added in jruby@2fd826b and then the default changed back in jruby@d3ee8f0 shortly after when issues were discovered, so given it's undocumented/unsupported, it is unlikely to be relied upon by anyone.
On JRuby 9.4 this causes Rubygems initialisation which means realisation of init values. This screws with jruby-rack's own guarantees about env implied by its config values and can cause issues in boot hooks such as jruby/warbler#575 due to Rubygems being in a different state to what they expect.
…nt state As noted at jruby/warbler#575 for warbler, it is similarly possible for jruby-rack to leave ENV['GEM_PATH'] and Gem.path in an inconsistent state after it updates them. This would make any later Gem.clear_paths or Bundler usage (driven from the ENV vars) unpredictable. This happens because jruby-rack alters `ENV['GEM_PATH']``, in some cases but does not force Rubygems to recalculate Gem.paths. Normally this is fine, however if Gem.paths had already been used and cached prior to this mangling `Gem.path` will contain a "stale" value with respect to ENV. (e.g possibly missing the `GEM_HOME`/`Gem.default_dir` value, or retaining values from an old `GEM_PATH`. Clearing the paths is the only way to ensure things are consistent for later usage. In particular this currently can happen on JRuby 9.4+ because often `Gem.path` is already initialized by the time we boot, due to the use of default gems such as `stringio`. Rather than assume a given state, it would be better to ensure it is consistent by clearing paths whenever we touch `ENV['GEM_PATH']`.
…lse init parameter option Changes the `false` value to behave the same way as empty, and not touch ENV['GEM_PATH'] or Gem.path at all. Previously this allowed you to alter Gem.path without touching the ENV['GEM_PATH']'. This was unsafe with Bundler 1.6+ (so for a long time), because many things may cause Gem.path to be recalculated from env, including bundler initialisations, restarts and later changes within an application's boot hooks. Furthermore the behaviour varied wildly depending on whether Rubygems was initialised prior to the Rack booter, or afterwards, even without bundler causing indeterminism and issues similar to jruby/warbler#575 I cannot find any reference to use of this value on GitHub, or discussion, and it would not work at all with modern JRuby/bundler so removing it, because it helps avoid further issues. Note that it was added in jruby@2fd826b and then the default changed back in jruby@d3ee8f0 shortly after when issues were discovered, so given it's undocumented/unsupported, it is unlikely to be relied upon by anyone.
On JRuby 9.4 this causes Rubygems initialisation which means realisation of init values. This screws with jruby-rack's own guarantees about env implied by its config values and can cause issues in boot hooks such as jruby/warbler#575 due to Rubygems being in a different state to what they expect.
572be95
to
bb2222c
Compare
The default platform name was changed from 1.8 -> 8
bb2222c
to
77afa06
Compare
This is a great piece of work and a nice discovery that the changes needed were pretty simple after all. I'll review and merge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still can't believe how simple this turned out to be!
This PR attempts a proper solution after digging into JRuby / Rubygems and bundler changes and reviewing the many attempts to address this over the years.
bundle install
first." for Gems referenced at Github #537This fixes the integration tests when run via #574 but submitting these PRs independently. I'll rebase one on the other.
Gem.clear_paths
, but not in the ideal locationJRuby 9.4+
andRails 7+
#572Gem.clear_paths
, but not in the ideal locationObserved problem
GEM_HOME
andGEM_PATH
but theGem.paths
are not updatedGEM_PATH
is not as intended.config.override_gem_home
.Why is this happening?
Gem.paths
are cached on usage. If you change ENV afterwards you need toGem.clear_paths
or directly update viaGem.paths
GEM_HOME
andGEM_PATH
(especially if using the defaultoverride_gem_home = true
but does not clear any paths already cached byGem
. It seems to assume that no Rubygems will have been used or needed prior to this point.jar.erb
)warbler/lib/warbler/templates/war.erb
Lines 12 to 15 in 523237b
What else happens before this code?
Jruby-rack does all sorts of stuff before calling warbler's
init.rb
hook.RackLibrary.load(...)
runtime.evalScriptlet("require 'rack/handler/servlet'");
<-- PROBLEMrequire 'jruby/rack
<-- PROBLEMrequire
all sorts of initial utility jruby-rack stuffrequire 'jruby/rack/core_ext'
<-- PROBLEMrequire 'jruby/rack/capture'
<-- PROBLEMrequire 'stringio'
<-- ROOT CAUSE of Gem.path initialisationrequire 'stringio.jar'
in here.checkAndSetRackVersion
to decide how to boot rack (bundler? rubygems? vendored?)runtime.evalScriptlet("load 'jruby/rack/boot/rack.rb'");
require 'jruby/rack/booter'
Booter.boot
rackadjust_gem_paths
META-INF/init.rb
script <-- this is where warbler's script runsBooter.boot
rails <-- (if using rails, usually things fail here from user perspective)Why did it start happening in JRuby 9.4?
In Jruby 9.3 StringIO is entirely a JRuby extension. No RubyGems involved:
In JRuby 9.4 StringIO extension has been moved to the default gem (although baked into stdlib on jruby?)
I don't really understand why it's different, but this change seems to have changed the load mechanism and cause
Gem.paths
to be initialized as soon as 'stringio.jar' has been required, which means it is initiailized as soon as the jruby-rack servlet handling is initialized.Why I think we should address it as in this PR
The change I propose here was already proposed in #437 for a different issue much earlier.
Without clearing
Gem.paths
whenever we mutateGEM_HOME
,GEM_PATH
etc, we can't be confident they are at least accurate for future calls - as far as I can tell?Additional changes to possibly make
require 'stringio'
from jruby-rack to be done later in process (?)jruby/jruby-rack@86a5b6f
1.2.6
1.2.6
Alternatives
jruby-rack
, and perhaps set things in init parameters that tell jruby-rack what to do. (likeconfig.webxml.gem.path
and similar...).Gem.paths
directly rather than using ENV, similar to https://github.com/jruby/warbler/pull/572/files. I believe that might lead to inconsistency though, seems better to update both.