path_list 0.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +125 -0
- data/LICENSE.txt +21 -0
- data/README.md +317 -0
- data/lib/path_list.rb +62 -0
- data/lib/path_list/backports.rb +66 -0
- data/lib/path_list/gitignore_include_rule_builder.rb +95 -0
- data/lib/path_list/gitignore_rule_builder.rb +192 -0
- data/lib/path_list/gitignore_rule_group.rb +31 -0
- data/lib/path_list/gitignore_rule_scanner.rb +85 -0
- data/lib/path_list/global_gitignore.rb +50 -0
- data/lib/path_list/matchers/allow_any_dir.rb +35 -0
- data/lib/path_list/matchers/allow_path_regexp.rb +45 -0
- data/lib/path_list/matchers/ignore_path_regexp.rb +45 -0
- data/lib/path_list/matchers/shebang_regexp.rb +46 -0
- data/lib/path_list/matchers/unmatchable.rb +31 -0
- data/lib/path_list/matchers/within_dir.rb +54 -0
- data/lib/path_list/path_regexp_builder.rb +78 -0
- data/lib/path_list/patterns.rb +33 -0
- data/lib/path_list/relative_candidate.rb +20 -0
- data/lib/path_list/root_candidate.rb +56 -0
- data/lib/path_list/rule_builder.rb +42 -0
- data/lib/path_list/rule_group.rb +42 -0
- data/lib/path_list/rule_groups.rb +59 -0
- data/lib/path_list/version.rb +5 -0
- data/lib/path_list/walkers/file_system.rb +45 -0
- data/lib/path_list/walkers/gitignore_collecting_file_system.rb +47 -0
- metadata +198 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 91d6f384f20b71300e57606743061284dc17782a28cea3526ca68cc27787cc62
|
4
|
+
data.tar.gz: 355fd59a3a051fab5408d1fb3c7533d869c56b2619384dd60cfc6f688f44b6e5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 67ff7ebb50d8a66ac2305f5bf3ba911af59fce623313f4a2868cdee18445bdf3e21a6445ddb3b5ebfcd0c80accedfa2ada5fb017a156b7846367cfd0ca936cda
|
7
|
+
data.tar.gz: 7b558aaa6c071d63122c29238fb1ae9742d21f3c49171762f3eee94d6d5e45d90e6d6b2e7edf2d4afdc67ac8c86d7db19e4e83f5d1b9e76e064416e234c8e2f5
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
# v0.16.0
|
2
|
+
- Remove relative: true/false, always return relative paths like git does, its the only way i've ever used this gem
|
3
|
+
- Remove follow_symlinks: true/false. it's inaccuurately named and unnecessary
|
4
|
+
- relative paths to allowed? are expanded relative to the current dir not the PathList.root dir.
|
5
|
+
- each starts at the current directory, or optionally a given directory
|
6
|
+
- rename gem to path_list with everything in the constant PathList. I've renamed the gem because there's going to be a LOT of api changes soon.
|
7
|
+
|
8
|
+
# v0.15.2
|
9
|
+
- Updated methods with multiple `_` arguments to have different names to make sorbet happy
|
10
|
+
|
11
|
+
# v0.15.1
|
12
|
+
- Updated dependencies to allow running on ruby 3.0.0.preview1
|
13
|
+
|
14
|
+
# v0.15.0
|
15
|
+
- fixed a handful of character class edge cases to match git behavior
|
16
|
+
- mostly ranges with - or / as one end of the range
|
17
|
+
- major refactoring of the regexp builder that shouldn't have any behaviour implications but should make development easier (e.g. seeing those unhandled edge cases).
|
18
|
+
- improved speed of repos with many sub-gitignore files
|
19
|
+
- mentioned submodules & sparse checkout in the readme as yet another thing git does that this project doesn't because submodule details are hidden in the git index.
|
20
|
+
|
21
|
+
# v0.14.0
|
22
|
+
- significant performance improvements ~50% faster
|
23
|
+
- add `PathList#to_proc` for no good reason
|
24
|
+
|
25
|
+
# v0.13.0
|
26
|
+
- Attempt to improve documentation structure
|
27
|
+
- Remove `gitignore: true` raising `Errno::ENOENT` if root:/.gitignore didn't exist. I can't think of a use. Now `gitignore: true` is just the default behaviour.
|
28
|
+
- Don't ignore `.git` if `gitignore: false`.
|
29
|
+
|
30
|
+
# v0.12.1
|
31
|
+
- Reads all relevant git config files when finding a global .gitignore
|
32
|
+
|
33
|
+
# v0.12.0
|
34
|
+
- Reads all relevant gitignore files (nested .gitignore files, global .gitignore referred to in .gitconfig, and .git/info/exclude)
|
35
|
+
|
36
|
+
# v0.11.0
|
37
|
+
- major performance improvement (use regexp rather than fnmatch)
|
38
|
+
- optionally pass directory: and content: into allowed? if these are already loaded.
|
39
|
+
|
40
|
+
# v0.10.2
|
41
|
+
- add PathList#=== as an alias for PathList#allowed? so that PathList objects can be used for case statements.
|
42
|
+
- Fix shebangs in non-pwd-root situations
|
43
|
+
|
44
|
+
# v0.10.1
|
45
|
+
- Add option to follow symlinks (turns out i needed it)
|
46
|
+
- performance improvements
|
47
|
+
|
48
|
+
# v0.10.0
|
49
|
+
- patterns with middle slashes are anchored to the root (like the gitignore documentation, now that it more clearly explains)
|
50
|
+
- new shebang pattern (#!:), the previous version was extremely janky.
|
51
|
+
- now you can ignore by shebang pattern
|
52
|
+
- symlinks aren't followed when deciding if a path is a directory or not (this now matches git)
|
53
|
+
- documentation improvements
|
54
|
+
- root can be given as a path relative to PWD
|
55
|
+
- includes with 'a/**/d' now matches a/b/c/d properly
|
56
|
+
|
57
|
+
# v0.9.0
|
58
|
+
- speed improvements, which may break things (Specifically, only using relative paths internally, is about 30% faster (depending on root depth))
|
59
|
+
- using a `ignore_files:` or `include_files:` that are outside the `root: (default $PWD)` will now raise an error.
|
60
|
+
- remove deprecated `gitignore:` a path (e.g. `gitignore: '/path/to/gitignore'`). please use `gitignore: false, ignore_files: '/path/to/gitignore'` instead.
|
61
|
+
|
62
|
+
# v0.8.3
|
63
|
+
- fix `ignore_rules` not matching directories when using `include_shebangs:`
|
64
|
+
|
65
|
+
# v0.8.2
|
66
|
+
- fix `include_rules` not matching filenames with no extension when using `include_shebangs:`
|
67
|
+
|
68
|
+
# v0.8.1
|
69
|
+
- `include_shebangs:` can be given non array value
|
70
|
+
|
71
|
+
# v0.8.0
|
72
|
+
- drop support for ruby 2.3. My plan is to only support supported ruby versions
|
73
|
+
- add coverage to the pipeline. removed some methods, added some tests, and now we have 100% test coverage
|
74
|
+
- deprecate using `gitignore: '/path/to/gitignore'`. please use `gitignore: false, ignore_files: '/path/to/gitignore'` instead.
|
75
|
+
|
76
|
+
# v0.7.0
|
77
|
+
- add `include_shebangs:` which filters by shebangs
|
78
|
+
|
79
|
+
# v0.6.0
|
80
|
+
- nicer argv handling
|
81
|
+
- add `argv_rules:` option, which resolves paths and considers everything that doesn't start with a `*` to start with a `/`
|
82
|
+
- combine the different includes methods and files using AND
|
83
|
+
- slightly more realistic version comparison just in case someone releases ruby 2.10
|
84
|
+
- can be run with --disable-gems
|
85
|
+
- `.allowed?` now more exactly matches `.each`, it returns false for directories and unreadable files.
|
86
|
+
|
87
|
+
# v0.5.2
|
88
|
+
- performance improvements
|
89
|
+
|
90
|
+
# v0.5.1
|
91
|
+
- restore `.allowed?`. now i have tests for it. oops
|
92
|
+
|
93
|
+
# v0.5.0
|
94
|
+
- remove deprecated `:rules` and `:files` arguments
|
95
|
+
- ! is now evaluated in sequence for include_rules
|
96
|
+
- it's a big refactor, sorry if i broke something
|
97
|
+
- some performance improvements
|
98
|
+
|
99
|
+
# v0.4.1
|
100
|
+
- oops i did a regexp wrong
|
101
|
+
|
102
|
+
# v0.4.0
|
103
|
+
- include_rules support
|
104
|
+
- to make room for this, `:rules` and `:files` keyword arguments are deprecated.
|
105
|
+
Please use `:ignore_rules` and `:ignore_files` instead.
|
106
|
+
|
107
|
+
# v0.3.3
|
108
|
+
- some performance improvements. maybe
|
109
|
+
|
110
|
+
# v0.3.2
|
111
|
+
- handle soft links to nowhere
|
112
|
+
|
113
|
+
# v0.3.1
|
114
|
+
- upgrade rubocop version requirement to avoid github security warning
|
115
|
+
|
116
|
+
# v0.3.0
|
117
|
+
- Supports 2.3 - 2.6
|
118
|
+
|
119
|
+
# v0.2.0
|
120
|
+
- Considers rules relative to the location of the gitignore file instead of just relative to PWD
|
121
|
+
- Can override the path to the gitignore file, using `PathList.new(gitignore: path)`
|
122
|
+
- Mention PathList#allowed? in the documentation.
|
123
|
+
|
124
|
+
# v0.1.0
|
125
|
+
Initial Release
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Dana Sherson
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,317 @@
|
|
1
|
+
# PathList
|
2
|
+
|
3
|
+
# This is undergoing a major API redesign and when i'm done it'll be 1.0.0, please pin the exact version 0.whatever number in your gemfile
|
4
|
+
|
5
|
+
[![travis](https://travis-ci.com/robotdana/path_list.svg?branch=main)](https://travis-ci.com/robotdana/path_list)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/path_list.svg)](https://rubygems.org/gems/path_list)
|
7
|
+
|
8
|
+
This started as a way to quickly and natively ruby-ly parse gitignore files and find matching files.
|
9
|
+
It's now gained an equivalent includes file functionality, ARGV awareness, and some shebang matching, while still being extremely fast, to be a one-stop file-list for your linter.
|
10
|
+
|
11
|
+
Filter a directory tree using a .gitignore file. Recognises all of the [gitignore rules](https://www.git-scm.com/docs/gitignore#_pattern_format)
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
PathList.new.sort == `git ls-files`.split("\n").sort
|
15
|
+
```
|
16
|
+
|
17
|
+
## Features
|
18
|
+
|
19
|
+
- Fast (faster than using `` `git ls-files`.split("\n") `` for small repos (because it avoids the overhead of ``` `` ```))
|
20
|
+
- Supports ruby 2.4-3.0.0.preview1 & jruby
|
21
|
+
- supports all [gitignore rule patterns](https://git-scm.com/docs/gitignore#_pattern_format)
|
22
|
+
- doesn't require git to be installed
|
23
|
+
- supports a gitignore-esque "include" patterns. ([`include_rules:`](#include_rules)/[`include_files:`](#include_files))
|
24
|
+
- supports an expansion of include patterns, expanding and anchoring paths ([`argv_rules:`](#argv_rules))
|
25
|
+
- supports [matching by shebang](#shebang_rules) rather than filename for extensionless files: `#!:`
|
26
|
+
- reads .gitignore in all subdirectories
|
27
|
+
- reads .git/info/excludes
|
28
|
+
- reads the global gitignore file mentioned in your git config
|
29
|
+
|
30
|
+
## Installation
|
31
|
+
|
32
|
+
Add this line to your application's Gemfile:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
gem 'path_list'
|
36
|
+
```
|
37
|
+
|
38
|
+
And then execute:
|
39
|
+
```sh
|
40
|
+
$ bundle
|
41
|
+
```
|
42
|
+
Or install it yourself as:
|
43
|
+
```sh
|
44
|
+
$ gem install path_list
|
45
|
+
```
|
46
|
+
|
47
|
+
## Usage
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
PathList.new.each { |file| puts "#{file} is not ignored by the .gitignore file" }
|
51
|
+
```
|
52
|
+
|
53
|
+
### `#each`, `#map` etc
|
54
|
+
|
55
|
+
This yields paths that are _not_ ignored by the gitignore, i.e. the paths that would be returned by `git ls-files`.
|
56
|
+
|
57
|
+
A PathList instance is an Enumerable and responds to all Enumerable methods:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
PathList.new.to_a
|
61
|
+
PathList.new.map { |file| file.upcase }
|
62
|
+
```
|
63
|
+
|
64
|
+
Like other enumerables, `PathList#each` can return an enumerator:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
PathList.new.each.with_index { |file, index| puts "#{file}#{index}" }
|
68
|
+
```
|
69
|
+
|
70
|
+
**Warning: Do not change directory (e.g. `Dir.chdir`) in the block.**
|
71
|
+
|
72
|
+
### `#allowed?`
|
73
|
+
|
74
|
+
To check if a single path is allowed, use
|
75
|
+
```ruby
|
76
|
+
PathList.new.allowed?('relative/path')
|
77
|
+
PathList.new.allowed?('./relative/path')
|
78
|
+
PathList.new.allowed?('/absolute/path')
|
79
|
+
PathList.new.allowed?('~/home/path')
|
80
|
+
```
|
81
|
+
|
82
|
+
Relative paths will be considered relative to the [`root:`](#root) directory, not the current directory.
|
83
|
+
|
84
|
+
This is aliased as `===` so you can use a PathList instance in case statements.
|
85
|
+
```ruby
|
86
|
+
case my_path
|
87
|
+
when PathList.new
|
88
|
+
puts(my_path)
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
It's recommended to save the PathList instance to a variable to avoid having to read and parse the gitignore file and gitconfig files repeatedly.
|
93
|
+
|
94
|
+
See [Optimising allowed](#optimising_allowed) for ways to make this even faster
|
95
|
+
|
96
|
+
**Note: A file must exist at that path and not be a directory for it to be considered allowed.**
|
97
|
+
Essentially it can be thought of as `` `git ls-files`.include?(path) `` but much faster.
|
98
|
+
This excludes all directories and all possible path names that don't exist.
|
99
|
+
|
100
|
+
### `root:`
|
101
|
+
|
102
|
+
**Default: Dir.pwd ($PWD, the current working directory)**
|
103
|
+
|
104
|
+
This directory is used for:
|
105
|
+
- the location of `.git/core/exclude`
|
106
|
+
- the ancestor of all non-global [automatically loaded `.gitignore` files](#gitignore_false)
|
107
|
+
- the root directory for array rules ([`ignore_rules:`](#ignore_rules), [`include_rules:`](#include_rules), [`argv_rules:`](#argv_rules)) containing `/`
|
108
|
+
- the path that yielded paths are relative to
|
109
|
+
- the ancestor of all paths yielded by [`#each`](#each_map_etc)
|
110
|
+
- the path that [`#allowed?`](#allowed) considers relative paths relative to
|
111
|
+
- the ancestor of all [`include_files:`](#include_files) and [`ignore_files:`](#ignore_files)
|
112
|
+
|
113
|
+
To use a different directory:
|
114
|
+
```ruby
|
115
|
+
PathList.new(root: '/absolute/path/to/root').to_a
|
116
|
+
PathList.new(root: '../relative/path/to/root').to_a
|
117
|
+
```
|
118
|
+
|
119
|
+
A relative root will be found relative to the current working directory when the PathList instance is initialized, and that will be the last time the current working directory is relevant.
|
120
|
+
|
121
|
+
**Note: Changes to the current working directory (e.g. with `Dir.chdir`), after initialising a PathList instance, will _not_ affect the PathList instance. `root:` will always be what it was when the instance was initialized, even as a default value.**
|
122
|
+
|
123
|
+
### `gitignore:`
|
124
|
+
|
125
|
+
**Default: true**
|
126
|
+
|
127
|
+
When `gitignore: true`: the .gitignore file in the [`root:`](#root) directory is loaded, plus any .gitignore files in its subdirectories, the global git ignore file as described in git config, and .git/info/exclude. `.git` directories are also excluded to match the behaviour of `git ls-files`.
|
128
|
+
When `gitignore: false`: no ignore files or git config files are automatically read, and `.git` will not be automatically excluded.
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
PathList.new(gitignore: false).to_a
|
132
|
+
```
|
133
|
+
|
134
|
+
### `ignore_files:`
|
135
|
+
|
136
|
+
**This is a list of files in the gitignore format to parse and match paths against, not a list of files to ignore** If you want an array of files use [`ignore_rules:`](#ignore_rules)
|
137
|
+
|
138
|
+
Additional gitignore-style files, either as a path or an array of paths.
|
139
|
+
|
140
|
+
You can specify other gitignore-style files to ignore as well.
|
141
|
+
Missing files will raise an `Errno::ENOENT` error.
|
142
|
+
|
143
|
+
Relative paths are relative to the [`root:`](#root) directory.
|
144
|
+
Absolute paths also need to be within the [`root:`](#root) directory.
|
145
|
+
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
PathList.new(ignore_files: 'relative/path/to/my/ignore/file').to_a
|
149
|
+
PathList.new(ignore_files: ['/absolute/path/to/my/ignore/file', '/and/another']).to_a
|
150
|
+
```
|
151
|
+
|
152
|
+
Note: the location of the files will affect rules beginning with or containing `/`.
|
153
|
+
|
154
|
+
To avoid raising `Errno::ENOENT` when the file doesn't exist:
|
155
|
+
```ruby
|
156
|
+
PathList.new(ignore_files: ['/ignore/file'].select { |f| File.exist?(f) }).to_a
|
157
|
+
```
|
158
|
+
|
159
|
+
### `ignore_rules:`
|
160
|
+
|
161
|
+
This can be a string, or an array of strings, and multiline strings can be used with one rule per line.
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
PathList.new(ignore_rules: '.DS_Store').to_a
|
165
|
+
PathList.new(ignore_rules: ['.git', '.gitkeep']).to_a
|
166
|
+
PathList.new(ignore_rules: ".git\n.gitkeep").to_a
|
167
|
+
```
|
168
|
+
|
169
|
+
These rules use the [`root:`](#root) argument to resolve rules containing `/`.
|
170
|
+
|
171
|
+
### `include_files:`
|
172
|
+
|
173
|
+
**This is an array of files in the gitignore format to parse and match paths against, not a list of files to include.** If you want an array of files use [`include_rules:`](#include_rules).
|
174
|
+
|
175
|
+
Building on the gitignore format, PathList also accepts rules to include matching paths (rather than ignoring them).
|
176
|
+
A rule matching a directory will include all descendants of that directory.
|
177
|
+
|
178
|
+
These rules can be provided in files either as absolute or relative paths, or an array of paths.
|
179
|
+
Relative paths are relative to the [`root:`](#root) directory.
|
180
|
+
Absolute paths also need to be within the [`root:`](#root) directory.
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
PathList.new(include_files: 'my_include_file').to_a
|
184
|
+
PathList.new(include_files: ['/absolute/include/file', './relative/include/file']).to_a
|
185
|
+
```
|
186
|
+
|
187
|
+
Missing files will raise an `Errno::ENOENT` error.
|
188
|
+
|
189
|
+
To avoid raising `Errno::ENOENT` when the file doesn't exist:
|
190
|
+
```ruby
|
191
|
+
PathList.new(include_files: ['include/file'].select { |f| File.exist?(f) }).to_a
|
192
|
+
```
|
193
|
+
|
194
|
+
**Note: All paths checked must not be excluded by any ignore files AND each included by include file separately AND the [`include_rules:`](#include_rules) AND the [`argv_rules:`](#argv_rules). see [Combinations](#combinations) for solutions to using OR.**
|
195
|
+
|
196
|
+
### `include_rules:`
|
197
|
+
|
198
|
+
Building on the gitignore format, PathList also accepts rules to include matching paths (rather than ignoring them).
|
199
|
+
A rule matching a directory will include all descendants of that directory.
|
200
|
+
|
201
|
+
This can be a string, or an array of strings, and multiline strings can be used with one rule per line.
|
202
|
+
```ruby
|
203
|
+
PathList.new(include_rules: %w{my*rule /and/another !rule}, gitignore: false).to_a
|
204
|
+
```
|
205
|
+
|
206
|
+
Rules use the [`root:`](#root) argument to resolve rules containing `/`.
|
207
|
+
|
208
|
+
**Note: All paths checked must not be excluded by any ignore files AND each included by [include file](#include_files) separately AND the `include_rules:` AND the [`argv_rules:`](#argv_rules). see [Combinations](#combinations) for solutions to using OR.**
|
209
|
+
|
210
|
+
### `argv_rules:`
|
211
|
+
This is like [`include_rules:`](#include_rules) with additional features meant for dealing with humans and `ARGV` values.
|
212
|
+
|
213
|
+
It expands rules that are absolute paths, and paths beginning with `~`, `../` and `./` (with and without `!`).
|
214
|
+
This means rules beginning with `/` are absolute. Not relative to [`root:`](#root).
|
215
|
+
|
216
|
+
Additionally it assumes all rules are relative to the [`root:`](#root) directory (after resolving absolute paths) unless they begin with `*` (or `!*`).
|
217
|
+
|
218
|
+
This can be a string, or an array of strings, and multiline strings can be used with one rule per line.
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
PathList.new(argv_rules: ['./a/pasted/path', '/or/a/path/from/stdin', 'an/argument', '*.txt']).to_a
|
222
|
+
```
|
223
|
+
|
224
|
+
**Warning: it will *not* expand e.g. `/../` in the middle of a rule that doesn't begin with any of `~`,`../`,`./`,`/`.**
|
225
|
+
|
226
|
+
**Note: All paths checked must not be excluded by any ignore files AND each included by [include file](#include_files) separately AND the [`include_rules:`](#include_rules) AND the `argv_rules:`. see [Combinations](#combinations) for solutions to using OR.**
|
227
|
+
|
228
|
+
### shebang rules
|
229
|
+
|
230
|
+
Sometimes you need to match files by their shebang/hashbang/etc rather than their path or filename
|
231
|
+
|
232
|
+
Rules beginning with `#!:` will match whole words in the shebang line of extensionless files.
|
233
|
+
e.g.
|
234
|
+
```gitignore
|
235
|
+
#!:ruby
|
236
|
+
```
|
237
|
+
will match shebang lines: `#!/usr/bin/env ruby` or `#!/usr/bin/ruby` or `#!/usr/bin/ruby -w`
|
238
|
+
|
239
|
+
e.g.
|
240
|
+
```gitignore
|
241
|
+
#!:bin/ruby
|
242
|
+
```
|
243
|
+
will match `#!/bin/ruby` or `#!/usr/bin/ruby` or `#!/usr/bin/ruby -w`
|
244
|
+
Only exact substring matches are available, There's no special handling of * or / or etc.
|
245
|
+
|
246
|
+
These rules can be supplied any way regular rules are, whether in a .gitignore file or files mentioned in [`include_files:`](#include_files) or [`ignore_files:`](#ignore_files) or [`include_rules:`](#include_rules) or [`ignore_rules:`](#ignore_rules) or [`argv_rules:`](#argv_rules)
|
247
|
+
```ruby
|
248
|
+
PathList.new(include_rules: ['*.rb', '#!:ruby']).to_a
|
249
|
+
PathList.new(ignore_rules: ['*.sh', '#!:sh', '#!:bash', '#!:zsh']).to_a
|
250
|
+
```
|
251
|
+
|
252
|
+
**Note: git considers rules like this as a comment and will ignore them.**
|
253
|
+
|
254
|
+
## Combinations
|
255
|
+
|
256
|
+
In the simplest case a file must be allowed by each ignore file, each include file, and each array of rules. That is, they are combined using `AND`.
|
257
|
+
|
258
|
+
To combine files using `OR`, that is, a file may be matched by either file it doesn't have to be referred to in both:
|
259
|
+
provide the files as strings to [`include_rules:`](#include_rules) or [`ignore_rules:`](#ignore_rules)
|
260
|
+
```ruby
|
261
|
+
PathList.new(include_rules: [File.read('/my/path'), File.read('/another/path')])).to_a
|
262
|
+
```
|
263
|
+
This does unfortunately lose the file path as the root for rules containing `/`.
|
264
|
+
If that's important, combine the files in the file system and use [`include_files:`](#include_files) or [`ignore_files:`](#ignore_files) as normal.
|
265
|
+
|
266
|
+
To use the additional `ARGV` handling of [`argv_rules:`](#argv_rules) on a file, read the file into the array.
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
PathList.new(argv_rules: ["my/rule", File.read('/my/path')]).to_a
|
270
|
+
```
|
271
|
+
|
272
|
+
This does unfortunately lose the file path as the root `/` and there is no workaround except setting the [`root:`](#root) for the whole PathList instance.
|
273
|
+
|
274
|
+
### optimising #allowed?
|
275
|
+
|
276
|
+
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
|
277
|
+
```ruby
|
278
|
+
PathList.new.allowed?('relative/path', directory: false, content: "#!/usr/bin/ruby\n\nputs 'ok'\n")
|
279
|
+
```
|
280
|
+
This is not required, and if PathList does have to go to the filesystem for this information it's well optimised to only read what is necessary.
|
281
|
+
|
282
|
+
## Limitations
|
283
|
+
- Doesn't know what to do if you change the current working directory inside the [`PathList#each`](#each_map_etc) block.
|
284
|
+
So don't do that.
|
285
|
+
|
286
|
+
(It does handle changing the current working directory between [`PathList#allowed?`](#allowed) calls)
|
287
|
+
- PathList always matches patterns case-insensitively. (git varies by filesystem).
|
288
|
+
- PathList always outputs paths as literal UTF-8 characters. (git depends on your core.quotepath setting but by default outputs non ascii paths with octal escapes surrounded by quotes).
|
289
|
+
- Because git looks at its own index objects and PathList looks at the file system there may be some differences between PathList and `git ls-files`. To avoid these differences you may want to use the [`git_ls`](https://github.com/robotdana/git_ls) gem instead
|
290
|
+
- Tracked files that were committed before the matching ignore rule was committed will be returned by `git ls-files`, but not by PathList.
|
291
|
+
- Untracked files will be returned by PathList, but not by `git ls-files`
|
292
|
+
- Deleted files whose deletions haven't been committed will be returned by `git ls-files`, but not by PathList
|
293
|
+
- On a case insensitive file system, with files that differ only by case, `git ls-files` will include all case variations, while PathList will only include whichever variation git placed in the file system.
|
294
|
+
- PathList is unaware of submodules and just treats them like regular directories. For example: `git ls-files --recurse-submodules` won't use the parent repo's gitignore on a submodule, while PathList doesn't know it's a submodule and will.
|
295
|
+
- PathList will only return the files actually on the file system when using `git sparse-checkout`.
|
296
|
+
|
297
|
+
## Contributing
|
298
|
+
|
299
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/robotdana/path_list.
|
300
|
+
|
301
|
+
Some tools that may help:
|
302
|
+
|
303
|
+
- `bin/setup`: install development dependencies
|
304
|
+
- `bundle exec rspec`: run all tests
|
305
|
+
- `bundle exec rake`: run all tests and linters
|
306
|
+
- `bin/console`: open a `pry` console with everything required for experimenting
|
307
|
+
- `bin/ls [argv_rules]`: the equivalent of `git ls-files`
|
308
|
+
- `bin/prof/ls [argv_rules]`: ruby-prof report for `bin/ls`
|
309
|
+
- `bin/prof/parse [argv_rules]`: ruby-prof report for parsing root and global gitignore files and any arguments.
|
310
|
+
- `bin/time [argv_rules]`: the average time for 30 runs of `bin/ls`<br>
|
311
|
+
This repo is too small to stress bin/time more than 0.01s, switch to a large repo and find the average time before and after changes.
|
312
|
+
- `bin/compare`: compare the speed and output of PathList and `git ls-files`.
|
313
|
+
(suppressing differences that are because of known [limitations](#limitations))
|
314
|
+
|
315
|
+
## License
|
316
|
+
|
317
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|