Skip to content

Commit

Permalink
Add search path for overridden gems
Browse files Browse the repository at this point in the history
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
  • Loading branch information
kbrock committed Jan 3, 2024
1 parent ecbb5b2 commit 4151483
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ original declaration.

## Configuration

### Disabling warnings

To disable warnings that are output to the console when `override_gem` or
`ensure_gem` is in use, you can update a bundler setting:

Expand All @@ -95,6 +97,32 @@ $ export BUNDLE_BUNDLER_INJECT__DISABLE_WARN_OVERRIDE_GEM=true
There is a fallback for those that will check the `RAILS_ENV` environment
variable, and will disable the warning when in `"production"`.

### Specifying gem source directories

Many developers checkout gems into a single directory for enhancement.
Instead of specifying the full path of gems every time, specify a gem path
to locate these directories. This can be defined with a bundler setting:

```console
$ bundle config bundler_inject.gem_path ~/src:~/gem_src
```

or use an environment variable:

```console
$ export BUNDLE_BUNDLER_INJECT__GEM_PATH=~/src:~/gem_src
```

An override will find a gem in either of these two directories or in the directory
where the Gemfile override is located.

```Gemfile
# located in ~/src/ansi
override_gem "ansi"
# located in $PWD/mime_override
override_gem "mime/type", path: "mime_override"
```

## What is this sorcery?

While this is technically a bundler plugin, bundler-inject does not use the
Expand Down
27 changes: 24 additions & 3 deletions lib/bundler/inject/dsl_patch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def override_gem(name, *args)
calling_file = "#{calling_loc.path}:#{calling_loc.lineno}"

remove_dependencies_and_sources(dependency)
expand_gem_path(args, calling_file)
expand_gem_path(name, args, calling_file)
gem(name, *args).tap do
warn_override_gem(calling_file, name, args)
end
Expand Down Expand Up @@ -59,10 +59,12 @@ def remove_dependencies_and_sources(dependency)
end
end

def expand_gem_path(args, calling_file)
def expand_gem_path(name, args, calling_file)
args << {:path => name} if args.empty?
return unless args.last.kind_of?(Hash) && args.last[:path]

args.last[:path] = File.expand_path(args.last[:path], File.dirname(calling_file))
full_path = bundler_inject_search_path(File.dirname(calling_file)).map { |p| File.expand_path(args.last[:path], p) }.detect { |f| File.exist?(f) }
args.last[:path] = full_path if full_path
end

def extract_version_opts(args)
Expand Down Expand Up @@ -98,6 +100,25 @@ def load_bundler_d(dir)
eval_gemfile(f)
end
end

# Location to look for overriden gems
#
# This can be set in two ways:
#
# - Via bundler's Bundler::Settings
#
# To configure the setting, you can run:
#
# bundle config bundler_inject.gem_path ~/src:~/gems_src
#
# OR use an environment variable
#
# BUNDLE_BUNDLER_INJECT__GEM_PATH=~/src:~/gems_src
#
def bundler_inject_search_path(gemfile_dir)
@bundler_inject_gem_path ||= (Bundler.settings["bundler_inject.gem_path"] || "").split(File::PATH_SEPARATOR)
[gemfile_dir] + @bundler_inject_gem_path
end
end
end
end
24 changes: 24 additions & 0 deletions spec/bundler_inject_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,30 @@
end
end

it "with a filename path in a gem_path location " do
with_path_based_gem("https://github.com/rubyworks/ansi", "the_gem") do |path|
write_bundler_d_file <<~F
override_gem "ansi", :path => "the_gem"
F
bundle(:update, :env => {"BUNDLE_BUNDLER_INJECT__GEM_PATH" => path.dirname.to_s})

expect(lockfile_specs).to eq [["ansi", "1.5.0"]]
expect(err).to match %r{^\*\* override_gem\("ansi", :path=>#{path.expand_path.to_s.inspect}\) at .+/bundler\.d/local_overrides\.rb:1$}
end
end

it "with no path in a gem_path location " do
with_path_based_gem("https://github.com/rubyworks/ansi", "ansi") do |path|
write_bundler_d_file <<~F
override_gem "ansi"
F
bundle(:update, :env => {"BUNDLE_BUNDLER_INJECT__GEM_PATH" => path.dirname.to_s})

expect(lockfile_specs).to eq [["ansi", "1.5.0"]]
expect(err).to match %r{^\*\* override_gem\("ansi", :path=>#{path.expand_path.to_s.inspect}\) at .+/bundler\.d/local_overrides\.rb:1$}
end
end

it "when the gem doesn't exist" do
write_bundler_d_file <<~F
override_gem "omg"
Expand Down

0 comments on commit 4151483

Please sign in to comment.