fast_ignore 0.16.1 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7952045a743c12fa1963ffba7aa81a8ca3cc81aec40b0bfc9c0e6bb6424e9433
4
- data.tar.gz: dcacd0bdd1873638156c9b2323263cf1ee7fc349b012f40c28caa4fe10d82f91
3
+ metadata.gz: 78cb85cea0888d67c91de09bd54ad644510167c993dc355d187593003d341393
4
+ data.tar.gz: fb1fda9c1675ee28f4a6ff23191f95c2dd6e497ca2a70c4791dc5dfb85baecd1
5
5
  SHA512:
6
- metadata.gz: 35c9fedb895b3e30632b29aab2eba3369ec6512bd6c5b9cfa563156c4c0c291b5c7854877aa4c8da063b54ed97a6f132c5d903622d2a6e2fc69c57c708150c33
7
- data.tar.gz: ca894c9a8e11471d3c1f81f959862cd16a60db784898ef0d0e4da880e063257334fdf6aad061d95c23850c726ffde781076e6c248ebecfa808701d0731fbb125
6
+ metadata.gz: 10531a1d819b74fcc442ce7591be124430d3c55c55afbccb79ba295dd89c0e85e4a1a0a75b11996557057fa2f5dbad71e9284789143395d229e3abbbbd42ba3c
7
+ data.tar.gz: d0b07a2757c3b962a59973581234ec9e346717d24cdbd5443073c0fd14f840fb287419d63eeb31d4aa52d3fff2e1c0842cc119ed52e836cd55ed73bcd29a3fc7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # v0.17.0
2
+ - allow overriding `exists:` in `allowed?`
3
+ - allow setting `include_directories: true` in `allowed?`
4
+ - subsequent calls to `allowed?` with the same path but different `directory:` or `content:` arguments won't potentially mess up the cache
5
+ - slight performance improvements of the shebang rule matcher loading the first line
6
+ - drop support for ruby 2.4
7
+ - add ruby 3.1 to the test matrix
8
+
1
9
  # v0.16.1
2
10
  - respect GIT_CONFIG_SYSTEM, GIT_CONFIG_NOSYSTEM and GIT_CONFIG_GLOBAL env vars the same way git does
3
11
  - make the tests more resilient to whatever global config is going on.
data/README.md CHANGED
@@ -15,7 +15,7 @@ FastIgnore.new(relative: true).sort == `git ls-files`.split("\n").sort
15
15
  ## Features
16
16
 
17
17
  - Fast (faster than using `` `git ls-files`.split("\n") `` for small repos (because it avoids the overhead of ``` `` ```))
18
- - Supports ruby 2.4-3.0.x & jruby
18
+ - Supports ruby 2.5-3.1.x & jruby
19
19
  - supports all [gitignore rule patterns](https://git-scm.com/docs/gitignore#_pattern_format)
20
20
  - doesn't require git to be installed
21
21
  - supports a gitignore-esque "include" patterns. ([`include_rules:`](#include_rules)/[`include_files:`](#include_files))
@@ -81,20 +81,79 @@ Relative paths will be considered relative to the [`root:`](#root) directory, no
81
81
 
82
82
  This is aliased as `===` so you can use a FastIgnore instance in case statements.
83
83
  ```ruby
84
+ @path_matcher ||= FastIgnore.new
85
+
84
86
  case my_path
85
- when FastIgnore.new
87
+ when @path_matcher
86
88
  puts(my_path)
87
89
  end
88
90
  ```
89
91
 
90
92
  It's recommended to save the FastIgnore instance to a variable to avoid having to read and parse the gitignore file and gitconfig files repeatedly.
91
93
 
92
- See [Optimising allowed](#optimising_allowed) for ways to make this even faster
94
+ #### directory: true/false/nil
95
+
96
+ If your code already knows the path to test is/not a directory or wants to lie about whether it is/is not a directory, you can pass `directory: true` or `directory: false` as an argument to `allowed?` (to have FastIgnore ask the file system, you can pass `directory: nil` or nothing)
97
+
98
+ ```
99
+ FastIgnore.new.allowed?('relative/path', directory: false) # matches `path` as a file
100
+ FastIgnore.new.allowed?('relative/path', directory: true) # matches `path` as a directory
101
+ FastIgnore.new.allowed?('relative/path', directory: nil) # matches path as whatever it is on the filesystem
102
+ FastIgnore.new.allowed?('relative/path) # or as a file if it doesn't exist on the file system
103
+ ```
104
+
105
+ #### content: true/false/nil
106
+
107
+ default: `nil`
108
+
109
+ If your code already knows the path to test is has a particular text content or wants to lie about the content, you can pass `directory: true` or `directory: false` as an argument to `allowed?` (to have FastIgnore ask the file system, you can pass `directory: nil` or nothing)
110
+
111
+ ```
112
+ FastIgnore.new.allowed?('relative/path', content: "#!/usr/bin/env ruby\n\nputs 'hello'") # matches ruby shebang
113
+ FastIgnore.new.allowed?('relative/path', content: "#!/usr/bin/env bash\n\necho 'hello'") # matches bash shebang
114
+ FastIgnore.new.allowed?('relative/path', content: nil) # matches path as whatever content is on the filesystem
115
+ FastIgnore.new.allowed?('relative/path) # or as an empty file if it doesn't actually exist
116
+ ```
117
+
118
+ #### content: true/false/nil
119
+
120
+ default: `nil`
121
+
122
+ If your code already knows the path to test is has a particular text content or wants to lie about the content, you can pass `directory: true` or `directory: false` as an argument to `allowed?` (to have FastIgnore ask the file system, you can pass `directory: nil` or nothing)
123
+
124
+ ```
125
+ FastIgnore.new.allowed?('relative/path', content: "#!/usr/bin/env ruby\n\nputs 'hello'") # matches ruby shebang
126
+ FastIgnore.new.allowed?('relative/path', content: "#!/usr/bin/env bash\n\necho 'hello'") # matches bash shebang
127
+ FastIgnore.new.allowed?('relative/path', content: nil) # matches path as whatever content is on the filesystem
128
+ FastIgnore.new.allowed?('relative/path) # or as an empty file if it doesn't actually exist
129
+ ```
93
130
 
94
- **Note: A file must exist at that path and not be a directory for it to be considered allowed.**
95
- Essentially it can be thought of as `` `git ls-files`.include?(path) `` but much faster.
96
- This excludes all directories and all possible path names that don't exist.
131
+ #### exist: true/false/nil
97
132
 
133
+ default: `nil`
134
+
135
+ If your code already knows the path to test exists or wants to lie about its existence, you can pass `exists: true` or `exists: false` as an argument to `allowed?` (to have FastIgnore ask the file system, you can pass `exists: nil` or nothing)
136
+
137
+ ```
138
+ FastIgnore.new.allowed?('relative/path', exists: true) # will check the path regardless of whether it actually truly exists
139
+ FastIgnore.new.allowed?('relative/path', exists: false) # will always return false
140
+ FastIgnore.new.allowed?('relative/path', exists: nil) # asks the filesystem
141
+ FastIgnore.new.allowed?('relative/path) # asks the filesystem
142
+ ```
143
+
144
+ #### include_directories: true/false
145
+
146
+ default: `false`
147
+
148
+ By default a file must not be a directory for it to be considered allowed. This is intended to match the behaviour of `git ls-files` which only lists files.
149
+
150
+ To match directories you can pass `include_directories: true` to `allowed?`
151
+
152
+ ```
153
+ FastIgnore.new.allowed?('relative/path', include_directories: true) # will test the path even if it's a directory
154
+ FastIgnore.new.allowed?('relative/path', include_directories: false) # will always return false if the path is a directory
155
+ FastIgnore.new.allowed?('relative/path) # will always return false if the path is a directory
156
+ ```
98
157
 
99
158
  ### `relative: true`
100
159
 
@@ -293,15 +352,6 @@ FastIgnore.new(argv_rules: ["my/rule", File.read('/my/path')]).to_a
293
352
  ```
294
353
 
295
354
  This does unfortunately lose the file path as the root `/` and there is no workaround except setting the [`root:`](#root) for the whole FastIgnore instance.
296
-
297
- ### optimising #allowed?
298
-
299
- To avoid unnecessary calls to the filesystem, if your code already knows whether or not it's a directory, or if you're checking shebangs and you have already read the content of the file: use
300
- ```ruby
301
- FastIgnore.new.allowed?('relative/path', directory: false, content: "#!/usr/bin/ruby\n\nputs 'ok'\n")
302
- ```
303
- This is not required, and if FastIgnore does have to go to the filesystem for this information it's well optimised to only read what is necessary.
304
-
305
355
  ## Limitations
306
356
  - Doesn't know what to do if you change the current working directory inside the [`FastIgnore#each`](#each_map_etc) block.
307
357
  So don't do that.
@@ -11,7 +11,7 @@ class FastIgnore
11
11
  @file_rules = (squash ? squash_rules(rules.reject(&:dir_only?)) : rules.reject(&:dir_only?)).freeze
12
12
  @has_shebang_rules = rules.any?(&:shebang?)
13
13
 
14
- @allowed_recursive = { '.' => true }
14
+ @allowed_recursive = { ['.', true, nil] => true }
15
15
  @allow = allow
16
16
  @gitignore = gitignore
17
17
 
@@ -27,8 +27,8 @@ class FastIgnore
27
27
  end
28
28
 
29
29
  def allowed_recursive?(relative_path, dir, full_path, filename, content = nil)
30
- @allowed_recursive.fetch(relative_path) do
31
- @allowed_recursive[relative_path] =
30
+ @allowed_recursive.fetch([relative_path, dir, content]) do |key|
31
+ @allowed_recursive[key] =
32
32
  allowed_recursive?(::File.dirname(relative_path), true, nil, nil, nil) &&
33
33
  allowed_unrecursive?(relative_path, dir, full_path, filename, content)
34
34
  end
@@ -27,8 +27,8 @@ class FastIgnore
27
27
  @array.freeze if @gitignore_rule_set
28
28
  end
29
29
 
30
- def allowed_recursive?(relative_path, full_path, filename, content)
31
- @array.all? { |r| r.allowed_recursive?(relative_path, false, full_path, filename, content) }
30
+ def allowed_recursive?(relative_path, dir, full_path, filename, content)
31
+ @array.all? { |r| r.allowed_recursive?(relative_path, dir, full_path, filename, content) }
32
32
  end
33
33
 
34
34
  def allowed_unrecursive?(relative_path, dir, full_path, filename)
@@ -61,12 +61,9 @@ class FastIgnore
61
61
 
62
62
  def first_line(path) # rubocop:disable Metrics/MethodLength
63
63
  file = ::File.new(path)
64
- first_line = new_fragment = file.sysread(64)
64
+ first_line = file.sysread(64)
65
65
  if first_line.start_with?('#!')
66
- until new_fragment.include?("\n")
67
- new_fragment = file.sysread(64)
68
- first_line += new_fragment
69
- end
66
+ first_line += file.readline unless first_line.match?(/\n/)
70
67
  else
71
68
  file.close
72
69
  return
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class FastIgnore
4
- VERSION = '0.16.1'
4
+ VERSION = '0.17.0'
5
5
  end
data/lib/fast_ignore.rb CHANGED
@@ -49,19 +49,30 @@ class FastIgnore
49
49
  each_recursive(root_from_pwd, '', &block)
50
50
  end
51
51
 
52
- def allowed?(path, directory: nil, content: nil)
52
+ def allowed?(path, directory: nil, content: nil, exists: nil, include_directories: false) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
53
53
  full_path = ::File.expand_path(path, @root)
54
54
  return false unless full_path.start_with?(@root)
55
- return false if directory.nil? ? @follow_symlinks_method.call(full_path).directory? : directory
55
+
56
+ begin
57
+ directory = directory.nil? ? @follow_symlinks_method.call(full_path).directory? : directory
58
+ rescue ::Errno::ENOENT, ::Errno::EACCES, ::Errno::ENOTDIR, ::Errno::ELOOP, ::Errno::ENAMETOOLONG
59
+ exists = false if exists.nil?
60
+ directory = false
61
+ end
62
+
63
+ return false if !include_directories && directory
64
+
65
+ exists = exists.nil? ? ::File.exist?(full_path) : exists
66
+
67
+ return false unless exists
56
68
 
57
69
  relative_path = full_path.delete_prefix(@root)
58
70
  load_gitignore_recursive(relative_path) if @gitignore_enabled
59
71
 
60
72
  filename = ::File.basename(relative_path)
73
+ content = content.slice(/.*/) if content # we only care about the first line
61
74
 
62
- @rule_sets.allowed_recursive?(relative_path, full_path, filename, content)
63
- rescue ::Errno::ENOENT, ::Errno::EACCES, ::Errno::ENOTDIR, ::Errno::ELOOP, ::Errno::ENAMETOOLONG
64
- false
75
+ @rule_sets.allowed_recursive?(relative_path, directory, full_path, filename, content)
65
76
  end
66
77
  alias_method :===, :allowed?
67
78
 
@@ -77,7 +88,7 @@ class FastIgnore
77
88
  paths << path
78
89
  end
79
90
 
80
- paths.reverse_each(&method(:load_gitignore))
91
+ paths.reverse_each { |p| load_gitignore(p) }
81
92
  end
82
93
 
83
94
  def load_gitignore(parent_path, check_exists: true)
@@ -93,21 +104,19 @@ class FastIgnore
93
104
  load_gitignore(parent_relative_path, check_exists: false) if @gitignore_enabled && children.include?('.gitignore')
94
105
 
95
106
  children.each do |filename|
96
- begin
97
- full_path = parent_full_path + filename
98
- relative_path = parent_relative_path + filename
99
- dir = @follow_symlinks_method.call(full_path).directory?
100
-
101
- next unless @rule_sets.allowed_unrecursive?(relative_path, dir, full_path, filename)
102
-
103
- if dir
104
- each_recursive(full_path + '/', relative_path + '/', &block)
105
- else
106
- yield(@relative ? relative_path : @root + relative_path)
107
- end
108
- rescue ::Errno::ENOENT, ::Errno::EACCES, ::Errno::ENOTDIR, ::Errno::ELOOP, ::Errno::ENAMETOOLONG
109
- nil
107
+ full_path = parent_full_path + filename
108
+ relative_path = parent_relative_path + filename
109
+ dir = @follow_symlinks_method.call(full_path).directory?
110
+
111
+ next unless @rule_sets.allowed_unrecursive?(relative_path, dir, full_path, filename)
112
+
113
+ if dir
114
+ each_recursive(full_path + '/', relative_path + '/', &block)
115
+ else
116
+ yield(@relative ? relative_path : @root + relative_path)
110
117
  end
118
+ rescue ::Errno::ENOENT, ::Errno::EACCES, ::Errno::ENOTDIR, ::Errno::ELOOP, ::Errno::ENAMETOOLONG
119
+ nil
111
120
  end
112
121
  end
113
122
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_ignore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.1
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dana Sherson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-11 00:00:00.000000000 Z
11
+ date: 2022-03-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -211,7 +211,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
211
211
  requirements:
212
212
  - - ">="
213
213
  - !ruby/object:Gem::Version
214
- version: 2.4.0
214
+ version: 2.5.0
215
215
  required_rubygems_version: !ruby/object:Gem::Requirement
216
216
  requirements:
217
217
  - - ">="