Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions lib/bundler/runtime.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def cache(custom_path = nil, local = false)
end
end

Dir[cache_path.join("*/.git")].each do |git_dir|
Gem::Util.glob_files_in_dir("*/.git", cache_path.to_s).each do |git_dir|
FileUtils.rm_rf(git_dir)
FileUtils.touch(File.expand_path("../.bundlecache", git_dir))
end
Expand All @@ -159,13 +159,13 @@ def prune_cache(cache_path)
end

def clean(dry_run = false)
gem_bins = Dir["#{Gem.dir}/bin/*"]
git_dirs = Dir["#{Gem.dir}/bundler/gems/*"]
git_cache_dirs = Dir["#{Gem.dir}/cache/bundler/git/*"]
gem_dirs = Dir["#{Gem.dir}/gems/*"]
gem_files = Dir["#{Gem.dir}/cache/*.gem"]
gemspec_files = Dir["#{Gem.dir}/specifications/*.gemspec"]
extension_dirs = Dir["#{Gem.dir}/extensions/*/*/*"] + Dir["#{Gem.dir}/bundler/gems/extensions/*/*/*"]
gem_bins = Gem::Util.glob_files_in_dir("bin/*", Gem.dir)
git_dirs = Gem::Util.glob_files_in_dir("bundler/gems/*", Gem.dir)
git_cache_dirs = Gem::Util.glob_files_in_dir("cache/bundler/git/*", Gem.dir)
gem_dirs = Gem::Util.glob_files_in_dir("gems/*", Gem.dir)
gem_files = Gem::Util.glob_files_in_dir("cache/*.gem", Gem.dir)
gemspec_files = Gem::Util.glob_files_in_dir("specifications/*.gemspec", Gem.dir)
extension_dirs = Gem::Util.glob_files_in_dir("extensions/*/*/*", Gem.dir) + Gem::Util.glob_files_in_dir("bundler/gems/extensions/*/*/*", Gem.dir)
spec_gem_paths = []
# need to keep git sources around
spec_git_paths = @definition.spec_git_paths
Expand Down Expand Up @@ -232,7 +232,7 @@ def clean(dry_run = false)
private

def prune_gem_cache(resolve, cache_path)
cached = Dir["#{cache_path}/*.gem"]
cached = Gem::Util.glob_files_in_dir("*.gem", cache_path.to_s)

cached = cached.delete_if do |path|
spec = Bundler.rubygems.spec_from_gem path
Expand All @@ -257,7 +257,7 @@ def prune_gem_cache(resolve, cache_path)
end

def prune_git_and_path_cache(resolve, cache_path)
cached = Dir["#{cache_path}/*/.bundlecache"]
cached = Gem::Util.glob_files_in_dir("*/.bundlecache", cache_path.to_s)

cached = cached.delete_if do |path|
name = File.basename(File.dirname(path))
Expand All @@ -283,7 +283,7 @@ def setup_manpath
# Add man/ subdirectories from activated bundles to MANPATH for man(1)
manuals = $LOAD_PATH.filter_map do |path|
man_subdir = path.sub(/lib$/, "man")
man_subdir unless Dir[man_subdir + "/man?/"].empty?
man_subdir unless Dir.glob("man?/", base: man_subdir).empty?
end

return if manuals.empty?
Expand Down
2 changes: 1 addition & 1 deletion lib/bundler/source/git.rb
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ def humanized_ref

def serialize_gemspecs_in(destination)
destination = destination.expand_path(Bundler.root) if destination.relative?
Dir["#{destination}/#{@glob}"].each do |spec_path|
Gem::Util.glob_files_in_dir(@glob, destination.to_s).each do |spec_path|
# Evaluate gemspecs and cache the result. Gemspecs
# in git might require git or other dependencies.
# The gemspecs we cache should already be evaluated.
Expand Down
2 changes: 1 addition & 1 deletion lib/bundler/source/rubygems.rb
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ def cached_specs
@cached_specs ||= begin
idx = Index.new

Dir["#{cache_path}/*.gem"].each do |gemfile|
Gem::Util.glob_files_in_dir("*.gem", cache_path.to_s).each do |gemfile|
s ||= Bundler.rubygems.spec_from_gem(gemfile)
s.source = self
idx << s
Expand Down
32 changes: 18 additions & 14 deletions lib/rubygems/basic_specification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,7 @@ def source_paths
# Return all files in this gem that match for +glob+.

def matches_for_glob(glob) # TODO: rename?
glob = File.join(lib_dirs_glob, glob)

Dir[glob]
Gem::Util.glob_files_in_dir(File.join(lib_dirs, glob), full_gem_path)
end

##
Expand All @@ -323,17 +321,7 @@ def plugins
# for this spec.

def lib_dirs_glob
dirs = if raw_require_paths
if raw_require_paths.size > 1
"{#{raw_require_paths.join(",")}}"
else
raw_require_paths.first
end
else
"lib" # default value for require_paths for bundler/inline
end

"#{full_gem_path}/#{dirs}"
"#{full_gem_path}/#{lib_dirs}"
end

##
Expand Down Expand Up @@ -364,6 +352,22 @@ def this

private

##
# Returns the require_paths of this gem as a string usable in Dir.glob,
# relative to full_gem_path.

def lib_dirs
if raw_require_paths
if raw_require_paths.size > 1
"{#{raw_require_paths.join(",")}}"
else
raw_require_paths.first
end
else
"lib" # default value for require_paths for bundler/inline
end
end

def have_extensions?
!extensions.empty?
end
Expand Down
4 changes: 3 additions & 1 deletion lib/rubygems/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ def self.traverse_parents(directory, &block)

##
# Globs for files matching +pattern+ inside of +directory+,
# returning absolute paths to the matching files.
# returning absolute paths to the matching files. Unlike a plain
# Dir.glob with an interpolated path, glob metacharacters in
# +base_path+ are not treated as part of the pattern.
Comment on lines 78 to +81

def self.glob_files_in_dir(glob, base_path)
Dir.glob(glob, base: base_path).map! {|f| File.expand_path(f, base_path) }
Expand Down
28 changes: 28 additions & 0 deletions spec/commands/clean_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,34 @@ def should_not_have_gems(*gems)
expect(vendored_gems("bin/myrackup")).to exist
end

it "removes unused gems when the bundle path contains glob metacharacters" do
gemfile <<-G
source "https://gem.repo1"

gem "thin"
gem "foo"
G

bundle_config "path vendor/dir[1]"
bundle_config "clean false"
bundle "install"

gemfile <<-G
source "https://gem.repo1"

gem "thin"
G
bundle "install"

bundle :clean

expect(out).to include("Removing foo (1.0)")

metachar_vendored_gems = scoped_gem_path(bundled_app("vendor/dir[1]"))
expect(metachar_vendored_gems.join("gems/foo-1.0")).not_to exist
expect(metachar_vendored_gems.join("gems/thin-1.0")).to exist
end

it "removes old version of gem if unused" do
gemfile <<-G
source "https://gem.repo1"
Expand Down
20 changes: 20 additions & 0 deletions spec/install/gemfile/git_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,26 @@
expect(file_code).to eq(ruby_code)
end

it "caches the evaluated gemspec when the bundle path contains glob metacharacters" do
bundle_config "path vendor/dir[1]"
install_base_gemfile
git = update_git "foo" do |s|
s.executables = ["foobar"] # we added this the first time, so keep it now
s.files = ["bin/foobar"] # updating git nukes the files list
foospec = s.to_ruby.gsub(/s\.files.*/, 's.files = `git ls-files -z`.split("\x0")')
s.write "foo.gemspec", foospec
end

bundle "update foo"

sha = git.ref_for("main", 11)
spec_file = scoped_gem_path(bundled_app("vendor/dir[1]")).join("bundler/gems/foo-1.0-#{sha}/foo.gemspec")
expect(spec_file).to exist
ruby_code = Gem::Specification.load(spec_file.to_s).to_ruby
file_code = File.read(spec_file)
expect(file_code).to eq(ruby_code)
end

it "does not update the git source implicitly" do
install_base_gemfile
update_git "foo"
Expand Down
25 changes: 25 additions & 0 deletions test/rubygems/test_gem_stub_specification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,31 @@ def test_matches_for_glob
assert_equal code_rb, stub.matches_for_glob("code*").first
end

def test_matches_for_glob_with_glob_metacharacters_in_gem_dir
base_dir = File.join @tempdir, "dir[1]"
gems_dir = File.join base_dir, "gems"
spec_dir = File.join base_dir, "specifications"
FileUtils.mkdir_p spec_dir

spec = File.join spec_dir, "stub-2.gemspec"
File.write spec, <<~STUB
# -*- encoding: utf-8 -*-
# stub: stub 2 ruby lib

Gem::Specification.new do |s|
s.name = 'stub'
s.version = Gem::Version.new '2'
end
STUB

stub = Gem::StubSpecification.gemspec_stub spec, base_dir, gems_dir
code_rb = File.join stub.gem_dir, "lib", "code.rb"
FileUtils.mkdir_p File.dirname code_rb
FileUtils.touch code_rb

assert_equal code_rb, stub.matches_for_glob("code*").first
end

def test_matches_for_glob_with_bundler_inline
stub = stub_with_extension
code_rb = File.join stub.gem_dir, "lib", "code.rb"
Expand Down