Compare commits

..

78 Commits

Author SHA1 Message Date
Andrew Gallant
00bfcd14a6 ignore-0.4.11 2020-01-10 15:08:27 -05:00
Andrew Gallant
bf0ddc4675 ci: fix musl docker build
Looks like the old japaric images are bunk. We update our docker image
to be based on the new rustembedded images and configure cross to use
it.

Turns out that this wasn't due to a stale docker image, but rather, a
bug in cross: https://github.com/rust-embedded/cross/issues/357
We work around that bug by installing the master branch of cross. Sigh.
2020-01-10 15:07:47 -05:00
Andrew Gallant
0fb3f6a159 ci: disable github actions for now
The CI build failures are annoying and distracting. Hopefully soon I'll
be able to invest more time in the switch.
2020-01-10 15:07:47 -05:00
Andrew Gallant
837fb5e21f deps: update to crossbeam-channel 0.4
Closes #1427
2020-01-10 15:07:47 -05:00
Andrew Gallant
2e1815606e deps: update to bytecount 0.6
Looks like there aren't any major changes other than dependency updates.
2020-01-10 15:07:47 -05:00
Andrew Gallant
cb2f6ddc61 deps: update to thread_local 1.0
We also update the pcre2 and regex dependencies, which removes any other
lingering uses of thread_local 0.3.
2020-01-10 15:07:47 -05:00
Andrew Gallant
bd7a42602f deps: bump to base64 0.11 2020-01-10 15:07:47 -05:00
Andrew Gallant
528ce56e1b deps: run cargo update
The only new dependency is an unused target specific dependency hermit
via the atty crate.
2020-01-10 15:07:47 -05:00
Yevgen Antymyrov
8892bf648c doc: fix typo in FAQ 2019-09-25 08:13:27 -04:00
Jonathan Clem
8cb7271b64 ci: get GitHub Actions running again
Basically, matrix.os needs to be defined for every build. We
were commenting out some of the builds in order to debug
CI in the `include` section, but we also need to comment them
out in the `build section.
2019-09-11 09:08:24 -04:00
Andrew Gallant
4858267f3b ci: initial github actions config 2019-08-31 09:24:44 -04:00
Andrew Gallant
5011dba2fd ignore: remove unused parameter 2019-08-28 20:21:34 -04:00
Andrew Gallant
e14f9195e5 deps: update everything 2019-08-28 20:18:47 -04:00
Andrew Gallant
ef0e7af56a deps: update bstr to 0.2.7
The new bstr release contains a small performance bug fix where some
trivial methods weren't being inlined.
2019-08-11 10:41:05 -04:00
Todd Walton
b266818aa5 doc: use XDG_CONFIG_HOME in comments
XDG_CONFIG_DIR does not actually exist.

PR #1347
2019-08-09 13:37:37 -04:00
LawAbidingCactus
81415ae52d doc: update to reflect glob matching behavior change
Specifically, paths contains a `/` are not allowed to match any
other slash in the path, even as a prefix. So `!.git` is the correct
incantation for ignoring a `.git` directory that occurs anywhere 
in the path.
2019-08-07 13:47:18 -04:00
Andrew Gallant
5c4584aa7c grep-regex-0.1.5 2019-08-06 09:51:13 -04:00
Andrew Gallant
0972c6e7c7 grep-searcher-0.1.6 2019-08-06 09:50:52 -04:00
Andrew Gallant
0a372bf2e4 deps: update ignore 2019-08-06 09:50:35 -04:00
Andrew Gallant
345124a7fa ignore-0.4.10 2019-08-06 09:47:45 -04:00
Andrew Gallant
31807f805a deps: drop tempfile
We were only using it to create temporary directories for `ignore`
tests, but it pulls in a bunch of dependencies and we don't really need
randomness. So just use our own simple wrapper instead.
2019-08-06 09:46:05 -04:00
Andrew Gallant
4de227fd9a deps: update everything
Mostly this just updates regex and its assorted dependencies. This does
drop utf8-ranges and ucd-util, in accordance with changes to
regex-syntax and regex.
2019-08-05 13:50:55 -04:00
jimbo1qaz
d7ce274722 readme: Debian Buster is stable now
PR #1338
2019-08-04 08:06:10 -04:00
Andrew Gallant
5b10328f41 changelog: update with bug fix 2019-08-02 07:37:27 -04:00
Andrew Gallant
813c676eca searcher: fix roll buffer bug
This commit fixes a subtle bug in how the line buffer was rolling its
contents. Specifically, when ripgrep searches without memory maps,
it uses a "roll" buffer for incremental line oriented search without
needing to read the entire file into memory at once. The roll buffer
works by reading a chunk of bytes from the file into memory, and then
searching everything in that buffer up to the last `\n` byte. The bytes
*after* the last `\n` byte are preserved, since they likely correspond
to *part* of the next line. Once ripgrep is done searching the buffer,
it "rolls" the buffer such that the start of the next line is at the
beginning of the buffer, and then ripgrep reads more data into the
buffer starting at the (possibly) partial end of that line.

The implication of this strategy, necessarily so, is that a buffer must
be big enough to fit a single line in memory. This is because the regex
engine needs a contiguous block of memory to search, so there is no way
to search anything smaller than a single line. So if a file contains a
single line with 7.5 million bytes, then the buffer will grow to be at
least that size. (Many files have super long lines like this, but they
tend to be *binary* files, which ripgrep will detect and stop searching
unless the user forces it with the `-a/--text` flag. So in practice,
they aren't usually a problem. However, in this case, #1335 found a case
where a plain text file had a line with 7.5 million bytes.)

Now, for performance reasons, ripgrep reuses these buffers across its
search. Typically, it will create `N` of these line buffers when it
starts (where `N` is the number of threads it is using), and then reuse
them without creating any new ones as it searches through files.

This means that if you search a file with a very long line, that buffer
will expand to be big enough to store that line. ripgrep never contracts
these buffers, so once it searches the next file, ripgrep will continue
to use this large buffer. While it might be prudent to contract these
buffers in some circumstances, this isn't otherwise inherently a
problem. The memory has already been allocated, and there isn't much
cost to using it, other than the fact that ripgrep hangs on to it and
never gives it back to the OS.

However, the `roll` implementation described above had a really
important bug in it that was impacted by the size of the buffer.
Specifically, it used the following to "roll" the partial line at the
end of the buffer to the beginning:

    self.buf.copy_within_str(self.pos.., 0);

Which means that if the buffer is very large, ripgrep will copy
*everything* from `self.pos` (which might be very small, e.g., for small
files) to the end of the buffer, and move it to the beginning of the
buffer. This will happen repeatedly each time the buffer is used to
search small files, which winds up being quite a large slow down if the
line was exceptionally large (say, megabytes).

It turns out that copying everything is completely unnecessary. We only
need to copy the remainder of the last read to the beginning of the
buffer. Everything *after* the last read in the buffer is just free
space that can be filled for the next read. So, all we need to do is
copy just those bytes:

    self.buf.copy_within_str(self.pos..self.end, 0);

... which is typically much much smaller than the rest of the buffer.

This was likely also causing small performance losses in other cases as
well. For example, when searching a lot of small files, ripgrep would
likely do a lot more copying than necessary. Although, given that the
default buffer size is 8KB, this extra copying was likely pretty small,
and was thus harder to observe.

Fixes #1335
2019-08-02 07:23:27 -04:00
Andrew Gallant
f625d72b6f pkg: update brew tap to 11.0.2 2019-08-01 19:39:53 -04:00
Andrew Gallant
3de31f7527 ci: fix musl deployment
The docker image that the Linux binary is now built in does not have
ASCII doc installed, so setup Cross to point to my own image with those
tools installed.
2019-08-01 18:41:44 -04:00
Andrew Gallant
e402d6c260 ripgrep: release 11.0.2 2019-08-01 18:02:15 -04:00
Andrew Gallant
48b5bdc441 src: remove old directories
termcolor has had its own repository for a while now. No need for these
redirects any more.
2019-08-01 17:49:28 -04:00
Andrew Gallant
709ca91f50 ignore: release 0.4.9 2019-08-01 17:48:37 -04:00
Andrew Gallant
9c220f9a9b grep-regex: release 0.1.4 2019-08-01 17:47:45 -04:00
Andrew Gallant
9085bed139 grep-matcher: release 0.1.3 2019-08-01 17:46:59 -04:00
Andrew Gallant
931ab35f76 changelog: start work on 11.0.2 release 2019-08-01 17:42:38 -04:00
Andrew Gallant
b5e5979ff1 deps: update everything
This drops `spin` and `autocfg`, yay.
2019-08-01 17:42:38 -04:00
Andrew Gallant
052c857da0 doc: mention .ignore and .rgignore more prominently
Fixes #1284
2019-08-01 17:37:46 -04:00
Andrew Gallant
5e84e784c8 doc: add translations section
We note that they may not be up to date and are unofficial.

Fixes #1246
2019-08-01 17:37:46 -04:00
Andrew Gallant
01e8e11621 doc: improve PCRE2 failure mode documentation
If a user tries to search for an explicit `\n` character in a PCRE2
regex, ripgrep won't report an error and instead will (likely) silently
fail to match.

Fixes #1261
2019-08-01 17:32:44 -04:00
Ninan John
9268ff8e8d ripgrep: fix bug when CWD has directory named -
Specifically, when searching stdin, if the current directory has a
directory named `-`, then the `--with-filename` flag would automatically
be turned on. This is because `--with-filename` is automatically enabled
when ripgrep is given a single path that is a directory. When ripgrep is
given empty arguments, and if it is searching stdin, then its default
path list is just simple `["-"]`. The `is_dir` check passes, and
`--with-filename` gets enabled.

This commit fixes the problem by checking whether the path is `-` first.
If so, then we assume it isn't a directory. This is fine, since if it is
a directory and one asks to search it explicitly, then ripgrep will
interpret `-` as stdin anyway (which is arguably a bug on its own, but
probably not one worth fixing).

Fixes #1223, Closes #1292
2019-08-01 17:27:23 -04:00
dana
c2cb0a4de4 ripgrep: add --glob-case-insensitive
This flag forces -g/--glob patterns to be treated case-insensitively, as with
--iglob patterns.

Fixes #1293
2019-08-01 17:08:58 -04:00
Andrew Gallant
adb9332f52 regex: fix -F aho-corasick optimization
It turns out that when the -F flag was used, if any of the patterns
contained a regex meta character (such as `.`), then we winded up
escaping the pattern first before handing it off to Aho-Corasick, which
treats all patterns literally.

We continue to apply band-aides here and just avoid Aho-Corasick if
there is an escape in any of the literal patterns. This is unfortunate,
but making this work better requires more refactoring, and the right
solution is to get this optimization pushed down into the regex engine.

Fixes #1334
2019-08-01 16:58:12 -04:00
Matthew Davidson
bc37c32717 ignore/types: add edn type from Clojure ecosystem
PR #1330
2019-07-29 16:43:28 -04:00
Andrew Gallant
08ae4da2b7 deps: update them
There are some nice removals. It looks like rand has slimmed down, and
smallvec is gone now as well.
2019-07-25 07:52:33 -04:00
Andrew Gallant
7ac95c1f50 deps: bump ignore 2019-07-24 12:56:47 -04:00
Andrew Gallant
7a6903bd4e ignore-0.4.8 2019-07-24 12:56:01 -04:00
Tiziano Santoro
9801fae29f ignore: support compilation on wasm
Currently the crate assumes that exactly one of `cfg(windows)` or
`cfg(unix)` is true, but this is not actually the case, for instance
when compiling for `wasm32`.

Implement the missing functions so that the crate can compile on other
platforms, even though those functions will always return an error.

PR #1327
2019-07-24 12:55:37 -04:00
Miloš Stojanović
abdf7140d7 readme: fix broken link to Scoop bucket
PR #1324
2019-07-20 12:03:46 -04:00
Conrad Olega
b83e7968ef ignore/types: add Robot Framework
PR #1322
2019-07-14 08:12:34 -04:00
Hugo Locurcio
8ebc113847 doc: improve docs for --replace flag
Specifically, we document shell-specific caveats related to the `--replace`
flag.

PR #1318
2019-07-04 11:42:35 -04:00
Andrew Gallant
785c1f1766 release: globset, grep-cli, grep-printer, grep-searcher 2019-06-26 16:53:30 -04:00
Andrew Gallant
8b734cb490 deps: update everything 2019-06-26 16:51:06 -04:00
Andrew Gallant
b93762ea7a bstr: update everything to bstr 0.2 2019-06-26 16:47:33 -04:00
Andrew Gallant
34677d2622 search: a few small touchups 2019-06-18 20:23:47 -04:00
Andrew Gallant
d1389db2e3 search: better errors for preprocessor commands
If a preprocessor command could not be started, we now show some
additional context with the error message. Previously, it showed
something like this:

  some/file: No such file or directory (os error 2)

Which is itself pretty misleading. Now it shows:

  some/file: preprocessor command could not start: '"nonexist" "some/file"': No such file or directory (os error 2)

Fixes #1302
2019-06-16 19:02:02 -04:00
Andrew Gallant
50bcb7409e deps: update everything 2019-06-16 18:38:45 -04:00
Andrew Gallant
7b9972c308 style: fix deprecations
Use `dyn` for trait objects and use `..=` for inclusive ranges.
2019-06-16 18:37:51 -04:00
Hitesh Jasani
9f000c2910 ignore/types: add more nim types
PR #1297
2019-06-12 14:02:28 -04:00
skierpage
392682d352 doc: point regex doc link to the latest version
The latest doc is different, e.g. adds "symmetric differences" under
https://docs.rs/regex/*/regex/#character-classes

PR #1287
2019-06-01 08:44:55 -04:00
Andrew Gallant
7d3f794588 ignore: remove .git check in some cases
When we know we aren't going to process gitignores, we shouldn't waste
the syscall in every directory to check for a git repo.
2019-05-29 18:06:11 -04:00
bruce-one
290fd2a7b6 readme: mention Zstandard and Brotli
Also alphabetise the list.

PR #1288
2019-05-29 13:37:31 -04:00
Fabian Würfl
d1e4d28f30 readme: remove outdated statement
Issue #10 already states that "ripgrep is now in most or all of the major
package repositories."

PR #1280
2019-05-14 18:44:50 -04:00
Andrew Gallant
5ce2d7351d ci: use cross for musl x86_64 builds
This is necessary because jemalloc + musl + Ubuntu 16.04 is apparently
broken.

Moreover, jemalloc doesn't support i686, so we accept the performance
regression there.

See also: https://github.com/gnzlbg/jemallocator/issues/124
2019-04-25 11:12:14 -04:00
Andrew Gallant
9dcfd9a205 deps: bump pcre2-sys to 0.2.1
This brings in a bug fix that no longer tries to run `git` to update the
submodule if the `git` command doesn't exist.

This is useful is more restricted build contexts where `git` isn't
installed. Such as in the docker image used for running `cross`.
2019-04-25 11:12:14 -04:00
Andrew Gallant
36b276c6d0 printer: remove unnecessary mut 2019-04-24 17:22:27 -04:00
Andrew Gallant
03bf37ff4a alloc: use jemalloc when building with musl
It turns out that musl's allocator is slow enough to cause a fairly
noticeable performance regression when ripgrep is built as a static
binary with musl. We fix this by using jemalloc when building with musl.

We continue to use the default system allocator in all other scenarios.
Namely, glibc's allocator doesn't noticeably regress performance compared
to jemalloc. But we could add more targets to this logic if other
system allocators (macOS, Windows) prove to be slow.

This wasn't necessary before because rustc recently stopped using jemalloc
by default.

Fixes #1268
2019-04-24 17:21:38 -04:00
Andrew Gallant
e7829c05d3 cli: fix bug where last byte was stripped
In an effort to strip line terminators, we assumed their existence. But
a pattern file may not end with a line terminator, so we shouldn't
unconditionally strip them.

We fix this by moving to bstr's line handling, which does this for us
automatically.
2019-04-19 07:11:44 -04:00
Rory O’Kane
a6222939f9 readme: mention --pcre2 as long form of -P
This is for consistency with the short and long flags given in other
bullet points. I originally assumed there was no long flag for `-P`
because none was given here.

PR #1254
2019-04-16 21:22:48 -04:00
Rory O’Kane
6ffd434232 readme: mention --auto-hybrid-regex in advantages
This feature solves a major reason I was skeptical of using ripgrep, so
I think it’s good to mention it in the section about why one should use
it.

I use backreferences a lot, so I had previously thought that ripgrep
would provide no speed advantage over ag, since I would always have
`-P` enabled. But when I saw `--auto-hybrid-regex` in the 11.0.0
changelog, I learned that ripgrep can use it to speed up simple queries
while still allowing me to write backreferences.

PR #1253
2019-04-16 17:21:40 -04:00
Andrew Gallant
1f1cd9b467 pkg: update brew tap to 11.0.1 2019-04-16 13:39:56 -04:00
Andrew Gallant
973de50c9e ripgrep: release 11.0.1, take 2 2019-04-16 13:11:28 -04:00
Andrew Gallant
5f8805a496 ripgrep: release 11.0.1 2019-04-16 13:10:29 -04:00
Andrew Gallant
fdde2bcd38 deps: update regex to 1.1.6
This brings in a fix for a regression introduced in ripgrep 11.

Fixes #1247
2019-04-16 08:34:30 -04:00
Gerard de Melo
7b3fe6b325 doc: fix typo in FAQ
PR #1248
2019-04-16 08:32:30 -04:00
Max Horn
b3dd3ae203 ignore/types: add GAP
Add support for file types used by the GAP language, a research system
computational discrete algebra, see <https://www.gap-system.org>

PR #1249
2019-04-16 08:31:58 -04:00
Andrew Gallant
f3083e4574 readme: remove brew tap instructions
The brew tap isn't really needed any more, since SIMD is now
automatically enabled in all binaries.
2019-04-15 18:32:33 -04:00
Andrew Gallant
d03e30707e pkg: update brew tap to 11.0.0 2019-04-15 18:32:10 -04:00
Andrew Gallant
d7f57d9aab ripgrep: release 11.0.0 2019-04-15 18:09:40 -04:00
Andrew Gallant
1a2a24ea74 grep: release 0.2.4 2019-04-15 18:03:46 -04:00
Andrew Gallant
d66610b295 grep-cli: release 0.1.2 2019-04-15 18:02:44 -04:00
56 changed files with 1212 additions and 988 deletions

108
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,108 @@
name: ci
on:
pull_request:
push:
branches:
- master
schedule:
- cron: '00 01 * * *'
jobs:
test:
name: test
runs-on: ubuntu-18.04
steps:
- name: no-op
run: echo hello
# test:
# name: test
# runs-on: ${{ matrix.os }}
# strategy:
# matrix:
# # The docs seem to suggest that we can have a matrix with just an
# # include directive, but it result in a "matrix must define at least
# # one vector" error in the CI system.
# build:
# # - pinned-glibc
# - pinned-musl
# - stable
# # - beta
# # We test musl with nightly because every once in a while, this will
# # catch an upstream regression.
# # - nightly-glibc
# # - nightly-musl
# # - macos
# # - win-msvc-32
# # - win-msvc-64
# # - win-gnu-32
# # - win-gnu-64
# include:
# # - build: pinned-glibc
# # os: ubuntu-18.04
# # rust: 1.34.0
# # target: x86_64-unknown-linux-gnu
# - build: pinned-musl
# os: ubuntu-18.04
# rust: 1.34.0
# target: x86_64-unknown-linux-musl
# - build: stable
# os: ubuntu-18.04
# rust: stable
# target: x86_64-unknown-linux-gnu
# # - build: beta
# # os: ubuntu-18.04
# # rust: beta
# # target: x86_64-unknown-linux-gnu
# # - build: nightly-glibc
# # os: ubuntu-18.04
# # rust: nightly
# # target: x86_64-unknown-linux-gnu
# # - build: nightly-musl
# # os: ubuntu-18.04
# # rust: nightly
# # target: x86_64-unknown-linux-musl
# # - build: macos
# # os: macOS-10.14
# # rust: stable
# # target: x86_64-apple-darwin
# # - build: win-msvc-32
# # os: windows-2019
# # rust: stable
# # target: i686-pc-windows-msvc
# # - build: win-msvc-64
# # os: windows-2019
# # rust: stable
# # target: x86_64-pc-windows-msvc
# # - build: win-gnu-32
# # os: windows-2019
# # rust: stable-i686-gnu
# # target: i686-pc-windows-gnu
# # - build: win-gnu-64
# # os: windows-2019
# # rust: stable-x86_64-gnu
# # target: x86_64-pc-windows-gnu
# steps:
# - name: Checkout repository
# uses: actions/checkout@v1
# with:
# fetch-depth: 1
# - name: Install Rust
# uses: hecrj/setup-rust-action@v1
# with:
# rust-version: ${{ matrix.rust }}
# - name: Install Rust Target
# run: rustup target add ${{ matrix.target }}
# - name: Install musl-gcc
# if: contains(matrix.target, 'musl')
# run: |
# sudo apt-get install musl-tools
# - name: Build everything
# run: cargo build --verbose --target ${{ matrix.target }} --all --features pcre2
# - name: Install zsh
# if: matrix.build == 'stable'
# run: sudo apt-get install zsh
# - name: Test zsh auto-completions
# if: matrix.build == 'stable'
# run: ./ci/test_complete.sh
# - name: Run tests
# run: cargo test --verbose --target ${{ matrix.target }} --all --features pcre2

View File

@@ -1,5 +1,58 @@
11.0.0 (TBD) TBD
============ ===
TODO
Bug fixes:
* [BUG #1335](https://github.com/BurntSushi/ripgrep/issues/1335):
Fixes a performance bug when searching plain text files with very long lines.
11.0.2 (2019-08-01)
===================
ripgrep 11.0.2 is a new patch release that fixes a few bugs, including a
performance regression and a matching bug when using the `-F/--fixed-strings`
flag.
Feature enhancements:
* [FEATURE #1293](https://github.com/BurntSushi/ripgrep/issues/1293):
Added `--glob-case-insensitive` flag that makes `--glob` behave as `--iglob`.
Bug fixes:
* [BUG #1246](https://github.com/BurntSushi/ripgrep/issues/1246):
Add translations to README, starting with an unofficial Chinese translation.
* [BUG #1259](https://github.com/BurntSushi/ripgrep/issues/1259):
Fix bug where the last byte of a `-f file` was stripped if it wasn't a `\n`.
* [BUG #1261](https://github.com/BurntSushi/ripgrep/issues/1261):
Document that no error is reported when searching for `\n` with `-P/--pcre2`.
* [BUG #1284](https://github.com/BurntSushi/ripgrep/issues/1284):
Mention `.ignore` and `.rgignore` more prominently in the README.
* [BUG #1292](https://github.com/BurntSushi/ripgrep/issues/1292):
Fix bug where `--with-filename` was sometimes enabled incorrectly.
* [BUG #1268](https://github.com/BurntSushi/ripgrep/issues/1268):
Fix major performance regression in GitHub `x86_64-linux` binary release.
* [BUG #1302](https://github.com/BurntSushi/ripgrep/issues/1302):
Show better error messages when a non-existent preprocessor command is given.
* [BUG #1334](https://github.com/BurntSushi/ripgrep/issues/1334):
Fix match regression with `-F` flag when patterns contain meta characters.
11.0.1 (2019-04-16)
===================
ripgrep 11.0.1 is a new patch release that fixes a search regression introduced
in the previous 11.0.0 release. In particular, ripgrep can enter an infinite
loop for some search patterns when searching invalid UTF-8.
Bug fixes:
* [BUG #1247](https://github.com/BurntSushi/ripgrep/issues/1247):
Fix search bug that can cause ripgrep to enter an infinite loop.
11.0.0 (2019-04-15)
===================
ripgrep 11 is a new major version release of ripgrep that contains many bug ripgrep 11 is a new major version release of ripgrep that contains many bug
fixes, some performance improvements and a few feature enhancements. Notably, fixes, some performance improvements and a few feature enhancements. Notably,
ripgrep's user experience for binary file filtering has been improved. See the ripgrep's user experience for binary file filtering has been improved. See the
@@ -32,9 +85,9 @@ This release increases the **minimum supported Rust version** from 1.28.0 to
terminal. That is, `rg -uuu foo` should now be equivalent to `grep -r foo`. terminal. That is, `rg -uuu foo` should now be equivalent to `grep -r foo`.
* The `avx-accel` feature of ripgrep has been removed since it is no longer * The `avx-accel` feature of ripgrep has been removed since it is no longer
necessary. All uses of AVX in ripgrep are now enabled automatically via necessary. All uses of AVX in ripgrep are now enabled automatically via
runtime CPU feature detection. The `simd-accel` feature does remain runtime CPU feature detection. The `simd-accel` feature does remain available
available, however, it does increase compilation times substantially at the (only for enabling SIMD for transcoding), however, it does increase
moment. compilation times substantially at the moment.
Performance improvements: Performance improvements:

646
Cargo.lock generated
View File

@@ -2,68 +2,65 @@
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.3" version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.11" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "0.1.2" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.10.1" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.0.4" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "bstr" name = "bstr"
version = "0.1.2" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-automata 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "bytecount" name = "bytecount"
version = "0.5.1" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.3.1" version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.35" version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "0.1.7" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@@ -71,44 +68,36 @@ name = "clap"
version = "2.33.0" version = "2.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.3.8" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.6.5" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.17" version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@@ -117,7 +106,7 @@ name = "encoding_rs_io"
version = "0.1.6" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -126,8 +115,8 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "fuchsia-cprng" name = "fs_extra"
version = "0.1.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@@ -137,147 +126,172 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "globset" name = "globset"
version = "0.4.3" version = "0.4.4"
dependencies = [ dependencies = [
"aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"bstr 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "grep" name = "grep"
version = "0.2.3" version = "0.2.4"
dependencies = [ dependencies = [
"grep-cli 0.1.1", "grep-cli 0.1.3",
"grep-matcher 0.1.2", "grep-matcher 0.1.3",
"grep-pcre2 0.1.3", "grep-pcre2 0.1.3",
"grep-printer 0.1.2", "grep-printer 0.1.3",
"grep-regex 0.1.3", "grep-regex 0.1.5",
"grep-searcher 0.1.4", "grep-searcher 0.1.6",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "grep-cli" name = "grep-cli"
version = "0.1.1" version = "0.1.3"
dependencies = [ dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"bstr 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.4.3", "globset 0.4.4",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "grep-matcher" name = "grep-matcher"
version = "0.1.2" version = "0.1.3"
dependencies = [ dependencies = [
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "grep-pcre2" name = "grep-pcre2"
version = "0.1.3" version = "0.1.3"
dependencies = [ dependencies = [
"grep-matcher 0.1.2", "grep-matcher 0.1.3",
"pcre2 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "grep-printer" name = "grep-printer"
version = "0.1.2" version = "0.1.3"
dependencies = [ dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bstr 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"grep-matcher 0.1.2", "grep-matcher 0.1.3",
"grep-regex 0.1.3", "grep-regex 0.1.5",
"grep-searcher 0.1.4", "grep-searcher 0.1.6",
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "grep-regex" name = "grep-regex"
version = "0.1.3" version = "0.1.5"
dependencies = [ dependencies = [
"aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"grep-matcher 0.1.2", "grep-matcher 0.1.3",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "grep-searcher" name = "grep-searcher"
version = "0.1.4" version = "0.1.6"
dependencies = [ dependencies = [
"bstr 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytecount 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs_io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs_io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"grep-matcher 0.1.2", "grep-matcher 0.1.3",
"grep-regex 0.1.3", "grep-regex 0.1.5",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hermit-abi"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "ignore" name = "ignore"
version = "0.4.7" version = "0.4.11"
dependencies = [ dependencies = [
"crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.4.3", "globset 0.4.4",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.3" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "jemalloc-sys"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jemallocator"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.3.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.51" version = "0.2.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.6" version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.2.0" version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@@ -285,16 +299,17 @@ name = "memmap"
version = "0.7.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.10.0" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -302,230 +317,102 @@ name = "packed_simd"
version = "0.3.3" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "pcre2" name = "pcre2"
version = "0.2.0" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pcre2-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pcre2-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "pcre2-sys" name = "pcre2-sys"
version = "0.2.0" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.14" version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "0.4.27" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "0.6.12" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_jitter"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.1.5" version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.1.6" version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.6" version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "remove_dir_all"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "ripgrep" name = "ripgrep"
version = "0.10.0" version = "11.0.2"
dependencies = [ dependencies = [
"bstr 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"grep 0.2.3", "grep 0.2.4",
"ignore 0.4.7", "ignore 0.4.11",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "0.2.7" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "same-file" name = "same-file"
version = "1.0.4" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -533,34 +420,29 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.90" version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.90" version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.39" version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "smallvec"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.8.0" version = "0.8.0"
@@ -568,43 +450,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "syn" name = "syn"
version = "0.15.31" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tempfile"
version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.0.4" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -612,50 +471,40 @@ name = "textwrap"
version = "0.11.0" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "thread_local" name = "thread_local"
version = "0.3.6" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "ucd-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.5" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.1.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "utf8-ranges"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.2.7" version = "2.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.7" version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -672,7 +521,7 @@ name = "winapi-util"
version = "0.1.2" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -682,83 +531,66 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "wincolor" name = "wincolor"
version = "1.0.1" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[metadata] [metadata]
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum bstr 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6c8203ca06c502958719dae5f653a79e0cc6ba808ed02beffbf27d09610f2143" "checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
"checksum bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c" "checksum bytecount 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c"
"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" "checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28"
"checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed"
"checksum encoding_rs_io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9619ee7a2bf4e777e020b95c1439abaf008f8ea8041b78a0552c4f1bcf4df32c" "checksum encoding_rs_io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9619ee7a2bf4e777e020b95c1439abaf008f8ea8041b78a0552c4f1bcf4df32c"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" "checksum jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" "checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
"checksum packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220" "checksum packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
"checksum pcre2 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a08c8195dd1d8a2a1b5e2af94bf0c4c3c195c2359930442a016bf123196f7155" "checksum pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "85b30f2f69903b439dd9dc9e824119b82a55bf113b29af8d70948a03c1b11ab1"
"checksum pcre2-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0092a7eae1c569cf7dbec61eef956516df93eb4afda8f600ccb16980aca849" "checksum pcre2-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "876c72d05059d23a84bd9fcdc3b1d31c50ea7fe00fe1522b4e68cd3608db8d5b"
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" "checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" "checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "559008764a17de49a3146b234641644ed37d118d1ef641a0bb573d146edc6ce0"
"checksum regex-automata 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a25a7daa2eea48550e9946133d6cc9621020d29cc7069089617234bf8b6a8693"
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
"checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4"
"checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79"
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a" "checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8"
"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum thread_local 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88ddf1ad580c7e3d1efff877d972bcc93f995556b9087a5a259630985c88ceab"
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e"
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9"

View File

@@ -1,11 +1,11 @@
[package] [package]
name = "ripgrep" name = "ripgrep"
version = "0.10.0" #:version version = "11.0.2" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
ripgrep is a line-oriented search tool that recursively searches your current ripgrep is a line-oriented search tool that recursively searches your current
directory for a regex pattern while respecting your gitignore rules. ripgrep directory for a regex pattern while respecting your gitignore rules. ripgrep
has first class support on Windows, macOS and Linux has first class support on Windows, macOS and Linux.
""" """
documentation = "https://github.com/BurntSushi/ripgrep" documentation = "https://github.com/BurntSushi/ripgrep"
homepage = "https://github.com/BurntSushi/ripgrep" homepage = "https://github.com/BurntSushi/ripgrep"
@@ -46,8 +46,8 @@ members = [
] ]
[dependencies] [dependencies]
bstr = "0.1.2" bstr = "0.2.0"
grep = { version = "0.2.3", path = "grep" } grep = { version = "0.2.4", path = "grep" }
ignore = { version = "0.4.7", path = "ignore" } ignore = { version = "0.4.7", path = "ignore" }
lazy_static = "1.1.0" lazy_static = "1.1.0"
log = "0.4.5" log = "0.4.5"
@@ -61,6 +61,9 @@ version = "2.32.0"
default-features = false default-features = false
features = ["suggestions"] features = ["suggestions"]
[target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator]
version = "0.3.0"
[build-dependencies] [build-dependencies]
lazy_static = "1.1.0" lazy_static = "1.1.0"

2
Cross.toml Normal file
View File

@@ -0,0 +1,2 @@
[target.x86_64-unknown-linux-musl]
image = "burntsushi/cross:x86_64-unknown-linux-musl"

4
FAQ.md
View File

@@ -934,8 +934,8 @@ Here are some cases where you might *not* want to use ripgrep. The same caveats
for the previous section apply. for the previous section apply.
* Are you writing portable shell scripts intended to work in a variety of * Are you writing portable shell scripts intended to work in a variety of
environments? Great, probably not a good idea to use ripgrep! ripgrep is has environments? Great, probably not a good idea to use ripgrep! ripgrep has
nowhere near the ubquity of grep, so if you do use ripgrep, you might need nowhere near the ubiquity of grep, so if you do use ripgrep, you might need
to futz with the installation process more than you would with grep. to futz with the installation process more than you would with grep.
* Do you care about POSIX compatibility? If so, then you can't use ripgrep * Do you care about POSIX compatibility? If so, then you can't use ripgrep
because it never was, isn't and never will be POSIX compatible. because it never was, isn't and never will be POSIX compatible.

View File

@@ -110,7 +110,7 @@ colors, you'll notice that `faster` will be highlighted instead of just the
It is beyond the scope of this guide to provide a full tutorial on regular It is beyond the scope of this guide to provide a full tutorial on regular
expressions, but ripgrep's specific syntax is documented here: expressions, but ripgrep's specific syntax is documented here:
https://docs.rs/regex/0.2.5/regex/#syntax https://docs.rs/regex/*/regex/#syntax
### Recursive search ### Recursive search

View File

@@ -29,6 +29,7 @@ Please see the [CHANGELOG](CHANGELOG.md) for a release history.
* [Configuration files](GUIDE.md#configuration-file) * [Configuration files](GUIDE.md#configuration-file)
* [Shell completions](FAQ.md#complete) * [Shell completions](FAQ.md#complete)
* [Building](#building) * [Building](#building)
* [Translations](#translations)
### Screenshot of search results ### Screenshot of search results
@@ -92,11 +93,11 @@ increases the times to `2.640s` for ripgrep and `10.277s` for GNU grep.
[the FAQ](FAQ.md#posix4ever) for more details on whether ripgrep can truly [the FAQ](FAQ.md#posix4ever) for more details on whether ripgrep can truly
replace grep.) replace grep.)
* Like other tools specialized to code search, ripgrep defaults to recursive * Like other tools specialized to code search, ripgrep defaults to recursive
directory search and won't search files ignored by your `.gitignore` files. directory search and won't search files ignored by your
It also ignores hidden and binary files by default. ripgrep also implements `.gitignore`/`.ignore`/`.rgignore` files. It also ignores hidden and binary
full support for `.gitignore`, whereas there are many bugs related to that files by default. ripgrep also implements full support for `.gitignore`,
functionality in other code search tools claiming to provide the same whereas there are many bugs related to that functionality in other code
functionality. search tools claiming to provide the same functionality.
* ripgrep can search specific types of files. For example, `rg -tpy foo` * ripgrep can search specific types of files. For example, `rg -tpy foo`
limits your search to Python files and `rg -Tjs foo` excludes Javascript limits your search to Python files and `rg -Tjs foo` excludes Javascript
files from your search. ripgrep can be taught about new file types with files from your search. ripgrep can be taught about new file types with
@@ -108,13 +109,14 @@ increases the times to `2.640s` for ripgrep and `10.277s` for GNU grep.
* ripgrep has optional support for switching its regex engine to use PCRE2. * ripgrep has optional support for switching its regex engine to use PCRE2.
Among other things, this makes it possible to use look-around and Among other things, this makes it possible to use look-around and
backreferences in your patterns, which are not supported in ripgrep's default backreferences in your patterns, which are not supported in ripgrep's default
regex engine. PCRE2 support is enabled with `-P`. regex engine. PCRE2 support can be enabled with `-P/--pcre2` (use PCRE2
always) or `--auto-hybrid-regex` (use PCRE2 only if needed).
* ripgrep supports searching files in text encodings other than UTF-8, such * ripgrep supports searching files in text encodings other than UTF-8, such
as UTF-16, latin-1, GBK, EUC-JP, Shift_JIS and more. (Some support for as UTF-16, latin-1, GBK, EUC-JP, Shift_JIS and more. (Some support for
automatically detecting UTF-16 is provided. Other text encodings must be automatically detecting UTF-16 is provided. Other text encodings must be
specifically specified with the `-E/--encoding` flag.) specifically specified with the `-E/--encoding` flag.)
* ripgrep supports searching files compressed in a common format (gzip, xz, * ripgrep supports searching files compressed in a common format (brotli,
lzma, bzip2 or lz4) with the `-z/--search-zip` flag. bzip2, gzip, lz4, lzma, xz, or zstandard) with the `-z/--search-zip` flag.
* ripgrep supports arbitrary input preprocessing filters which could be PDF * ripgrep supports arbitrary input preprocessing filters which could be PDF
text extraction, less supported decompression, decrypting, automatic encoding text extraction, less supported decompression, decrypting, automatic encoding
detection and so on. detection and so on.
@@ -208,14 +210,6 @@ from homebrew-core, (compiled with rust stable, no SIMD):
$ brew install ripgrep $ brew install ripgrep
``` ```
or you can install a binary compiled with rust nightly (including SIMD and all
optimizations) by utilizing a custom tap:
```
$ brew tap burntsushi/ripgrep https://github.com/BurntSushi/ripgrep.git
$ brew install ripgrep-bin
```
If you're a **MacPorts** user, then you can install ripgrep from the If you're a **MacPorts** user, then you can install ripgrep from the
[official ports](https://www.macports.org/ports.php?by=name&substr=ripgrep): [official ports](https://www.macports.org/ports.php?by=name&substr=ripgrep):
@@ -231,7 +225,7 @@ $ choco install ripgrep
``` ```
If you're a **Windows Scoop** user, then you can install ripgrep from the If you're a **Windows Scoop** user, then you can install ripgrep from the
[official bucket](https://github.com/lukesampson/scoop/blob/master/bucket/ripgrep.json): [official bucket](https://github.com/ScoopInstaller/Main/blob/master/bucket/ripgrep.json):
``` ```
$ scoop install ripgrep $ scoop install ripgrep
@@ -294,11 +288,11 @@ then ripgrep can be installed using a binary `.deb` file provided in each
[ripgrep release](https://github.com/BurntSushi/ripgrep/releases). [ripgrep release](https://github.com/BurntSushi/ripgrep/releases).
``` ```
$ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/0.10.0/ripgrep_0.10.0_amd64.deb $ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/11.0.2/ripgrep_11.0.2_amd64.deb
$ sudo dpkg -i ripgrep_0.10.0_amd64.deb $ sudo dpkg -i ripgrep_11.0.2_amd64.deb
``` ```
If you run Debian Buster (currently Debian testing) or Debian sid, ripgrep is If you run Debian Buster (currently Debian stable) or Debian sid, ripgrep is
[officially maintained by Debian](https://tracker.debian.org/pkg/rust-ripgrep). [officially maintained by Debian](https://tracker.debian.org/pkg/rust-ripgrep).
``` ```
$ sudo apt-get install ripgrep $ sudo apt-get install ripgrep
@@ -350,9 +344,6 @@ If you're a **Rust programmer**, ripgrep can be installed with `cargo`.
$ cargo install ripgrep $ cargo install ripgrep
``` ```
ripgrep isn't currently in any other package repositories.
[I'd like to change that](https://github.com/BurntSushi/ripgrep/issues/10).
### Building ### Building
@@ -428,3 +419,11 @@ $ cargo test --all
``` ```
from the repository root. from the repository root.
### Translations
The following is a list of known translations of ripgrep's documentation. These
are unofficially maintained and may not be up to date.
* [Chinese](https://github.com/chinanf-boy/ripgrep-zh#%E6%9B%B4%E6%96%B0-)

View File

@@ -8,12 +8,13 @@ set -ex
# Generate artifacts for release # Generate artifacts for release
mk_artifacts() { mk_artifacts() {
CARGO="$(builder)"
if is_arm; then if is_arm; then
cargo build --target "$TARGET" --release "$CARGO" build --target "$TARGET" --release
else else
# Technically, MUSL builds will force PCRE2 to get statically compiled, # Technically, MUSL builds will force PCRE2 to get statically compiled,
# but we also want PCRE2 statically build for macOS binaries. # but we also want PCRE2 statically build for macOS binaries.
PCRE2_SYS_STATIC=1 cargo build --target "$TARGET" --release --features 'pcre2' PCRE2_SYS_STATIC=1 "$CARGO" build --target "$TARGET" --release --features 'pcre2'
fi fi
} }

View File

@@ -0,0 +1,5 @@
FROM rustembedded/cross:x86_64-unknown-linux-musl
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
libxslt1-dev asciidoc docbook-xsl xsltproc libxml2-utils

View File

@@ -7,11 +7,13 @@ set -ex
. "$(dirname $0)/utils.sh" . "$(dirname $0)/utils.sh"
main() { main() {
CARGO="$(builder)"
# Test a normal debug build. # Test a normal debug build.
if is_arm; then if is_arm; then
cargo build --target "$TARGET" --verbose "$CARGO" build --target "$TARGET" --verbose
else else
cargo build --target "$TARGET" --verbose --all --features 'pcre2' "$CARGO" build --target "$TARGET" --verbose --all --features 'pcre2'
fi fi
# Show the output of the most recent build.rs stderr. # Show the output of the most recent build.rs stderr.
@@ -44,7 +46,7 @@ main() {
"$(dirname "${0}")/test_complete.sh" "$(dirname "${0}")/test_complete.sh"
# Run tests for ripgrep and all sub-crates. # Run tests for ripgrep and all sub-crates.
cargo test --target "$TARGET" --verbose --all --features 'pcre2' "$CARGO" test --target "$TARGET" --verbose --all --features 'pcre2'
} }
main main

View File

@@ -55,6 +55,13 @@ gcc_prefix() {
esac esac
} }
is_musl() {
case "$TARGET" in
*-musl) return 0 ;;
*) return 1 ;;
esac
}
is_x86() { is_x86() {
case "$(architecture)" in case "$(architecture)" in
amd64|i386) return 0 ;; amd64|i386) return 0 ;;
@@ -62,6 +69,13 @@ is_x86() {
esac esac
} }
is_x86_64() {
case "$(architecture)" in
amd64) return 0 ;;
*) return 1 ;;
esac
}
is_arm() { is_arm() {
case "$(architecture)" in case "$(architecture)" in
armhf) return 0 ;; armhf) return 0 ;;
@@ -82,3 +96,14 @@ is_osx() {
*) return 1 ;; *) return 1 ;;
esac esac
} }
builder() {
if is_musl && is_x86_64; then
# cargo install cross
# To work around https://github.com/rust-embedded/cross/issues/357
cargo install --git https://github.com/rust-embedded/cross --force
echo "cross"
else
echo "cargo"
fi
}

View File

@@ -104,6 +104,10 @@ _rg() {
'*'{-g+,--glob=}'[include/exclude files matching specified glob]:glob' '*'{-g+,--glob=}'[include/exclude files matching specified glob]:glob'
'*--iglob=[include/exclude files matching specified case-insensitive glob]:glob' '*--iglob=[include/exclude files matching specified case-insensitive glob]:glob'
+ '(glob-case-insensitive)' # File-glob case sensitivity options
'--glob-case-insensitive[treat -g/--glob patterns case insensitively]'
$no'--no-glob-case-insensitive[treat -g/--glob patterns case sensitively]'
+ '(heading)' # Heading options + '(heading)' # Heading options
'(pretty-vimgrep)--heading[show matches grouped by file name]' '(pretty-vimgrep)--heading[show matches grouped by file name]'
"(pretty-vimgrep)--no-heading[don't show matches grouped by file name]" "(pretty-vimgrep)--no-heading[don't show matches grouped by file name]"

View File

@@ -143,16 +143,16 @@ would behave identically to the following command
same with using globs same with using globs
--glob=!git/* --glob=!.git
or or
--glob --glob
!git/* !.git
would behave identically to the following command would behave identically to the following command
rg --glob '!git/*' foo rg --glob '!.git' foo
ripgrep also provides a flag, *--no-config*, that when present will suppress ripgrep also provides a flag, *--no-config*, that when present will suppress
any and all support for configuration. This includes any future support any and all support for configuration. This includes any future support

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "globset" name = "globset"
version = "0.4.3" #:version version = "0.4.4" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
Cross platform single glob and glob set matching. Glob set matching is the Cross platform single glob and glob set matching. Glob set matching is the
@@ -20,7 +20,7 @@ bench = false
[dependencies] [dependencies]
aho-corasick = "0.7.3" aho-corasick = "0.7.3"
bstr = { version = "0.1.2", default-features = false, features = ["std"] } bstr = { version = "0.2.0", default-features = false, features = ["std"] }
fnv = "1.0.6" fnv = "1.0.6"
log = "0.4.5" log = "0.4.5"
regex = "1.1.5" regex = "1.1.5"

View File

@@ -120,7 +120,7 @@ impl GlobMatcher {
/// Tests whether the given path matches this pattern or not. /// Tests whether the given path matches this pattern or not.
pub fn is_match_candidate(&self, path: &Candidate) -> bool { pub fn is_match_candidate(&self, path: &Candidate) -> bool {
self.re.is_match(path.path.as_bytes()) self.re.is_match(&path.path)
} }
} }
@@ -145,7 +145,7 @@ impl GlobStrategic {
/// Tests whether the given path matches this pattern or not. /// Tests whether the given path matches this pattern or not.
fn is_match_candidate(&self, candidate: &Candidate) -> bool { fn is_match_candidate(&self, candidate: &Candidate) -> bool {
let byte_path = candidate.path.as_bytes(); let byte_path = &*candidate.path;
match self.strategy { match self.strategy {
MatchStrategy::Literal(ref lit) => lit.as_bytes() == byte_path, MatchStrategy::Literal(ref lit) => lit.as_bytes() == byte_path,

View File

@@ -119,7 +119,7 @@ use std::path::Path;
use std::str; use std::str;
use aho_corasick::AhoCorasick; use aho_corasick::AhoCorasick;
use bstr::{B, BStr, BString}; use bstr::{B, ByteSlice, ByteVec};
use regex::bytes::{Regex, RegexBuilder, RegexSet}; use regex::bytes::{Regex, RegexBuilder, RegexSet};
use pathutil::{file_name, file_name_ext, normalize_path}; use pathutil::{file_name, file_name_ext, normalize_path};
@@ -490,15 +490,15 @@ impl GlobSetBuilder {
/// path against multiple globs or sets of globs. /// path against multiple globs or sets of globs.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Candidate<'a> { pub struct Candidate<'a> {
path: Cow<'a, BStr>, path: Cow<'a, [u8]>,
basename: Cow<'a, BStr>, basename: Cow<'a, [u8]>,
ext: Cow<'a, BStr>, ext: Cow<'a, [u8]>,
} }
impl<'a> Candidate<'a> { impl<'a> Candidate<'a> {
/// Create a new candidate for matching from the given path. /// Create a new candidate for matching from the given path.
pub fn new<P: AsRef<Path> + ?Sized>(path: &'a P) -> Candidate<'a> { pub fn new<P: AsRef<Path> + ?Sized>(path: &'a P) -> Candidate<'a> {
let path = normalize_path(BString::from_path_lossy(path.as_ref())); let path = normalize_path(Vec::from_path_lossy(path.as_ref()));
let basename = file_name(&path).unwrap_or(Cow::Borrowed(B(""))); let basename = file_name(&path).unwrap_or(Cow::Borrowed(B("")));
let ext = file_name_ext(&basename).unwrap_or(Cow::Borrowed(B(""))); let ext = file_name_ext(&basename).unwrap_or(Cow::Borrowed(B("")));
Candidate { Candidate {
@@ -508,7 +508,7 @@ impl<'a> Candidate<'a> {
} }
} }
fn path_prefix(&self, max: usize) -> &BStr { fn path_prefix(&self, max: usize) -> &[u8] {
if self.path.len() <= max { if self.path.len() <= max {
&*self.path &*self.path
} else { } else {
@@ -516,7 +516,7 @@ impl<'a> Candidate<'a> {
} }
} }
fn path_suffix(&self, max: usize) -> &BStr { fn path_suffix(&self, max: usize) -> &[u8] {
if self.path.len() <= max { if self.path.len() <= max {
&*self.path &*self.path
} else { } else {

View File

@@ -1,15 +1,15 @@
use std::borrow::Cow; use std::borrow::Cow;
use bstr::BStr; use bstr::{ByteSlice, ByteVec};
/// The final component of the path, if it is a normal file. /// The final component of the path, if it is a normal file.
/// ///
/// If the path terminates in ., .., or consists solely of a root of prefix, /// If the path terminates in ., .., or consists solely of a root of prefix,
/// file_name will return None. /// file_name will return None.
pub fn file_name<'a>(path: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> { pub fn file_name<'a>(path: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
if path.is_empty() { if path.is_empty() {
return None; return None;
} else if path.last() == Some(b'.') { } else if path.last_byte() == Some(b'.') {
return None; return None;
} }
let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0); let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0);
@@ -39,7 +39,7 @@ pub fn file_name<'a>(path: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> {
/// a pattern like `*.rs` is obviously trying to match files with a `rs` /// a pattern like `*.rs` is obviously trying to match files with a `rs`
/// extension, but it also matches files like `.rs`, which doesn't have an /// extension, but it also matches files like `.rs`, which doesn't have an
/// extension according to std::path::Path::extension. /// extension according to std::path::Path::extension.
pub fn file_name_ext<'a>(name: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> { pub fn file_name_ext<'a>(name: &Cow<'a, [u8]>) -> Option<Cow<'a, [u8]>> {
if name.is_empty() { if name.is_empty() {
return None; return None;
} }
@@ -60,7 +60,7 @@ pub fn file_name_ext<'a>(name: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> {
/// Normalizes a path to use `/` as a separator everywhere, even on platforms /// Normalizes a path to use `/` as a separator everywhere, even on platforms
/// that recognize other characters as separators. /// that recognize other characters as separators.
#[cfg(unix)] #[cfg(unix)]
pub fn normalize_path(path: Cow<BStr>) -> Cow<BStr> { pub fn normalize_path(path: Cow<[u8]>) -> Cow<[u8]> {
// UNIX only uses /, so we're good. // UNIX only uses /, so we're good.
path path
} }
@@ -68,7 +68,7 @@ pub fn normalize_path(path: Cow<BStr>) -> Cow<BStr> {
/// Normalizes a path to use `/` as a separator everywhere, even on platforms /// Normalizes a path to use `/` as a separator everywhere, even on platforms
/// that recognize other characters as separators. /// that recognize other characters as separators.
#[cfg(not(unix))] #[cfg(not(unix))]
pub fn normalize_path(mut path: Cow<BStr>) -> Cow<BStr> { pub fn normalize_path(mut path: Cow<[u8]>) -> Cow<[u8]> {
use std::path::is_separator; use std::path::is_separator;
for i in 0..path.len() { for i in 0..path.len() {
@@ -84,7 +84,7 @@ pub fn normalize_path(mut path: Cow<BStr>) -> Cow<BStr> {
mod tests { mod tests {
use std::borrow::Cow; use std::borrow::Cow;
use bstr::{B, BString}; use bstr::{B, ByteVec};
use super::{file_name_ext, normalize_path}; use super::{file_name_ext, normalize_path};
@@ -92,7 +92,7 @@ mod tests {
($name:ident, $file_name:expr, $ext:expr) => { ($name:ident, $file_name:expr, $ext:expr) => {
#[test] #[test]
fn $name() { fn $name() {
let bs = BString::from($file_name); let bs = Vec::from($file_name);
let got = file_name_ext(&Cow::Owned(bs)); let got = file_name_ext(&Cow::Owned(bs));
assert_eq!($ext.map(|s| Cow::Borrowed(B(s))), got); assert_eq!($ext.map(|s| Cow::Borrowed(B(s))), got);
} }
@@ -109,7 +109,7 @@ mod tests {
($name:ident, $path:expr, $expected:expr) => { ($name:ident, $path:expr, $expected:expr) => {
#[test] #[test]
fn $name() { fn $name() {
let bs = BString::from_slice($path); let bs = Vec::from_slice($path);
let got = normalize_path(Cow::Owned(bs)); let got = normalize_path(Cow::Owned(bs));
assert_eq!($expected.to_vec(), got.into_owned()); assert_eq!($expected.to_vec(), got.into_owned());
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "grep-cli" name = "grep-cli"
version = "0.1.1" #:version version = "0.1.3" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
Utilities for search oriented command line applications. Utilities for search oriented command line applications.
@@ -14,7 +14,7 @@ license = "Unlicense/MIT"
[dependencies] [dependencies]
atty = "0.2.11" atty = "0.2.11"
bstr = "0.1.2" bstr = "0.2.0"
globset = { version = "0.4.3", path = "../globset" } globset = { version = "0.4.3", path = "../globset" }
lazy_static = "1.1.0" lazy_static = "1.1.0"
log = "0.4.5" log = "0.4.5"

View File

@@ -1,7 +1,7 @@
use std::ffi::OsStr; use std::ffi::OsStr;
use std::str; use std::str;
use bstr::{BStr, BString}; use bstr::{ByteSlice, ByteVec};
/// A single state in the state machine used by `unescape`. /// A single state in the state machine used by `unescape`.
#[derive(Clone, Copy, Eq, PartialEq)] #[derive(Clone, Copy, Eq, PartialEq)]
@@ -38,7 +38,6 @@ enum State {
/// assert_eq!(r"foo\nbar\xFFbaz", escape(b"foo\nbar\xFFbaz")); /// assert_eq!(r"foo\nbar\xFFbaz", escape(b"foo\nbar\xFFbaz"));
/// ``` /// ```
pub fn escape(bytes: &[u8]) -> String { pub fn escape(bytes: &[u8]) -> String {
let bytes = BStr::new(bytes);
let mut escaped = String::new(); let mut escaped = String::new();
for (s, e, ch) in bytes.char_indices() { for (s, e, ch) in bytes.char_indices() {
if ch == '\u{FFFD}' { if ch == '\u{FFFD}' {
@@ -56,7 +55,7 @@ pub fn escape(bytes: &[u8]) -> String {
/// ///
/// This is like [`escape`](fn.escape.html), but accepts an OS string. /// This is like [`escape`](fn.escape.html), but accepts an OS string.
pub fn escape_os(string: &OsStr) -> String { pub fn escape_os(string: &OsStr) -> String {
escape(BString::from_os_str_lossy(string).as_bytes()) escape(Vec::from_os_str_lossy(string).as_bytes())
} }
/// Unescapes a string. /// Unescapes a string.
@@ -111,7 +110,7 @@ pub fn unescape(s: &str) -> Vec<u8> {
} }
HexFirst => { HexFirst => {
match c { match c {
'0'...'9' | 'A'...'F' | 'a'...'f' => { '0'..='9' | 'A'..='F' | 'a'..='f' => {
state = HexSecond(c); state = HexSecond(c);
} }
c => { c => {
@@ -122,7 +121,7 @@ pub fn unescape(s: &str) -> Vec<u8> {
} }
HexSecond(first) => { HexSecond(first) => {
match c { match c {
'0'...'9' | 'A'...'F' | 'a'...'f' => { '0'..='9' | 'A'..='F' | 'a'..='f' => {
let ordinal = format!("{}{}", first, c); let ordinal = format!("{}{}", first, c);
let byte = u8::from_str_radix(&ordinal, 16).unwrap(); let byte = u8::from_str_radix(&ordinal, 16).unwrap();
bytes.push(byte); bytes.push(byte);
@@ -174,7 +173,7 @@ fn escape_char(cp: char, into: &mut String) {
/// Adds the given byte to the given string, escaping it if necessary. /// Adds the given byte to the given string, escaping it if necessary.
fn escape_byte(byte: u8, into: &mut String) { fn escape_byte(byte: u8, into: &mut String) {
match byte { match byte {
0x21...0x5B | 0x5D...0x7D => into.push(byte as char), 0x21..=0x5B | 0x5D..=0x7D => into.push(byte as char),
b'\n' => into.push_str(r"\n"), b'\n' => into.push_str(r"\n"),
b'\r' => into.push_str(r"\r"), b'\r' => into.push_str(r"\r"),
b'\t' => into.push_str(r"\t"), b'\t' => into.push_str(r"\t"),

View File

@@ -2,10 +2,12 @@ use std::error;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fmt; use std::fmt;
use std::fs::File; use std::fs::File;
use std::io::{self, BufRead}; use std::io;
use std::path::Path; use std::path::Path;
use std::str; use std::str;
use bstr::io::BufReadExt;
use escape::{escape, escape_os}; use escape::{escape, escape_os};
/// An error that occurs when a pattern could not be converted to valid UTF-8. /// An error that occurs when a pattern could not be converted to valid UTF-8.
@@ -156,28 +158,22 @@ pub fn patterns_from_stdin() -> io::Result<Vec<String>> {
/// ``` /// ```
pub fn patterns_from_reader<R: io::Read>(rdr: R) -> io::Result<Vec<String>> { pub fn patterns_from_reader<R: io::Read>(rdr: R) -> io::Result<Vec<String>> {
let mut patterns = vec![]; let mut patterns = vec![];
let mut bufrdr = io::BufReader::new(rdr);
let mut line = vec![];
let mut line_number = 0; let mut line_number = 0;
while { io::BufReader::new(rdr).for_byte_line(|line| {
line.clear();
line_number += 1; line_number += 1;
bufrdr.read_until(b'\n', &mut line)? > 0 match pattern_from_bytes(line) {
} { Ok(pattern) => {
line.pop().unwrap(); // remove trailing '\n' patterns.push(pattern.to_string());
if line.last() == Some(&b'\r') { Ok(true)
line.pop().unwrap(); }
}
match pattern_from_bytes(&line) {
Ok(pattern) => patterns.push(pattern.to_string()),
Err(err) => { Err(err) => {
return Err(io::Error::new( Err(io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("{}: {}", line_number, err), format!("{}: {}", line_number, err),
)); ))
} }
} }
} })?;
Ok(patterns) Ok(patterns)
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "grep-matcher" name = "grep-matcher"
version = "0.1.2" #:version version = "0.1.3" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
A trait for regular expressions, with a focus on line oriented search. A trait for regular expressions, with a focus on line oriented search.

View File

@@ -134,7 +134,7 @@ fn find_cap_ref(replacement: &[u8]) -> Option<CaptureRef> {
/// Returns true if and only if the given byte is allowed in a capture name. /// Returns true if and only if the given byte is allowed in a capture name.
fn is_valid_cap_letter(b: &u8) -> bool { fn is_valid_cap_letter(b: &u8) -> bool {
match *b { match *b {
b'0' ... b'9' | b'a' ... b'z' | b'A' ... b'Z' | b'_' => true, b'0' ..= b'9' | b'a' ..= b'z' | b'A' ..= b'Z' | b'_' => true,
_ => false, _ => false,
} }
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "grep-printer" name = "grep-printer"
version = "0.1.2" #:version version = "0.1.3" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
An implementation of the grep crate's Sink trait that provides standard An implementation of the grep crate's Sink trait that provides standard
@@ -18,8 +18,8 @@ default = ["serde1"]
serde1 = ["base64", "serde", "serde_derive", "serde_json"] serde1 = ["base64", "serde", "serde_derive", "serde_json"]
[dependencies] [dependencies]
base64 = { version = "0.10.0", optional = true } base64 = { version = "0.11.0", optional = true }
bstr = "0.1.2" bstr = "0.2.0"
grep-matcher = { version = "0.1.2", path = "../grep-matcher" } grep-matcher = { version = "0.1.2", path = "../grep-matcher" }
grep-searcher = { version = "0.1.4", path = "../grep-searcher" } grep-searcher = { version = "0.1.4", path = "../grep-searcher" }
termcolor = "1.0.4" termcolor = "1.0.4"

View File

@@ -5,7 +5,7 @@ use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use std::time::Instant; use std::time::Instant;
use bstr::BStr; use bstr::ByteSlice;
use grep_matcher::{Match, Matcher}; use grep_matcher::{Match, Matcher};
use grep_searcher::{ use grep_searcher::{
LineStep, Searcher, LineStep, Searcher,
@@ -1029,7 +1029,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
let mut count = 0; let mut count = 0;
let mut stepper = LineStep::new(line_term, 0, bytes.len()); let mut stepper = LineStep::new(line_term, 0, bytes.len());
while let Some((start, end)) = stepper.next(bytes) { while let Some((start, end)) = stepper.next(bytes) {
let mut line = Match::new(start, end); let line = Match::new(start, end);
self.write_prelude( self.write_prelude(
self.sunk.absolute_byte_offset() + line.start() as u64, self.sunk.absolute_byte_offset() + line.start() as u64,
self.sunk.line_number().map(|n| n + count), self.sunk.line_number().map(|n| n + count),
@@ -1105,7 +1105,6 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
let spec = self.config().colors.matched(); let spec = self.config().colors.matched();
let bytes = self.sunk.bytes(); let bytes = self.sunk.bytes();
for &m in self.sunk.matches() { for &m in self.sunk.matches() {
let mut m = m;
let mut count = 0; let mut count = 0;
let mut stepper = LineStep::new(line_term, 0, bytes.len()); let mut stepper = LineStep::new(line_term, 0, bytes.len());
while let Some((start, end)) = stepper.next(bytes) { while let Some((start, end)) = stepper.next(bytes) {
@@ -1275,7 +1274,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
) -> io::Result<()> { ) -> io::Result<()> {
if self.config().max_columns_preview { if self.config().max_columns_preview {
let original = line; let original = line;
let end = BStr::new(&bytes[line]) let end = bytes[line]
.grapheme_indices() .grapheme_indices()
.map(|(_, end, _)| end) .map(|(_, end, _)| end)
.take(self.config().max_columns.unwrap_or(0) as usize) .take(self.config().max_columns.unwrap_or(0) as usize)
@@ -1397,7 +1396,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
} }
let remainder = format!( let remainder = format!(
"after match (found {:?} byte around offset {})\n", "after match (found {:?} byte around offset {})\n",
BStr::new(&[byte]), offset, [byte].as_bstr(), offset,
); );
self.write(remainder.as_bytes())?; self.write(remainder.as_bytes())?;
} else if let Some(byte) = bin.convert_byte() { } else if let Some(byte) = bin.convert_byte() {
@@ -1408,7 +1407,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
} }
let remainder = format!( let remainder = format!(
"matches (found {:?} byte around offset {})\n", "matches (found {:?} byte around offset {})\n",
BStr::new(&[byte]), offset, [byte].as_bstr(), offset,
); );
self.write(remainder.as_bytes())?; self.write(remainder.as_bytes())?;
} }

View File

@@ -4,7 +4,7 @@ use std::io;
use std::path::Path; use std::path::Path;
use std::time; use std::time;
use bstr::{BStr, BString}; use bstr::{ByteSlice, ByteVec};
use grep_matcher::{Captures, LineTerminator, Match, Matcher}; use grep_matcher::{Captures, LineTerminator, Match, Matcher};
use grep_searcher::{ use grep_searcher::{
LineIter, LineIter,
@@ -263,12 +263,12 @@ impl<'a> Sunk<'a> {
/// portability with a small cost: on Windows, paths that are not valid UTF-16 /// portability with a small cost: on Windows, paths that are not valid UTF-16
/// will not roundtrip correctly. /// will not roundtrip correctly.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PrinterPath<'a>(Cow<'a, BStr>); pub struct PrinterPath<'a>(Cow<'a, [u8]>);
impl<'a> PrinterPath<'a> { impl<'a> PrinterPath<'a> {
/// Create a new path suitable for printing. /// Create a new path suitable for printing.
pub fn new(path: &'a Path) -> PrinterPath<'a> { pub fn new(path: &'a Path) -> PrinterPath<'a> {
PrinterPath(BString::from_path_lossy(path)) PrinterPath(Vec::from_path_lossy(path))
} }
/// Create a new printer path from the given path which can be efficiently /// Create a new printer path from the given path which can be efficiently
@@ -289,7 +289,7 @@ impl<'a> PrinterPath<'a> {
/// path separators that are both replaced by `new_sep`. In all other /// path separators that are both replaced by `new_sep`. In all other
/// environments, only `/` is treated as a path separator. /// environments, only `/` is treated as a path separator.
fn replace_separator(&mut self, new_sep: u8) { fn replace_separator(&mut self, new_sep: u8) {
let transformed_path: BString = self.0.bytes().map(|b| { let transformed_path: Vec<u8> = self.0.bytes().map(|b| {
if b == b'/' || (cfg!(windows) && b == b'\\') { if b == b'/' || (cfg!(windows) && b == b'\\') {
new_sep new_sep
} else { } else {
@@ -301,7 +301,7 @@ impl<'a> PrinterPath<'a> {
/// Return the raw bytes for this path. /// Return the raw bytes for this path.
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes() &self.0
} }
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "grep-regex" name = "grep-regex"
version = "0.1.3" #:version version = "0.1.5" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
Use Rust's regex library with the 'grep' crate. Use Rust's regex library with the 'grep' crate.
@@ -18,5 +18,4 @@ grep-matcher = { version = "0.1.2", path = "../grep-matcher" }
log = "0.4.5" log = "0.4.5"
regex = "1.1" regex = "1.1"
regex-syntax = "0.6.5" regex-syntax = "0.6.5"
thread_local = "0.3.6" thread_local = "1"
utf8-ranges = "1.0.1"

View File

@@ -11,7 +11,6 @@ extern crate log;
extern crate regex; extern crate regex;
extern crate regex_syntax; extern crate regex_syntax;
extern crate thread_local; extern crate thread_local;
extern crate utf8_ranges;
pub use error::{Error, ErrorKind}; pub use error::{Error, ErrorKind};
pub use matcher::{RegexCaptures, RegexMatcher, RegexMatcherBuilder}; pub use matcher::{RegexCaptures, RegexMatcher, RegexMatcherBuilder};

View File

@@ -71,10 +71,31 @@ impl RegexMatcherBuilder {
&self, &self,
literals: &[B], literals: &[B],
) -> Result<RegexMatcher, Error> { ) -> Result<RegexMatcher, Error> {
let slices: Vec<_> = literals.iter().map(|s| s.as_ref()).collect(); let mut has_escape = false;
if !self.config.can_plain_aho_corasick() || literals.len() < 40 { let mut slices = vec![];
for lit in literals {
slices.push(lit.as_ref());
has_escape = has_escape || lit.as_ref().contains('\\');
}
// Even when we have a fixed set of literals, we might still want to
// use the regex engine. Specifically, if any string has an escape
// in it, then we probably can't feed it to Aho-Corasick without
// removing the escape. Additionally, if there are any particular
// special match semantics we need to honor, that Aho-Corasick isn't
// enough. Finally, the regex engine can do really well with a small
// number of literals (at time of writing, this is changing soon), so
// we use it when there's a small set.
//
// Yes, this is one giant hack. Ideally, this entirely separate literal
// matcher that uses Aho-Corasick would be pushed down into the regex
// engine.
if has_escape
|| !self.config.can_plain_aho_corasick()
|| literals.len() < 40
{
return self.build(&slices.join("|")); return self.build(&slices.join("|"));
} }
let matcher = MultiLiteralMatcher::new(&slices)?; let matcher = MultiLiteralMatcher::new(&slices)?;
let imp = RegexMatcherImpl::MultiLiteral(matcher); let imp = RegexMatcherImpl::MultiLiteral(matcher);
Ok(RegexMatcher { Ok(RegexMatcher {

View File

@@ -1,6 +1,6 @@
use grep_matcher::ByteSet; use grep_matcher::ByteSet;
use regex_syntax::hir::{self, Hir, HirKind}; use regex_syntax::hir::{self, Hir, HirKind};
use utf8_ranges::Utf8Sequences; use regex_syntax::utf8::Utf8Sequences;
/// Return a confirmed set of non-matching bytes from the given expression. /// Return a confirmed set of non-matching bytes from the given expression.
pub fn non_matching_bytes(expr: &Hir) -> ByteSet { pub fn non_matching_bytes(expr: &Hir) -> ByteSet {

View File

@@ -78,7 +78,7 @@ impl Matcher for WordMatcher {
// if it's worth it. // if it's worth it.
let cell = self.locs.get_or(|| { let cell = self.locs.get_or(|| {
Box::new(RefCell::new(self.regex.capture_locations())) RefCell::new(self.regex.capture_locations())
}); });
let mut caps = cell.borrow_mut(); let mut caps = cell.borrow_mut();
self.regex.captures_read_at(&mut caps, haystack, at); self.regex.captures_read_at(&mut caps, haystack, at);

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "grep-searcher" name = "grep-searcher"
version = "0.1.4" #:version version = "0.1.6" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
Fast line oriented regex searching as a library. Fast line oriented regex searching as a library.
@@ -13,8 +13,8 @@ keywords = ["regex", "grep", "egrep", "search", "pattern"]
license = "Unlicense/MIT" license = "Unlicense/MIT"
[dependencies] [dependencies]
bstr = { version = "0.1.2", default-features = false, features = ["std"] } bstr = { version = "0.2.0", default-features = false, features = ["std"] }
bytecount = "0.5" bytecount = "0.6"
encoding_rs = "0.8.14" encoding_rs = "0.8.14"
encoding_rs_io = "0.1.6" encoding_rs_io = "0.1.6"
grep-matcher = { version = "0.1.2", path = "../grep-matcher" } grep-matcher = { version = "0.1.2", path = "../grep-matcher" }

View File

@@ -17,7 +17,7 @@ fn main() {
} }
} }
fn example() -> Result<(), Box<Error>> { fn example() -> Result<(), Box<dyn Error>> {
let pattern = match env::args().nth(1) { let pattern = match env::args().nth(1) {
Some(pattern) => pattern, Some(pattern) => pattern,
None => return Err(From::from(format!( None => return Err(From::from(format!(

View File

@@ -1,7 +1,7 @@
use std::cmp; use std::cmp;
use std::io; use std::io;
use bstr::{BStr, BString}; use bstr::ByteSlice;
/// The default buffer capacity that we use for the line buffer. /// The default buffer capacity that we use for the line buffer.
pub(crate) const DEFAULT_BUFFER_CAPACITY: usize = 8 * (1<<10); // 8 KB pub(crate) const DEFAULT_BUFFER_CAPACITY: usize = 8 * (1<<10); // 8 KB
@@ -122,7 +122,7 @@ impl LineBufferBuilder {
pub fn build(&self) -> LineBuffer { pub fn build(&self) -> LineBuffer {
LineBuffer { LineBuffer {
config: self.config, config: self.config,
buf: BString::from(vec![0; self.config.capacity]), buf: vec![0; self.config.capacity],
pos: 0, pos: 0,
last_lineterm: 0, last_lineterm: 0,
end: 0, end: 0,
@@ -254,13 +254,14 @@ impl<'b, R: io::Read> LineBufferReader<'b, R> {
/// Return the contents of this buffer. /// Return the contents of this buffer.
pub fn buffer(&self) -> &[u8] { pub fn buffer(&self) -> &[u8] {
self.line_buffer.buffer().as_bytes() self.line_buffer.buffer()
} }
/// Return the underlying buffer as a byte string. Used for tests only. /// Return the buffer as a BStr, used for convenient equality checking
/// in tests only.
#[cfg(test)] #[cfg(test)]
fn bstr(&self) -> &BStr { fn bstr(&self) -> &::bstr::BStr {
self.line_buffer.buffer() self.buffer().as_bstr()
} }
/// Consume the number of bytes provided. This must be less than or equal /// Consume the number of bytes provided. This must be less than or equal
@@ -289,7 +290,7 @@ pub struct LineBuffer {
/// The configuration of this buffer. /// The configuration of this buffer.
config: Config, config: Config,
/// The primary buffer with which to hold data. /// The primary buffer with which to hold data.
buf: BString, buf: Vec<u8>,
/// The current position of this buffer. This is always a valid sliceable /// The current position of this buffer. This is always a valid sliceable
/// index into `buf`, and its maximum value is the length of `buf`. /// index into `buf`, and its maximum value is the length of `buf`.
pos: usize, pos: usize,
@@ -352,13 +353,13 @@ impl LineBuffer {
} }
/// Return the contents of this buffer. /// Return the contents of this buffer.
fn buffer(&self) -> &BStr { fn buffer(&self) -> &[u8] {
&self.buf[self.pos..self.last_lineterm] &self.buf[self.pos..self.last_lineterm]
} }
/// Return the contents of the free space beyond the end of the buffer as /// Return the contents of the free space beyond the end of the buffer as
/// a mutable slice. /// a mutable slice.
fn free_buffer(&mut self) -> &mut BStr { fn free_buffer(&mut self) -> &mut [u8] {
&mut self.buf[self.end..] &mut self.buf[self.end..]
} }
@@ -481,7 +482,7 @@ impl LineBuffer {
} }
let roll_len = self.end - self.pos; let roll_len = self.end - self.pos;
self.buf.copy_within(self.pos.., 0); self.buf.copy_within_str(self.pos..self.end, 0);
self.pos = 0; self.pos = 0;
self.last_lineterm = roll_len; self.last_lineterm = roll_len;
self.end = roll_len; self.end = roll_len;
@@ -519,7 +520,7 @@ impl LineBuffer {
/// Replaces `src` with `replacement` in bytes, and return the offset of the /// Replaces `src` with `replacement` in bytes, and return the offset of the
/// first replacement, if one exists. /// first replacement, if one exists.
fn replace_bytes(bytes: &mut BStr, src: u8, replacement: u8) -> Option<usize> { fn replace_bytes(bytes: &mut [u8], src: u8, replacement: u8) -> Option<usize> {
if src == replacement { if src == replacement {
return None; return None;
} }
@@ -542,7 +543,7 @@ fn replace_bytes(bytes: &mut BStr, src: u8, replacement: u8) -> Option<usize> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::str; use std::str;
use bstr::BString; use bstr::{ByteSlice, ByteVec};
use super::*; use super::*;
const SHERLOCK: &'static str = "\ const SHERLOCK: &'static str = "\
@@ -563,7 +564,7 @@ and exhibited clearly, with a label attached.\
src: u8, src: u8,
replacement: u8, replacement: u8,
) -> (String, Option<usize>) { ) -> (String, Option<usize>) {
let mut dst = BString::from(slice); let mut dst = Vec::from(slice);
let result = replace_bytes(&mut dst, src, replacement); let result = replace_bytes(&mut dst, src, replacement);
(dst.into_string().unwrap(), result) (dst.into_string().unwrap(), result)
} }
@@ -677,12 +678,12 @@ and exhibited clearly, with a label attached.\
let mut linebuf = LineBufferBuilder::new().capacity(1).build(); let mut linebuf = LineBufferBuilder::new().capacity(1).build();
let mut rdr = LineBufferReader::new(bytes.as_bytes(), &mut linebuf); let mut rdr = LineBufferReader::new(bytes.as_bytes(), &mut linebuf);
let mut got = BString::new(); let mut got = vec![];
while rdr.fill().unwrap() { while rdr.fill().unwrap() {
got.push(rdr.buffer()); got.push_str(rdr.buffer());
rdr.consume_all(); rdr.consume_all();
} }
assert_eq!(bytes, got); assert_eq!(bytes, got.as_bstr());
assert_eq!(rdr.absolute_byte_offset(), bytes.len() as u64); assert_eq!(rdr.absolute_byte_offset(), bytes.len() as u64);
assert_eq!(rdr.binary_byte_offset(), None); assert_eq!(rdr.binary_byte_offset(), None);
} }

View File

@@ -2,7 +2,7 @@
A collection of routines for performing operations on lines. A collection of routines for performing operations on lines.
*/ */
use bstr::B; use bstr::ByteSlice;
use bytecount; use bytecount;
use grep_matcher::{LineTerminator, Match}; use grep_matcher::{LineTerminator, Match};
@@ -85,7 +85,7 @@ impl LineStep {
#[inline(always)] #[inline(always)]
fn next_impl(&mut self, mut bytes: &[u8]) -> Option<(usize, usize)> { fn next_impl(&mut self, mut bytes: &[u8]) -> Option<(usize, usize)> {
bytes = &bytes[..self.end]; bytes = &bytes[..self.end];
match B(&bytes[self.pos..]).find_byte(self.line_term) { match bytes[self.pos..].find_byte(self.line_term) {
None => { None => {
if self.pos < bytes.len() { if self.pos < bytes.len() {
let m = (self.pos, bytes.len()); let m = (self.pos, bytes.len());
@@ -135,14 +135,14 @@ pub fn locate(
line_term: u8, line_term: u8,
range: Match, range: Match,
) -> Match { ) -> Match {
let line_start = B(&bytes[..range.start()]) let line_start = bytes[..range.start()]
.rfind_byte(line_term) .rfind_byte(line_term)
.map_or(0, |i| i + 1); .map_or(0, |i| i + 1);
let line_end = let line_end =
if range.end() > line_start && bytes[range.end() - 1] == line_term { if range.end() > line_start && bytes[range.end() - 1] == line_term {
range.end() range.end()
} else { } else {
B(&bytes[range.end()..]) bytes[range.end()..]
.find_byte(line_term) .find_byte(line_term)
.map_or(bytes.len(), |i| range.end() + i + 1) .map_or(bytes.len(), |i| range.end() + i + 1)
}; };
@@ -182,7 +182,7 @@ fn preceding_by_pos(
pos -= 1; pos -= 1;
} }
loop { loop {
match B(&bytes[..pos]).rfind_byte(line_term) { match bytes[..pos].rfind_byte(line_term) {
None => { None => {
return 0; return 0;
} }

View File

@@ -1,6 +1,6 @@
use std::cmp; use std::cmp;
use bstr::B; use bstr::ByteSlice;
use grep_matcher::{LineMatchKind, Matcher}; use grep_matcher::{LineMatchKind, Matcher};
use lines::{self, LineStep}; use lines::{self, LineStep};
@@ -161,7 +161,7 @@ impl<'s, M: Matcher, S: Sink> Core<'s, M, S> {
BinaryDetection::Convert(b) => b, BinaryDetection::Convert(b) => b,
_ => return Ok(false), _ => return Ok(false),
}; };
if let Some(i) = B(&buf[*range]).find_byte(binary_byte) { if let Some(i) = buf[*range].find_byte(binary_byte) {
let offset = range.start() + i; let offset = range.start() + i;
self.binary_byte_offset = Some(offset); self.binary_byte_offset = Some(offset);
if !self.binary_data(offset as u64)? { if !self.binary_data(offset as u64)? {

View File

@@ -1,3 +1,4 @@
use std::error;
use std::fmt; use std::fmt;
use std::io; use std::io;
@@ -49,9 +50,9 @@ impl SinkError for io::Error {
/// A `Box<std::error::Error>` can be used as an error for `Sink` /// A `Box<std::error::Error>` can be used as an error for `Sink`
/// implementations out of the box. /// implementations out of the box.
impl SinkError for Box<::std::error::Error> { impl SinkError for Box<dyn error::Error> {
fn error_message<T: fmt::Display>(message: T) -> Box<::std::error::Error> { fn error_message<T: fmt::Display>(message: T) -> Box<dyn error::Error> {
Box::<::std::error::Error>::from(message.to_string()) Box::<dyn error::Error>::from(message.to_string())
} }
} }

View File

@@ -1,7 +1,7 @@
use std::io::{self, Write}; use std::io::{self, Write};
use std::str; use std::str;
use bstr::B; use bstr::ByteSlice;
use grep_matcher::{ use grep_matcher::{
LineMatchKind, LineTerminator, Match, Matcher, NoCaptures, NoError, LineMatchKind, LineTerminator, Match, Matcher, NoCaptures, NoError,
}; };
@@ -94,7 +94,7 @@ impl Matcher for RegexMatcher {
} }
// Make it interesting and return the last byte in the current // Make it interesting and return the last byte in the current
// line. // line.
let i = B(haystack) let i = haystack
.find_byte(self.line_term.unwrap().as_byte()) .find_byte(self.line_term.unwrap().as_byte())
.map(|i| i) .map(|i| i)
.unwrap_or(haystack.len() - 1); .unwrap_or(haystack.len() - 1);

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "grep" name = "grep"
version = "0.2.3" #:version version = "0.2.4" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
Fast line oriented regex searching as a library. Fast line oriented regex searching as a library.
@@ -13,7 +13,7 @@ keywords = ["regex", "grep", "egrep", "search", "pattern"]
license = "Unlicense/MIT" license = "Unlicense/MIT"
[dependencies] [dependencies]
grep-cli = { version = "0.1.1", path = "../grep-cli" } grep-cli = { version = "0.1.2", path = "../grep-cli" }
grep-matcher = { version = "0.1.2", path = "../grep-matcher" } grep-matcher = { version = "0.1.2", path = "../grep-matcher" }
grep-pcre2 = { version = "0.1.3", path = "../grep-pcre2", optional = true } grep-pcre2 = { version = "0.1.3", path = "../grep-pcre2", optional = true }
grep-printer = { version = "0.1.2", path = "../grep-printer" } grep-printer = { version = "0.1.2", path = "../grep-printer" }

View File

@@ -21,7 +21,7 @@ fn main() {
} }
} }
fn try_main() -> Result<(), Box<Error>> { fn try_main() -> Result<(), Box<dyn Error>> {
let mut args: Vec<OsString> = env::args_os().collect(); let mut args: Vec<OsString> = env::args_os().collect();
if args.len() < 2 { if args.len() < 2 {
return Err("Usage: simplegrep <pattern> [<path> ...]".into()); return Err("Usage: simplegrep <pattern> [<path> ...]".into());
@@ -32,7 +32,7 @@ fn try_main() -> Result<(), Box<Error>> {
search(cli::pattern_from_os(&args[1])?, &args[2..]) search(cli::pattern_from_os(&args[1])?, &args[2..])
} }
fn search(pattern: &str, paths: &[OsString]) -> Result<(), Box<Error>> { fn search(pattern: &str, paths: &[OsString]) -> Result<(), Box<dyn Error>> {
let matcher = RegexMatcher::new_line_matcher(&pattern)?; let matcher = RegexMatcher::new_line_matcher(&pattern)?;
let mut searcher = SearcherBuilder::new() let mut searcher = SearcherBuilder::new()
.binary_detection(BinaryDetection::quit(b'\x00')) .binary_detection(BinaryDetection::quit(b'\x00'))

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "ignore" name = "ignore"
version = "0.4.7" #:version version = "0.4.11" #:version
authors = ["Andrew Gallant <jamslam@gmail.com>"] authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """ description = """
A fast library for efficiently matching ignore files such as `.gitignore` A fast library for efficiently matching ignore files such as `.gitignore`
@@ -18,21 +18,18 @@ name = "ignore"
bench = false bench = false
[dependencies] [dependencies]
crossbeam-channel = "0.3.6" crossbeam-channel = "0.4.0"
globset = { version = "0.4.3", path = "../globset" } globset = { version = "0.4.3", path = "../globset" }
lazy_static = "1.1" lazy_static = "1.1"
log = "0.4.5" log = "0.4.5"
memchr = "2.1" memchr = "2.1"
regex = "1.1" regex = "1.1"
same-file = "1.0.4" same-file = "1.0.4"
thread_local = "0.3.6" thread_local = "1"
walkdir = "2.2.7" walkdir = "2.2.7"
[target.'cfg(windows)'.dependencies.winapi-util] [target.'cfg(windows)'.dependencies.winapi-util]
version = "0.1.2" version = "0.1.2"
[dev-dependencies]
tempfile = "3.0.5"
[features] [features]
simd-accel = ["globset/simd-accel"] simd-accel = ["globset/simd-accel"]

View File

@@ -14,13 +14,13 @@
// well. // well.
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::{OsString, OsStr}; use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use gitignore::{self, Gitignore, GitignoreBuilder}; use gitignore::{self, Gitignore, GitignoreBuilder};
use pathutil::{is_hidden, strip_prefix};
use overrides::{self, Override}; use overrides::{self, Override};
use pathutil::{is_hidden, strip_prefix};
use types::{self, Types}; use types::{self, Types};
use walk::DirEntry; use walk::DirEntry;
use {Error, Match, PartialErrorBuilder}; use {Error, Match, PartialErrorBuilder};
@@ -152,10 +152,7 @@ impl Ignore {
/// ///
/// Note that this can only be called on an `Ignore` matcher with no /// Note that this can only be called on an `Ignore` matcher with no
/// parents (i.e., `is_root` returns `true`). This will panic otherwise. /// parents (i.e., `is_root` returns `true`). This will panic otherwise.
pub fn add_parents<P: AsRef<Path>>( pub fn add_parents<P: AsRef<Path>>(&self, path: P) -> (Ignore, Option<Error>) {
&self,
path: P,
) -> (Ignore, Option<Error>) {
if !self.0.opts.parents if !self.0.opts.parents
&& !self.0.opts.git_ignore && !self.0.opts.git_ignore
&& !self.0.opts.git_exclude && !self.0.opts.git_exclude
@@ -197,7 +194,11 @@ impl Ignore {
errs.maybe_push(err); errs.maybe_push(err);
igtmp.is_absolute_parent = true; igtmp.is_absolute_parent = true;
igtmp.absolute_base = Some(absolute_base.clone()); igtmp.absolute_base = Some(absolute_base.clone());
igtmp.has_git = parent.join(".git").exists(); igtmp.has_git = if self.0.opts.git_ignore {
parent.join(".git").exists()
} else {
false
};
ig = Ignore(Arc::new(igtmp)); ig = Ignore(Arc::new(igtmp));
compiled.insert(parent.as_os_str().to_os_string(), ig.clone()); compiled.insert(parent.as_os_str().to_os_string(), ig.clone());
} }
@@ -212,10 +213,7 @@ impl Ignore {
/// returned if it exists. /// returned if it exists.
/// ///
/// Note that all I/O errors are completely ignored. /// Note that all I/O errors are completely ignored.
pub fn add_child<P: AsRef<Path>>( pub fn add_child<P: AsRef<Path>>(&self, dir: P) -> (Ignore, Option<Error>) {
&self,
dir: P,
) -> (Ignore, Option<Error>) {
let (ig, err) = self.add_child_path(dir.as_ref()); let (ig, err) = self.add_child_path(dir.as_ref());
(Ignore(Arc::new(ig)), err) (Ignore(Arc::new(ig)), err)
} }
@@ -223,58 +221,49 @@ impl Ignore {
/// Like add_child, but takes a full path and returns an IgnoreInner. /// Like add_child, but takes a full path and returns an IgnoreInner.
fn add_child_path(&self, dir: &Path) -> (IgnoreInner, Option<Error>) { fn add_child_path(&self, dir: &Path) -> (IgnoreInner, Option<Error>) {
let mut errs = PartialErrorBuilder::default(); let mut errs = PartialErrorBuilder::default();
let custom_ig_matcher = let custom_ig_matcher = if self.0.custom_ignore_filenames.is_empty() {
if self.0.custom_ignore_filenames.is_empty() { Gitignore::empty()
Gitignore::empty() } else {
} else { let (m, err) = create_gitignore(
let (m, err) = &dir,
create_gitignore( &self.0.custom_ignore_filenames,
&dir, self.0.opts.ignore_case_insensitive,
&self.0.custom_ignore_filenames, );
self.0.opts.ignore_case_insensitive, errs.maybe_push(err);
); m
errs.maybe_push(err); };
m let ig_matcher = if !self.0.opts.ignore {
}; Gitignore::empty()
let ig_matcher = } else {
if !self.0.opts.ignore { let (m, err) =
Gitignore::empty() create_gitignore(&dir, &[".ignore"], self.0.opts.ignore_case_insensitive);
} else { errs.maybe_push(err);
let (m, err) = m
create_gitignore( };
&dir, let gi_matcher = if !self.0.opts.git_ignore {
&[".ignore"], Gitignore::empty()
self.0.opts.ignore_case_insensitive, } else {
); let (m, err) =
errs.maybe_push(err); create_gitignore(&dir, &[".gitignore"], self.0.opts.ignore_case_insensitive);
m errs.maybe_push(err);
}; m
let gi_matcher = };
if !self.0.opts.git_ignore { let gi_exclude_matcher = if !self.0.opts.git_exclude {
Gitignore::empty() Gitignore::empty()
} else { } else {
let (m, err) = let (m, err) = create_gitignore(
create_gitignore( &dir,
&dir, &[".git/info/exclude"],
&[".gitignore"], self.0.opts.ignore_case_insensitive,
self.0.opts.ignore_case_insensitive, );
); errs.maybe_push(err);
errs.maybe_push(err); m
m };
}; let has_git = if self.0.opts.git_ignore {
let gi_exclude_matcher = dir.join(".git").exists()
if !self.0.opts.git_exclude { } else {
Gitignore::empty() false
} else { };
let (m, err) =
create_gitignore(
&dir,
&[".git/info/exclude"],
self.0.opts.ignore_case_insensitive,
);
errs.maybe_push(err);
m
};
let ig = IgnoreInner { let ig = IgnoreInner {
compiled: self.0.compiled.clone(), compiled: self.0.compiled.clone(),
dir: dir.to_path_buf(), dir: dir.to_path_buf(),
@@ -290,7 +279,7 @@ impl Ignore {
git_global_matcher: self.0.git_global_matcher.clone(), git_global_matcher: self.0.git_global_matcher.clone(),
git_ignore_matcher: gi_matcher, git_ignore_matcher: gi_matcher,
git_exclude_matcher: gi_exclude_matcher, git_exclude_matcher: gi_exclude_matcher,
has_git: dir.join(".git").exists(), has_git: has_git,
opts: self.0.opts, opts: self.0.opts,
}; };
(ig, errs.into_error_option()) (ig, errs.into_error_option())
@@ -302,16 +291,16 @@ impl Ignore {
let has_custom_ignore_files = !self.0.custom_ignore_filenames.is_empty(); let has_custom_ignore_files = !self.0.custom_ignore_filenames.is_empty();
let has_explicit_ignores = !self.0.explicit_ignores.is_empty(); let has_explicit_ignores = !self.0.explicit_ignores.is_empty();
opts.ignore || opts.git_global || opts.git_ignore opts.ignore
|| opts.git_exclude || has_custom_ignore_files || opts.git_global
|| has_explicit_ignores || opts.git_ignore
|| opts.git_exclude
|| has_custom_ignore_files
|| has_explicit_ignores
} }
/// Like `matched`, but works with a directory entry instead. /// Like `matched`, but works with a directory entry instead.
pub fn matched_dir_entry<'a>( pub fn matched_dir_entry<'a>(&'a self, dent: &DirEntry) -> Match<IgnoreMatch<'a>> {
&'a self,
dent: &DirEntry,
) -> Match<IgnoreMatch<'a>> {
let m = self.matched(dent.path(), dent.is_dir()); let m = self.matched(dent.path(), dent.is_dir());
if m.is_none() && self.0.opts.hidden && is_hidden(dent) { if m.is_none() && self.0.opts.hidden && is_hidden(dent) {
return Match::Ignore(IgnoreMatch::hidden()); return Match::Ignore(IgnoreMatch::hidden());
@@ -323,11 +312,7 @@ impl Ignore {
/// ignored or not. /// ignored or not.
/// ///
/// The match contains information about its origin. /// The match contains information about its origin.
fn matched<'a, P: AsRef<Path>>( fn matched<'a, P: AsRef<Path>>(&'a self, path: P, is_dir: bool) -> Match<IgnoreMatch<'a>> {
&'a self,
path: P,
is_dir: bool,
) -> Match<IgnoreMatch<'a>> {
// We need to be careful with our path. If it has a leading ./, then // We need to be careful with our path. If it has a leading ./, then
// strip it because it causes nothing but trouble. // strip it because it causes nothing but trouble.
let mut path = path.as_ref(); let mut path = path.as_ref();
@@ -339,9 +324,11 @@ impl Ignore {
// return that result immediately. Overrides have the highest // return that result immediately. Overrides have the highest
// precedence. // precedence.
if !self.0.overrides.is_empty() { if !self.0.overrides.is_empty() {
let mat = let mat = self
self.0.overrides.matched(path, is_dir) .0
.map(IgnoreMatch::overrides); .overrides
.matched(path, is_dir)
.map(IgnoreMatch::overrides);
if !mat.is_none() { if !mat.is_none() {
return mat; return mat;
} }
@@ -356,8 +343,7 @@ impl Ignore {
} }
} }
if !self.0.types.is_empty() { if !self.0.types.is_empty() {
let mat = let mat = self.0.types.matched(path, is_dir).map(IgnoreMatch::types);
self.0.types.matched(path, is_dir).map(IgnoreMatch::types);
if mat.is_ignore() { if mat.is_ignore() {
return mat; return mat;
} else if mat.is_whitelist() { } else if mat.is_whitelist() {
@@ -369,61 +355,70 @@ impl Ignore {
/// Performs matching only on the ignore files for this directory and /// Performs matching only on the ignore files for this directory and
/// all parent directories. /// all parent directories.
fn matched_ignore<'a>( fn matched_ignore<'a>(&'a self, path: &Path, is_dir: bool) -> Match<IgnoreMatch<'a>> {
&'a self, let (mut m_custom_ignore, mut m_ignore, mut m_gi, mut m_gi_exclude, mut m_explicit) = (
path: &Path, Match::None,
is_dir: bool, Match::None,
) -> Match<IgnoreMatch<'a>> { Match::None,
let (mut m_custom_ignore, mut m_ignore, mut m_gi, mut m_gi_exclude, mut m_explicit) = Match::None,
(Match::None, Match::None, Match::None, Match::None, Match::None); Match::None,
);
let any_git = self.parents().any(|ig| ig.0.has_git); let any_git = self.parents().any(|ig| ig.0.has_git);
let mut saw_git = false; let mut saw_git = false;
for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) { for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) {
if m_custom_ignore.is_none() { if m_custom_ignore.is_none() {
m_custom_ignore = m_custom_ignore =
ig.0.custom_ignore_matcher.matched(path, is_dir) ig.0.custom_ignore_matcher
.map(IgnoreMatch::gitignore); .matched(path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if m_ignore.is_none() { if m_ignore.is_none() {
m_ignore = m_ignore =
ig.0.ignore_matcher.matched(path, is_dir) ig.0.ignore_matcher
.map(IgnoreMatch::gitignore); .matched(path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if any_git && !saw_git && m_gi.is_none() { if any_git && !saw_git && m_gi.is_none() {
m_gi = m_gi =
ig.0.git_ignore_matcher.matched(path, is_dir) ig.0.git_ignore_matcher
.map(IgnoreMatch::gitignore); .matched(path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if any_git && !saw_git && m_gi_exclude.is_none() { if any_git && !saw_git && m_gi_exclude.is_none() {
m_gi_exclude = m_gi_exclude =
ig.0.git_exclude_matcher.matched(path, is_dir) ig.0.git_exclude_matcher
.map(IgnoreMatch::gitignore); .matched(path, is_dir)
.map(IgnoreMatch::gitignore);
} }
saw_git = saw_git || ig.0.has_git; saw_git = saw_git || ig.0.has_git;
} }
if self.0.opts.parents { if self.0.opts.parents {
if let Some(abs_parent_path) = self.absolute_base() { if let Some(abs_parent_path) = self.absolute_base() {
let path = abs_parent_path.join(path); let path = abs_parent_path.join(path);
for ig in self.parents().skip_while(|ig|!ig.0.is_absolute_parent) { for ig in self.parents().skip_while(|ig| !ig.0.is_absolute_parent) {
if m_custom_ignore.is_none() { if m_custom_ignore.is_none() {
m_custom_ignore = m_custom_ignore =
ig.0.custom_ignore_matcher.matched(&path, is_dir) ig.0.custom_ignore_matcher
.map(IgnoreMatch::gitignore); .matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if m_ignore.is_none() { if m_ignore.is_none() {
m_ignore = m_ignore =
ig.0.ignore_matcher.matched(&path, is_dir) ig.0.ignore_matcher
.map(IgnoreMatch::gitignore); .matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if any_git && !saw_git && m_gi.is_none() { if any_git && !saw_git && m_gi.is_none() {
m_gi = m_gi =
ig.0.git_ignore_matcher.matched(&path, is_dir) ig.0.git_ignore_matcher
.map(IgnoreMatch::gitignore); .matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
} }
if any_git && !saw_git && m_gi_exclude.is_none() { if any_git && !saw_git && m_gi_exclude.is_none() {
m_gi_exclude = m_gi_exclude =
ig.0.git_exclude_matcher.matched(&path, is_dir) ig.0.git_exclude_matcher
.map(IgnoreMatch::gitignore); .matched(&path, is_dir)
.map(IgnoreMatch::gitignore);
} }
saw_git = saw_git || ig.0.has_git; saw_git = saw_git || ig.0.has_git;
} }
@@ -435,16 +430,21 @@ impl Ignore {
} }
m_explicit = gi.matched(&path, is_dir).map(IgnoreMatch::gitignore); m_explicit = gi.matched(&path, is_dir).map(IgnoreMatch::gitignore);
} }
let m_global = let m_global = if any_git {
if any_git { self.0
self.0.git_global_matcher .git_global_matcher
.matched(&path, is_dir) .matched(&path, is_dir)
.map(IgnoreMatch::gitignore) .map(IgnoreMatch::gitignore)
} else { } else {
Match::None Match::None
}; };
m_custom_ignore.or(m_ignore).or(m_gi).or(m_gi_exclude).or(m_global).or(m_explicit) m_custom_ignore
.or(m_ignore)
.or(m_gi)
.or(m_gi_exclude)
.or(m_global)
.or(m_explicit)
} }
/// Returns an iterator over parent ignore matchers, including this one. /// Returns an iterator over parent ignore matchers, including this one.
@@ -524,20 +524,19 @@ impl IgnoreBuilder {
/// The matcher returned won't match anything until ignore rules from /// The matcher returned won't match anything until ignore rules from
/// directories are added to it. /// directories are added to it.
pub fn build(&self) -> Ignore { pub fn build(&self) -> Ignore {
let git_global_matcher = let git_global_matcher = if !self.opts.git_global {
if !self.opts.git_global { Gitignore::empty()
Gitignore::empty() } else {
} else { let mut builder = GitignoreBuilder::new("");
let mut builder = GitignoreBuilder::new(""); builder
builder .case_insensitive(self.opts.ignore_case_insensitive)
.case_insensitive(self.opts.ignore_case_insensitive) .unwrap();
.unwrap(); let (gi, err) = builder.build_global();
let (gi, err) = builder.build_global(); if let Some(err) = err {
if let Some(err) = err { debug!("{}", err);
debug!("{}", err); }
} gi
gi };
};
Ignore(Arc::new(IgnoreInner { Ignore(Arc::new(IgnoreInner {
compiled: Arc::new(RwLock::new(HashMap::new())), compiled: Arc::new(RwLock::new(HashMap::new())),
@@ -593,9 +592,10 @@ impl IgnoreBuilder {
/// later names. /// later names.
pub fn add_custom_ignore_filename<S: AsRef<OsStr>>( pub fn add_custom_ignore_filename<S: AsRef<OsStr>>(
&mut self, &mut self,
file_name: S file_name: S,
) -> &mut IgnoreBuilder { ) -> &mut IgnoreBuilder {
self.custom_ignore_filenames.push(file_name.as_ref().to_os_string()); self.custom_ignore_filenames
.push(file_name.as_ref().to_os_string());
self self
} }
@@ -667,10 +667,7 @@ impl IgnoreBuilder {
/// Process ignore files case insensitively /// Process ignore files case insensitively
/// ///
/// This is disabled by default. /// This is disabled by default.
pub fn ignore_case_insensitive( pub fn ignore_case_insensitive(&mut self, yes: bool) -> &mut IgnoreBuilder {
&mut self,
yes: bool,
) -> &mut IgnoreBuilder {
self.opts.ignore_case_insensitive = yes; self.opts.ignore_case_insensitive = yes;
self self
} }
@@ -710,10 +707,9 @@ mod tests {
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
use tempfile::{self, TempDir};
use dir::IgnoreBuilder; use dir::IgnoreBuilder;
use gitignore::Gitignore; use gitignore::Gitignore;
use tests::TempDir;
use Error; use Error;
fn wfile<P: AsRef<Path>>(path: P, contents: &str) { fn wfile<P: AsRef<Path>>(path: P, contents: &str) {
@@ -732,19 +728,21 @@ mod tests {
} }
} }
fn tmpdir(prefix: &str) -> TempDir { fn tmpdir() -> TempDir {
tempfile::Builder::new().prefix(prefix).tempdir().unwrap() TempDir::new().unwrap()
} }
#[test] #[test]
fn explicit_ignore() { fn explicit_ignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join("not-an-ignore"), "foo\n!bar"); wfile(td.path().join("not-an-ignore"), "foo\n!bar");
let (gi, err) = Gitignore::new(td.path().join("not-an-ignore")); let (gi, err) = Gitignore::new(td.path().join("not-an-ignore"));
assert!(err.is_none()); assert!(err.is_none());
let (ig, err) = IgnoreBuilder::new() let (ig, err) = IgnoreBuilder::new()
.add_ignore(gi).build().add_child(td.path()); .add_ignore(gi)
.build()
.add_child(td.path());
assert!(err.is_none()); assert!(err.is_none());
assert!(ig.matched("foo", false).is_ignore()); assert!(ig.matched("foo", false).is_ignore());
assert!(ig.matched("bar", false).is_whitelist()); assert!(ig.matched("bar", false).is_whitelist());
@@ -753,7 +751,7 @@ mod tests {
#[test] #[test]
fn git_exclude() { fn git_exclude() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git/info")); mkdirp(td.path().join(".git/info"));
wfile(td.path().join(".git/info/exclude"), "foo\n!bar"); wfile(td.path().join(".git/info/exclude"), "foo\n!bar");
@@ -766,7 +764,7 @@ mod tests {
#[test] #[test]
fn gitignore() { fn gitignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
wfile(td.path().join(".gitignore"), "foo\n!bar"); wfile(td.path().join(".gitignore"), "foo\n!bar");
@@ -779,7 +777,7 @@ mod tests {
#[test] #[test]
fn gitignore_no_git() { fn gitignore_no_git() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "foo\n!bar"); wfile(td.path().join(".gitignore"), "foo\n!bar");
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
@@ -791,7 +789,7 @@ mod tests {
#[test] #[test]
fn ignore() { fn ignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".ignore"), "foo\n!bar"); wfile(td.path().join(".ignore"), "foo\n!bar");
let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
@@ -803,13 +801,14 @@ mod tests {
#[test] #[test]
fn custom_ignore() { fn custom_ignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
let custom_ignore = ".customignore"; let custom_ignore = ".customignore";
wfile(td.path().join(custom_ignore), "foo\n!bar"); wfile(td.path().join(custom_ignore), "foo\n!bar");
let (ig, err) = IgnoreBuilder::new() let (ig, err) = IgnoreBuilder::new()
.add_custom_ignore_filename(custom_ignore) .add_custom_ignore_filename(custom_ignore)
.build().add_child(td.path()); .build()
.add_child(td.path());
assert!(err.is_none()); assert!(err.is_none());
assert!(ig.matched("foo", false).is_ignore()); assert!(ig.matched("foo", false).is_ignore());
assert!(ig.matched("bar", false).is_whitelist()); assert!(ig.matched("bar", false).is_whitelist());
@@ -819,14 +818,15 @@ mod tests {
// Tests that a custom ignore file will override an .ignore. // Tests that a custom ignore file will override an .ignore.
#[test] #[test]
fn custom_ignore_over_ignore() { fn custom_ignore_over_ignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
let custom_ignore = ".customignore"; let custom_ignore = ".customignore";
wfile(td.path().join(".ignore"), "foo"); wfile(td.path().join(".ignore"), "foo");
wfile(td.path().join(custom_ignore), "!foo"); wfile(td.path().join(custom_ignore), "!foo");
let (ig, err) = IgnoreBuilder::new() let (ig, err) = IgnoreBuilder::new()
.add_custom_ignore_filename(custom_ignore) .add_custom_ignore_filename(custom_ignore)
.build().add_child(td.path()); .build()
.add_child(td.path());
assert!(err.is_none()); assert!(err.is_none());
assert!(ig.matched("foo", false).is_whitelist()); assert!(ig.matched("foo", false).is_whitelist());
} }
@@ -834,7 +834,7 @@ mod tests {
// Tests that earlier custom ignore files have lower precedence than later. // Tests that earlier custom ignore files have lower precedence than later.
#[test] #[test]
fn custom_ignore_precedence() { fn custom_ignore_precedence() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
let custom_ignore1 = ".customignore1"; let custom_ignore1 = ".customignore1";
let custom_ignore2 = ".customignore2"; let custom_ignore2 = ".customignore2";
wfile(td.path().join(custom_ignore1), "foo"); wfile(td.path().join(custom_ignore1), "foo");
@@ -843,7 +843,8 @@ mod tests {
let (ig, err) = IgnoreBuilder::new() let (ig, err) = IgnoreBuilder::new()
.add_custom_ignore_filename(custom_ignore1) .add_custom_ignore_filename(custom_ignore1)
.add_custom_ignore_filename(custom_ignore2) .add_custom_ignore_filename(custom_ignore2)
.build().add_child(td.path()); .build()
.add_child(td.path());
assert!(err.is_none()); assert!(err.is_none());
assert!(ig.matched("foo", false).is_whitelist()); assert!(ig.matched("foo", false).is_whitelist());
} }
@@ -851,7 +852,7 @@ mod tests {
// Tests that an .ignore will override a .gitignore. // Tests that an .ignore will override a .gitignore.
#[test] #[test]
fn ignore_over_gitignore() { fn ignore_over_gitignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "foo"); wfile(td.path().join(".gitignore"), "foo");
wfile(td.path().join(".ignore"), "!foo"); wfile(td.path().join(".ignore"), "!foo");
@@ -863,7 +864,7 @@ mod tests {
// Tests that exclude has lower precedent than both .ignore and .gitignore. // Tests that exclude has lower precedent than both .ignore and .gitignore.
#[test] #[test]
fn exclude_lowest() { fn exclude_lowest() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "!foo"); wfile(td.path().join(".gitignore"), "!foo");
wfile(td.path().join(".ignore"), "!bar"); wfile(td.path().join(".ignore"), "!bar");
mkdirp(td.path().join(".git/info")); mkdirp(td.path().join(".git/info"));
@@ -878,7 +879,7 @@ mod tests {
#[test] #[test]
fn errored() { fn errored() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "{foo"); wfile(td.path().join(".gitignore"), "{foo");
let (_, err) = IgnoreBuilder::new().build().add_child(td.path()); let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
@@ -887,7 +888,7 @@ mod tests {
#[test] #[test]
fn errored_both() { fn errored_both() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "{foo"); wfile(td.path().join(".gitignore"), "{foo");
wfile(td.path().join(".ignore"), "{bar"); wfile(td.path().join(".ignore"), "{bar");
@@ -897,7 +898,7 @@ mod tests {
#[test] #[test]
fn errored_partial() { fn errored_partial() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
wfile(td.path().join(".gitignore"), "{foo\nbar"); wfile(td.path().join(".gitignore"), "{foo\nbar");
@@ -908,7 +909,7 @@ mod tests {
#[test] #[test]
fn errored_partial_and_ignore() { fn errored_partial_and_ignore() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
wfile(td.path().join(".gitignore"), "{foo\nbar"); wfile(td.path().join(".gitignore"), "{foo\nbar");
wfile(td.path().join(".ignore"), "!bar"); wfile(td.path().join(".ignore"), "!bar");
@@ -919,7 +920,7 @@ mod tests {
#[test] #[test]
fn not_present_empty() { fn not_present_empty() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
let (_, err) = IgnoreBuilder::new().build().add_child(td.path()); let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
assert!(err.is_none()); assert!(err.is_none());
@@ -929,7 +930,7 @@ mod tests {
fn stops_at_git_dir() { fn stops_at_git_dir() {
// This tests that .gitignore files beyond a .git barrier aren't // This tests that .gitignore files beyond a .git barrier aren't
// matched, but .ignore files are. // matched, but .ignore files are.
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
mkdirp(td.path().join("foo/.git")); mkdirp(td.path().join("foo/.git"));
wfile(td.path().join(".gitignore"), "foo"); wfile(td.path().join(".gitignore"), "foo");
@@ -950,7 +951,7 @@ mod tests {
#[test] #[test]
fn absolute_parent() { fn absolute_parent() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
mkdirp(td.path().join("foo")); mkdirp(td.path().join("foo"));
wfile(td.path().join(".gitignore"), "bar"); wfile(td.path().join(".gitignore"), "bar");
@@ -973,7 +974,7 @@ mod tests {
#[test] #[test]
fn absolute_parent_anchored() { fn absolute_parent_anchored() {
let td = tmpdir("ignore-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
mkdirp(td.path().join("src/llvm")); mkdirp(td.path().join("src/llvm"));
wfile(td.path().join(".gitignore"), "/llvm/\nfoo"); wfile(td.path().join(".gitignore"), "/llvm/\nfoo");

View File

@@ -249,7 +249,7 @@ impl Gitignore {
return Match::None; return Match::None;
} }
let path = path.as_ref(); let path = path.as_ref();
let _matches = self.matches.as_ref().unwrap().get_default(); let _matches = self.matches.as_ref().unwrap().get_or_default();
let mut matches = _matches.borrow_mut(); let mut matches = _matches.borrow_mut();
let candidate = Candidate::new(path); let candidate = Candidate::new(path);
self.set.matches_candidate_into(&candidate, &mut *matches); self.set.matches_candidate_into(&candidate, &mut *matches);
@@ -537,7 +537,7 @@ impl GitignoreBuilder {
/// ///
/// Note that the file path returned may not exist. /// Note that the file path returned may not exist.
fn gitconfig_excludes_path() -> Option<PathBuf> { fn gitconfig_excludes_path() -> Option<PathBuf> {
// git supports $HOME/.gitconfig and $XDG_CONFIG_DIR/git/config. Notably, // git supports $HOME/.gitconfig and $XDG_CONFIG_HOME/git/config. Notably,
// both can be active at the same time, where $HOME/.gitconfig takes // both can be active at the same time, where $HOME/.gitconfig takes
// precedent. So if $HOME/.gitconfig defines a `core.excludesFile`, then // precedent. So if $HOME/.gitconfig defines a `core.excludesFile`, then
// we're done. // we're done.
@@ -568,7 +568,7 @@ fn gitconfig_home_contents() -> Option<Vec<u8>> {
} }
/// Returns the file contents of git's global config file, if one exists, in /// Returns the file contents of git's global config file, if one exists, in
/// the user's XDG_CONFIG_DIR directory. /// the user's XDG_CONFIG_HOME directory.
fn gitconfig_xdg_contents() -> Option<Vec<u8>> { fn gitconfig_xdg_contents() -> Option<Vec<u8>> {
let path = env::var_os("XDG_CONFIG_HOME") let path = env::var_os("XDG_CONFIG_HOME")
.and_then(|x| if x.is_empty() { None } else { Some(PathBuf::from(x)) }) .and_then(|x| if x.is_empty() { None } else { Some(PathBuf::from(x)) })

View File

@@ -55,8 +55,6 @@ extern crate log;
extern crate memchr; extern crate memchr;
extern crate regex; extern crate regex;
extern crate same_file; extern crate same_file;
#[cfg(test)]
extern crate tempfile;
extern crate thread_local; extern crate thread_local;
extern crate walkdir; extern crate walkdir;
#[cfg(windows)] #[cfg(windows)]
@@ -442,3 +440,66 @@ impl<T> Match<T> {
} }
} }
} }
#[cfg(test)]
mod tests {
use std::env;
use std::error;
use std::fs;
use std::path::{Path, PathBuf};
use std::result;
/// A convenient result type alias.
pub type Result<T> =
result::Result<T, Box<dyn error::Error + Send + Sync>>;
macro_rules! err {
($($tt:tt)*) => {
Box::<dyn error::Error + Send + Sync>::from(format!($($tt)*))
}
}
/// A simple wrapper for creating a temporary directory that is
/// automatically deleted when it's dropped.
///
/// We use this in lieu of tempfile because tempfile brings in too many
/// dependencies.
#[derive(Debug)]
pub struct TempDir(PathBuf);
impl Drop for TempDir {
fn drop(&mut self) {
fs::remove_dir_all(&self.0).unwrap();
}
}
impl TempDir {
/// Create a new empty temporary directory under the system's configured
/// temporary directory.
pub fn new() -> Result<TempDir> {
use std::sync::atomic::{AtomicUsize, Ordering};
static TRIES: usize = 100;
static COUNTER: AtomicUsize = AtomicUsize::new(0);
let tmpdir = env::temp_dir();
for _ in 0..TRIES {
let count = COUNTER.fetch_add(1, Ordering::SeqCst);
let path = tmpdir.join("rust-ignore").join(count.to_string());
if path.is_dir() {
continue;
}
fs::create_dir_all(&path).map_err(|e| {
err!("failed to create {}: {}", path.display(), e)
})?;
return Ok(TempDir(path));
}
Err(err!("failed to create temp dir after {} tries", TRIES))
}
/// Return the underlying path to this temporary directory.
pub fn path(&self) -> &Path {
&self.0
}
}
}

View File

@@ -135,6 +135,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("d", &["*.d"]), ("d", &["*.d"]),
("dhall", &["*.dhall"]), ("dhall", &["*.dhall"]),
("docker", &["*Dockerfile*"]), ("docker", &["*Dockerfile*"]),
("edn", &["*.edn"]),
("elisp", &["*.el"]), ("elisp", &["*.el"]),
("elixir", &["*.ex", "*.eex", "*.exs"]), ("elixir", &["*.ex", "*.eex", "*.exs"]),
("elm", &["*.elm"]), ("elm", &["*.elm"]),
@@ -146,6 +147,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
"*.f90", "*.F90", "*.f95", "*.F95", "*.f90", "*.F90", "*.f95", "*.F95",
]), ]),
("fsharp", &["*.fs", "*.fsx", "*.fsi"]), ("fsharp", &["*.fs", "*.fsx", "*.fsi"]),
("gap", &["*.g", "*.gap", "*.gi", "*.gd", "*.tst"]),
("gn", &["*.gn", "*.gni"]), ("gn", &["*.gn", "*.gni"]),
("go", &["*.go"]), ("go", &["*.go"]),
("gzip", &["*.gz", "*.tgz"]), ("gzip", &["*.gz", "*.tgz"]),
@@ -218,7 +220,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("msbuild", &[ ("msbuild", &[
"*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets" "*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets"
]), ]),
("nim", &["*.nim"]), ("nim", &["*.nim", "*.nimf", "*.nimble", "*.nims"]),
("nix", &["*.nix"]), ("nix", &["*.nix"]),
("objc", &["*.h", "*.m"]), ("objc", &["*.h", "*.m"]),
("objcpp", &["*.h", "*.mm"]), ("objcpp", &["*.h", "*.mm"]),
@@ -240,6 +242,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
("readme", &["README*", "*README"]), ("readme", &["README*", "*README"]),
("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]), ("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
("rdoc", &["*.rdoc"]), ("rdoc", &["*.rdoc"]),
("robot", &["*.robot"]),
("rst", &["*.rst"]), ("rst", &["*.rst"]),
("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]), ("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]),
("rust", &["*.rs"]), ("rust", &["*.rs"]),
@@ -512,7 +515,7 @@ impl Types {
return Match::None; return Match::None;
} }
}; };
let mut matches = self.matches.get_default().borrow_mut(); let mut matches = self.matches.get_or_default().borrow_mut();
self.set.matches_into(name, &mut *matches); self.set.matches_into(name, &mut *matches);
// The highest precedent match is the last one. // The highest precedent match is the last one.
if let Some(&i) = matches.last() { if let Some(&i) = matches.last() {

View File

@@ -4,8 +4,8 @@ use std::fmt;
use std::fs::{self, FileType, Metadata}; use std::fs::{self, FileType, Metadata};
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use std::vec; use std::vec;
@@ -182,14 +182,14 @@ impl DirEntryInner {
match *self { match *self {
Stdin => { Stdin => {
let err = Error::Io(io::Error::new( let err = Error::Io(io::Error::new(
io::ErrorKind::Other, "<stdin> has no metadata")); io::ErrorKind::Other,
"<stdin> has no metadata",
));
Err(err.with_path("<stdin>")) Err(err.with_path("<stdin>"))
} }
Walkdir(ref x) => { Walkdir(ref x) => x
x.metadata().map_err(|err| { .metadata()
Error::Io(io::Error::from(err)).with_path(x.path()) .map_err(|err| Error::Io(io::Error::from(err)).with_path(x.path())),
})
}
Raw(ref x) => x.metadata(), Raw(ref x) => x.metadata(),
} }
} }
@@ -223,8 +223,8 @@ impl DirEntryInner {
#[cfg(unix)] #[cfg(unix)]
fn ino(&self) -> Option<u64> { fn ino(&self) -> Option<u64> {
use walkdir::DirEntryExt;
use self::DirEntryInner::*; use self::DirEntryInner::*;
use walkdir::DirEntryExt;
match *self { match *self {
Stdin => None, Stdin => None,
Walkdir(ref x) => Some(x.ino()), Walkdir(ref x) => Some(x.ino()),
@@ -297,7 +297,8 @@ impl DirEntryRaw {
fs::metadata(&self.path) fs::metadata(&self.path)
} else { } else {
Ok(self.metadata.clone()) Ok(self.metadata.clone())
}.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path)) }
.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path))
} }
#[cfg(not(windows))] #[cfg(not(windows))]
@@ -306,7 +307,8 @@ impl DirEntryRaw {
fs::metadata(&self.path) fs::metadata(&self.path)
} else { } else {
fs::symlink_metadata(&self.path) fs::symlink_metadata(&self.path)
}.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path)) }
.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path))
} }
fn file_type(&self) -> FileType { fn file_type(&self) -> FileType {
@@ -314,7 +316,9 @@ impl DirEntryRaw {
} }
fn file_name(&self) -> &OsStr { fn file_name(&self) -> &OsStr {
self.path.file_name().unwrap_or_else(|| self.path.as_os_str()) self.path
.file_name()
.unwrap_or_else(|| self.path.as_os_str())
} }
fn depth(&self) -> usize { fn depth(&self) -> usize {
@@ -326,10 +330,7 @@ impl DirEntryRaw {
self.ino self.ino
} }
fn from_entry( fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntryRaw, Error> {
depth: usize,
ent: &fs::DirEntry,
) -> Result<DirEntryRaw, Error> {
let ty = ent.file_type().map_err(|err| { let ty = ent.file_type().map_err(|err| {
let err = Error::Io(io::Error::from(err)).with_path(ent.path()); let err = Error::Io(io::Error::from(err)).with_path(ent.path());
Error::WithDepth { Error::WithDepth {
@@ -379,15 +380,22 @@ impl DirEntryRaw {
}) })
} }
#[cfg(not(unix))] // Placeholder implementation to allow compiling on non-standard platforms (e.g. wasm32).
fn from_path( #[cfg(not(any(windows, unix)))]
fn from_entry_os(
depth: usize, depth: usize,
pb: PathBuf, ent: &fs::DirEntry,
link: bool, ty: fs::FileType,
) -> Result<DirEntryRaw, Error> { ) -> Result<DirEntryRaw, Error> {
let md = fs::metadata(&pb).map_err(|err| { Err(Error::Io(io::Error::new(
Error::Io(err).with_path(&pb) io::ErrorKind::Other,
})?; "unsupported platform",
)))
}
#[cfg(windows)]
fn from_path(depth: usize, pb: PathBuf, link: bool) -> Result<DirEntryRaw, Error> {
let md = fs::metadata(&pb).map_err(|err| Error::Io(err).with_path(&pb))?;
Ok(DirEntryRaw { Ok(DirEntryRaw {
path: pb, path: pb,
ty: md.file_type(), ty: md.file_type(),
@@ -398,16 +406,10 @@ impl DirEntryRaw {
} }
#[cfg(unix)] #[cfg(unix)]
fn from_path( fn from_path(depth: usize, pb: PathBuf, link: bool) -> Result<DirEntryRaw, Error> {
depth: usize,
pb: PathBuf,
link: bool,
) -> Result<DirEntryRaw, Error> {
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::MetadataExt;
let md = fs::metadata(&pb).map_err(|err| { let md = fs::metadata(&pb).map_err(|err| Error::Io(err).with_path(&pb))?;
Error::Io(err).with_path(&pb)
})?;
Ok(DirEntryRaw { Ok(DirEntryRaw {
path: pb, path: pb,
ty: md.file_type(), ty: md.file_type(),
@@ -416,6 +418,15 @@ impl DirEntryRaw {
ino: md.ino(), ino: md.ino(),
}) })
} }
// Placeholder implementation to allow compiling on non-standard platforms (e.g. wasm32).
#[cfg(not(any(windows, unix)))]
fn from_path(depth: usize, pb: PathBuf, link: bool) -> Result<DirEntryRaw, Error> {
Err(Error::Io(io::Error::new(
io::ErrorKind::Other,
"unsupported platform",
)))
}
} }
/// WalkBuilder builds a recursive directory iterator. /// WalkBuilder builds a recursive directory iterator.
@@ -481,8 +492,8 @@ pub struct WalkBuilder {
#[derive(Clone)] #[derive(Clone)]
enum Sorter { enum Sorter {
ByName(Arc<Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static>), ByName(Arc<dyn Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static>),
ByPath(Arc<Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static>), ByPath(Arc<dyn Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static>),
} }
impl fmt::Debug for WalkBuilder { impl fmt::Debug for WalkBuilder {
@@ -525,33 +536,34 @@ impl WalkBuilder {
let follow_links = self.follow_links; let follow_links = self.follow_links;
let max_depth = self.max_depth; let max_depth = self.max_depth;
let sorter = self.sorter.clone(); let sorter = self.sorter.clone();
let its = self.paths.iter().map(move |p| { let its = self
if p == Path::new("-") { .paths
(p.to_path_buf(), None) .iter()
} else { .map(move |p| {
let mut wd = WalkDir::new(p); if p == Path::new("-") {
wd = wd.follow_links(follow_links || p.is_file()); (p.to_path_buf(), None)
wd = wd.same_file_system(self.same_file_system); } else {
if let Some(max_depth) = max_depth { let mut wd = WalkDir::new(p);
wd = wd.max_depth(max_depth); wd = wd.follow_links(follow_links || p.is_file());
} wd = wd.same_file_system(self.same_file_system);
if let Some(ref sorter) = sorter { if let Some(max_depth) = max_depth {
match sorter.clone() { wd = wd.max_depth(max_depth);
Sorter::ByName(cmp) => { }
wd = wd.sort_by(move |a, b| { if let Some(ref sorter) = sorter {
cmp(a.file_name(), b.file_name()) match sorter.clone() {
}); Sorter::ByName(cmp) => {
} wd = wd.sort_by(move |a, b| cmp(a.file_name(), b.file_name()));
Sorter::ByPath(cmp) => { }
wd = wd.sort_by(move |a, b| { Sorter::ByPath(cmp) => {
cmp(a.path(), b.path()) wd = wd.sort_by(move |a, b| cmp(a.path(), b.path()));
}); }
} }
} }
(p.to_path_buf(), Some(WalkEventIter::from(wd)))
} }
(p.to_path_buf(), Some(WalkEventIter::from(wd))) })
} .collect::<Vec<_>>()
}).collect::<Vec<_>>().into_iter(); .into_iter();
let ig_root = self.ig_builder.build(); let ig_root = self.ig_builder.build();
Walk { Walk {
its: its, its: its,
@@ -635,8 +647,12 @@ impl WalkBuilder {
let mut errs = PartialErrorBuilder::default(); let mut errs = PartialErrorBuilder::default();
errs.maybe_push(builder.add(path)); errs.maybe_push(builder.add(path));
match builder.build() { match builder.build() {
Ok(gi) => { self.ig_builder.add_ignore(gi); } Ok(gi) => {
Err(err) => { errs.push(err); } self.ig_builder.add_ignore(gi);
}
Err(err) => {
errs.push(err);
}
} }
errs.into_error_option() errs.into_error_option()
} }
@@ -649,7 +665,7 @@ impl WalkBuilder {
/// later names. /// later names.
pub fn add_custom_ignore_filename<S: AsRef<OsStr>>( pub fn add_custom_ignore_filename<S: AsRef<OsStr>>(
&mut self, &mut self,
file_name: S file_name: S,
) -> &mut WalkBuilder { ) -> &mut WalkBuilder {
self.ig_builder.add_custom_ignore_filename(file_name); self.ig_builder.add_custom_ignore_filename(file_name);
self self
@@ -786,11 +802,9 @@ impl WalkBuilder {
/// by `sort_by_file_name`. /// by `sort_by_file_name`.
/// ///
/// Note that this is not used in the parallel iterator. /// Note that this is not used in the parallel iterator.
pub fn sort_by_file_path<F>( pub fn sort_by_file_path<F>(&mut self, cmp: F) -> &mut WalkBuilder
&mut self, where
cmp: F, F: Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static,
) -> &mut WalkBuilder
where F: Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static
{ {
self.sorter = Some(Sorter::ByPath(Arc::new(cmp))); self.sorter = Some(Sorter::ByPath(Arc::new(cmp)));
self self
@@ -808,7 +822,8 @@ impl WalkBuilder {
/// ///
/// Note that this is not used in the parallel iterator. /// Note that this is not used in the parallel iterator.
pub fn sort_by_file_name<F>(&mut self, cmp: F) -> &mut WalkBuilder pub fn sort_by_file_name<F>(&mut self, cmp: F) -> &mut WalkBuilder
where F: Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static where
F: Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static,
{ {
self.sorter = Some(Sorter::ByName(Arc::new(cmp))); self.sorter = Some(Sorter::ByName(Arc::new(cmp)));
self self
@@ -989,7 +1004,11 @@ enum WalkEvent {
impl From<WalkDir> for WalkEventIter { impl From<WalkDir> for WalkEventIter {
fn from(it: WalkDir) -> WalkEventIter { fn from(it: WalkDir) -> WalkEventIter {
WalkEventIter { depth: 0, it: it.into_iter(), next: None } WalkEventIter {
depth: 0,
it: it.into_iter(),
next: None,
}
} }
} }
@@ -1072,10 +1091,10 @@ impl WalkParallel {
/// Execute the parallel recursive directory iterator. `mkf` is called /// Execute the parallel recursive directory iterator. `mkf` is called
/// for each thread used for iteration. The function produced by `mkf` /// for each thread used for iteration. The function produced by `mkf`
/// is then in turn called for each visited file path. /// is then in turn called for each visited file path.
pub fn run<F>( pub fn run<F>(self, mut mkf: F)
self, where
mut mkf: F, F: FnMut() -> Box<dyn FnMut(Result<DirEntry, Error>) -> WalkState + Send + 'static>,
) where F: FnMut() -> Box<FnMut(Result<DirEntry, Error>) -> WalkState + Send + 'static> { {
let mut f = mkf(); let mut f = mkf();
let threads = self.threads(); let threads = self.threads();
// TODO: Figure out how to use a bounded channel here. With an // TODO: Figure out how to use a bounded channel here. With an
@@ -1092,30 +1111,16 @@ impl WalkParallel {
// Note that we only send directories. For files, we send to them the // Note that we only send directories. For files, we send to them the
// callback directly. // callback directly.
for path in self.paths { for path in self.paths {
let (dent, root_device) = let (dent, root_device) = if path == Path::new("-") {
if path == Path::new("-") { (DirEntry::new_stdin(), None)
(DirEntry::new_stdin(), None) } else {
let root_device = if !self.same_file_system {
None
} else { } else {
let root_device = match device_num(&path) {
if !self.same_file_system { Ok(root_device) => Some(root_device),
None
} else {
match device_num(&path) {
Ok(root_device) => Some(root_device),
Err(err) => {
let err = Error::Io(err).with_path(path);
if f(Err(err)).is_quit() {
return;
}
continue;
}
}
};
match DirEntryRaw::from_path(0, path, false) {
Ok(dent) => {
(DirEntry::new_raw(dent, None), root_device)
}
Err(err) => { Err(err) => {
let err = Error::Io(err).with_path(path);
if f(Err(err)).is_quit() { if f(Err(err)).is_quit() {
return; return;
} }
@@ -1123,11 +1128,22 @@ impl WalkParallel {
} }
} }
}; };
match DirEntryRaw::from_path(0, path, false) {
Ok(dent) => (DirEntry::new_raw(dent, None), root_device),
Err(err) => {
if f(Err(err)).is_quit() {
return;
}
continue;
}
}
};
tx.send(Message::Work(Work { tx.send(Message::Work(Work {
dent: dent, dent: dent,
ignore: self.ig_root.clone(), ignore: self.ig_root.clone(),
root_device: root_device, root_device: root_device,
})).unwrap(); }))
.unwrap();
any_work = true; any_work = true;
} }
// ... but there's no need to start workers if we don't need them. // ... but there's no need to start workers if we don't need them.
@@ -1253,7 +1269,7 @@ impl Work {
/// Note that a worker is *both* a producer and a consumer. /// Note that a worker is *both* a producer and a consumer.
struct Worker { struct Worker {
/// The caller's callback. /// The caller's callback.
f: Box<FnMut(Result<DirEntry, Error>) -> WalkState + Send + 'static>, f: Box<dyn FnMut(Result<DirEntry, Error>) -> WalkState + Send + 'static>,
/// The push side of our mpmc queue. /// The push side of our mpmc queue.
tx: channel::Sender<Message>, tx: channel::Sender<Message>,
/// The receive side of our mpmc queue. /// The receive side of our mpmc queue.
@@ -1319,22 +1335,21 @@ impl Worker {
continue; continue;
} }
}; };
let descend = let descend = if let Some(root_device) = work.root_device {
if let Some(root_device) = work.root_device { match is_same_file_system(root_device, work.dent.path()) {
match is_same_file_system(root_device, work.dent.path()) { Ok(true) => true,
Ok(true) => true, Ok(false) => false,
Ok(false) => false, Err(err) => {
Err(err) => { if (self.f)(Err(err)).is_quit() {
if (self.f)(Err(err)).is_quit() { self.quit_now();
self.quit_now(); return;
return;
}
false
} }
false
} }
} else { }
true } else {
}; true
};
let depth = work.dent.depth(); let depth = work.dent.depth();
match (self.f)(Ok(work.dent)) { match (self.f)(Ok(work.dent)) {
@@ -1352,12 +1367,7 @@ impl Worker {
continue; continue;
} }
for result in readdir { for result in readdir {
let state = self.run_one( let state = self.run_one(&work.ignore, depth + 1, work.root_device, result);
&work.ignore,
depth + 1,
work.root_device,
result,
);
if state.is_quit() { if state.is_quit() {
self.quit_now(); self.quit_now();
return; return;
@@ -1422,23 +1432,24 @@ impl Worker {
} }
} }
let should_skip_path = should_skip_entry(ig, &dent); let should_skip_path = should_skip_entry(ig, &dent);
let should_skip_filesize = let should_skip_filesize = if self.max_filesize.is_some() && !dent.is_dir() {
if self.max_filesize.is_some() && !dent.is_dir() { skip_filesize(
skip_filesize( self.max_filesize.unwrap(),
self.max_filesize.unwrap(), dent.path(),
dent.path(), &dent.metadata().ok(),
&dent.metadata().ok(), )
) } else {
} else { false
false };
};
if !should_skip_path && !should_skip_filesize { if !should_skip_path && !should_skip_filesize {
self.tx.send(Message::Work(Work { self.tx
dent: dent, .send(Message::Work(Work {
ignore: ig.clone(), dent: dent,
root_device: root_device, ignore: ig.clone(),
})).unwrap(); root_device: root_device,
}))
.unwrap();
} }
WalkState::Continue WalkState::Continue
} }
@@ -1568,17 +1579,25 @@ fn check_symlink_loop(
child_depth: usize, child_depth: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
let hchild = Handle::from_path(child_path).map_err(|err| { let hchild = Handle::from_path(child_path).map_err(|err| {
Error::from(err).with_path(child_path).with_depth(child_depth) Error::from(err)
.with_path(child_path)
.with_depth(child_depth)
})?; })?;
for ig in ig_parent.parents().take_while(|ig| !ig.is_absolute_parent()) { for ig in ig_parent
.parents()
.take_while(|ig| !ig.is_absolute_parent())
{
let h = Handle::from_path(ig.path()).map_err(|err| { let h = Handle::from_path(ig.path()).map_err(|err| {
Error::from(err).with_path(child_path).with_depth(child_depth) Error::from(err)
.with_path(child_path)
.with_depth(child_depth)
})?; })?;
if hchild == h { if hchild == h {
return Err(Error::Loop { return Err(Error::Loop {
ancestor: ig.path().to_path_buf(), ancestor: ig.path().to_path_buf(),
child: child_path.to_path_buf(), child: child_path.to_path_buf(),
}.with_depth(child_depth)); }
.with_depth(child_depth));
} }
} }
Ok(()) Ok(())
@@ -1586,14 +1605,10 @@ fn check_symlink_loop(
// Before calling this function, make sure that you ensure that is really // Before calling this function, make sure that you ensure that is really
// necessary as the arguments imply a file stat. // necessary as the arguments imply a file stat.
fn skip_filesize( fn skip_filesize(max_filesize: u64, path: &Path, ent: &Option<Metadata>) -> bool {
max_filesize: u64,
path: &Path,
ent: &Option<Metadata>
) -> bool {
let filesize = match *ent { let filesize = match *ent {
Some(ref md) => Some(md.len()), Some(ref md) => Some(md.len()),
None => None None => None,
}; };
if let Some(fs) = filesize { if let Some(fs) = filesize {
@@ -1608,10 +1623,7 @@ fn skip_filesize(
} }
} }
fn should_skip_entry( fn should_skip_entry(ig: &Ignore, dent: &DirEntry) -> bool {
ig: &Ignore,
dent: &DirEntry,
) -> bool {
let m = ig.matched_dir_entry(dent); let m = ig.matched_dir_entry(dent);
if m.is_ignore() { if m.is_ignore() {
debug!("ignoring {}: {:?}", dent.path().display(), m); debug!("ignoring {}: {:?}", dent.path().display(), m);
@@ -1673,28 +1685,27 @@ fn path_equals(dent: &DirEntry, handle: &Handle) -> Result<bool, Error> {
/// Returns true if and only if the given path is on the same device as the /// Returns true if and only if the given path is on the same device as the
/// given root device. /// given root device.
fn is_same_file_system(root_device: u64, path: &Path) -> Result<bool, Error> { fn is_same_file_system(root_device: u64, path: &Path) -> Result<bool, Error> {
let dent_device = device_num(path) let dent_device = device_num(path).map_err(|err| Error::Io(err).with_path(path))?;
.map_err(|err| Error::Io(err).with_path(path))?;
Ok(root_device == dent_device) Ok(root_device == dent_device)
} }
#[cfg(unix)] #[cfg(unix)]
fn device_num<P: AsRef<Path>>(path: P)-> io::Result<u64> { fn device_num<P: AsRef<Path>>(path: P) -> io::Result<u64> {
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::MetadataExt;
path.as_ref().metadata().map(|md| md.dev()) path.as_ref().metadata().map(|md| md.dev())
} }
#[cfg(windows)] #[cfg(windows)]
fn device_num<P: AsRef<Path>>(path: P) -> io::Result<u64> { fn device_num<P: AsRef<Path>>(path: P) -> io::Result<u64> {
use winapi_util::{Handle, file}; use winapi_util::{file, Handle};
let h = Handle::from_path_any(path)?; let h = Handle::from_path_any(path)?;
file::information(h).map(|info| info.volume_serial_number()) file::information(h).map(|info| info.volume_serial_number())
} }
#[cfg(not(any(unix, windows)))] #[cfg(not(any(unix, windows)))]
fn device_num<P: AsRef<Path>>(_: P)-> io::Result<u64> { fn device_num<P: AsRef<Path>>(_: P) -> io::Result<u64> {
Err(io::Error::new( Err(io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
"walkdir: same_file_system option not supported on this platform", "walkdir: same_file_system option not supported on this platform",
@@ -1708,9 +1719,8 @@ mod tests {
use std::path::Path; use std::path::Path;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use tempfile::{self, TempDir};
use super::{DirEntry, WalkBuilder, WalkState}; use super::{DirEntry, WalkBuilder, WalkState};
use tests::TempDir;
fn wfile<P: AsRef<Path>>(path: P, contents: &str) { fn wfile<P: AsRef<Path>>(path: P, contents: &str) {
let mut file = File::create(path).unwrap(); let mut file = File::create(path).unwrap();
@@ -1757,10 +1767,7 @@ mod tests {
paths paths
} }
fn walk_collect_parallel( fn walk_collect_parallel(prefix: &Path, builder: &WalkBuilder) -> Vec<String> {
prefix: &Path,
builder: &WalkBuilder,
) -> Vec<String> {
let mut paths = vec![]; let mut paths = vec![];
for dent in walk_collect_entries_parallel(builder) { for dent in walk_collect_entries_parallel(builder) {
let path = dent.path().strip_prefix(prefix).unwrap(); let path = dent.path().strip_prefix(prefix).unwrap();
@@ -1795,15 +1802,11 @@ mod tests {
paths paths
} }
fn tmpdir(prefix: &str) -> TempDir { fn tmpdir() -> TempDir {
tempfile::Builder::new().prefix(prefix).tempdir().unwrap() TempDir::new().unwrap()
} }
fn assert_paths( fn assert_paths(prefix: &Path, builder: &WalkBuilder, expected: &[&str]) {
prefix: &Path,
builder: &WalkBuilder,
expected: &[&str],
) {
let got = walk_collect(prefix, builder); let got = walk_collect(prefix, builder);
assert_eq!(got, mkpaths(expected), "single threaded"); assert_eq!(got, mkpaths(expected), "single threaded");
let got = walk_collect_parallel(prefix, builder); let got = walk_collect_parallel(prefix, builder);
@@ -1812,20 +1815,22 @@ mod tests {
#[test] #[test]
fn no_ignores() { fn no_ignores() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("a/b/c")); mkdirp(td.path().join("a/b/c"));
mkdirp(td.path().join("x/y")); mkdirp(td.path().join("x/y"));
wfile(td.path().join("a/b/foo"), ""); wfile(td.path().join("a/b/foo"), "");
wfile(td.path().join("x/y/foo"), ""); wfile(td.path().join("x/y/foo"), "");
assert_paths(td.path(), &WalkBuilder::new(td.path()), &[ assert_paths(
"x", "x/y", "x/y/foo", "a", "a/b", "a/b/foo", "a/b/c", td.path(),
]); &WalkBuilder::new(td.path()),
&["x", "x/y", "x/y/foo", "a", "a/b", "a/b/foo", "a/b/c"],
);
} }
#[test] #[test]
fn custom_ignore() { fn custom_ignore() {
let td = tmpdir("walk-test-"); let td = tmpdir();
let custom_ignore = ".customignore"; let custom_ignore = ".customignore";
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(td.path().join(custom_ignore), "foo"); wfile(td.path().join(custom_ignore), "foo");
@@ -1841,7 +1846,7 @@ mod tests {
#[test] #[test]
fn custom_ignore_exclusive_use() { fn custom_ignore_exclusive_use() {
let td = tmpdir("walk-test-"); let td = tmpdir();
let custom_ignore = ".customignore"; let custom_ignore = ".customignore";
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(td.path().join(custom_ignore), "foo"); wfile(td.path().join(custom_ignore), "foo");
@@ -1861,7 +1866,7 @@ mod tests {
#[test] #[test]
fn gitignore() { fn gitignore() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(td.path().join(".gitignore"), "foo"); wfile(td.path().join(".gitignore"), "foo");
@@ -1870,14 +1875,16 @@ mod tests {
wfile(td.path().join("bar"), ""); wfile(td.path().join("bar"), "");
wfile(td.path().join("a/bar"), ""); wfile(td.path().join("a/bar"), "");
assert_paths(td.path(), &WalkBuilder::new(td.path()), &[ assert_paths(
"bar", "a", "a/bar", td.path(),
]); &WalkBuilder::new(td.path()),
&["bar", "a", "a/bar"],
);
} }
#[test] #[test]
fn explicit_ignore() { fn explicit_ignore() {
let td = tmpdir("walk-test-"); let td = tmpdir();
let igpath = td.path().join(".not-an-ignore"); let igpath = td.path().join(".not-an-ignore");
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(&igpath, "foo"); wfile(&igpath, "foo");
@@ -1893,7 +1900,7 @@ mod tests {
#[test] #[test]
fn explicit_ignore_exclusive_use() { fn explicit_ignore_exclusive_use() {
let td = tmpdir("walk-test-"); let td = tmpdir();
let igpath = td.path().join(".not-an-ignore"); let igpath = td.path().join(".not-an-ignore");
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(&igpath, "foo"); wfile(&igpath, "foo");
@@ -1905,13 +1912,16 @@ mod tests {
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
builder.standard_filters(false); builder.standard_filters(false);
assert!(builder.add_ignore(&igpath).is_none()); assert!(builder.add_ignore(&igpath).is_none());
assert_paths(td.path(), &builder, assert_paths(
&[".not-an-ignore", "bar", "a", "a/bar"]); td.path(),
&builder,
&[".not-an-ignore", "bar", "a", "a/bar"],
);
} }
#[test] #[test]
fn gitignore_parent() { fn gitignore_parent() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
mkdirp(td.path().join("a")); mkdirp(td.path().join("a"));
wfile(td.path().join(".gitignore"), "foo"); wfile(td.path().join(".gitignore"), "foo");
@@ -1924,7 +1934,7 @@ mod tests {
#[test] #[test]
fn max_depth() { fn max_depth() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("a/b/c")); mkdirp(td.path().join("a/b/c"));
wfile(td.path().join("foo"), ""); wfile(td.path().join("foo"), "");
wfile(td.path().join("a/foo"), ""); wfile(td.path().join("a/foo"), "");
@@ -1932,19 +1942,23 @@ mod tests {
wfile(td.path().join("a/b/c/foo"), ""); wfile(td.path().join("a/b/c/foo"), "");
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
assert_paths(td.path(), &builder, &[ assert_paths(
"a", "a/b", "a/b/c", "foo", "a/foo", "a/b/foo", "a/b/c/foo", td.path(),
]); &builder,
&["a", "a/b", "a/b/c", "foo", "a/foo", "a/b/foo", "a/b/c/foo"],
);
assert_paths(td.path(), builder.max_depth(Some(0)), &[]); assert_paths(td.path(), builder.max_depth(Some(0)), &[]);
assert_paths(td.path(), builder.max_depth(Some(1)), &["a", "foo"]); assert_paths(td.path(), builder.max_depth(Some(1)), &["a", "foo"]);
assert_paths(td.path(), builder.max_depth(Some(2)), &[ assert_paths(
"a", "a/b", "foo", "a/foo", td.path(),
]); builder.max_depth(Some(2)),
&["a", "a/b", "foo", "a/foo"],
);
} }
#[test] #[test]
fn max_filesize() { fn max_filesize() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("a/b")); mkdirp(td.path().join("a/b"));
wfile_size(td.path().join("foo"), 0); wfile_size(td.path().join("foo"), 0);
wfile_size(td.path().join("bar"), 400); wfile_size(td.path().join("bar"), 400);
@@ -1954,41 +1968,49 @@ mod tests {
wfile_size(td.path().join("a/baz"), 200); wfile_size(td.path().join("a/baz"), 200);
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
assert_paths(td.path(), &builder, &[ assert_paths(
"a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz", td.path(),
]); &builder,
assert_paths(td.path(), builder.max_filesize(Some(0)), &[ &["a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz"],
"a", "a/b", "foo" );
]); assert_paths(
assert_paths(td.path(), builder.max_filesize(Some(500)), &[ td.path(),
"a", "a/b", "foo", "bar", "a/bar", "a/baz" builder.max_filesize(Some(0)),
]); &["a", "a/b", "foo"],
assert_paths(td.path(), builder.max_filesize(Some(50000)), &[ );
"a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz", assert_paths(
]); td.path(),
builder.max_filesize(Some(500)),
&["a", "a/b", "foo", "bar", "a/bar", "a/baz"],
);
assert_paths(
td.path(),
builder.max_filesize(Some(50000)),
&["a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz"],
);
} }
#[cfg(unix)] // because symlinks on windows are weird #[cfg(unix)] // because symlinks on windows are weird
#[test] #[test]
fn symlinks() { fn symlinks() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("a/b")); mkdirp(td.path().join("a/b"));
symlink(td.path().join("a/b"), td.path().join("z")); symlink(td.path().join("a/b"), td.path().join("z"));
wfile(td.path().join("a/b/foo"), ""); wfile(td.path().join("a/b/foo"), "");
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
assert_paths(td.path(), &builder, &[ assert_paths(td.path(), &builder, &["a", "a/b", "a/b/foo", "z"]);
"a", "a/b", "a/b/foo", "z", assert_paths(
]); td.path(),
assert_paths(td.path(), &builder.follow_links(true), &[ &builder.follow_links(true),
"a", "a/b", "a/b/foo", "z", "z/foo", &["a", "a/b", "a/b/foo", "z", "z/foo"],
]); );
} }
#[cfg(unix)] // because symlinks on windows are weird #[cfg(unix)] // because symlinks on windows are weird
#[test] #[test]
fn first_path_not_symlink() { fn first_path_not_symlink() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("foo")); mkdirp(td.path().join("foo"));
let dents = WalkBuilder::new(td.path().join("foo")) let dents = WalkBuilder::new(td.path().join("foo"))
@@ -1999,9 +2021,7 @@ mod tests {
assert_eq!(1, dents.len()); assert_eq!(1, dents.len());
assert!(!dents[0].path_is_symlink()); assert!(!dents[0].path_is_symlink());
let dents = walk_collect_entries_parallel( let dents = walk_collect_entries_parallel(&WalkBuilder::new(td.path().join("foo")));
&WalkBuilder::new(td.path().join("foo")),
);
assert_eq!(1, dents.len()); assert_eq!(1, dents.len());
assert!(!dents[0].path_is_symlink()); assert!(!dents[0].path_is_symlink());
} }
@@ -2009,17 +2029,13 @@ mod tests {
#[cfg(unix)] // because symlinks on windows are weird #[cfg(unix)] // because symlinks on windows are weird
#[test] #[test]
fn symlink_loop() { fn symlink_loop() {
let td = tmpdir("walk-test-"); let td = tmpdir();
mkdirp(td.path().join("a/b")); mkdirp(td.path().join("a/b"));
symlink(td.path().join("a"), td.path().join("a/b/c")); symlink(td.path().join("a"), td.path().join("a/b/c"));
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
assert_paths(td.path(), &builder, &[ assert_paths(td.path(), &builder, &["a", "a/b", "a/b/c"]);
"a", "a/b", "a/b/c", assert_paths(td.path(), &builder.follow_links(true), &["a", "a/b"]);
]);
assert_paths(td.path(), &builder.follow_links(true), &[
"a", "a/b",
]);
} }
// It's a little tricky to test the 'same_file_system' option since // It's a little tricky to test the 'same_file_system' option since
@@ -2039,7 +2055,7 @@ mod tests {
// If our test directory actually isn't a different volume from /sys, // If our test directory actually isn't a different volume from /sys,
// then this test is meaningless and we shouldn't run it. // then this test is meaningless and we shouldn't run it.
let td = tmpdir("walk-test-"); let td = tmpdir();
if device_num(td.path()).unwrap() == device_num("/sys").unwrap() { if device_num(td.path()).unwrap() == device_num("/sys").unwrap() {
return; return;
} }
@@ -2053,8 +2069,6 @@ mod tests {
// completely. // completely.
let mut builder = WalkBuilder::new(td.path()); let mut builder = WalkBuilder::new(td.path());
builder.follow_links(true).same_file_system(true); builder.follow_links(true).same_file_system(true);
assert_paths(td.path(), &builder, &[ assert_paths(td.path(), &builder, &["same_file", "same_file/alink"]);
"same_file", "same_file/alink",
]);
} }
} }

View File

@@ -1,14 +1,14 @@
class RipgrepBin < Formula class RipgrepBin < Formula
version '0.10.0' version '11.0.2'
desc "Recursively search directories for a regex pattern." desc "Recursively search directories for a regex pattern."
homepage "https://github.com/BurntSushi/ripgrep" homepage "https://github.com/BurntSushi/ripgrep"
if OS.mac? if OS.mac?
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz" url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz"
sha256 "32754b4173ac87a7bfffd436d601a49362676eb1841ab33440f2f49c002c8967" sha256 "0ba26423691deedf2649b12b1abe3d2be294ee1cb17c40b68fe85efe194f4f57"
elsif OS.linux? elsif OS.linux?
url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-unknown-linux-musl.tar.gz" url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-unknown-linux-musl.tar.gz"
sha256 "c76080aa807a339b44139885d77d15ad60ab8cdd2c2fdaf345d0985625bc0f97" sha256 "2e7978e346553fbc45c0940d9fa11e12f9afbae8213b261aad19b698150e169a"
end end
conflicts_with "ripgrep" conflicts_with "ripgrep"

View File

@@ -571,6 +571,7 @@ pub fn all_args_and_flags() -> Vec<RGArg> {
flag_fixed_strings(&mut args); flag_fixed_strings(&mut args);
flag_follow(&mut args); flag_follow(&mut args);
flag_glob(&mut args); flag_glob(&mut args);
flag_glob_case_insensitive(&mut args);
flag_heading(&mut args); flag_heading(&mut args);
flag_hidden(&mut args); flag_hidden(&mut args);
flag_iglob(&mut args); flag_iglob(&mut args);
@@ -1218,6 +1219,25 @@ it.
args.push(arg); args.push(arg);
} }
fn flag_glob_case_insensitive(args: &mut Vec<RGArg>) {
const SHORT: &str = "Process all glob patterns case insensitively.";
const LONG: &str = long!("\
Process glob patterns given with the -g/--glob flag case insensitively. This
effectively treats --glob as --iglob.
This flag can be disabled with the --no-glob-case-insensitive flag.
");
let arg = RGArg::switch("glob-case-insensitive")
.help(SHORT).long_help(LONG)
.overrides("no-glob-case-insensitive");
args.push(arg);
let arg = RGArg::switch("no-glob-case-insensitive")
.hidden()
.overrides("glob-case-insensitive");
args.push(arg);
}
fn flag_heading(args: &mut Vec<RGArg>) { fn flag_heading(args: &mut Vec<RGArg>) {
const SHORT: &str = "Print matches grouped by each file."; const SHORT: &str = "Print matches grouped by each file.";
const LONG: &str = long!("\ const LONG: &str = long!("\
@@ -1975,7 +1995,12 @@ or backreferences.
Note that PCRE2 is an optional ripgrep feature. If PCRE2 wasn't included in Note that PCRE2 is an optional ripgrep feature. If PCRE2 wasn't included in
your build of ripgrep, then using this flag will result in ripgrep printing your build of ripgrep, then using this flag will result in ripgrep printing
an error message and exiting. an error message and exiting. PCRE2 may also have worse user experience in
some cases, since it has fewer introspection APIs than ripgrep's default regex
engine. For example, if you use a '\n' in a PCRE2 regex without the
'-U/--multiline' flag, then ripgrep will silently fail to match anything
instead of reporting an error immediately (like it does with the default
regex engine).
Related flags: --no-pcre2-unicode Related flags: --no-pcre2-unicode
@@ -2171,7 +2196,10 @@ Replace every match with the text given when printing results. Neither this
flag nor any other ripgrep flag will modify your files. flag nor any other ripgrep flag will modify your files.
Capture group indices (e.g., $5) and names (e.g., $foo) are supported in the Capture group indices (e.g., $5) and names (e.g., $foo) are supported in the
replacement string. replacement string. In shells such as Bash and zsh, you should wrap the
pattern in single quotes instead of double quotes. Otherwise, capture group
indices will be replaced by expanded shell variables which will most likely
be empty.
Note that the replacement by default replaces each match, and NOT the entire Note that the replacement by default replaces each match, and NOT the entire
line. To replace the entire line, you should match the entire line. line. To replace the entire line, you should match the entire line.

View File

@@ -1268,6 +1268,10 @@ impl ArgMatches {
/// Builds the set of glob overrides from the command line flags. /// Builds the set of glob overrides from the command line flags.
fn overrides(&self) -> Result<Override> { fn overrides(&self) -> Result<Override> {
let mut builder = OverrideBuilder::new(env::current_dir()?); let mut builder = OverrideBuilder::new(env::current_dir()?);
// Make all globs case insensitive with --glob-case-insensitive.
if self.is_present("glob-case-insensitive") {
builder.case_insensitive(true).unwrap();
}
for glob in self.values_of_lossy_vec("glob") { for glob in self.values_of_lossy_vec("glob") {
builder.add(&glob)?; builder.add(&glob)?;
} }
@@ -1590,10 +1594,11 @@ impl ArgMatches {
if self.is_present("no-filename") { if self.is_present("no-filename") {
false false
} else { } else {
let path_stdin = Path::new("-");
self.is_present("with-filename") self.is_present("with-filename")
|| self.is_present("vimgrep") || self.is_present("vimgrep")
|| paths.len() > 1 || paths.len() > 1
|| paths.get(0).map_or(false, |p| p.is_dir()) || paths.get(0).map_or(false, |p| p != path_stdin && p.is_dir())
} }
} }
} }

View File

@@ -9,7 +9,7 @@ use std::io;
use std::ffi::OsString; use std::ffi::OsString;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use bstr::io::BufReadExt; use bstr::{io::BufReadExt, ByteSlice};
use log; use log;
use crate::Result; use crate::Result;
@@ -55,7 +55,7 @@ pub fn args() -> Vec<OsString> {
/// for each line in addition to successfully parsed arguments. /// for each line in addition to successfully parsed arguments.
fn parse<P: AsRef<Path>>( fn parse<P: AsRef<Path>>(
path: P, path: P,
) -> Result<(Vec<OsString>, Vec<Box<Error>>)> { ) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
let path = path.as_ref(); let path = path.as_ref();
match File::open(&path) { match File::open(&path) {
Ok(file) => parse_reader(file), Ok(file) => parse_reader(file),
@@ -76,7 +76,7 @@ fn parse<P: AsRef<Path>>(
/// in addition to successfully parsed arguments. /// in addition to successfully parsed arguments.
fn parse_reader<R: io::Read>( fn parse_reader<R: io::Read>(
rdr: R, rdr: R,
) -> Result<(Vec<OsString>, Vec<Box<Error>>)> { ) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
let bufrdr = io::BufReader::new(rdr); let bufrdr = io::BufReader::new(rdr);
let (mut args, mut errs) = (vec![], vec![]); let (mut args, mut errs) = (vec![], vec![]);
let mut line_number = 0; let mut line_number = 0;

View File

@@ -1,3 +1,4 @@
use std::error;
use std::io::{self, Write}; use std::io::{self, Write};
use std::process; use std::process;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@@ -19,7 +20,30 @@ mod path_printer;
mod search; mod search;
mod subject; mod subject;
type Result<T> = ::std::result::Result<T, Box<::std::error::Error>>; // Since Rust no longer uses jemalloc by default, ripgrep will, by default,
// use the system allocator. On Linux, this would normally be glibc's
// allocator, which is pretty good. In particular, ripgrep does not have a
// particularly allocation heavy workload, so there really isn't much
// difference (for ripgrep's purposes) between glibc's allocator and jemalloc.
//
// However, when ripgrep is built with musl, this means ripgrep will use musl's
// allocator, which appears to be substantially worse. (musl's goal is not to
// have the fastest version of everything. Its goal is to be small and amenable
// to static compilation.) Even though ripgrep isn't particularly allocation
// heavy, musl's allocator appears to slow down ripgrep quite a bit. Therefore,
// when building with musl, we use jemalloc.
//
// We don't unconditionally use jemalloc because it can be nice to use the
// system's default allocator by default. Moreover, jemalloc seems to increase
// compilation times by a bit.
//
// Moreover, we only do this on 64-bit systems since jemalloc doesn't support
// i686.
#[cfg(all(target_env = "musl", target_pointer_width = "64"))]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
type Result<T> = ::std::result::Result<T, Box<dyn error::Error>>;
fn main() { fn main() {
if let Err(err) = Args::parse().and_then(try_main) { if let Err(err) = Args::parse().and_then(try_main) {

View File

@@ -315,7 +315,24 @@ pub struct SearchWorker<W> {
impl<W: WriteColor> SearchWorker<W> { impl<W: WriteColor> SearchWorker<W> {
/// Execute a search over the given subject. /// Execute a search over the given subject.
pub fn search(&mut self, subject: &Subject) -> io::Result<SearchResult> { pub fn search(&mut self, subject: &Subject) -> io::Result<SearchResult> {
self.search_impl(subject) let bin =
if subject.is_explicit() {
self.config.binary_explicit.clone()
} else {
self.config.binary_implicit.clone()
};
self.searcher.set_binary_detection(bin);
let path = subject.path();
if subject.is_stdin() {
self.search_reader(path, io::stdin().lock())
} else if self.should_preprocess(path) {
self.search_preprocessor(path)
} else if self.should_decompress(path) {
self.search_decompress(path)
} else {
self.search_path(path)
}
} }
/// Return a mutable reference to the underlying printer. /// Return a mutable reference to the underlying printer.
@@ -341,30 +358,6 @@ impl<W: WriteColor> SearchWorker<W> {
} }
} }
/// Search the given subject using the appropriate strategy.
fn search_impl(&mut self, subject: &Subject) -> io::Result<SearchResult> {
let bin =
if subject.is_explicit() {
self.config.binary_explicit.clone()
} else {
self.config.binary_implicit.clone()
};
self.searcher.set_binary_detection(bin);
let path = subject.path();
if subject.is_stdin() {
let stdin = io::stdin();
// A `return` here appeases the borrow checker. NLL will fix this.
return self.search_reader(path, stdin.lock());
} else if self.should_preprocess(path) {
self.search_preprocessor(path)
} else if self.should_decompress(path) {
self.search_decompress(path)
} else {
self.search_path(path)
}
}
/// Returns true if and only if the given file path should be /// Returns true if and only if the given file path should be
/// decompressed before searching. /// decompressed before searching.
fn should_decompress(&self, path: &Path) -> bool { fn should_decompress(&self, path: &Path) -> bool {
@@ -392,11 +385,23 @@ impl<W: WriteColor> SearchWorker<W> {
&mut self, &mut self,
path: &Path, path: &Path,
) -> io::Result<SearchResult> { ) -> io::Result<SearchResult> {
let bin = self.config.preprocessor.clone().unwrap(); let bin = self.config.preprocessor.as_ref().unwrap();
let mut cmd = Command::new(&bin); let mut cmd = Command::new(bin);
cmd.arg(path).stdin(Stdio::from(File::open(path)?)); cmd.arg(path).stdin(Stdio::from(File::open(path)?));
let rdr = self.command_builder.build(&mut cmd)?; let rdr = self
.command_builder
.build(&mut cmd)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!(
"preprocessor command could not start: '{:?}': {}",
cmd,
err,
),
)
})?;
self.search_reader(path, rdr).map_err(|err| { self.search_reader(path, rdr).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,

View File

@@ -1,2 +0,0 @@
termcolor has moved to its own repository:
https://github.com/BurntSushi/termcolor

View File

@@ -341,6 +341,14 @@ rgtest!(glob_case_sensitive, |dir: Dir, mut cmd: TestCommand| {
eqnice!("file2.html:Sherlock\n", cmd.stdout()); eqnice!("file2.html:Sherlock\n", cmd.stdout());
}); });
rgtest!(glob_always_case_insensitive, |dir: Dir, mut cmd: TestCommand| {
dir.create("sherlock", SHERLOCK);
dir.create("file.HTML", "Sherlock");
cmd.args(&["--glob-case-insensitive", "--glob", "*.html", "Sherlock"]);
eqnice!("file.HTML:Sherlock\n", cmd.stdout());
});
rgtest!(byte_offset_only_matching, |dir: Dir, mut cmd: TestCommand| { rgtest!(byte_offset_only_matching, |dir: Dir, mut cmd: TestCommand| {
dir.create("sherlock", SHERLOCK); dir.create("sherlock", SHERLOCK);
cmd.arg("-b").arg("-o").arg("Sherlock"); cmd.arg("-b").arg("-o").arg("Sherlock");

View File

@@ -705,3 +705,36 @@ rgtest!(r1203_reverse_suffix_literal, |dir: Dir, _: TestCommand| {
let mut cmd = dir.command(); let mut cmd = dir.command();
eqnice!("153.230000\n", cmd.arg(r"\d\d\d000").arg("test").stdout()); eqnice!("153.230000\n", cmd.arg(r"\d\d\d000").arg("test").stdout());
}); });
// See: https://github.com/BurntSushi/ripgrep/issues/1223
rgtest!(r1223_no_dir_check_for_default_path, |dir: Dir, mut cmd: TestCommand| {
dir.create_dir("-");
dir.create("a.json", "{}");
dir.create("a.txt", "some text");
eqnice!(
"a.json\na.txt\n",
sort_lines(&cmd.arg("a").pipe(b"a.json\na.txt"))
);
});
// See: https://github.com/BurntSushi/ripgrep/issues/1259
rgtest!(r1259_drop_last_byte_nonl, |dir: Dir, mut cmd: TestCommand| {
dir.create("patterns-nonl", "[foo]");
dir.create("patterns-nl", "[foo]\n");
dir.create("test", "fz");
eqnice!("fz\n", cmd.arg("-f").arg("patterns-nonl").arg("test").stdout());
cmd = dir.command();
eqnice!("fz\n", cmd.arg("-f").arg("patterns-nl").arg("test").stdout());
});
// See: https://github.com/BurntSushi/ripgrep/issues/1334
rgtest!(r1334_crazy_literals, |dir: Dir, mut cmd: TestCommand| {
dir.create("patterns", &"1.208.0.0/12\n".repeat(40));
dir.create("corpus", "1.208.0.0/12\n");
eqnice!(
"1.208.0.0/12\n",
cmd.arg("-Ff").arg("patterns").arg("corpus").stdout()
);
});

View File

@@ -1,2 +0,0 @@
wincolor has moved to the termcolor repository:
https://github.com/BurntSushi/termcolor