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

Allow user to specify a PATH to search for gem overrides #34

Merged
merged 2 commits into from
Jan 9, 2024

Conversation

kbrock
Copy link
Member

@kbrock kbrock commented Dec 19, 2023

This uses a PATH to locate an override gem.

The idea behind this is a developer has a common directory where they git clone gems and tweak them.

I think the 2 outstanding issues are:

  • What do we call the override path?
  • When do we not want to override a path? (maybe the developer has a gem checked out but they are overriding it with a github repo?) SOLUTION: only override if no options specified (or they provide a partial path)

@kbrock
Copy link
Member Author

kbrock commented Dec 19, 2023

update:

  • s/(File.)exists/exist/g

(annoyingly, I had added File.exists? and File.exist?)

@@ -97,6 +99,10 @@ def load_bundler_d(dir)
eval_gemfile(f)
end
end

def search_path(calling_file)
[File.dirname(calling_file)] + ENV.fetch("BUNDLE_BUNDLER_INJECT__GEM_PATH", "").split(':')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should specify in the README what the search order is, I think this is perfect though prioritize the local dir then in order in the BUNDLE_BUNDLER_INJECT__GEM_PATH

Copy link
Member

@Fryguy Fryguy Dec 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but let's move any env var handling to the same place that skip_warnings? is, and wrap it in a proper method.

Main reason is we want as little methods here as possible because this patches into Bundler::Dsl, so pure functional methods like this can live elsewhere.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, once you move over there, you'll see the preferable way to access the settings is with Bundler.settings["bundler_inject.gem_path"]. This allows all of ENV var, .bundle/config file, global bundler config, and local bundler config.

@Fryguy
Copy link
Member

Fryguy commented Dec 19, 2023

Please also include some README docs next to the current docs for skip warnings.

Separately, I'm not sure about gem_path as the setting name, but I can't think of anything better offhand...I'll think about it.

@Fryguy
Copy link
Member

Fryguy commented Dec 19, 2023

I tend to like explicitness with these kinds of options. My first thought was override_gem_default_path (though if this is also used by ensure_gem, then that doesn't work)

write_bundler_d_file <<~F
override_gem "ansi", :path => "the_gem"
F
bundle(:update, env: { "BUNDLE_BUNDLER_INJECT__GEM_PATH" => "#{path.dirname.to_s}/"})
Copy link
Member

@Fryguy Fryguy Dec 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the .to_s here is redundant.

Also why the trailing slash? I wouldn't expect a caller to do that (unless we have a separate test for trailing slash and not trailing slash to support both.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the interpolation, but ended up needing the to_s again. (blew up without it)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, if interpolating you don't need the to_s, but if you removed the interpolation, then you do need it.

args.last[:path] = File.expand_path(args.last[:path], File.dirname(calling_file))
def expand_gem_path(name, args, calling_file)
args << {} unless args.last.kind_of?(Hash)
path_specified = args.last[:path] || name
Copy link
Member

@Fryguy Fryguy Dec 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are cases where we do override gem but only want to override the version (or some other non-path value), and not the path. How would we avoid this automatic path detection in that case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess not setting the setting could be the answer, and if you have the setting, then we assume all overrides are path based? If so, we need to detail that nuance in the readme.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I avoided looking to into the args.
We now skip if version or anything is specified

@kbrock kbrock force-pushed the gem_path branch 2 times, most recently from d3de88d to 82ee2fc Compare December 19, 2023 22:16
@kbrock
Copy link
Member Author

kbrock commented Dec 19, 2023

update:

  • only add a path if there is no version or any other argument
  • use bundler_inject.gem_path or $BUNDLE_BUNDLER_INJECT__GEM_PATH
  • use File::PATH_SEPARATOR
  • using hashrocket for env
  • no longer fix coverage_helper fix (another PR)

update:

  • added README documentation
  • rubocops

update:

  • add Bundler::Inject.gem_path
  • Path.to_s in specs (fix errors)

update:

  • fix trailing whitespace

@kbrock kbrock force-pushed the gem_path branch 2 times, most recently from edda056 to d2cf9e6 Compare December 19, 2023 22:53
@Fryguy
Copy link
Member

Fryguy commented Dec 20, 2023

Can you update the PR title to reflect what you are doing here?

# BUNDLE_BUNDLER_INJECT__GEM_PATH=~/src:~/gems_src
#
def gem_path
@gem_path ||= (Bundler.settings["bundler_inject.gem_path"] || "").split(File::PATH_SEPARATOR)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also .map { |p| File.expand_path(p) }, on the end of this to expand any ~?

@@ -92,14 +92,14 @@ def rm_global_bundler_d_dir
FileUtils.rm_rf(Helpers.global_bundler_d_dir)
end

def with_path_based_gem(source_repo)
def with_path_based_gem(source_repo, dir_name = "the_gem")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed a bunch of the callers were changed (e.g. spec/bundler_inject_spec.rb:121) to set the dir_name at the caller side. If they are all hardcoded at the caller, do we still need the default value here anymore (hard to tell if they were all changed)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops. I stated this below.
I think this is only called from a few spots. I will remove the default.

it "with a path" do
with_path_based_gem("https://github.com/rubyworks/ansi") do |path|
it "with an absolute path" do
with_path_based_gem("https://github.com/rubyworks/ansi", "the_gem") do |path|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More out of curiosity, why was this hardcoded to the parameter default?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had it as the default in the helper method because I wanted the interface to be backwards compatible.
In this spec, it referenced "the_gem", so I felt it was good to have this string in the spec.

We could probably drop the default.

write_bundler_d_file <<~F
override_gem "ansi", :path => "the_gem"
F
bundle(:update, :env => {"BUNDLE_BUNDLER_INJECT__GEM_PATH" => path.dirname.to_s})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a spec that shows multiple paths in the ENV var, and then something appearing in not the first path? This would exercise the File::PATH_SEPARATOR code as well as that the map picks a later value.

@@ -97,6 +100,10 @@ def load_bundler_d(dir)
eval_gemfile(f)
end
end

def search_path(gemfile_dir)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if this should just be inlined into the expand_gem_path method, since it's not being reused anywhere else. The reason is that this method will be patched into the Bundler::Dsl module, and the generic name of the method concerns me that it might conflict in the future.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also concerned about gem_path. I will change that as well.

@kbrock kbrock changed the title Gem path Allow user to specify a PATH to search for gem overrides Jan 3, 2024
@kbrock kbrock force-pushed the gem_path branch 2 times, most recently from 4151483 to 7fe6e23 Compare January 3, 2024 15:19
Before
------

Given a relative path to an overriding gem, use the Gemfile directory to
locate a gem

After
-----

Given a relative path (or no path at all - assume it is the gem name),
use the Gemfile directory and BUNDLE_BUNDLER_INJECT__GEM_PATH directories
to locate a gem
@kbrock
Copy link
Member Author

kbrock commented Jan 3, 2024

update:

  • rebased master (to fix conflict)
  • inlined gem_path into search_path
  • renamed search_path to bundler_inject_search_path (to avoid possible collision)

update:

  • added spec with multiple directories

update:

  • remove default name for helper method with_path_based_gem
  • inline search_path into expand_gempath
  • extract bundler_inject_gem_path -- misunderstood inline comment above

@orangewolf
Copy link

found this plugin, which is great for a fairly odd usecase we have, but my first thought was that we'd want a custom path. this seems like a well baked solution to me! thank you for it =-)

Copy link
Member

@agrare agrare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@agrare agrare merged commit c1b0037 into ManageIQ:master Jan 9, 2024
19 checks passed
@agrare agrare assigned agrare and unassigned Fryguy Jan 9, 2024
@agrare
Copy link
Member

agrare commented Jan 9, 2024

@orangewolf glad you found it useful!

but my first thought was that we'd want a custom path

You could pass paths as an option before so for example: override_gem "manageiq-api", :path => "~/src/manageiq/manageiq-api" and this path could be anywhere. This PR helps if you have a lot of overrides and they all tend to live in the same dir, you don't have to keep repeating yourself :)

agrare added a commit that referenced this pull request Jan 9, 2024
Fixed
* Remove remnants of bundler 1.x support (#20)
* Fix detection of bundler version (#21)
* Fix spec issues after release of bundler 2.4.17 (#32)

Added
* Switch to GitHub Actions (#25)
* Add bundler 2.4 to the test matrix (#28)
* Add Ruby 3.1 and 3.2 to test matrix (#29)
* Allow user to specify a PATH to search for gem overrides (#34)
@kbrock kbrock deleted the gem_path branch January 16, 2024 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants