1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
# frozen_string_literal: true
require 'pathspec/gitignorespec'
require 'pathspec/regexspec'
require 'find'
require 'pathname'
# Main PathSpec class, provides interfaces to various spec implementations
class PathSpec
attr_reader :specs
def initialize(lines = nil, type = :git)
@specs = []
add(lines, type) if lines
self
end
# Check if a path matches the pathspecs described
# Returns true if there are matches and none are excluded
# Returns false if there aren't matches or none are included
def match(path)
matches = specs_matching(path.to_s)
!matches.empty? && matches.all? {|m| m.inclusive?}
end
alias match? match
def specs_matching(path)
@specs.select do |spec|
spec if spec.match(path)
end
end
# Check if any files in a given directory or subdirectories match the specs
# Returns matched paths or nil if no paths matched
def match_tree(root)
rootpath = Pathname.new(root)
matching = []
Find.find(root) do |path|
relpath = Pathname.new(path).relative_path_from(rootpath).to_s
relpath += '/' if File.directory? path
matching << path if match(relpath)
end
matching
end
def match_path(path, root = '/')
rootpath = Pathname.new(drive_letter_to_path(root))
relpath = Pathname.new(drive_letter_to_path(path)).relative_path_from(rootpath).to_s
relpath += '/' if path[-1].chr == '/'
match(relpath)
end
def match_paths(paths, root = '/')
matching = []
paths.each do |path|
matching << path if match_path(path, root)
end
matching
end
def drive_letter_to_path(path)
path.gsub(%r{^([a-zA-Z]):/}, '/\1/')
end
# Generate specs from a filename, such as a .gitignore
def self.from_filename(filename, type = :git)
File.open(filename, 'r') { |io| from_lines(io, type) }
end
def self.from_lines(lines, type = :git)
new lines, type
end
# Generate specs from lines of text
def add(obj, type = :git)
spec_class = spec_type(type)
if obj.respond_to?(:each_line)
obj.each_line do |l|
spec = spec_class.new(l.rstrip)
@specs << spec if !spec.regex.nil? && !spec.inclusive?.nil?
end
elsif obj.respond_to?(:each)
obj.each do |l|
add(l, type)
end
else
raise 'Cannot make Pathspec from non-string/non-enumerable object.'
end
self
end
def empty?
@specs.empty?
end
def spec_type(type)
case type
when :git
GitIgnoreSpec
when :regex
RegexSpec
else
raise "Unknown spec type #{type}"
end
end
end
|