Skip to content

Add a method to match recursively paths against Regexp #40

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
46 changes: 40 additions & 6 deletions lib/net/sftp/operations/dir.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,7 @@ def glob(path, pattern, flags=0)
while queue.any?
entry = queue.shift

if entry.directory? && !%w(. ..).include?(::File.basename(entry.name))
queue += entries("#{path}/#{entry.name}").map do |e|
e.name.replace("#{entry.name}/#{e.name}")
e
end
end
queue = enqueue_subtree_if_dir(queue, entry, path)

if ::File.fnmatch(pattern, entry.name, flags)
if block_given?
Expand All @@ -88,6 +83,45 @@ def glob(path, pattern, flags=0)
def [](path, pattern)
glob(path, pattern, 0)
end

# Finds paths matching recursively all directory entries under +path+
# against Regexp +regexp+. If a block is given, matches will be yielded
# to the block as they are found; otherwise, they will be returned in
# an array when the method finishes.
def match(path, regexp)
path = path.chop if path[-1,1] == "/"

results = [] unless block_given?
queue = entries(path).reject { |e| e.name == "." || e.name == ".." }
while queue.any?
entry = queue.shift

queue = enqueue_subtree_if_dir(queue, entry, path)

if regexp.match(entry.name)
if block_given?
yield entry
else
results << entry
end
end
end

return results unless block_given?
end

private

# Returns given queue with found subtree entries (Only one level deeper).
def enqueue_subtree_if_dir(queue, entry, path)
if entry.directory? && !%w(. ..).include?(::File.basename(entry.name))
queue += entries("#{path}/#{entry.name}").map do |e|
e.name.replace("#{entry.name}/#{e.name}")
e
end
end
queue
end
end

end; end; end
46 changes: 39 additions & 7 deletions test/test_dir.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,53 @@ def test_entries_should_return_all_entries_in_a_single_array
end

def test_glob_should_search_under_path_for_matching_entries
@sftp.expects(:opendir!).with("/path/to/remote").returns("handle")
@sftp.expects(:opendir!).with("/path/to/remote/e3").returns("handle-e3")
@sftp.expects(:opendir!).with("/path/to/remote/e5").returns("handle-e5")
stub_folder_structure
@sftp.expects(:readdir!).with("handle").returns([n(".", true), n("..", true), n("e1"), n("e2"), n("e3", true)], [n("e4"), n("e5", true)], nil).times(3)
@sftp.expects(:readdir!).with("handle-e3").returns([n(".", true), n("..", true), n("e3e1"), n("e3e2")], nil).times(2)
@sftp.expects(:readdir!).with("handle-e5").returns([n(".", true), n("..", true), n("e5e1"), n("e5e2"), n("e5e3")], nil).times(2)
@sftp.expects(:close!).with("handle")
@sftp.expects(:close!).with("handle-e3")
@sftp.expects(:close!).with("handle-e5")

assert_equal %w(e3/e3e2 e5/e5e2), @dir.glob("/path/to/remote", "**/e?e2").map { |e| e.name }
assert_equal %w(e3/e3e2 e5/e5e2),
@dir.glob("/path/to/remote", "**/e?e2").map { |e| e.name }
end

def test_match_should_search_a_path_matching_regexp
stub_folder_structure

assert_equal %w(e3/e3e2),
@dir.match("/path/to/remote", /e3e2/).map { |e| e.name }
end

def test_match_should_search_a_path_matching_a_complex_regexp
stub_folder_structure

assert_equal %w(e3 e5/e5e1 e5/e5e2 e5/e5e3),
@dir.match("/path/to/remote", /^(e3|e5\/e5.*)$/).map { |e| e.name }
end

private

def stub_folder_structure
# /path/to/remote
# |- e1
# |- e2
# |- e3
# |- e3e1
# |- e3e2
# |- e4
# |- e5
# |- e5e1
# |- e5e2
@sftp.stubs(:opendir!).with("/path/to/remote").returns("handle")
@sftp.stubs(:opendir!).with("/path/to/remote/e3").returns("handle-e3")
@sftp.stubs(:opendir!).with("/path/to/remote/e5").returns("handle-e5")
@sftp.stubs(:readdir!).with("handle").returns([n(".", true), n("..", true), n("e1"), n("e2"), n("e3", true)], [n("e4"), n("e5", true)], nil)
@sftp.stubs(:readdir!).with("handle-e3").returns([n(".", true), n("..", true), n("e3e1"), n("e3e2")], nil)
@sftp.stubs(:readdir!).with("handle-e5").returns([n(".", true), n("..", true), n("e5e1"), n("e5e2"), n("e5e3")], nil)
@sftp.stubs(:close!).with("handle")
@sftp.stubs(:close!).with("handle-e3")
@sftp.stubs(:close!).with("handle-e5")
end

def n(name, directory=false)
Net::SFTP::Protocol::V01::Name.new(name.to_s, "longname for #{name}",
Net::SFTP::Protocol::V01::Attributes.new(:permissions => directory ? 040755 : 0100644))
Expand Down