Skip to content
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

Cannot require 'bundler' when we are using --bundle flag and --bundle_path flag #5335

Open
wenyikuang opened this issue Dec 19, 2024 · 7 comments
Labels
Triage Issue needs to be assessed and labeled, further information on reported might be needed

Comments

@wenyikuang
Copy link
Collaborator

wenyikuang commented Dec 19, 2024

Similar to #5161 , the issue about

'ArgumentError: Trying to register Bundler::GemfileError for status code 4 but Bundler::GemfileError is already registered'

The way I reproduce the issue:

//generate an empty Gemfile and install it

In NREL/openstudio:3.9.0

mkdir debug
cd debug
touch Gemfile
bundle _2.4.10_ install  --path "./gems"

//run openstudio with --bundle --bundle_path flags with require bundler

openstudio --bundle "./Gemfile" --bundle_path "./gems" -e "require 'bundler'"

It will raise exception:

Warn: Bundle activated but ENV['BUNDLE_WITHOUT'] is not set
Info: Setting BUNDLE_WITHOUT to 'test'
:/ruby/3.2.0/gems/bundler-2.4.10/lib/bundler/vendor/fileutils/lib/fileutils.rb:183: warning: already initialized constant Bundler::FileUtils::VERSION
:/ruby/3.2.0/bundler/vendor/fileutils/lib/fileutils.rb:183: warning: previous definition of VERSION was here
:/ruby/3.2.0/gems/bundler-2.4.10/lib/bundler/vendor/fileutils/lib/fileutils.rb:2165: warning: already initialized constant Bundler::FileUtils::Entry_::S_IF_DOOR
:/ruby/3.2.0/bundler/vendor/fileutils/lib/fileutils.rb:2165: warning: previous definition of S_IF_DOOR was here
:/ruby/3.2.0/gems/bundler-2.4.10/lib/bundler/vendor/fileutils/lib/fileutils.rb:2461: warning: already initialized constant Bundler::FileUtils::Entry_::DIRECTORY_TERM
:/ruby/3.2.0/bundler/vendor/fileutils/lib/fileutils.rb:2461: warning: previous definition of DIRECTORY_TERM was here
:/ruby/3.2.0/gems/bundler-2.4.10/lib/bundler/vendor/fileutils/lib/fileutils.rb:2569: warning: already initialized constant Bundler::FileUtils::OPT_TABLE
:/ruby/3.2.0/bundler/vendor/fileutils/lib/fileutils.rb:2569: warning: previous definition of OPT_TABLE was here
:/ruby/3.2.0/gems/bundler-2.4.10/lib/bundler/vendor/fileutils/lib/fileutils.rb:2627: warning: already initialized constant Bundler::FileUtils::LOW_METHODS
:/ruby/3.2.0/bundler/vendor/fileutils/lib/fileutils.rb:2627: warning: previous definition of LOW_METHODS was here
:/ruby/3.2.0/gems/bundler-2.4.10/lib/bundler/vendor/fileutils/lib/fileutils.rb:2634: warning: already initialized constant Bundler::FileUtils::METHODS
:/ruby/3.2.0/bundler/vendor/fileutils/lib/fileutils.rb:2634: warning: previous definition of METHODS was here
terminate called after throwing an instance of 'RubyException'
  what():  ArgumentError: Trying to register Bundler::GemfileError for status code 4 but Bundler::GemfileError is already registered
Aborted

Issue overview

Current Behavior

Expected Behavior

I think in the old release it will not block the execution of rb file from

openstudio --bundle "./Gemfile" --bundle_path "./installed_gems" "lib/measures/urban_geometry_creation/tests/urban_geometry_creation_test.rb"

The root cause is tracing back through:
"lib/measures/urban_geometry_creation/tests/urban_geometry_creation_test.rb" -> "urbanopt/geojson" -> "urbanopt/core" -> "openstudio/extension" -> "bundler"

Steps to Reproduce

Has mentioned above.

Possible Solution

I offered a bypass in openstudio/extension to avoid requiring bundler when there is Bundler constants.

in this commit:

NREL/openstudio-extension-gem@9c1e2da
and it do fix the issue, but I am not sure how it should be handle gracefully.

Details

Environment

Some additional details about your environment for this issue (if relevant):

  • Platform (Operating system, version):
  • Version of OpenStudio (if using an intermediate build, include SHA):

Context

@wenyikuang wenyikuang added the Triage Issue needs to be assessed and labeled, further information on reported might be needed label Dec 19, 2024
@jmarrec
Copy link
Collaborator

jmarrec commented Dec 20, 2024

I was going to say that to workaround it you could just do require 'bundler' unless defined?(Bundler) but I see you already proposed that (nice!).

@jmarrec
Copy link
Collaborator

jmarrec commented Dec 20, 2024

https://github.com/ruby/ruby/blob/3110d5c8abf8f710de42989fbc35870287a12f75/lib/bundler/errors.rb#L3-L20

module Bundler
  class BundlerError < StandardError
    def self.status_code(code)
      define_method(:status_code) { code }
      if match = BundlerError.all_errors.find {|_k, v| v == code }
        error, _ = match
        raise ArgumentError,
          "Trying to register #{self} for status code #{code} but #{error} is already registered"
      end
      BundlerError.all_errors[self] = code
    end

    def self.all_errors
      @all_errors ||= {}
    end
  end

  class GemfileError < BundlerError; status_code(4); end

@jmarrec
Copy link
Collaborator

jmarrec commented Dec 20, 2024

require 'bundler/errors'

@jmarrec
Copy link
Collaborator

jmarrec commented Dec 20, 2024

This only happens because of the embedded filesystem. We use Kernel::eval when it's embedded, so it still tries to load it, whether normally require "bundler/errors" a second time would just say false since it's already loaded.

The chain is:

  • require "bundler/gem_tasks" -> require_relative "gem_helper" -> require_relative "../bundler" -> require_relative "bundler/errors"

@jmarrec
Copy link
Collaborator

jmarrec commented Dec 20, 2024

I hate the embedded filesystem.

Anyways, seems like we may be able to trick it...

prev_features = $LOADED_FEATURES.dup
puts prev_features.select{|x| x.include?('bundler') }
puts "require bundler"
require 'bundler'
new_features = $LOADED_FEATURES.dup
puts new_features - prev_features
puts "bundler features"
puts new_features.select{|x| x.include?('bundler') }

see the difference when you call ruby versus openstudio on test.rb

$ ruby test.rb 
require bundler
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/rubygems/bundler_version_finder.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/vendor/fileutils/lib/fileutils.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/vendored_fileutils.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/x86_64-linux/pathname.so
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/pathname.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/errors.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/environment_preserver.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/plugin/api.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/plugin.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/rubygems/text.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/rubygems/source/git.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/rubygems/source/installed.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/rubygems/source/specific_file.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/rubygems/source/local.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/rubygems/source/lock.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/rubygems/source/vendor.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/rubygems/source.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/match_metadata.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/force_platform.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/gem_helpers.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/match_platform.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/rubygems_ext.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/rubygems_integration.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/version.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/constants.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/current_ruby.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/build_metadata.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler.rb
bundler features
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/rubygems/bundler_version_finder.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/vendor/fileutils/lib/fileutils.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/vendored_fileutils.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/errors.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/environment_preserver.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/plugin/api.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/plugin.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/match_metadata.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/force_platform.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/gem_helpers.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/match_platform.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/rubygems_ext.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/rubygems_integration.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/version.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/constants.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/current_ruby.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler/build_metadata.rb
/home/julien/.rbenv/versions/3.2.2/lib/ruby/3.2.0/bundler.rb
$ openstudio test.rb 
require bundler
pathname.so
bundler features

@jmarrec
Copy link
Collaborator

jmarrec commented Dec 20, 2024

Oh. we actually don't try to load the same file twice from embedded either. It's just that it still returns "true"...

But the issue is that initially when InitRubyBindings does it, this is the file that's loaded

":/ruby/3.2.0/bundler/errors.rb"

But then, when you call require 'bundler/errors' after the initialization, what is required is instead

":/ruby/3.2.0/gems/bundler-2.4.10/lib/bundler/errors.rb"

We shouldn't have two bundlers (built in ruby + bundler gem)... I think we've said that before...

@jmarrec
Copy link
Collaborator

jmarrec commented Dec 20, 2024


Meh, I think it's going to be hard, and given what we discussed about possibly eliminating the embedded file system, I suppose it's not wise to go down the rabbit hole. @DavidGoldwasser @kbenne .

@wenyikuang I think your workaround in openstudio-extension-gem is probably fine for now

jmarrec added a commit that referenced this issue Dec 20, 2024
$os_build3/Products/openstudio --loglevel Debug --bundle Gemfile --bundle_path ./gems -e "puts ''; puts ''; puts 'REQUIRE AGAIN'; STDOUT.flush; require 'bundler/errors'" &> log.txt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Triage Issue needs to be assessed and labeled, further information on reported might be needed
Projects
None yet
Development

No branches or pull requests

2 participants