Added -j2
[ruby.git] / lib / find.rb
blob98a79cc76dad7c55b64890d8382e6e9e49c5954a
1 # frozen_string_literal: true
3 # find.rb: the Find module for processing all files under a given directory.
7 # The +Find+ module supports the top-down traversal of a set of file paths.
9 # For example, to total the size of all files under your home directory,
10 # ignoring anything in a "dot" directory (e.g. $HOME/.ssh):
12 #   require 'find'
14 #   total_size = 0
16 #   Find.find(ENV["HOME"]) do |path|
17 #     if FileTest.directory?(path)
18 #       if File.basename(path).start_with?('.')
19 #         Find.prune       # Don't look any further into this directory.
20 #       else
21 #         next
22 #       end
23 #     else
24 #       total_size += FileTest.size(path)
25 #     end
26 #   end
28 module Find
30   VERSION = "0.2.0"
32   #
33   # Calls the associated block with the name of every file and directory listed
34   # as arguments, then recursively on their subdirectories, and so on.
35   #
36   # Returns an enumerator if no block is given.
37   #
38   # See the +Find+ module documentation for an example.
39   #
40   def find(*paths, ignore_error: true) # :yield: path
41     block_given? or return enum_for(__method__, *paths, ignore_error: ignore_error)
43     fs_encoding = Encoding.find("filesystem")
45     paths.collect!{|d| raise Errno::ENOENT, d unless File.exist?(d); d.dup}.each do |path|
46       path = path.to_path if path.respond_to? :to_path
47       enc = path.encoding == Encoding::US_ASCII ? fs_encoding : path.encoding
48       ps = [path]
49       while file = ps.shift
50         catch(:prune) do
51           yield file.dup
52           begin
53             s = File.lstat(file)
54           rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL
55             raise unless ignore_error
56             next
57           end
58           if s.directory? then
59             begin
60               fs = Dir.children(file, encoding: enc)
61             rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL
62               raise unless ignore_error
63               next
64             end
65             fs.sort!
66             fs.reverse_each {|f|
67               f = File.join(file, f)
68               ps.unshift f
69             }
70           end
71         end
72       end
73     end
74     nil
75   end
77   #
78   # Skips the current file or directory, restarting the loop with the next
79   # entry. If the current file is a directory, that directory will not be
80   # recursively entered. Meaningful only within the block associated with
81   # Find::find.
82   #
83   # See the +Find+ module documentation for an example.
84   #
85   def prune
86     throw :prune
87   end
89   module_function :find, :prune
90 end