Skip to content
Merged
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
2 changes: 1 addition & 1 deletion lib/bundler/cli/doctor/diagnose.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def dylibs(path)
end

def bundles_for_gem(spec)
Dir.glob("#{spec.full_gem_path}/**/*.bundle")
SharedHelpers.glob_files_in_dir("**/*.bundle", spec.full_gem_path)
end

def lookup_with_fiddle(path)
Expand Down
2 changes: 1 addition & 1 deletion lib/bundler/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def gemspec(opts = nil)
development_group = opts[:development_group] || :development
expanded_path = gemfile_root.join(path)

gemspecs = Gem::Util.glob_files_in_dir("{,*}.gemspec", expanded_path).filter_map {|g| Bundler.load_gemspec(g) }
gemspecs = SharedHelpers.glob_files_in_dir("{,*}.gemspec", expanded_path).filter_map {|g| Bundler.load_gemspec(g) }
gemspecs.reject! {|s| s.name != name } if name
specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] }

Expand Down
4 changes: 2 additions & 2 deletions lib/bundler/gem_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def gemspec(&block)

def initialize(base = nil, name = nil)
@base = File.expand_path(base || SharedHelpers.pwd)
gemspecs = name ? [File.join(@base, "#{name}.gemspec")] : Gem::Util.glob_files_in_dir("{,*}.gemspec", @base)
gemspecs = name ? [File.join(@base, "#{name}.gemspec")] : SharedHelpers.glob_files_in_dir("{,*}.gemspec", @base)
raise "Unable to determine name from existing gemspec. Use :name => 'gemname' in #install_tasks to manually set it." unless gemspecs.size == 1
@spec_path = gemspecs.first
@gemspec = Bundler.load_gemspec(@spec_path)
Expand Down Expand Up @@ -124,7 +124,7 @@ def rubygem_push(path)
end

def built_gem_path
Gem::Util.glob_files_in_dir("#{name}-*.gem", base).sort_by {|f| File.mtime(f) }.last
SharedHelpers.glob_files_in_dir("#{name}-*.gem", base).sort_by {|f| File.mtime(f) }.last
end

def git_push(remote = nil)
Expand Down
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

Gem::Util.glob_files_in_dir("*/.git", cache_path.to_s).each do |git_dir|
SharedHelpers.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 = 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)
gem_bins = SharedHelpers.glob_files_in_dir("bin/*", Gem.dir)
git_dirs = SharedHelpers.glob_files_in_dir("bundler/gems/*", Gem.dir)
git_cache_dirs = SharedHelpers.glob_files_in_dir("cache/bundler/git/*", Gem.dir)
gem_dirs = SharedHelpers.glob_files_in_dir("gems/*", Gem.dir)
gem_files = SharedHelpers.glob_files_in_dir("cache/*.gem", Gem.dir)
gemspec_files = SharedHelpers.glob_files_in_dir("specifications/*.gemspec", Gem.dir)
extension_dirs = SharedHelpers.glob_files_in_dir("extensions/*/*/*", Gem.dir) + SharedHelpers.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 = Gem::Util.glob_files_in_dir("*.gem", cache_path.to_s)
cached = SharedHelpers.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 = Gem::Util.glob_files_in_dir("*/.bundlecache", cache_path.to_s)
cached = SharedHelpers.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.glob("man?/", base: man_subdir).empty?
man_subdir unless SharedHelpers.glob_files_in_dir("man?/", man_subdir).empty?
end

return if manuals.empty?
Expand Down
15 changes: 15 additions & 0 deletions lib/bundler/shared_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,21 @@ def relative_path_to(destination, from: pwd)
destination
end

# Globs for entries matching +glob+ inside of +base_path+, returning
# absolute paths. Glob metacharacters in +base_path+ are not treated as
# part of the pattern, and matched entries are joined literally, so an
# entry starting with `~` is not expanded into the home directory.
#
# Bundler runs against whatever RubyGems the host provides, so this cannot
# delegate to Gem::Util.glob_files_in_dir, which only gained the literal
# join in RubyGems 4.1.
def glob_files_in_dir(glob, base_path)
expanded_path = nil
Dir.glob(glob, base: base_path).map! do |f|
File.join(expanded_path ||= File.expand_path(base_path), f)
end
end

private

def validate_bundle_path
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?
Gem::Util.glob_files_in_dir(@glob, destination.to_s).each do |spec_path|
SharedHelpers.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/path.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def load_spec_files

if File.directory?(expanded_path)
# We sort depth-first since `<<` will override the earlier-found specs
Gem::Util.glob_files_in_dir(@glob, expanded_path).sort_by {|p| -p.split(File::SEPARATOR).size }.each do |file|
SharedHelpers.glob_files_in_dir(@glob, expanded_path).sort_by {|p| -p.split(File::SEPARATOR).size }.each do |file|
next unless spec = load_gemspec(file)
spec.source = self

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

Gem::Util.glob_files_in_dir("*.gem", cache_path.to_s).each do |gemfile|
SharedHelpers.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
20 changes: 14 additions & 6 deletions lib/rubygems/commands/contents_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,21 @@ def files_in(spec)
end

def files_in_gem(spec)
gem_path = spec.full_gem_path
extra = "/{#{spec.require_paths.join ","}}" if options[:lib_only]
glob = "#{gem_path}#{extra}/**/*"
prefix_re = %r{#{Regexp.escape(gem_path)}/}
gem_path = spec.full_gem_path

Dir[glob].map do |file|
[gem_path, file.sub(prefix_re, "")]
if options[:lib_only]
# raw_require_paths rather than require_paths, since the latter prepends
# the absolute extension_dir, which would escape the glob base
require_paths = spec.raw_require_paths
return [] if require_paths.empty?

glob = "{#{require_paths.join ","}}/**/*"
else
glob = "**/*"
end

Dir.glob(glob, base: gem_path).map do |file|
[gem_path, file]
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/rubygems/commands/setup_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ def install_rdoc
(!File.exist?(rubygems_doc_dir) ||
File.writable?(rubygems_doc_dir))
say "Removing old RubyGems RDoc and ri" if @verbose
Dir[File.join(Gem.dir, "doc", "rubygems-[0-9]*")].each do |dir|
Gem::Util.glob_files_in_dir("rubygems-[0-9]*", gem_doc_dir).each do |dir|
rm_rf dir
end

Expand Down
2 changes: 1 addition & 1 deletion lib/rubygems/commands/stale_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def execute
gem_to_atime = {}
Gem::Specification.each do |spec|
name = spec.full_name
Dir["#{spec.full_gem_path}/**/*.*"].each do |file|
Gem::Util.glob_files_in_dir("**/*.*", spec.full_gem_path).each do |file|
next if File.directory?(file)
stat = File.stat(file)
gem_to_atime[name] ||= stat.atime
Expand Down
14 changes: 9 additions & 5 deletions lib/rubygems/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,19 @@ def self.traverse_parents(directory, &block)
end

##
# Globs for files matching +pattern+ inside of +directory+,
# 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.
# Globs for entries matching +glob+ inside of +base_path+, returning
# absolute paths to the matching files and directories. Unlike a plain
# Dir.glob with an interpolated path, glob metacharacters in +base_path+
# are not treated as part of the pattern. Matched entries are joined to
# +base_path+ literally, so an entry starting with `~` is not expanded
# into a home directory, and no other normalization is applied to them.

def self.glob_files_in_dir(glob, base_path)
expanded_path = nil
Dir.glob(glob, base: base_path).map! do |f|
File.expand_path(f, expanded_path ||= File.expand_path(base_path))
# File.join instead of File.expand_path, so that matched entries
# starting with `~` are not expanded into the home directory
File.join(expanded_path ||= File.expand_path(base_path), f)
end
end

Expand Down
25 changes: 25 additions & 0 deletions spec/cache/path_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,31 @@
expect(bundled_app("vendor/cache/foo-1.0")).not_to exist
end

it "removes stale entries whose names look like home directory expansions" do
build_lib "foo"

install_gemfile <<-G
source "https://gem.repo1"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G

bundle :cache

tilde_entry = bundled_app("vendor/cache/~")
# a name no account can have, so a regression cannot resolve it to a real home
tilde_user_entry = bundled_app("vendor/cache/~nonexistent.user")
[tilde_entry, tilde_user_entry].each do |entry|
FileUtils.mkdir_p entry
FileUtils.touch entry.join(".bundlecache")
end

bundle :cache

expect(tilde_entry).not_to exist
expect(tilde_user_entry).not_to exist
expect(home).to exist
end

it "does not cache path gems if cache_all is set to false" do
build_lib "foo"

Expand Down
41 changes: 41 additions & 0 deletions test/rubygems/test_gem_commands_contents_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,47 @@ def test_execute_lib_only
assert_equal "", @ui.error
end

def test_files_in_gem_with_glob_metacharacters_in_install_path
base_dir = File.join @tempdir, "dir[1]"
spec = util_spec "foo"
spec.loaded_from = File.join base_dir, "specifications", spec.spec_name

write_file File.join(spec.full_gem_path, "lib", "foo.rb")

files = @cmd.files_in_gem spec

assert_includes files, [spec.full_gem_path, "lib/foo.rb"]
end

def test_files_in_gem_lib_only_stays_inside_gem_dir_with_extensions
@cmd.options[:lib_only] = true

spec = util_spec "foo" do |s|
s.extensions = %w[ext/foo/extconf.rb]
end

write_file File.join(spec.full_gem_path, "lib", "foo.rb")
write_file File.join(spec.extension_dir, "foo.so")

files = @cmd.files_in_gem spec

assert_includes files, [spec.full_gem_path, "lib/foo.rb"]
files.each do |_prefix, relative|
refute File.absolute_path?(relative), "#{relative} escapes the gem directory"
end
end

def test_files_in_gem_lib_only_without_require_paths
@cmd.options[:lib_only] = true

spec = util_spec "foo"
spec.require_paths = []

write_file File.join(spec.full_gem_path, "lib", "foo.rb")

assert_empty @cmd.files_in_gem(spec)
end

def test_execute_missing_single
@cmd.options[:args] = %w[foo]

Expand Down
21 changes: 21 additions & 0 deletions test/rubygems/test_gem_commands_stale_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,25 @@ def test_execute_sorts
assert_equal("#{foo_bar.name}-#{foo_bar.version}", lines[0].split.first)
assert_equal("#{bar_baz.name}-#{bar_baz.version}", lines[1].split.first)
end

def test_execute_with_glob_metacharacters_in_gem_path
gemhome2 = File.join(@tempdir, "gemhome[2]")
Gem.use_paths gemhome2

foo = util_spec "foo" do |gem|
gem.files = %w[lib/foo.rb]
end
install_specs foo

filename = File.join(gemhome2, "gems", foo.full_name, "lib", "foo.rb")
FileUtils.mkdir_p File.dirname filename
FileUtils.touch filename

use_ui @stub_ui do
@cmd.execute
end

listed_gems = @stub_ui.output.split("\n").map {|line| line.split.first }
assert_includes listed_gems, "#{foo.name}-#{foo.version}"
end
end
14 changes: 14 additions & 0 deletions test/rubygems/test_gem_util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ def test_glob_files_in_dir
assert_equal expected_paths.sort, files_with_relative_base.sort
end

def test_glob_files_in_dir_with_leading_tilde_entries
FileUtils.mkdir_p "j"
FileUtils.touch File.join("j", "~")
FileUtils.touch File.join("j", "~k.rb")

expected_paths = [
File.join(@tempdir, "j", "~"),
File.join(@tempdir, "j", "~k.rb"),
]

files = Gem::Util.glob_files_in_dir("*", File.join(@tempdir, "j"))
assert_equal expected_paths.sort, files.sort
end

def test_correct_for_windows_path
path = "/C:/WINDOWS/Temp/gems"
assert_equal "C:/WINDOWS/Temp/gems", Gem::Util.correct_for_windows_path(path)
Expand Down