fast_ignore 0.12.0 → 0.15.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +157 -80
- data/lib/fast_ignore.rb +27 -26
- data/lib/fast_ignore/backports.rb +2 -2
- data/lib/fast_ignore/file_root.rb +39 -0
- data/lib/fast_ignore/gitignore_include_rule_builder.rb +102 -0
- data/lib/fast_ignore/gitignore_rule_builder.rb +182 -0
- data/lib/fast_ignore/gitignore_rule_regexp_builder.rb +76 -0
- data/lib/fast_ignore/gitignore_rule_scanner.rb +73 -0
- data/lib/fast_ignore/global_gitignore.rb +50 -0
- data/lib/fast_ignore/rule.rb +28 -12
- data/lib/fast_ignore/rule_builder.rb +18 -80
- data/lib/fast_ignore/rule_set.rb +23 -16
- data/lib/fast_ignore/rule_sets.rb +113 -0
- data/lib/fast_ignore/shebang_rule.rb +34 -14
- data/lib/fast_ignore/unmatchable_rule.rb +41 -0
- data/lib/fast_ignore/version.rb +1 -1
- metadata +19 -31
- data/.gitignore +0 -6
- data/.leftovers.yml +0 -5
- data/.rspec +0 -3
- data/.rubocop.yml +0 -216
- data/.simplecov +0 -10
- data/.spellr.yml +0 -5
- data/.spellr_wordlists/english.txt +0 -62
- data/.spellr_wordlists/ruby.txt +0 -1
- data/.spellr_wordlists/shell.txt +0 -3
- data/.travis.yml +0 -11
- data/Gemfile +0 -9
- data/Rakefile +0 -18
- data/bin/console +0 -8
- data/bin/ls +0 -6
- data/bin/ls_seconds +0 -21
- data/bin/setup +0 -8
- data/bin/time +0 -21
- data/fast_ignore.gemspec +0 -41
- data/lib/fast_ignore/fn_match_to_re.rb +0 -96
- data/lib/fast_ignore/rule_set_builder.rb +0 -126
data/.spellr_wordlists/ruby.txt
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rspec
|
data/.spellr_wordlists/shell.txt
DELETED
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bundler/gem_tasks'
|
4
|
-
require 'rspec/core/rake_task'
|
5
|
-
require 'rubocop/rake_task'
|
6
|
-
require 'spellr/rake_task'
|
7
|
-
require 'leftovers/rake_task'
|
8
|
-
|
9
|
-
RuboCop::RakeTask.new
|
10
|
-
RSpec::Core::RakeTask.new(:spec)
|
11
|
-
Spellr::RakeTask.generate_task
|
12
|
-
Leftovers::RakeTask.generate_task
|
13
|
-
|
14
|
-
if RUBY_PLATFORM == 'java'
|
15
|
-
task default: :spec
|
16
|
-
else
|
17
|
-
task default: [:spec, :rubocop, :spellr, :leftovers]
|
18
|
-
end
|
data/bin/console
DELETED
data/bin/ls
DELETED
data/bin/ls_seconds
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby --disable-all
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require_relative '../lib/fast_ignore'
|
5
|
-
|
6
|
-
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
7
|
-
new_a = FastIgnore.new(relative: true, argv_rules: ARGV).to_a
|
8
|
-
t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
9
|
-
puts "new #{new_a.count}: #{t2 - t1}"
|
10
|
-
fi = FastIgnore.new(relative: true, argv_rules: ARGV)
|
11
|
-
fi.to_a
|
12
|
-
t3 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
13
|
-
cached_a = fi.to_a
|
14
|
-
t4 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
15
|
-
puts "cached #{cached_a.count}: #{t4 - t3}"
|
16
|
-
t5 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
17
|
-
git_a = `git ls-files`.split("\n")
|
18
|
-
t6 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
19
|
-
puts "git ls-files #{git_a.count}: #{t6 - t5}"
|
20
|
-
|
21
|
-
exit 1 unless new_a.length == cached_a.length && new_a.length == git_a.length
|
data/bin/setup
DELETED
data/bin/time
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# use mac terminal not vs code terminal
|
5
|
-
# ensure nothing else is watching that dir in the filesystem e.g. webpack
|
6
|
-
|
7
|
-
require 'open3'
|
8
|
-
require 'shellwords'
|
9
|
-
RUNS = 30
|
10
|
-
SCRIPT = "time #{__dir__}/ls #{Shellwords.join(ARGV)}"
|
11
|
-
|
12
|
-
times = Array.new(RUNS).map do
|
13
|
-
run_times = Open3.capture3(SCRIPT)[1]
|
14
|
-
puts run_times.lstrip
|
15
|
-
run_times.scan(/(?:\d+(?:.\d+)?)/)
|
16
|
-
end
|
17
|
-
|
18
|
-
puts format(
|
19
|
-
"\e[1mAverage:\n\e[32m%0.2f real %0.2f user %0.2f sys\e[0m", # rubocop:disable Style/FormatStringToken
|
20
|
-
*times.transpose.map { |n| (n.map(&:to_f).sum / RUNS) }
|
21
|
-
)
|
data/fast_ignore.gemspec
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
lib = File.expand_path('lib', __dir__)
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require 'fast_ignore/version'
|
6
|
-
|
7
|
-
Gem::Specification.new do |spec|
|
8
|
-
spec.name = 'fast_ignore'
|
9
|
-
spec.version = FastIgnore::VERSION
|
10
|
-
spec.authors = ['Dana Sherson']
|
11
|
-
spec.email = ['robot@dana.sh']
|
12
|
-
|
13
|
-
spec.summary = 'Parse gitignore files, quickly'
|
14
|
-
spec.homepage = 'https://github.com/robotdana/fast_ignore'
|
15
|
-
spec.license = 'MIT'
|
16
|
-
|
17
|
-
spec.required_ruby_version = '~> 2.4'
|
18
|
-
|
19
|
-
if spec.respond_to?(:metadata)
|
20
|
-
spec.metadata['homepage_uri'] = spec.homepage
|
21
|
-
spec.metadata['source_code_uri'] = 'https://github.com/robotdana/fast_ignore'
|
22
|
-
spec.metadata['changelog_uri'] = 'https://github.com/robotdana/fast_ignore/blob/master/CHANGELOG.md'
|
23
|
-
end
|
24
|
-
|
25
|
-
# Specify which files should be added to the gem when it is released.
|
26
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
27
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
28
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
29
|
-
end
|
30
|
-
spec.require_paths = ['lib']
|
31
|
-
|
32
|
-
spec.add_development_dependency 'bundler', '>= 1.17'
|
33
|
-
spec.add_development_dependency 'leftovers', '>= 0.2.2'
|
34
|
-
spec.add_development_dependency 'pry', '> 0'
|
35
|
-
spec.add_development_dependency 'rake', '>= 12.3.3'
|
36
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
37
|
-
spec.add_development_dependency 'rubocop', '>= 0.74.0'
|
38
|
-
spec.add_development_dependency 'rubocop-rspec', '~> 1'
|
39
|
-
spec.add_development_dependency 'simplecov', '~> 0.18.5'
|
40
|
-
spec.add_development_dependency 'spellr', '>= 0.8.3'
|
41
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class FastIgnore
|
4
|
-
module FNMatchToRegex
|
5
|
-
# This doesn't look rubyish because i ported it from rust (the only rust i ever wrote that worked)
|
6
|
-
class << self
|
7
|
-
def call(pattern) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
8
|
-
re = '\\A'.dup
|
9
|
-
|
10
|
-
in_character_group = false
|
11
|
-
has_characters_in_group = false
|
12
|
-
escape_next_character = false
|
13
|
-
last_char_opened_character_group = false
|
14
|
-
negated_character_group = false
|
15
|
-
stars = 0
|
16
|
-
|
17
|
-
pattern.each_char do |char| # rubocop:disable Metrics/BlockLength
|
18
|
-
if escape_next_character
|
19
|
-
re << Regexp.escape(char)
|
20
|
-
escape_next_character = false
|
21
|
-
elsif char == '\\' # single char, just needs to be escaped
|
22
|
-
escape_next_character = true
|
23
|
-
elsif in_character_group
|
24
|
-
if char == '/'
|
25
|
-
if negated_character_group
|
26
|
-
has_characters_in_group = true
|
27
|
-
re << char
|
28
|
-
end
|
29
|
-
elsif char == '^'
|
30
|
-
if last_char_opened_character_group
|
31
|
-
re << char
|
32
|
-
negated_character_group = true
|
33
|
-
else
|
34
|
-
re << '\\^'
|
35
|
-
has_characters_in_group = true
|
36
|
-
end
|
37
|
-
# not characters in group
|
38
|
-
elsif char == ']'
|
39
|
-
break unless has_characters_in_group
|
40
|
-
|
41
|
-
re << ']'
|
42
|
-
in_character_group = false
|
43
|
-
has_characters_in_group = false
|
44
|
-
negated_character_group = false
|
45
|
-
last_char_opened_character_group = false
|
46
|
-
elsif char == '-'
|
47
|
-
has_characters_in_group = true
|
48
|
-
re << char
|
49
|
-
else
|
50
|
-
has_characters_in_group = true
|
51
|
-
re << Regexp.escape(char)
|
52
|
-
end
|
53
|
-
last_char_opened_character_group = false
|
54
|
-
elsif char == '*'
|
55
|
-
stars += 1
|
56
|
-
elsif char == '/'
|
57
|
-
re << if stars >= 2
|
58
|
-
'(?:.*/)?'
|
59
|
-
elsif stars.positive?
|
60
|
-
'[^/]*/'
|
61
|
-
else
|
62
|
-
char
|
63
|
-
end
|
64
|
-
stars = 0
|
65
|
-
else
|
66
|
-
if stars.positive?
|
67
|
-
re << '[^/]*'
|
68
|
-
stars = 0
|
69
|
-
end
|
70
|
-
if char == '?'
|
71
|
-
re << '[^/]'
|
72
|
-
elsif char == '['
|
73
|
-
re << '['
|
74
|
-
in_character_group = true
|
75
|
-
last_char_opened_character_group = true
|
76
|
-
else
|
77
|
-
re << Regexp.escape(char)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
if in_character_group
|
83
|
-
return /(?!)/ # impossible to match anything
|
84
|
-
end
|
85
|
-
|
86
|
-
if stars >= 2
|
87
|
-
re << '.*'
|
88
|
-
elsif stars.positive?
|
89
|
-
re << '[^/]*'
|
90
|
-
end
|
91
|
-
re << '\\z'
|
92
|
-
Regexp.new(re, Regexp::IGNORECASE)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class FastIgnore
|
4
|
-
module RuleSetBuilder
|
5
|
-
class << self
|
6
|
-
# :nocov:
|
7
|
-
using ::FastIgnore::Backports::DeletePrefixSuffix if defined?(::FastIgnore::Backports::DeletePrefixSuffix)
|
8
|
-
# :nocov:
|
9
|
-
|
10
|
-
def build( # rubocop:disable Metrics/ParameterLists
|
11
|
-
root:,
|
12
|
-
ignore_rules: nil,
|
13
|
-
ignore_files: nil,
|
14
|
-
gitignore: :auto,
|
15
|
-
include_rules: nil,
|
16
|
-
include_files: nil,
|
17
|
-
argv_rules: nil
|
18
|
-
)
|
19
|
-
prepare [
|
20
|
-
from_array(ignore_rules),
|
21
|
-
*from_files(ignore_files, project_root: root),
|
22
|
-
from_array('.git'),
|
23
|
-
from_gitignore_arg(gitignore, project_root: root),
|
24
|
-
from_array(include_rules, allow: true),
|
25
|
-
*from_files(include_files, allow: true, project_root: root),
|
26
|
-
from_array(argv_rules, allow: true, expand_path: root)
|
27
|
-
]
|
28
|
-
end
|
29
|
-
|
30
|
-
def append_gitignore(rule_sets, project_root:, relative_path:, soft: true)
|
31
|
-
new_gitignore = from_file(relative_path, project_root: project_root, gitignore: true, soft: soft)
|
32
|
-
return unless new_gitignore
|
33
|
-
|
34
|
-
base_gitignore = rule_sets.find(&:gitignore?)
|
35
|
-
if base_gitignore
|
36
|
-
base_gitignore << new_gitignore
|
37
|
-
else
|
38
|
-
rule_sets << new_gitignore
|
39
|
-
prepare(rule_sets)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def prepare(rule_sets)
|
46
|
-
rule_sets.compact!
|
47
|
-
rule_sets.reject!(&:empty?)
|
48
|
-
rule_sets.sort_by!(&:weight)
|
49
|
-
rule_sets
|
50
|
-
end
|
51
|
-
|
52
|
-
def from_file(filename, project_root:, allow: false, file_root: nil, gitignore: false, soft: false) # rubocop:disable Metrics/ParameterLists
|
53
|
-
filename = ::File.expand_path(filename, project_root)
|
54
|
-
return if soft && !::File.exist?(filename)
|
55
|
-
unless file_root || filename.start_with?(project_root)
|
56
|
-
raise FastIgnore::Error, "#{filename} is not within #{project_root}"
|
57
|
-
end
|
58
|
-
|
59
|
-
file_root ||= "#{::File.dirname(filename)}/".delete_prefix(project_root)
|
60
|
-
build_rule_set(::File.readlines(filename), allow, file_root: file_root, gitignore: gitignore)
|
61
|
-
end
|
62
|
-
|
63
|
-
def from_files(files, project_root:, allow: false)
|
64
|
-
Array(files).map do |file|
|
65
|
-
from_file(file, project_root: project_root, allow: allow)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def from_gitignore_arg(gitignore, project_root:)
|
70
|
-
return unless gitignore
|
71
|
-
|
72
|
-
gi = ::FastIgnore::RuleSet.new([], false, true)
|
73
|
-
gi << from_gitignore_file(gitconfig_global_gitignore_path || default_global_gitignore_path)
|
74
|
-
gi << from_gitignore_file(::File.join(project_root, '.git/info/exclude'))
|
75
|
-
gi << from_gitignore_file(::File.join(project_root, '.gitignore'), soft: gitignore == :auto)
|
76
|
-
gi
|
77
|
-
end
|
78
|
-
|
79
|
-
def from_gitignore_file(path, soft: true)
|
80
|
-
return if soft && !::File.exist?(path)
|
81
|
-
|
82
|
-
build_rule_set(::File.readlines(path), false, file_root: '', gitignore: true)
|
83
|
-
end
|
84
|
-
|
85
|
-
def gitconfig_global_gitignore_path
|
86
|
-
config_path = ::File.expand_path('~/.gitconfig')
|
87
|
-
return unless ::File.exist?(config_path)
|
88
|
-
|
89
|
-
ignore_path = ::File.readlines(config_path).find { |l| l.start_with?("\texcludesfile = ") }
|
90
|
-
return unless ignore_path
|
91
|
-
|
92
|
-
ignore_path.delete_prefix!("\texcludesfile = ")
|
93
|
-
ignore_path.strip!
|
94
|
-
::File.expand_path(ignore_path)
|
95
|
-
end
|
96
|
-
|
97
|
-
def default_global_gitignore_path
|
98
|
-
if ENV['XDG_CONFIG_HOME'] && !ENV['XDG_CONFIG_HOME'].empty?
|
99
|
-
::File.expand_path('git/ignore', ENV['XDG_CONFIG_HOME'])
|
100
|
-
else
|
101
|
-
::File.expand_path('~/.config/git/ignore')
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def from_array(rules, allow: false, expand_path: false)
|
106
|
-
return unless rules
|
107
|
-
|
108
|
-
rules = Array(rules)
|
109
|
-
|
110
|
-
return if rules.empty?
|
111
|
-
|
112
|
-
rules = rules.flat_map { |string| string.to_s.lines }
|
113
|
-
|
114
|
-
build_rule_set(rules, allow, expand_path: expand_path)
|
115
|
-
end
|
116
|
-
|
117
|
-
def build_rule_set(rules, allow, expand_path: false, file_root: nil, gitignore: false)
|
118
|
-
rules = rules.flat_map do |rule|
|
119
|
-
::FastIgnore::RuleBuilder.build(rule, allow, expand_path, file_root)
|
120
|
-
end
|
121
|
-
|
122
|
-
::FastIgnore::RuleSet.new(rules, allow, gitignore)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|