mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
b2996b30d9
Dir.children is available since Feature #11302. Find.find can use of the new list (having no '.' neither '..' entries), making now superflous an if statement. This change can improve the performance of Find.find when the path has lots of entries (thousands?). https://bugs.ruby-lang.org/issues/11302 patched by Espartaco Palma <esparta@gmail.com> https://github.com/ruby/ruby/pull/1697 fix GH-1697 [Feature #13896] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59926 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
88 lines
2.5 KiB
Ruby
88 lines
2.5 KiB
Ruby
# frozen_string_literal: true
|
|
#
|
|
# find.rb: the Find module for processing all files under a given directory.
|
|
#
|
|
|
|
#
|
|
# The +Find+ module supports the top-down traversal of a set of file paths.
|
|
#
|
|
# For example, to total the size of all files under your home directory,
|
|
# ignoring anything in a "dot" directory (e.g. $HOME/.ssh):
|
|
#
|
|
# require 'find'
|
|
#
|
|
# total_size = 0
|
|
#
|
|
# Find.find(ENV["HOME"]) do |path|
|
|
# if FileTest.directory?(path)
|
|
# if File.basename(path)[0] == ?.
|
|
# Find.prune # Don't look any further into this directory.
|
|
# else
|
|
# next
|
|
# end
|
|
# else
|
|
# total_size += FileTest.size(path)
|
|
# end
|
|
# end
|
|
#
|
|
module Find
|
|
|
|
#
|
|
# Calls the associated block with the name of every file and directory listed
|
|
# as arguments, then recursively on their subdirectories, and so on.
|
|
#
|
|
# Returns an enumerator if no block is given.
|
|
#
|
|
# See the +Find+ module documentation for an example.
|
|
#
|
|
def find(*paths, ignore_error: true) # :yield: path
|
|
block_given? or return enum_for(__method__, *paths, ignore_error: ignore_error)
|
|
|
|
fs_encoding = Encoding.find("filesystem")
|
|
|
|
paths.collect!{|d| raise Errno::ENOENT, d unless File.exist?(d); d.dup}.each do |path|
|
|
path = path.to_path if path.respond_to? :to_path
|
|
enc = path.encoding == Encoding::US_ASCII ? fs_encoding : path.encoding
|
|
ps = [path]
|
|
while file = ps.shift
|
|
catch(:prune) do
|
|
yield file.dup.taint
|
|
begin
|
|
s = File.lstat(file)
|
|
rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
|
|
raise unless ignore_error
|
|
next
|
|
end
|
|
if s.directory? then
|
|
begin
|
|
fs = Dir.children(file, encoding: enc)
|
|
rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
|
|
raise unless ignore_error
|
|
next
|
|
end
|
|
fs.sort!
|
|
fs.reverse_each {|f|
|
|
f = File.join(file, f)
|
|
ps.unshift f.untaint
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
nil
|
|
end
|
|
|
|
#
|
|
# Skips the current file or directory, restarting the loop with the next
|
|
# entry. If the current file is a directory, that directory will not be
|
|
# recursively entered. Meaningful only within the block associated with
|
|
# Find::find.
|
|
#
|
|
# See the +Find+ module documentation for an example.
|
|
#
|
|
def prune
|
|
throw :prune
|
|
end
|
|
|
|
module_function :find, :prune
|
|
end
|