94 lines
2 KiB
Crystal
94 lines
2 KiB
Crystal
|
|
require "walk"
|
|
|
|
module CodePreloader
|
|
|
|
# Manage a list of files
|
|
class FileList
|
|
|
|
alias Filter = String -> Bool
|
|
|
|
class NotADirectory < Exception
|
|
def initialize(path)
|
|
super(path.to_s)
|
|
end
|
|
end
|
|
|
|
@sources : Array(String)
|
|
@filters_in : Array(Filter)
|
|
@filters_out : Array(Filter)
|
|
|
|
def initialize(dirs = [] of String)
|
|
@sources = [] of String
|
|
@filters_in = [] of Filter
|
|
@filters_out = [] of Filter
|
|
dirs.each { |dir| self.add(dir) }
|
|
end
|
|
|
|
def add(dirs : Array(String))
|
|
dirs.each { |dir| add(dir) }
|
|
end
|
|
|
|
def add(dir : String)
|
|
raise NotADirectory.new(dir) if !File.exists? dir
|
|
|
|
@sources << dir
|
|
end
|
|
|
|
def select(&filter : Filter)
|
|
@filters_in << filter
|
|
end
|
|
|
|
def reject(&filter : Filter)
|
|
@filters_out << filter
|
|
end
|
|
|
|
def each(&block)
|
|
# ensure we display files only once
|
|
seen = Set(String).new
|
|
|
|
# walk each source
|
|
@sources.each do |dir|
|
|
walker = Walk::Down.new(dir)
|
|
|
|
walker = walker.filter do |path|
|
|
is_dir = File.directory? path
|
|
keep = true
|
|
must_select = false
|
|
must_reject = false
|
|
|
|
@filters_in.each do |filter_in|
|
|
must_select = must_select || filter_in.call(path.to_s)
|
|
end
|
|
keep = keep && must_select if @filters_in.any?
|
|
keep = keep || is_dir
|
|
|
|
@filters_out.each do |filter_out|
|
|
must_reject = must_reject || filter_out.call(path.to_s)
|
|
end
|
|
keep = keep && !must_reject if @filters_out.any?
|
|
|
|
keep
|
|
end
|
|
|
|
walker.each do |path|
|
|
next if File.directory? path
|
|
|
|
path = File.realpath(path) if File.symlink? path
|
|
next if seen.includes? path.to_s
|
|
|
|
seen << path.to_s
|
|
yield path.to_s
|
|
end
|
|
end
|
|
end
|
|
|
|
def to_a()
|
|
files = [] of String
|
|
self.each do |path|
|
|
files << path.to_s
|
|
end
|
|
files
|
|
end
|
|
end
|
|
end
|