| module Jekyll |
| class EntryFilter |
| attr_reader :site |
| SPECIAL_LEADING_CHARACTERS = [ |
| ".", "_", "#", "~", |
| ].freeze |
| |
| def initialize(site, base_directory = nil) |
| @site = site |
| @base_directory = derive_base_directory( |
| @site, base_directory.to_s.dup |
| ) |
| end |
| |
| def base_directory |
| @base_directory.to_s |
| end |
| |
| def derive_base_directory(site, base_dir) |
| base_dir[site.source] = "" if base_dir.start_with?(site.source) |
| base_dir |
| end |
| |
| def relative_to_source(entry) |
| File.join( |
| base_directory, entry |
| ) |
| end |
| |
| def filter(entries) |
| entries.reject do |e| |
| unless included?(e) |
| special?(e) || backup?(e) || excluded?(e) || symlink?(e) |
| end |
| end |
| end |
| |
| def included?(entry) |
| glob_include?(site.include, entry) || |
| glob_include?(site.include, File.basename(entry)) |
| end |
| |
| def special?(entry) |
| SPECIAL_LEADING_CHARACTERS.include?(entry[0..0]) || |
| SPECIAL_LEADING_CHARACTERS.include?(File.basename(entry)[0..0]) |
| end |
| |
| def backup?(entry) |
| entry[-1..-1] == "~" |
| end |
| |
| def excluded?(entry) |
| glob_include?(site.exclude, relative_to_source(entry)).tap do |excluded| |
| if excluded |
| Jekyll.logger.debug( |
| "EntryFilter:", |
| "excluded #{relative_to_source(entry)}" |
| ) |
| end |
| end |
| end |
| |
| # -- |
| # Check if a file is a symlink. |
| # NOTE: This can be converted to allowing even in safe, |
| # since we use Pathutil#in_path? now. |
| # -- |
| def symlink?(entry) |
| site.safe && File.symlink?(entry) && symlink_outside_site_source?(entry) |
| end |
| |
| # -- |
| # NOTE: Pathutil#in_path? gets the realpath. |
| # @param [<Anything>] entry the entry you want to validate. |
| # Check if a path is outside of our given root. |
| # -- |
| def symlink_outside_site_source?(entry) |
| !Pathutil.new(entry).in_path?( |
| site.in_source_dir |
| ) |
| end |
| |
| # -- |
| # Check if an entry matches a specific pattern and return true,false. |
| # Returns true if path matches against any glob pattern. |
| # -- |
| def glob_include?(enum, e) |
| entry = Pathutil.new(site.in_source_dir).join(e) |
| enum.any? do |exp| |
| # Users who send a Regexp knows what they want to |
| # exclude, so let them send a Regexp to exclude files, |
| # we will not bother caring if it works or not, it's |
| # on them at this point. |
| |
| if exp.is_a?(Regexp) |
| entry =~ exp |
| |
| else |
| item = Pathutil.new(site.in_source_dir).join(exp) |
| |
| # If it's a directory they want to exclude, AKA |
| # ends with a "/" then we will go on to check and |
| # see if the entry falls within that path and |
| # exclude it if that's the case. |
| |
| if e.end_with?("/") |
| entry.in_path?( |
| item |
| ) |
| |
| else |
| File.fnmatch?(item, entry) || |
| entry.to_path.start_with?( |
| item |
| ) |
| end |
| end |
| end |
| end |
| end |
| end |