Skip to content

Commit 797ac69

Browse files
committed
Fix Dir.glob returning a blank string entry in some cases
When the first part of the glob is '**' and the base keyword argument is provided. Add several additional tests to ensure compatibility.
1 parent 17ec84b commit 797ac69

File tree

3 files changed

+102
-15
lines changed

3 files changed

+102
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ New features:
55

66
Bug fixes:
77

8+
* Fix `Dir.glob` returning blank string entry with leading `**/` in glob and `base:` argument (@rwstauner).
89

910
Compatibility:
1011

spec/ruby/core/dir/glob_spec.rb

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,90 @@
182182
Dir.glob('**/**/**').should_not.empty?
183183
end
184184

185+
it "handles **/** with base keyword argument" do
186+
Dir.glob('**/**', base: "dir").should == ["filename_ordering"]
187+
188+
expected = %w[
189+
directory
190+
directory/structure
191+
directory/structure/bar
192+
directory/structure/baz
193+
directory/structure/file_one
194+
directory/structure/file_one.ext
195+
directory/structure/foo
196+
].sort
197+
198+
Dir.glob('**/**', base: "deeply/nested").sort.should == expected
199+
end
200+
201+
it "handles **/ with base keyword argument" do
202+
expected = %w[
203+
/
204+
directory/
205+
directory/structure/
206+
]
207+
Dir.glob('**/', base: "deeply/nested").sort.should == expected
208+
end
209+
210+
# 2.7 and 3.0 include a "." entry for every dir: ["directory/.", "directory/structure/.", ...]
211+
guard_not -> { ruby_version_is ''...'3.1' } do
212+
it "handles **/.* with base keyword argument" do
213+
expected = %w[
214+
.dotfile.ext
215+
directory/structure/.ext
216+
].sort
217+
218+
Dir.glob('**/.*', base: "deeply/nested").sort.should == expected
219+
end
220+
221+
it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
222+
expected = %w[
223+
.
224+
.dotfile.ext
225+
directory/structure/.ext
226+
].sort
227+
228+
Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
229+
end
230+
231+
it "handles **/** with base keyword argument and FNM_DOTMATCH" do
232+
expected = %w[
233+
.
234+
.dotfile.ext
235+
directory
236+
directory/structure
237+
directory/structure/.ext
238+
directory/structure/bar
239+
directory/structure/baz
240+
directory/structure/file_one
241+
directory/structure/file_one.ext
242+
directory/structure/foo
243+
].sort
244+
245+
Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
246+
end
247+
end
248+
249+
it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do
250+
expected = %w[
251+
.dotfile.ext
252+
directory/structure/file_one
253+
directory/structure/file_one.ext
254+
]
255+
256+
Dir.glob('**/*file*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
257+
end
258+
259+
it "handles **/glob with base keyword argument and FNM_EXTGLOB" do
260+
expected = %w[
261+
directory/structure/bar
262+
directory/structure/file_one
263+
directory/structure/file_one.ext
264+
]
265+
266+
Dir.glob('**/*{file,bar}*', File::FNM_EXTGLOB, base: "deeply/nested").sort.should == expected
267+
end
268+
185269
it "handles simple filename patterns" do
186270
Dir.glob('.dotfile').should == ['.dotfile']
187271
end

src/main/ruby/truffleruby/core/dir_glob.rb

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -225,18 +225,18 @@ class StartRecursiveDirectories < Node
225225
def process_directory(matches, parent, entry, glob_base_dir)
226226
raise 'invalid usage' if parent || entry
227227

228-
# Even though the recursive entry is zero width
229-
# in this case, its left separator is still the
230-
# dominant one, so we fix things up to use it.
231-
if @separator
232-
else
233-
@next.process_entry '', Truffle::DirOperations::DT_DIR, matches, parent, glob_base_dir if glob_base_dir
234-
end
235-
236228
stack = [[nil, subdir_entries(glob_base_dir, nil)]]
237229

238230
allow_dots = ((@flags & File::FNM_DOTMATCH) != 0)
239231

232+
if glob_base_dir
233+
if Primitive.is_a?(@next, DirectoriesOnly)
234+
@next.process_entry '', Truffle::DirOperations::DT_DIR, matches, parent, glob_base_dir
235+
else
236+
@next.process_entry '.', Truffle::DirOperations::DT_DIR, matches, parent, glob_base_dir if allow_dots
237+
end
238+
end
239+
240240
until stack.empty?
241241
path, dir_entries = *stack.pop
242242

@@ -245,13 +245,15 @@ def process_directory(matches, parent, entry, glob_base_dir)
245245
type = entry.type
246246

247247
full = path_join(path, ent)
248-
if (type == Truffle::DirOperations::DT_DIR) and (allow_dots or ent.getbyte(0) != 46) # ?.
249-
@next.process_entry ent, type, matches, path, glob_base_dir
250-
251-
stack << [path, dir_entries]
252-
path = full
253-
dir_entries = subdir_entries(glob_base_dir, full)
254-
elsif (allow_dots or ent.getbyte(0) != 46) # ?.
248+
if (type == Truffle::DirOperations::DT_DIR)
249+
if (allow_dots or ent.getbyte(0) != 46) # ?.
250+
@next.process_entry ent, type, matches, path, glob_base_dir
251+
252+
stack << [path, dir_entries]
253+
path = full
254+
dir_entries = subdir_entries(glob_base_dir, full)
255+
end
256+
else
255257
@next.process_entry ent, type, matches, path, glob_base_dir
256258
end
257259
end

0 commit comments

Comments
 (0)