fast_ignore 0.16.1 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ">="