Compare commits

..

1 Commits

Author SHA1 Message Date
Andrew Gallant
7bf7ceb5d3 progress 2019-05-29 18:07:03 -04:00
53 changed files with 1381 additions and 1168 deletions

View File

@@ -1,99 +0,0 @@
# test
name: ci
on:
pull_request:
push:
branches:
- master
schedule:
- cron: '00 01 * * *'
jobs:
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: |
# apt-get install musl-tools
- name: Build everything
run: cargo build --verbose --target ${{ matrix.target }} --all --features pcre2
- 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,42 +1,11 @@
TBD TBD
=== ===
TODO TODO.
Bug fixes: 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): * [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`. 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) 11.0.1 (2019-04-16)

657
Cargo.lock generated
View File

@@ -2,19 +2,47 @@
# 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.6" version = "0.7.3"
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.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.13" version = "0.2.11"
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.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.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]]
name = "autocfg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "backtrace"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -22,22 +50,22 @@ name = "base64"
version = "0.10.1" version = "0.10.1"
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.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.1.0" version = "1.0.4"
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.2.7" 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 = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -47,17 +75,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.3.2" version = "1.3.1"
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.41" version = "1.0.35"
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.9" 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]]
@@ -65,27 +93,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.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (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.9" 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 = [
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (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.6" version = "0.6.5"
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.9 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -93,7 +130,7 @@ name = "encoding_rs"
version = "0.8.17" version = "0.8.17"
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.9 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.7 (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)",
] ]
@@ -115,6 +152,11 @@ name = "fs_extra"
version = "1.1.0" 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]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "glob" name = "glob"
version = "0.3.0" version = "0.3.0"
@@ -122,164 +164,166 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "globset" name = "globset"
version = "0.4.4" version = "0.4.3"
dependencies = [ dependencies = [
"aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bstr 0.1.2 (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.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "grep" name = "grep"
version = "0.2.4" version = "0.2.4"
dependencies = [ dependencies = [
"grep-cli 0.1.3", "grep-cli 0.1.2",
"grep-matcher 0.1.3", "grep-matcher 0.1.2",
"grep-pcre2 0.1.3", "grep-pcre2 0.1.3",
"grep-printer 0.1.3", "grep-printer 0.1.2",
"grep-regex 0.1.5", "grep-regex 0.1.3",
"grep-searcher 0.1.6", "grep-searcher 0.1.4",
"termcolor 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)",
"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)",
] ]
[[package]] [[package]]
name = "grep-cli" name = "grep-cli"
version = "0.1.3" version = "0.1.2"
dependencies = [ dependencies = [
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bstr 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.4.4", "globset 0.4.3",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 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)", "termcolor 1.0.4 (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.3" version = "0.1.2"
dependencies = [ dependencies = [
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.6 (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.3", "grep-matcher 0.1.2",
"pcre2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pcre2 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "grep-printer" name = "grep-printer"
version = "0.1.3" version = "0.1.2"
dependencies = [ dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bstr 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"grep-matcher 0.1.3", "grep-matcher 0.1.2",
"grep-regex 0.1.5", "grep-regex 0.1.3",
"grep-searcher 0.1.6", "grep-searcher 0.1.4",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 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)",
] ]
[[package]] [[package]]
name = "grep-regex" name = "grep-regex"
version = "0.1.5" version = "0.1.3"
dependencies = [ dependencies = [
"aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"grep-matcher 0.1.3", "grep-matcher 0.1.2",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.6 (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 0.3.6 (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.6" version = "0.1.4"
dependencies = [ dependencies = [
"bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bstr 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytecount 0.5.1 (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.17 (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.3", "grep-matcher 0.1.2",
"grep-regex 0.1.5", "grep-regex 0.1.3",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (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.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "ignore" name = "ignore"
version = "0.4.10" version = "0.4.7"
dependencies = [ dependencies = [
"crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.4.4", "globset 0.4.3",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.7 (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 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.4" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "jemalloc-sys" name = "jemalloc-sys"
version = "0.3.2" version = "0.3.0"
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.41 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"fs_extra 1.1.0 (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.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "jemallocator" name = "jemallocator"
version = "0.3.2" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jemalloc-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.3.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.62" version = "0.2.51"
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.8" version = "0.4.6"
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.9 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.2.1" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@@ -287,16 +331,16 @@ 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.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (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 = "num_cpus" name = "num_cpus"
version = "1.10.1" version = "1.10.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.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -304,102 +348,237 @@ 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.9 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "pcre2" name = "pcre2"
version = "0.2.1" version = "0.2.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.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pcre2-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "pcre2-sys 0.2.1 (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 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "pcre2-sys" name = "pcre2-sys"
version = "0.2.2" version = "0.2.1"
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.41 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.15" version = "0.3.14"
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 = "1.0.1" version = "0.4.27"
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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.2" version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (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.2.1" version = "1.1.6"
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.6 (registry+https://github.com/rust-lang/crates.io-index)", "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.6 (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 0.3.6 (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.8" 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 = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.11" version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ripgrep"
version = "11.0.2"
dependencies = [ dependencies = [
"bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "ucd-util 0.1.3 (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.4",
"ignore 0.4.10",
"jemallocator 0.3.2 (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.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.5 (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]]
name = "ripgrep"
version = "11.0.1"
dependencies = [
"bstr 0.1.2 (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.4",
"ignore 0.4.7",
"jemallocator 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"snafu 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.0" version = "0.2.7"
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.5" version = "1.0.4"
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)",
@@ -407,27 +586,51 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.99" version = "1.0.90"
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.99" version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.40" version = "1.0.39"
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.4 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.90 (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]]
name = "snafu"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"snafu-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "snafu-derive"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -437,20 +640,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.5" version = "0.15.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.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.5" version = "1.0.4"
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.2 (registry+https://github.com/rust-lang/crates.io-index)", "wincolor 1.0.1 (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]]
@@ -458,7 +684,7 @@ 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.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -466,32 +692,42 @@ name = "thread_local"
version = "0.3.6" version = "0.3.6"
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.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.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.6" version = "0.1.5"
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.2.0" version = "0.1.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.9" version = "2.2.7"
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.5 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.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 = "winapi" name = "winapi"
version = "0.3.8" version = "0.3.7"
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)",
@@ -508,7 +744,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.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@@ -518,64 +754,91 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "wincolor" name = "wincolor"
version = "1.0.2" version = "1.0.1"
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.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.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)",
] ]
[metadata] [metadata]
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
"checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94cdf78eb7e94c566c1f5dbe2abf8fc70a548fc902942a48c4b3a98b48ca9ade" "checksum bstr 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6c8203ca06c502958719dae5f653a79e0cc6ba808ed02beffbf27d09610f2143"
"checksum bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c" "checksum bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" "checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
"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 crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b"
"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
"checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed" "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 fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" "checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"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.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
"checksum jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45" "checksum jemalloc-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bef0d4ce37578dfd80b466e3d8324bd9de788e249f1accebb0c472ea4b52bdc"
"checksum jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69" "checksum jemallocator 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c2b69163a3cf2d0fffcd4e1b57921bc6d8fb97ec27f2aeef00562abdaf4ffe2a"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "603da5e101220b9b306bf28e4f1f8703458ce2f64d2787b374e1a19494317180" "checksum pcre2 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a08c8195dd1d8a2a1b5e2af94bf0c4c3c195c2359930442a016bf123196f7155"
"checksum pcre2-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "876c72d05059d23a84bd9fcdc3b1d31c50ea7fe00fe1522b4e68cd3608db8d5b" "checksum pcre2-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9699d43bebf25ee0fdafb9457b9a52da3c57506a3d39a2f9b6498800f032881"
"checksum pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c1d2cfa5a714db3b5f24f0915e74fcdf91d09d496ba61329705dda7774d2af" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" "checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832"
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"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.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
"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 rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
"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 snafu 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67a2e16c9b74a09d4bc84ea6e5eb68fef70b4cb14e8ccd26f2de76af2e9c2e8a"
"checksum snafu-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bf96650c2b31fa949780f792025f4ca79fbe87bd723a8b3573dce37be7193b08"
"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 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a"
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a"
"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 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
"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.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"

View File

@@ -1,11 +1,11 @@
[package] [package]
name = "ripgrep" name = "ripgrep"
version = "11.0.2" #:version version = "11.0.1" #: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,14 +46,15 @@ members = [
] ]
[dependencies] [dependencies]
bstr = "0.2.0" bstr = "0.1.2"
grep = { version = "0.2.4", 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 = { version = "0.4.5", features = ["std"] }
num_cpus = "1.8.0" num_cpus = "1.8.0"
regex = "1.0.5" regex = "1.0.5"
serde_json = "1.0.23" serde_json = "1.0.23"
snafu = "0.2.3"
termcolor = "1.0.3" termcolor = "1.0.3"
[dependencies.clap] [dependencies.clap]

View File

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

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/*/regex/#syntax https://docs.rs/regex/0.2.5/regex/#syntax
### Recursive search ### Recursive search

View File

@@ -29,7 +29,6 @@ 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
@@ -93,11 +92,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 directory search and won't search files ignored by your `.gitignore` files.
`.gitignore`/`.ignore`/`.rgignore` files. It also ignores hidden and binary It also ignores hidden and binary files by default. ripgrep also implements
files by default. ripgrep also implements full support for `.gitignore`, full support for `.gitignore`, whereas there are many bugs related to that
whereas there are many bugs related to that functionality in other code functionality in other code search tools claiming to provide the same
search tools claiming to provide the same functionality. 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
@@ -225,7 +224,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/ScoopInstaller/Main/blob/master/bucket/ripgrep.json): [official bucket](https://github.com/lukesampson/scoop/blob/master/bucket/ripgrep.json):
``` ```
$ scoop install ripgrep $ scoop install ripgrep
@@ -288,11 +287,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/11.0.2/ripgrep_11.0.2_amd64.deb $ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/11.0.1/ripgrep_11.0.1_amd64.deb
$ sudo dpkg -i ripgrep_11.0.2_amd64.deb $ sudo dpkg -i ripgrep_11.0.1_amd64.deb
``` ```
If you run Debian Buster (currently Debian stable) or Debian sid, ripgrep is If you run Debian Buster (currently Debian testing) 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
@@ -419,11 +418,3 @@ $ 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

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

View File

@@ -104,10 +104,6 @@ _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.4" #:version version = "0.4.3" #: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.2.0", default-features = false, features = ["std"] } bstr = { version = "0.1.2", 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) self.re.is_match(path.path.as_bytes())
} }
} }
@@ -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; let byte_path = candidate.path.as_bytes();
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, ByteSlice, ByteVec}; use bstr::{B, BStr, BString};
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, [u8]>, path: Cow<'a, BStr>,
basename: Cow<'a, [u8]>, basename: Cow<'a, BStr>,
ext: Cow<'a, [u8]>, ext: Cow<'a, BStr>,
} }
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(Vec::from_path_lossy(path.as_ref())); let path = normalize_path(BString::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) -> &[u8] { fn path_prefix(&self, max: usize) -> &BStr {
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) -> &[u8] { fn path_suffix(&self, max: usize) -> &BStr {
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::{ByteSlice, ByteVec}; use bstr::BStr;
/// 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, [u8]>) -> Option<Cow<'a, [u8]>> { pub fn file_name<'a>(path: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> {
if path.is_empty() { if path.is_empty() {
return None; return None;
} else if path.last_byte() == Some(b'.') { } else if path.last() == 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, [u8]>) -> Option<Cow<'a, [u8]>> {
/// 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, [u8]>) -> Option<Cow<'a, [u8]>> { pub fn file_name_ext<'a>(name: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> {
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, [u8]>) -> Option<Cow<'a, [u8]>> {
/// 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<[u8]>) -> Cow<[u8]> { pub fn normalize_path(path: Cow<BStr>) -> Cow<BStr> {
// 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<[u8]>) -> Cow<[u8]> {
/// 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<[u8]>) -> Cow<[u8]> { pub fn normalize_path(mut path: Cow<BStr>) -> Cow<BStr> {
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<[u8]>) -> Cow<[u8]> {
mod tests { mod tests {
use std::borrow::Cow; use std::borrow::Cow;
use bstr::{B, ByteVec}; use bstr::{B, BString};
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 = Vec::from($file_name); let bs = BString::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 = Vec::from_slice($path); let bs = BString::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.3" #:version version = "0.1.2" #: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.2.0" bstr = "0.1.2"
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::{ByteSlice, ByteVec}; use bstr::{BStr, BString};
/// 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,6 +38,7 @@ 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}' {
@@ -55,7 +56,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(Vec::from_os_str_lossy(string).as_bytes()) escape(BString::from_os_str_lossy(string).as_bytes())
} }
/// Unescapes a string. /// Unescapes a string.
@@ -110,7 +111,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 => {
@@ -121,7 +122,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);
@@ -173,7 +174,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

@@ -161,7 +161,7 @@ pub fn patterns_from_reader<R: io::Read>(rdr: R) -> io::Result<Vec<String>> {
let mut line_number = 0; let mut line_number = 0;
io::BufReader::new(rdr).for_byte_line(|line| { io::BufReader::new(rdr).for_byte_line(|line| {
line_number += 1; line_number += 1;
match pattern_from_bytes(line) { match pattern_from_bytes(line.as_bytes()) {
Ok(pattern) => { Ok(pattern) => {
patterns.push(pattern.to_string()); patterns.push(pattern.to_string());
Ok(true) Ok(true)

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "grep-matcher" name = "grep-matcher"
version = "0.1.3" #:version version = "0.1.2" #: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.3" #:version version = "0.1.2" #: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
@@ -19,7 +19,7 @@ serde1 = ["base64", "serde", "serde_derive", "serde_json"]
[dependencies] [dependencies]
base64 = { version = "0.10.0", optional = true } base64 = { version = "0.10.0", optional = true }
bstr = "0.2.0" bstr = "0.1.2"
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::ByteSlice; use bstr::BStr;
use grep_matcher::{Match, Matcher}; use grep_matcher::{Match, Matcher};
use grep_searcher::{ use grep_searcher::{
LineStep, Searcher, LineStep, Searcher,
@@ -1274,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 = bytes[line] let end = BStr::new(&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)
@@ -1396,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",
[byte].as_bstr(), offset, BStr::new(&[byte]), 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() {
@@ -1407,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",
[byte].as_bstr(), offset, BStr::new(&[byte]), 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::{ByteSlice, ByteVec}; use bstr::{BStr, BString};
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, [u8]>); pub struct PrinterPath<'a>(Cow<'a, BStr>);
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(Vec::from_path_lossy(path)) PrinterPath(BString::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: Vec<u8> = self.0.bytes().map(|b| { let transformed_path: BString = 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 self.0.as_bytes()
} }
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "grep-regex" name = "grep-regex"
version = "0.1.5" #:version version = "0.1.3" #: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.
@@ -19,3 +19,4 @@ 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 = "0.3.6"
utf8-ranges = "1.0.1"

View File

@@ -11,6 +11,7 @@ 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,31 +71,10 @@ impl RegexMatcherBuilder {
&self, &self,
literals: &[B], literals: &[B],
) -> Result<RegexMatcher, Error> { ) -> Result<RegexMatcher, Error> {
let mut has_escape = false; let slices: Vec<_> = literals.iter().map(|s| s.as_ref()).collect();
let mut slices = vec![]; if !self.config.can_plain_aho_corasick() || literals.len() < 40 {
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 regex_syntax::utf8::Utf8Sequences; use utf8_ranges::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

@@ -1,6 +1,6 @@
[package] [package]
name = "grep-searcher" name = "grep-searcher"
version = "0.1.6" #:version version = "0.1.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]
bstr = { version = "0.2.0", default-features = false, features = ["std"] } bstr = { version = "0.1.2", default-features = false, features = ["std"] }
bytecount = "0.5" bytecount = "0.5"
encoding_rs = "0.8.14" encoding_rs = "0.8.14"
encoding_rs_io = "0.1.6" encoding_rs_io = "0.1.6"

View File

@@ -17,7 +17,7 @@ fn main() {
} }
} }
fn example() -> Result<(), Box<dyn Error>> { fn example() -> Result<(), Box<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::ByteSlice; use bstr::{BStr, BString};
/// 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: vec![0; self.config.capacity], buf: BString::from(vec![0; self.config.capacity]),
pos: 0, pos: 0,
last_lineterm: 0, last_lineterm: 0,
end: 0, end: 0,
@@ -254,14 +254,13 @@ 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() self.line_buffer.buffer().as_bytes()
} }
/// Return the buffer as a BStr, used for convenient equality checking /// Return the underlying buffer as a byte string. Used for tests only.
/// in tests only.
#[cfg(test)] #[cfg(test)]
fn bstr(&self) -> &::bstr::BStr { fn bstr(&self) -> &BStr {
self.buffer().as_bstr() self.line_buffer.buffer()
} }
/// 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
@@ -290,7 +289,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: Vec<u8>, buf: BString,
/// 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,
@@ -353,13 +352,13 @@ impl LineBuffer {
} }
/// Return the contents of this buffer. /// Return the contents of this buffer.
fn buffer(&self) -> &[u8] { fn buffer(&self) -> &BStr {
&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 [u8] { fn free_buffer(&mut self) -> &mut BStr {
&mut self.buf[self.end..] &mut self.buf[self.end..]
} }
@@ -482,7 +481,7 @@ impl LineBuffer {
} }
let roll_len = self.end - self.pos; let roll_len = self.end - self.pos;
self.buf.copy_within_str(self.pos..self.end, 0); self.buf.copy_within(self.pos.., 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;
@@ -520,7 +519,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 [u8], src: u8, replacement: u8) -> Option<usize> { fn replace_bytes(bytes: &mut BStr, src: u8, replacement: u8) -> Option<usize> {
if src == replacement { if src == replacement {
return None; return None;
} }
@@ -543,7 +542,7 @@ fn replace_bytes(bytes: &mut [u8], src: u8, replacement: u8) -> Option<usize> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::str; use std::str;
use bstr::{ByteSlice, ByteVec}; use bstr::BString;
use super::*; use super::*;
const SHERLOCK: &'static str = "\ const SHERLOCK: &'static str = "\
@@ -564,7 +563,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 = Vec::from(slice); let mut dst = BString::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)
} }
@@ -678,12 +677,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 = vec![]; let mut got = BString::new();
while rdr.fill().unwrap() { while rdr.fill().unwrap() {
got.push_str(rdr.buffer()); got.push(rdr.buffer());
rdr.consume_all(); rdr.consume_all();
} }
assert_eq!(bytes, got.as_bstr()); assert_eq!(bytes, got);
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::ByteSlice; use bstr::B;
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 bytes[self.pos..].find_byte(self.line_term) { match B(&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 = bytes[..range.start()] let line_start = B(&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 {
bytes[range.end()..] B(&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 bytes[..pos].rfind_byte(line_term) { match B(&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::ByteSlice; use bstr::B;
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) = buf[*range].find_byte(binary_byte) { if let Some(i) = B(&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,4 +1,3 @@
use std::error;
use std::fmt; use std::fmt;
use std::io; use std::io;
@@ -50,9 +49,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<dyn error::Error> { impl SinkError for Box<::std::error::Error> {
fn error_message<T: fmt::Display>(message: T) -> Box<dyn error::Error> { fn error_message<T: fmt::Display>(message: T) -> Box<::std::error::Error> {
Box::<dyn error::Error>::from(message.to_string()) Box::<::std::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::ByteSlice; use bstr::B;
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 = haystack let i = B(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

@@ -21,7 +21,7 @@ fn main() {
} }
} }
fn try_main() -> Result<(), Box<dyn Error>> { fn try_main() -> Result<(), Box<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<dyn 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<dyn Error>> { fn search(pattern: &str, paths: &[OsString]) -> Result<(), Box<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.10" #:version version = "0.4.7" #: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`
@@ -31,5 +31,8 @@ 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::{OsStr, OsString}; use std::ffi::{OsString, OsStr};
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 overrides::{self, Override};
use pathutil::{is_hidden, strip_prefix}; use pathutil::{is_hidden, strip_prefix};
use overrides::{self, Override};
use types::{self, Types}; use types::{self, Types};
use walk::DirEntry; use walk::DirEntry;
use {Error, Match, PartialErrorBuilder}; use {Error, Match, PartialErrorBuilder};
@@ -152,7 +152,10 @@ 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>>(&self, path: P) -> (Ignore, Option<Error>) { pub fn add_parents<P: AsRef<Path>>(
&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
@@ -194,7 +197,8 @@ 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 = if self.0.opts.git_ignore { igtmp.has_git =
if self.0.opts.git_ignore {
parent.join(".git").exists() parent.join(".git").exists()
} else { } else {
false false
@@ -213,7 +217,10 @@ 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>>(&self, dir: P) -> (Ignore, Option<Error>) { pub fn add_child<P: AsRef<Path>>(
&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)
} }
@@ -221,10 +228,12 @@ 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 = if self.0.custom_ignore_filenames.is_empty() { let custom_ig_matcher =
if self.0.custom_ignore_filenames.is_empty() {
Gitignore::empty() Gitignore::empty()
} else { } else {
let (m, err) = create_gitignore( let (m, err) =
create_gitignore(
&dir, &dir,
&self.0.custom_ignore_filenames, &self.0.custom_ignore_filenames,
self.0.opts.ignore_case_insensitive, self.0.opts.ignore_case_insensitive,
@@ -232,26 +241,38 @@ impl Ignore {
errs.maybe_push(err); errs.maybe_push(err);
m m
}; };
let ig_matcher = if !self.0.opts.ignore { let ig_matcher =
if !self.0.opts.ignore {
Gitignore::empty() Gitignore::empty()
} else { } else {
let (m, err) = let (m, err) =
create_gitignore(&dir, &[".ignore"], self.0.opts.ignore_case_insensitive); create_gitignore(
&dir,
&[".ignore"],
self.0.opts.ignore_case_insensitive,
);
errs.maybe_push(err); errs.maybe_push(err);
m m
}; };
let gi_matcher = if !self.0.opts.git_ignore { let gi_matcher =
if !self.0.opts.git_ignore {
Gitignore::empty() Gitignore::empty()
} else { } else {
let (m, err) = let (m, err) =
create_gitignore(&dir, &[".gitignore"], self.0.opts.ignore_case_insensitive); create_gitignore(
&dir,
&[".gitignore"],
self.0.opts.ignore_case_insensitive,
);
errs.maybe_push(err); errs.maybe_push(err);
m m
}; };
let gi_exclude_matcher = if !self.0.opts.git_exclude { let gi_exclude_matcher =
if !self.0.opts.git_exclude {
Gitignore::empty() Gitignore::empty()
} else { } else {
let (m, err) = create_gitignore( let (m, err) =
create_gitignore(
&dir, &dir,
&[".git/info/exclude"], &[".git/info/exclude"],
self.0.opts.ignore_case_insensitive, self.0.opts.ignore_case_insensitive,
@@ -259,7 +280,8 @@ impl Ignore {
errs.maybe_push(err); errs.maybe_push(err);
m m
}; };
let has_git = if self.0.opts.git_ignore { let has_git =
if self.0.opts.git_ignore {
dir.join(".git").exists() dir.join(".git").exists()
} else { } else {
false false
@@ -291,16 +313,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.ignore || opts.git_global || opts.git_ignore
|| opts.git_global || opts.git_exclude || has_custom_ignore_files
|| opts.git_ignore
|| opts.git_exclude
|| has_custom_ignore_files
|| has_explicit_ignores || 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>(&'a self, dent: &DirEntry) -> Match<IgnoreMatch<'a>> { pub fn matched_dir_entry<'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());
@@ -312,7 +334,11 @@ 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>>(&'a self, path: P, is_dir: bool) -> Match<IgnoreMatch<'a>> { fn matched<'a, P: AsRef<Path>>(
&'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();
@@ -324,10 +350,8 @@ 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 = self let mat =
.0 self.0.overrides.matched(path, is_dir)
.overrides
.matched(path, is_dir)
.map(IgnoreMatch::overrides); .map(IgnoreMatch::overrides);
if !mat.is_none() { if !mat.is_none() {
return mat; return mat;
@@ -343,7 +367,8 @@ impl Ignore {
} }
} }
if !self.0.types.is_empty() { if !self.0.types.is_empty() {
let mat = self.0.types.matched(path, is_dir).map(IgnoreMatch::types); let mat =
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() {
@@ -355,39 +380,34 @@ 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>(&'a self, path: &Path, is_dir: bool) -> Match<IgnoreMatch<'a>> { fn matched_ignore<'a>(
let (mut m_custom_ignore, mut m_ignore, mut m_gi, mut m_gi_exclude, mut m_explicit) = ( &'a self,
Match::None, 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);
);
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 ig.0.custom_ignore_matcher.matched(path, is_dir)
.matched(path, is_dir)
.map(IgnoreMatch::gitignore); .map(IgnoreMatch::gitignore);
} }
if m_ignore.is_none() { if m_ignore.is_none() {
m_ignore = m_ignore =
ig.0.ignore_matcher ig.0.ignore_matcher.matched(path, is_dir)
.matched(path, is_dir)
.map(IgnoreMatch::gitignore); .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 ig.0.git_ignore_matcher.matched(path, is_dir)
.matched(path, is_dir)
.map(IgnoreMatch::gitignore); .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 ig.0.git_exclude_matcher.matched(path, is_dir)
.matched(path, is_dir)
.map(IgnoreMatch::gitignore); .map(IgnoreMatch::gitignore);
} }
saw_git = saw_git || ig.0.has_git; saw_git = saw_git || ig.0.has_git;
@@ -395,29 +415,25 @@ impl Ignore {
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 ig.0.custom_ignore_matcher.matched(&path, is_dir)
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore); .map(IgnoreMatch::gitignore);
} }
if m_ignore.is_none() { if m_ignore.is_none() {
m_ignore = m_ignore =
ig.0.ignore_matcher ig.0.ignore_matcher.matched(&path, is_dir)
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore); .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 ig.0.git_ignore_matcher.matched(&path, is_dir)
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore); .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 ig.0.git_exclude_matcher.matched(&path, is_dir)
.matched(&path, is_dir)
.map(IgnoreMatch::gitignore); .map(IgnoreMatch::gitignore);
} }
saw_git = saw_git || ig.0.has_git; saw_git = saw_git || ig.0.has_git;
@@ -430,21 +446,16 @@ 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 = if any_git { let m_global =
self.0 if any_git {
.git_global_matcher self.0.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 m_custom_ignore.or(m_ignore).or(m_gi).or(m_gi_exclude).or(m_global).or(m_explicit)
.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,7 +535,8 @@ 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 = if !self.opts.git_global { let git_global_matcher =
if !self.opts.git_global {
Gitignore::empty() Gitignore::empty()
} else { } else {
let mut builder = GitignoreBuilder::new(""); let mut builder = GitignoreBuilder::new("");
@@ -592,10 +604,9 @@ 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 self.custom_ignore_filenames.push(file_name.as_ref().to_os_string());
.push(file_name.as_ref().to_os_string());
self self
} }
@@ -667,7 +678,10 @@ 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(&mut self, yes: bool) -> &mut IgnoreBuilder { pub fn ignore_case_insensitive(
&mut self,
yes: bool,
) -> &mut IgnoreBuilder {
self.opts.ignore_case_insensitive = yes; self.opts.ignore_case_insensitive = yes;
self self
} }
@@ -707,9 +721,10 @@ 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) {
@@ -728,21 +743,19 @@ mod tests {
} }
} }
fn tmpdir() -> TempDir { fn tmpdir(prefix: &str) -> TempDir {
TempDir::new().unwrap() tempfile::Builder::new().prefix(prefix).tempdir().unwrap()
} }
#[test] #[test]
fn explicit_ignore() { fn explicit_ignore() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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) .add_ignore(gi).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());
@@ -751,7 +764,7 @@ mod tests {
#[test] #[test]
fn git_exclude() { fn git_exclude() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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");
@@ -764,7 +777,7 @@ mod tests {
#[test] #[test]
fn gitignore() { fn gitignore() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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");
@@ -777,7 +790,7 @@ mod tests {
#[test] #[test]
fn gitignore_no_git() { fn gitignore_no_git() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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());
@@ -789,7 +802,7 @@ mod tests {
#[test] #[test]
fn ignore() { fn ignore() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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());
@@ -801,14 +814,13 @@ mod tests {
#[test] #[test]
fn custom_ignore() { fn custom_ignore() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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() .build().add_child(td.path());
.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());
@@ -818,15 +830,14 @@ 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(); let td = tmpdir("ignore-test-");
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() .build().add_child(td.path());
.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 +845,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(); let td = tmpdir("ignore-test-");
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,8 +854,7 @@ 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() .build().add_child(td.path());
.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());
} }
@@ -852,7 +862,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(); let td = tmpdir("ignore-test-");
wfile(td.path().join(".gitignore"), "foo"); wfile(td.path().join(".gitignore"), "foo");
wfile(td.path().join(".ignore"), "!foo"); wfile(td.path().join(".ignore"), "!foo");
@@ -864,7 +874,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(); let td = tmpdir("ignore-test-");
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"));
@@ -879,7 +889,7 @@ mod tests {
#[test] #[test]
fn errored() { fn errored() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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());
@@ -888,7 +898,7 @@ mod tests {
#[test] #[test]
fn errored_both() { fn errored_both() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
wfile(td.path().join(".gitignore"), "{foo"); wfile(td.path().join(".gitignore"), "{foo");
wfile(td.path().join(".ignore"), "{bar"); wfile(td.path().join(".ignore"), "{bar");
@@ -898,7 +908,7 @@ mod tests {
#[test] #[test]
fn errored_partial() { fn errored_partial() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
mkdirp(td.path().join(".git")); mkdirp(td.path().join(".git"));
wfile(td.path().join(".gitignore"), "{foo\nbar"); wfile(td.path().join(".gitignore"), "{foo\nbar");
@@ -909,7 +919,7 @@ mod tests {
#[test] #[test]
fn errored_partial_and_ignore() { fn errored_partial_and_ignore() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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");
@@ -920,7 +930,7 @@ mod tests {
#[test] #[test]
fn not_present_empty() { fn not_present_empty() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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());
@@ -930,7 +940,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(); let td = tmpdir("ignore-test-");
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");
@@ -951,7 +961,7 @@ mod tests {
#[test] #[test]
fn absolute_parent() { fn absolute_parent() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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");
@@ -974,7 +984,7 @@ mod tests {
#[test] #[test]
fn absolute_parent_anchored() { fn absolute_parent_anchored() {
let td = tmpdir(); let td = tmpdir("ignore-test-");
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

@@ -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_HOME/git/config. Notably, // git supports $HOME/.gitconfig and $XDG_CONFIG_DIR/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_HOME directory. /// the user's XDG_CONFIG_DIR 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,6 +55,8 @@ 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)]
@@ -440,66 +442,3 @@ 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,7 +135,6 @@ 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"]),
@@ -220,7 +219,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", "*.nimf", "*.nimble", "*.nims"]), ("nim", &["*.nim"]),
("nix", &["*.nix"]), ("nix", &["*.nix"]),
("objc", &["*.h", "*.m"]), ("objc", &["*.h", "*.m"]),
("objcpp", &["*.h", "*.mm"]), ("objcpp", &["*.h", "*.mm"]),
@@ -242,7 +241,6 @@ 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"]),

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::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
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, io::ErrorKind::Other, "<stdin> has no metadata"));
"<stdin> has no metadata",
));
Err(err.with_path("<stdin>")) Err(err.with_path("<stdin>"))
} }
Walkdir(ref x) => x Walkdir(ref x) => {
.metadata() x.metadata().map_err(|err| {
.map_err(|err| Error::Io(io::Error::from(err)).with_path(x.path())), 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 self::DirEntryInner::*;
use walkdir::DirEntryExt; use walkdir::DirEntryExt;
use self::DirEntryInner::*;
match *self { match *self {
Stdin => None, Stdin => None,
Walkdir(ref x) => Some(x.ino()), Walkdir(ref x) => Some(x.ino()),
@@ -297,8 +297,7 @@ 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))]
@@ -307,8 +306,7 @@ 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 {
@@ -316,9 +314,7 @@ impl DirEntryRaw {
} }
fn file_name(&self) -> &OsStr { fn file_name(&self) -> &OsStr {
self.path self.path.file_name().unwrap_or_else(|| self.path.as_os_str())
.file_name()
.unwrap_or_else(|| self.path.as_os_str())
} }
fn depth(&self) -> usize { fn depth(&self) -> usize {
@@ -330,7 +326,10 @@ impl DirEntryRaw {
self.ino self.ino
} }
fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntryRaw, Error> { fn from_entry(
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 {
@@ -380,22 +379,15 @@ impl DirEntryRaw {
}) })
} }
// Placeholder implementation to allow compiling on non-standard platforms (e.g. wasm32). #[cfg(not(unix))]
#[cfg(not(any(windows, unix)))] fn from_path(
fn from_entry_os(
depth: usize, depth: usize,
ent: &fs::DirEntry, pb: PathBuf,
ty: fs::FileType, link: bool,
) -> Result<DirEntryRaw, Error> { ) -> Result<DirEntryRaw, Error> {
Err(Error::Io(io::Error::new( let md = fs::metadata(&pb).map_err(|err| {
io::ErrorKind::Other, Error::Io(err).with_path(&pb)
"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(),
@@ -406,10 +398,16 @@ impl DirEntryRaw {
} }
#[cfg(unix)] #[cfg(unix)]
fn from_path(depth: usize, pb: PathBuf, link: bool) -> Result<DirEntryRaw, Error> { fn from_path(
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| Error::Io(err).with_path(&pb))?; 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(),
@@ -418,15 +416,6 @@ 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.
@@ -492,8 +481,8 @@ pub struct WalkBuilder {
#[derive(Clone)] #[derive(Clone)]
enum Sorter { enum Sorter {
ByName(Arc<dyn Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static>), ByName(Arc<Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static>),
ByPath(Arc<dyn Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static>), ByPath(Arc<Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static>),
} }
impl fmt::Debug for WalkBuilder { impl fmt::Debug for WalkBuilder {
@@ -536,10 +525,7 @@ 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 let its = self.paths.iter().map(move |p| {
.paths
.iter()
.map(move |p| {
if p == Path::new("-") { if p == Path::new("-") {
(p.to_path_buf(), None) (p.to_path_buf(), None)
} else { } else {
@@ -552,18 +538,20 @@ impl WalkBuilder {
if let Some(ref sorter) = sorter { if let Some(ref sorter) = sorter {
match sorter.clone() { match sorter.clone() {
Sorter::ByName(cmp) => { Sorter::ByName(cmp) => {
wd = wd.sort_by(move |a, b| cmp(a.file_name(), b.file_name())); wd = wd.sort_by(move |a, b| {
cmp(a.file_name(), b.file_name())
});
} }
Sorter::ByPath(cmp) => { Sorter::ByPath(cmp) => {
wd = wd.sort_by(move |a, b| 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<_>>().into_iter();
.collect::<Vec<_>>()
.into_iter();
let ig_root = self.ig_builder.build(); let ig_root = self.ig_builder.build();
Walk { Walk {
its: its, its: its,
@@ -647,12 +635,8 @@ 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) => { Ok(gi) => { self.ig_builder.add_ignore(gi); }
self.ig_builder.add_ignore(gi); Err(err) => { errs.push(err); }
}
Err(err) => {
errs.push(err);
}
} }
errs.into_error_option() errs.into_error_option()
} }
@@ -665,7 +649,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
@@ -802,9 +786,11 @@ 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>(&mut self, cmp: F) -> &mut WalkBuilder pub fn sort_by_file_path<F>(
where &mut self,
F: Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static, cmp: F,
) -> &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
@@ -822,8 +808,7 @@ 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 where F: Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static
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
@@ -1004,11 +989,7 @@ enum WalkEvent {
impl From<WalkDir> for WalkEventIter { impl From<WalkDir> for WalkEventIter {
fn from(it: WalkDir) -> WalkEventIter { fn from(it: WalkDir) -> WalkEventIter {
WalkEventIter { WalkEventIter { depth: 0, it: it.into_iter(), next: None }
depth: 0,
it: it.into_iter(),
next: None,
}
} }
} }
@@ -1091,10 +1072,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>(self, mut mkf: F) pub fn run<F>(
where self,
F: FnMut() -> Box<dyn FnMut(Result<DirEntry, Error>) -> WalkState + Send + 'static>, mut mkf: F,
{ ) 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
@@ -1111,10 +1092,12 @@ 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) = if path == Path::new("-") { let (dent, root_device) =
if path == Path::new("-") {
(DirEntry::new_stdin(), None) (DirEntry::new_stdin(), None)
} else { } else {
let root_device = if !self.same_file_system { let root_device =
if !self.same_file_system {
None None
} else { } else {
match device_num(&path) { match device_num(&path) {
@@ -1129,7 +1112,9 @@ impl WalkParallel {
} }
}; };
match DirEntryRaw::from_path(0, path, false) { match DirEntryRaw::from_path(0, path, false) {
Ok(dent) => (DirEntry::new_raw(dent, None), root_device), Ok(dent) => {
(DirEntry::new_raw(dent, None), root_device)
}
Err(err) => { Err(err) => {
if f(Err(err)).is_quit() { if f(Err(err)).is_quit() {
return; return;
@@ -1142,8 +1127,7 @@ impl WalkParallel {
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.
@@ -1269,7 +1253,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<dyn FnMut(Result<DirEntry, Error>) -> WalkState + Send + 'static>, f: Box<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.
@@ -1335,7 +1319,8 @@ impl Worker {
continue; continue;
} }
}; };
let descend = if let Some(root_device) = work.root_device { let descend =
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,
@@ -1367,7 +1352,12 @@ impl Worker {
continue; continue;
} }
for result in readdir { for result in readdir {
let state = self.run_one(&work.ignore, depth + 1, work.root_device, result); let state = self.run_one(
&work.ignore,
depth + 1,
work.root_device,
result,
);
if state.is_quit() { if state.is_quit() {
self.quit_now(); self.quit_now();
return; return;
@@ -1432,7 +1422,8 @@ impl Worker {
} }
} }
let should_skip_path = should_skip_entry(ig, &dent); let should_skip_path = should_skip_entry(ig, &dent);
let should_skip_filesize = if self.max_filesize.is_some() && !dent.is_dir() { let should_skip_filesize =
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(),
@@ -1443,13 +1434,11 @@ impl Worker {
}; };
if !should_skip_path && !should_skip_filesize { if !should_skip_path && !should_skip_filesize {
self.tx self.tx.send(Message::Work(Work {
.send(Message::Work(Work {
dent: dent, dent: dent,
ignore: ig.clone(), ignore: ig.clone(),
root_device: root_device, root_device: root_device,
})) })).unwrap();
.unwrap();
} }
WalkState::Continue WalkState::Continue
} }
@@ -1579,25 +1568,17 @@ 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) Error::from(err).with_path(child_path).with_depth(child_depth)
.with_path(child_path)
.with_depth(child_depth)
})?; })?;
for ig in ig_parent for ig in ig_parent.parents().take_while(|ig| !ig.is_absolute_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) Error::from(err).with_path(child_path).with_depth(child_depth)
.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(())
@@ -1605,10 +1586,14 @@ 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(max_filesize: u64, path: &Path, ent: &Option<Metadata>) -> bool { fn skip_filesize(
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 {
@@ -1623,7 +1608,10 @@ fn skip_filesize(max_filesize: u64, path: &Path, ent: &Option<Metadata>) -> bool
} }
} }
fn should_skip_entry(ig: &Ignore, dent: &DirEntry) -> bool { fn should_skip_entry(
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);
@@ -1685,27 +1673,28 @@ 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).map_err(|err| Error::Io(err).with_path(path))?; let dent_device = device_num(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::{file, Handle}; use winapi_util::{Handle, file};
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",
@@ -1719,8 +1708,9 @@ 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();
@@ -1767,7 +1757,10 @@ mod tests {
paths paths
} }
fn walk_collect_parallel(prefix: &Path, builder: &WalkBuilder) -> Vec<String> { fn walk_collect_parallel(
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();
@@ -1802,11 +1795,15 @@ mod tests {
paths paths
} }
fn tmpdir() -> TempDir { fn tmpdir(prefix: &str) -> TempDir {
TempDir::new().unwrap() tempfile::Builder::new().prefix(prefix).tempdir().unwrap()
} }
fn assert_paths(prefix: &Path, builder: &WalkBuilder, expected: &[&str]) { fn assert_paths(
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);
@@ -1815,22 +1812,20 @@ mod tests {
#[test] #[test]
fn no_ignores() { fn no_ignores() {
let td = tmpdir(); let td = tmpdir("walk-test-");
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( assert_paths(td.path(), &WalkBuilder::new(td.path()), &[
td.path(), "x", "x/y", "x/y/foo", "a", "a/b", "a/b/foo", "a/b/c",
&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(); let td = tmpdir("walk-test-");
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");
@@ -1846,7 +1841,7 @@ mod tests {
#[test] #[test]
fn custom_ignore_exclusive_use() { fn custom_ignore_exclusive_use() {
let td = tmpdir(); let td = tmpdir("walk-test-");
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");
@@ -1866,7 +1861,7 @@ mod tests {
#[test] #[test]
fn gitignore() { fn gitignore() {
let td = tmpdir(); let td = tmpdir("walk-test-");
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");
@@ -1875,16 +1870,14 @@ 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( assert_paths(td.path(), &WalkBuilder::new(td.path()), &[
td.path(), "bar", "a", "a/bar",
&WalkBuilder::new(td.path()), ]);
&["bar", "a", "a/bar"],
);
} }
#[test] #[test]
fn explicit_ignore() { fn explicit_ignore() {
let td = tmpdir(); let td = tmpdir("walk-test-");
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");
@@ -1900,7 +1893,7 @@ mod tests {
#[test] #[test]
fn explicit_ignore_exclusive_use() { fn explicit_ignore_exclusive_use() {
let td = tmpdir(); let td = tmpdir("walk-test-");
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");
@@ -1912,16 +1905,13 @@ 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( assert_paths(td.path(), &builder,
td.path(), &[".not-an-ignore", "bar", "a", "a/bar"]);
&builder,
&[".not-an-ignore", "bar", "a", "a/bar"],
);
} }
#[test] #[test]
fn gitignore_parent() { fn gitignore_parent() {
let td = tmpdir(); let td = tmpdir("walk-test-");
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");
@@ -1934,7 +1924,7 @@ mod tests {
#[test] #[test]
fn max_depth() { fn max_depth() {
let td = tmpdir(); let td = tmpdir("walk-test-");
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"), "");
@@ -1942,23 +1932,19 @@ 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( assert_paths(td.path(), &builder, &[
td.path(), "a", "a/b", "a/b/c", "foo", "a/foo", "a/b/foo", "a/b/c/foo",
&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( assert_paths(td.path(), builder.max_depth(Some(2)), &[
td.path(), "a", "a/b", "foo", "a/foo",
builder.max_depth(Some(2)), ]);
&["a", "a/b", "foo", "a/foo"],
);
} }
#[test] #[test]
fn max_filesize() { fn max_filesize() {
let td = tmpdir(); let td = tmpdir("walk-test-");
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);
@@ -1968,49 +1954,41 @@ 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( assert_paths(td.path(), &builder, &[
td.path(), "a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz",
&builder, ]);
&["a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz"], assert_paths(td.path(), builder.max_filesize(Some(0)), &[
); "a", "a/b", "foo"
assert_paths( ]);
td.path(), assert_paths(td.path(), builder.max_filesize(Some(500)), &[
builder.max_filesize(Some(0)), "a", "a/b", "foo", "bar", "a/bar", "a/baz"
&["a", "a/b", "foo"], ]);
); assert_paths(td.path(), builder.max_filesize(Some(50000)), &[
assert_paths( "a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz",
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(); let td = tmpdir("walk-test-");
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, &["a", "a/b", "a/b/foo", "z"]); assert_paths(td.path(), &builder, &[
assert_paths( "a", "a/b", "a/b/foo", "z",
td.path(), ]);
&builder.follow_links(true), assert_paths(td.path(), &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(); let td = tmpdir("walk-test-");
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"))
@@ -2021,7 +1999,9 @@ 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(&WalkBuilder::new(td.path().join("foo"))); let dents = walk_collect_entries_parallel(
&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());
} }
@@ -2029,13 +2009,17 @@ 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(); let td = tmpdir("walk-test-");
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, &["a", "a/b", "a/b/c"]); assert_paths(td.path(), &builder, &[
assert_paths(td.path(), &builder.follow_links(true), &["a", "a/b"]); "a", "a/b", "a/b/c",
]);
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
@@ -2055,7 +2039,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(); let td = tmpdir("walk-test-");
if device_num(td.path()).unwrap() == device_num("/sys").unwrap() { if device_num(td.path()).unwrap() == device_num("/sys").unwrap() {
return; return;
} }
@@ -2069,6 +2053,8 @@ 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, &["same_file", "same_file/alink"]); assert_paths(td.path(), &builder, &[
"same_file", "same_file/alink",
]);
} }
} }

View File

@@ -1,14 +1,14 @@
class RipgrepBin < Formula class RipgrepBin < Formula
version '11.0.2' version '11.0.1'
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 "0ba26423691deedf2649b12b1abe3d2be294ee1cb17c40b68fe85efe194f4f57" sha256 "92446c6b28b6c726f91ad66a03bcd533fc6e1a28ef4b44c27bfe2d49a0f88531"
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 "2e7978e346553fbc45c0940d9fa11e12f9afbae8213b261aad19b698150e169a" sha256 "ce74cabac9b39b1ad55837ec01e2c670fa7e965772ac2647b209e31ead19008c"
end end
conflicts_with "ripgrep" conflicts_with "ripgrep"

View File

@@ -571,7 +571,6 @@ 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);
@@ -1219,25 +1218,6 @@ 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!("\
@@ -1995,12 +1975,7 @@ 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. PCRE2 may also have worse user experience in an error message and exiting.
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
@@ -2196,10 +2171,7 @@ 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. In shells such as Bash and zsh, you should wrap the replacement string.
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

@@ -36,6 +36,7 @@ use ignore::{Walk, WalkBuilder, WalkParallel};
use log; use log;
use num_cpus; use num_cpus;
use regex; use regex;
use snafu::{self, ResultExt};
use termcolor::{ use termcolor::{
WriteColor, WriteColor,
BufferWriter, ColorChoice, BufferWriter, ColorChoice,
@@ -43,6 +44,7 @@ use termcolor::{
use crate::app; use crate::app;
use crate::config; use crate::config;
use crate::err::{self, Result};
use crate::logger::Logger; use crate::logger::Logger;
use crate::messages::{set_messages, set_ignore_messages}; use crate::messages::{set_messages, set_ignore_messages};
use crate::path_printer::{PathPrinter, PathPrinterBuilder}; use crate::path_printer::{PathPrinter, PathPrinterBuilder};
@@ -50,7 +52,6 @@ use crate::search::{
PatternMatcher, Printer, SearchWorker, SearchWorkerBuilder, PatternMatcher, Printer, SearchWorker, SearchWorkerBuilder,
}; };
use crate::subject::SubjectBuilder; use crate::subject::SubjectBuilder;
use crate::Result;
/// The command that ripgrep should execute based on the command line /// The command that ripgrep should execute based on the command line
/// configuration. /// configuration.
@@ -141,9 +142,7 @@ impl Args {
set_messages(!early_matches.is_present("no-messages")); set_messages(!early_matches.is_present("no-messages"));
set_ignore_messages(!early_matches.is_present("no-ignore-messages")); set_ignore_messages(!early_matches.is_present("no-ignore-messages"));
if let Err(err) = Logger::init() { Logger::init()?;
return Err(format!("failed to initialize logger: {}", err).into());
}
if early_matches.is_present("trace") { if early_matches.is_present("trace") {
log::set_max_level(log::LevelFilter::Trace); log::set_max_level(log::LevelFilter::Trace);
} else if early_matches.is_present("debug") { } else if early_matches.is_present("debug") {
@@ -422,13 +421,22 @@ impl SortBy {
match self.kind { match self.kind {
SortByKind::None | SortByKind::Path => {} SortByKind::None | SortByKind::Path => {}
SortByKind::LastModified => { SortByKind::LastModified => {
env::current_exe()?.metadata()?.modified()?; env::current_exe()
.and_then(|x| x.metadata())
.and_then(|x| x.modified())
.context(err::UnsupportedSortModified)?;
} }
SortByKind::LastAccessed => { SortByKind::LastAccessed => {
env::current_exe()?.metadata()?.accessed()?; env::current_exe()
.and_then(|x| x.metadata())
.and_then(|x| x.accessed())
.context(err::UnsupportedSortAccess)?;
} }
SortByKind::Created => { SortByKind::Created => {
env::current_exe()?.metadata()?.created()?; env::current_exe()
.and_then(|x| x.metadata())
.and_then(|x| x.created())
.context(err::UnsupportedSortCreation)?;
} }
} }
Ok(()) Ok(())
@@ -611,21 +619,12 @@ impl ArgMatches {
Ok(matcher) => return Ok(PatternMatcher::PCRE2(matcher)), Ok(matcher) => return Ok(PatternMatcher::PCRE2(matcher)),
Err(err) => err, Err(err) => err,
}; };
Err(From::from(format!( err::Hybrid {
"regex could not be compiled with either the default regex \ rust_err: Box::new(rust_err),
engine or with PCRE2.\n\n\ pcre_err: Box::new(pcre_err),
default regex engine error:\n{}\n{}\n{}\n\n\ }.fail()
PCRE2 regex engine error:\n{}",
"~".repeat(79), rust_err, "~".repeat(79), pcre_err,
)))
} else { } else {
let matcher = match self.matcher_rust(patterns) { Ok(PatternMatcher::RustRegex(self.matcher_rust(patterns)?))
Ok(matcher) => matcher,
Err(err) => {
return Err(From::from(suggest_pcre2(err.to_string())));
}
};
Ok(PatternMatcher::RustRegex(matcher))
} }
} }
@@ -635,11 +634,7 @@ impl ArgMatches {
/// then this returns an error. /// then this returns an error.
#[cfg(not(feature = "pcre2"))] #[cfg(not(feature = "pcre2"))]
fn matcher(&self, patterns: &[String]) -> Result<PatternMatcher> { fn matcher(&self, patterns: &[String]) -> Result<PatternMatcher> {
if self.is_present("pcre2") { snafu::ensure!(!self.is_present("pcre2"), err::PCRE2Unavailable);
return Err(From::from(
"PCRE2 is not available in this build of ripgrep",
));
}
let matcher = self.matcher_rust(patterns)?; let matcher = self.matcher_rust(patterns)?;
Ok(PatternMatcher::RustRegex(matcher)) Ok(PatternMatcher::RustRegex(matcher))
} }
@@ -692,10 +687,7 @@ impl ArgMatches {
} else { } else {
builder.build(&patterns.join("|")) builder.build(&patterns.join("|"))
}; };
match res { res.eager_context(err::RustRegex)
Ok(m) => Ok(m),
Err(err) => Err(From::from(suggest_multiline(err.to_string()))),
}
} }
/// Build a matcher using PCRE2. /// Build a matcher using PCRE2.
@@ -737,7 +729,7 @@ impl ArgMatches {
if self.is_present("crlf") { if self.is_present("crlf") {
builder.crlf(true); builder.crlf(true);
} }
Ok(builder.build(&patterns.join("|"))?) Ok(builder.build(&patterns.join("|")).context(err::PCRE2Regex)?)
} }
/// Build a JSON printer that writes results to the given writer. /// Build a JSON printer that writes results to the given writer.
@@ -987,7 +979,7 @@ impl ArgMatches {
// Start with a default set of color specs. // Start with a default set of color specs.
let mut specs = default_color_specs(); let mut specs = default_color_specs();
for spec_str in self.values_of_lossy_vec("colors") { for spec_str in self.values_of_lossy_vec("colors") {
specs.push(spec_str.parse()?); specs.push(spec_str.parse().context(err::InvalidColorSpec)?);
} }
Ok(ColorSpecs::new(&specs)) Ok(ColorSpecs::new(&specs))
} }
@@ -1078,7 +1070,8 @@ impl ArgMatches {
return Ok(EncodingMode::Disabled); return Ok(EncodingMode::Disabled);
} }
Ok(EncodingMode::Some(Encoding::new(&label)?)) let enc = Encoding::new(&label).context(err::SearchConfig)?;
Ok(EncodingMode::Some(enc))
} }
/// Return the file separator to use based on the CLI configuration. /// Return the file separator to use based on the CLI configuration.
@@ -1267,20 +1260,17 @@ 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 cwd = env::current_dir().context(err::CurrentDir)?;
// Make all globs case insensitive with --glob-case-insensitive. let mut builder = OverrideBuilder::new(cwd);
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).context(err::InvalidGlobFlag)?;
} }
// This only enables case insensitivity for subsequent globs. // This only enables case insensitivity for subsequent globs.
builder.case_insensitive(true).unwrap(); builder.case_insensitive(true).unwrap();
for glob in self.values_of_lossy_vec("iglob") { for glob in self.values_of_lossy_vec("iglob") {
builder.add(&glob)?; builder.add(&glob).context(err::InvalidIGlobFlag)?;
} }
Ok(builder.build()?) Ok(builder.build().context(err::GlobBuild)?)
} }
/// Return all file paths that ripgrep should search. /// Return all file paths that ripgrep should search.
@@ -1334,16 +1324,10 @@ impl ArgMatches {
}; };
if sep.is_empty() { if sep.is_empty() {
Ok(None) Ok(None)
} else if sep.len() > 1 {
Err(From::from(format!(
"A path separator must be exactly one byte, but \
the given separator is {} bytes: {}\n\
In some shells on Windows '/' is automatically \
expanded. Use '//' instead.",
sep.len(),
cli::escape(&sep),
)))
} else { } else {
snafu::ensure!(sep.len() == 1, err::InvalidPathSeparator {
separator: sep.clone(),
});
Ok(Some(sep[0])) Ok(Some(sep[0]))
} }
} }
@@ -1390,19 +1374,19 @@ impl ArgMatches {
} }
if let Some(paths) = self.values_of_os("file") { if let Some(paths) = self.values_of_os("file") {
for path in paths { for path in paths {
let some_pats =
if path == "-" { if path == "-" {
pats.extend(cli::patterns_from_stdin()? cli::patterns_from_stdin()
.into_iter() .context(err::ReadManyPatterns)?
.map(|p| self.pattern_from_string(p))
);
} else { } else {
pats.extend(cli::patterns_from_path(path)? cli::patterns_from_path(path)
.into_iter() .context(err::ReadManyPatterns)?
.map(|p| self.pattern_from_string(p)) };
pats.extend(
some_pats.into_iter().map(|p| self.pattern_from_string(p))
); );
} }
} }
}
Ok(pats) Ok(pats)
} }
@@ -1421,7 +1405,7 @@ impl ArgMatches {
/// ///
/// If the pattern is not valid UTF-8, then an error is returned. /// If the pattern is not valid UTF-8, then an error is returned.
fn pattern_from_os_str(&self, pat: &OsStr) -> Result<String> { fn pattern_from_os_str(&self, pat: &OsStr) -> Result<String> {
let s = cli::pattern_from_os(pat)?; let s = cli::pattern_from_os(pat).context(err::ReadOSPattern)?;
Ok(self.pattern_from_str(s)) Ok(self.pattern_from_str(s))
} }
@@ -1479,11 +1463,12 @@ impl ArgMatches {
/// flag. If no --pre-globs are available, then this always returns an /// flag. If no --pre-globs are available, then this always returns an
/// empty set of globs. /// empty set of globs.
fn preprocessor_globs(&self) -> Result<Override> { fn preprocessor_globs(&self) -> Result<Override> {
let mut builder = OverrideBuilder::new(env::current_dir()?); let cwd = env::current_dir().context(err::CurrentDir)?;
let mut builder = OverrideBuilder::new(cwd);
for glob in self.values_of_lossy_vec("pre-glob") { for glob in self.values_of_lossy_vec("pre-glob") {
builder.add(&glob)?; builder.add(&glob).context(err::InvalidPreGlob)?;
} }
Ok(builder.build()?) Ok(builder.build().context(err::PreGlobBuild)?)
} }
/// Parse the regex-size-limit argument option into a byte count. /// Parse the regex-size-limit argument option into a byte count.
@@ -1565,7 +1550,7 @@ impl ArgMatches {
builder.clear(&ty); builder.clear(&ty);
} }
for def in self.values_of_lossy_vec("type-add") { for def in self.values_of_lossy_vec("type-add") {
builder.add_def(&def)?; builder.add_def(&def).context(err::InvalidTypeDefinition)?;
} }
for ty in self.values_of_lossy_vec("type") { for ty in self.values_of_lossy_vec("type") {
builder.select(&ty); builder.select(&ty);
@@ -1573,7 +1558,7 @@ impl ArgMatches {
for ty in self.values_of_lossy_vec("type-not") { for ty in self.values_of_lossy_vec("type-not") {
builder.negate(&ty); builder.negate(&ty);
} }
builder.build().map_err(From::from) builder.build().eager_context(err::TypeDefinitionBuild)
} }
/// Returns the number of times the `unrestricted` flag is provided. /// Returns the number of times the `unrestricted` flag is provided.
@@ -1594,11 +1579,10 @@ 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 != path_stdin && p.is_dir()) || paths.get(0).map_or(false, |p| p.is_dir())
} }
} }
} }
@@ -1633,7 +1617,11 @@ impl ArgMatches {
fn usize_of(&self, name: &str) -> Result<Option<usize>> { fn usize_of(&self, name: &str) -> Result<Option<usize>> {
match self.value_of_lossy(name) { match self.value_of_lossy(name) {
None => Ok(None), None => Ok(None),
Some(v) => v.parse().map(Some).map_err(From::from), Some(v) => {
v.parse()
.map(Some)
.eager_context(err::InvalidNumber { flag: name.to_string() })
}
} }
} }
@@ -1641,15 +1629,17 @@ impl ArgMatches {
/// ///
/// If the aforementioned format is not recognized, then this returns an /// If the aforementioned format is not recognized, then this returns an
/// error. /// error.
fn parse_human_readable_size( fn parse_human_readable_size(&self, name: &str) -> Result<Option<u64>> {
&self, match self.value_of_lossy(name) {
arg_name: &str, None => Ok(None),
) -> Result<Option<u64>> { Some(size) => {
let size = match self.value_of_lossy(arg_name) { cli::parse_human_readable_size(&size)
None => return Ok(None), .map(Some)
Some(size) => size, .eager_context(err::InvalidHumanSize {
}; flag: name.to_string()
Ok(Some(cli::parse_human_readable_size(&size)?)) })
}
}
} }
} }
@@ -1683,32 +1673,6 @@ impl ArgMatches {
} }
} }
/// Inspect an error resulting from building a Rust regex matcher, and if it's
/// believed to correspond to a syntax error that PCRE2 could handle, then
/// add a message to suggest the use of -P/--pcre2.
#[cfg(feature = "pcre2")]
fn suggest_pcre2(msg: String) -> String {
if !msg.contains("backreferences") && !msg.contains("look-around") {
msg
} else {
format!("{}
Consider enabling PCRE2 with the --pcre2 flag, which can handle backreferences
and look-around.", msg)
}
}
fn suggest_multiline(msg: String) -> String {
if msg.contains("the literal") && msg.contains("not allowed") {
format!("{}
Consider enabling multiline mode with the --multiline flag (or -U for short).
When multiline mode is enabled, new line characters can be matched.", msg)
} else {
msg
}
}
/// Convert the result of parsing a human readable file size to a `usize`, /// Convert the result of parsing a human readable file size to a `usize`,
/// failing if the type does not fit. /// failing if the type does not fit.
fn u64_to_usize( fn u64_to_usize(
@@ -1721,11 +1685,14 @@ fn u64_to_usize(
None => return Ok(None), None => return Ok(None),
Some(value) => value, Some(value) => value,
}; };
if value <= usize::MAX as u64 { snafu::ensure!(
Ok(Some(value as usize)) value <= usize::MAX as u64,
} else { err::NumberTooBig {
Err(From::from(format!("number too large for {}", arg_name))) flag: arg_name.to_string(),
limit: usize::MAX as u64,
} }
);
Ok(Some(value as usize))
} }
/// Builds a comparator for sorting two files according to a system time /// Builds a comparator for sorting two files according to a system time
@@ -1773,7 +1740,7 @@ where I: IntoIterator<Item=T>,
Err(err) => err, Err(err) => err,
}; };
if err.use_stderr() { if err.use_stderr() {
return Err(err.into()); return Err(snafu::Context { error: err, context: err::Clap }.into());
} }
// Explicitly ignore any error returned by write!. The most likely error // Explicitly ignore any error returned by write!. The most likely error
// at this point is a broken pipe error, in which case, we want to ignore // at this point is a broken pipe error, in which case, we want to ignore

View File

@@ -3,16 +3,16 @@
// argument corresponds precisely to one shell argument. // argument corresponds precisely to one shell argument.
use std::env; use std::env;
use std::error::Error;
use std::fs::File; use std::fs::File;
use std::io; 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, ByteSlice}; use bstr::io::BufReadExt;
use log; use log;
use snafu::{self, ResultExt};
use crate::Result; use crate::err::{self, Error, Result};
/// Return a sequence of arguments derived from ripgrep rc configuration files. /// Return a sequence of arguments derived from ripgrep rc configuration files.
pub fn args() -> Vec<OsString> { pub fn args() -> Vec<OsString> {
@@ -55,12 +55,11 @@ 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<dyn Error>>)> { ) -> Result<(Vec<OsString>, Vec<Error>)> {
let path = path.as_ref(); let path = path.as_ref();
match File::open(&path) { let file = File::open(&path).context(err::ConfigIO { path })?;
Ok(file) => parse_reader(file), let res = parse_reader(file).context(err::ConfigIO { path })?;
Err(err) => Err(From::from(format!("{}: {}", path.display(), err))), Ok(res)
}
} }
/// Parse a single ripgrep rc file from the given reader. /// Parse a single ripgrep rc file from the given reader.
@@ -76,10 +75,10 @@ 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<dyn Error>>)> { ) -> io::Result<(Vec<OsString>, Vec<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 = 0u64;
bufrdr.for_byte_line_with_terminator(|line| { bufrdr.for_byte_line_with_terminator(|line| {
line_number += 1; line_number += 1;
@@ -92,7 +91,11 @@ fn parse_reader<R: io::Read>(
args.push(osstr.to_os_string()); args.push(osstr.to_os_string());
} }
Err(err) => { Err(err) => {
errs.push(format!("{}: {}", line_number, err).into()); let ctx = snafu::Context {
error: err,
context: err::ConfigInvalidUTF8 { line_number },
};
errs.push(ctx.into());
} }
} }
Ok(true) Ok(true)

250
src/err.rs Normal file
View File

@@ -0,0 +1,250 @@
use std::io;
use std::path::{Path, PathBuf};
use std::result;
use snafu::{Backtrace, Context, Snafu};
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum Error {
#[snafu(display("I/O error: {}", source))]
IO {
backtrace: Backtrace,
source: io::Error,
},
#[snafu(display(
"failed to retrieve current working directory: {}", source,
))]
CurrentDir {
backtrace: Backtrace,
source: io::Error,
},
#[snafu(display("sorting by modified time is unsupported: {}", source))]
UnsupportedSortModified {
backtrace: Backtrace,
source: io::Error,
},
#[snafu(display("sorting by access time is unsupported: {}", source))]
UnsupportedSortAccess {
backtrace: Backtrace,
source: io::Error,
},
#[snafu(display("sorting by creation time is unsupported: {}", source))]
UnsupportedSortCreation {
backtrace: Backtrace,
source: io::Error,
},
#[snafu(display(
"I/O error parsing config in {}: {}",
path.display(),
source,
))]
ConfigIO {
backtrace: Backtrace,
source: io::Error,
path: PathBuf,
},
#[snafu(display(
"config parse error on line {}: {}",
line_number,
source,
))]
ConfigInvalidUTF8 {
backtrace: Backtrace,
source: bstr::Utf8Error,
line_number: u64,
},
#[snafu(display("failed to initialize logger: {}", source))]
LoggerInit {
backtrace: Backtrace,
source: log::SetLoggerError,
},
#[snafu(display("{}", source))]
Clap {
backtrace: Backtrace,
source: clap::Error,
},
#[snafu(display("{}", source))]
ReadManyPatterns {
backtrace: Backtrace,
source: io::Error,
},
#[snafu(display("{}", source))]
ReadOSPattern {
backtrace: Backtrace,
source: grep::cli::InvalidPatternError,
},
#[snafu(display(
"A path separator must be exactly one byte, but \
the given separator is {} bytes: {}\n\
In some shells on Windows '/' is automatically \
expanded. Use '//' instead.",
separator.len(), grep::cli::escape(&separator),
))]
InvalidPathSeparator {
backtrace: Backtrace,
separator: Vec<u8>,
},
#[snafu(display("error parsing -g/--glob: {}", source))]
InvalidGlobFlag {
backtrace: Backtrace,
source: ignore::Error,
},
#[snafu(display("error parsing --iglob: {}", source))]
InvalidIGlobFlag {
backtrace: Backtrace,
source: ignore::Error,
},
#[snafu(display("error building --glob matcher: {}", source))]
GlobBuild {
backtrace: Backtrace,
source: ignore::Error,
},
#[snafu(display("error parsing --pre-glob: {}", source))]
InvalidPreGlob {
backtrace: Backtrace,
source: ignore::Error,
},
#[snafu(display("error building --pre-glob matcher: {}", source))]
PreGlobBuild {
backtrace: Backtrace,
source: ignore::Error,
},
#[snafu(display("error parsing --type-add value: {}", source))]
InvalidTypeDefinition {
backtrace: Backtrace,
source: ignore::Error,
},
#[snafu(display("error building type matcher: {}", source))]
TypeDefinitionBuild {
backtrace: Backtrace,
source: ignore::Error,
},
#[snafu(display("failed to parse {} value as a number: {}", flag, source))]
InvalidNumber {
backtrace: Backtrace,
source: std::num::ParseIntError,
flag: String,
},
#[snafu(display(
"failed to parse {} value as a file size: {}", flag, source,
))]
InvalidHumanSize {
backtrace: Backtrace,
source: grep::cli::ParseSizeError,
flag: String,
},
#[snafu(display(
"number given to {} is too large (limit is {})",
flag, limit,
))]
NumberTooBig {
backtrace: Backtrace,
flag: String,
limit: u64,
},
#[snafu(display("{}", source))]
SearchConfig {
backtrace: Backtrace,
source: grep::searcher::ConfigError,
},
#[snafu(display("invalid --colors spec: {}", source))]
InvalidColorSpec {
backtrace: Backtrace,
source: grep::printer::ColorError,
},
#[snafu(display("{}", suggest(source)))]
RustRegex {
backtrace: Backtrace,
source: grep::regex::Error,
},
#[snafu(display(
"regex could not be compiled with either the default regex \
engine or with PCRE2.\n\n\
default regex engine error:\n{}\n{}\n{}\n\n\
PCRE2 regex engine error:\n{}",
"~".repeat(79),
rust_err,
"~".repeat(79),
pcre_err,
))]
Hybrid {
backtrace: Backtrace,
rust_err: Box<Error>,
pcre_err: Box<Error>,
},
#[snafu(display("failed to write type definitions to stdout: {}", source))]
WriteTypes {
backtrace: Backtrace,
source: io::Error,
},
#[cfg(feature = "pcre2")]
#[snafu(display("{}", suggest(source)))]
PCRE2Regex {
backtrace: Backtrace,
source: grep::pcre2::Error,
},
#[snafu(display("PCRE2 is not available in this build of ripgrep"))]
PCRE2Unavailable {
backtrace: Backtrace,
},
#[snafu(display("failed to write PCRE2 version to stdout: {}", source))]
PCRE2Version {
backtrace: Backtrace,
source: io::Error,
},
}
impl Error {
/// Return true if and only if this corresponds to an I/O error generated
/// by a broken pipe.
pub fn is_broken_pipe(&self) -> bool {
self.io_err().map_or(false, |e| e.kind() == io::ErrorKind::BrokenPipe)
}
/// Return a reference to this error's underlying I/O error, if one exists.
pub fn io_err(&self) -> Option<&io::Error> {
match *self {
Error::IO { ref source, .. } => Some(source),
Error::CurrentDir { ref source, .. } => Some(source),
Error::UnsupportedSortModified { ref source, .. } => Some(source),
Error::UnsupportedSortAccess { ref source, .. } => Some(source),
Error::UnsupportedSortCreation { ref source, .. } => Some(source),
Error::ConfigIO { ref source, .. } => Some(source),
Error::ReadManyPatterns { ref source, .. } => Some(source),
Error::WriteTypes { ref source, .. } => Some(source),
Error::PCRE2Version { ref source, .. } => Some(source),
_ => None,
}
}
}
/// Inspect an error's display string and look for potentially suggestions
/// to give to an end user.
///
/// These include:
///
/// 1. If the error results from the use of a new line literal, then return a
/// new message suggesting the use of the -U/--multiline flag.
/// 2. If the error correspond to a syntax error that PCRE2 could handle, then
/// add a message to suggest the use of -P/--pcre2.
fn suggest<E: std::error::Error>(err: &E) -> String {
let msg = err.to_string();
if msg.contains("the literal") && msg.contains("not allowed") {
format!("{}
Consider enabling multiline mode with the --multiline flag (or -U for short).
When multiline mode is enabled, new line characters can be matched.", msg)
} else if cfg!(feature = "pcre2") &&
(msg.contains("backreferences") || msg.contains("look-around"))
{
format!("{}
Consider enabling PCRE2 with the --pcre2 flag, which can handle backreferences
and look-around.", msg)
} else {
msg
}
}

View File

@@ -4,6 +4,9 @@
// for this functionality. // for this functionality.
use log::{self, Log}; use log::{self, Log};
use snafu::ResultExt;
use crate::err::{self, Result};
/// The simplest possible logger that logs to stderr. /// The simplest possible logger that logs to stderr.
/// ///
@@ -18,8 +21,8 @@ impl Logger {
/// Create a new logger that logs to stderr and initialize it as the /// Create a new logger that logs to stderr and initialize it as the
/// global logger. If there was a problem setting the logger, then an /// global logger. If there was a problem setting the logger, then an
/// error is returned. /// error is returned.
pub fn init() -> Result<(), log::SetLoggerError> { pub fn init() -> Result<()> {
log::set_logger(LOGGER) log::set_logger(LOGGER).eager_context(err::LoggerInit)
} }
} }

View File

@@ -1,12 +1,15 @@
use std::error; #![allow(warnings)]
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};
use std::time::Instant; use std::time::Instant;
use ignore::WalkState; use ignore::WalkState;
use snafu::ResultExt;
use args::Args; use args::Args;
use err::Result;
use subject::Subject; use subject::Subject;
#[macro_use] #[macro_use]
@@ -15,6 +18,7 @@ mod messages;
mod app; mod app;
mod args; mod args;
mod config; mod config;
mod err;
mod logger; mod logger;
mod path_printer; mod path_printer;
mod search; mod search;
@@ -43,7 +47,8 @@ mod subject;
#[global_allocator] #[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
type Result<T> = ::std::result::Result<T, Box<dyn error::Error>>; // type Result<T> = ::std::result::Result<T, Box<::std::error::Error>>;
// type Result<T> =
fn main() { fn main() {
if let Err(err) = Args::parse().and_then(try_main) { if let Err(err) = Args::parse().and_then(try_main) {
@@ -214,12 +219,12 @@ fn files(args: &Args) -> Result<bool> {
} }
if let Err(err) = path_printer.write_path(subject.path()) { if let Err(err) = path_printer.write_path(subject.path()) {
// A broken pipe means graceful termination. // A broken pipe means graceful termination.
if err.kind() == io::ErrorKind::BrokenPipe { if err.is_broken_pipe() {
break; break;
} }
// Otherwise, we have some other error that's preventing us from // Otherwise, we have some other error that's preventing us from
// writing to stdout, so we should bubble it up. // writing to stdout, so we should bubble it up.
return Err(err.into()); return Err(err);
} }
} }
Ok(matched) Ok(matched)
@@ -240,7 +245,7 @@ fn files_parallel(args: &Args) -> Result<bool> {
let matched = Arc::new(AtomicBool::new(false)); let matched = Arc::new(AtomicBool::new(false));
let (tx, rx) = mpsc::channel::<Subject>(); let (tx, rx) = mpsc::channel::<Subject>();
let print_thread = thread::spawn(move || -> io::Result<()> { let print_thread = thread::spawn(move || -> Result<()> {
for subject in rx.iter() { for subject in rx.iter() {
path_printer.write_path(subject.path())?; path_printer.write_path(subject.path())?;
} }
@@ -272,8 +277,8 @@ fn files_parallel(args: &Args) -> Result<bool> {
// A broken pipe means graceful termination, so fall through. // A broken pipe means graceful termination, so fall through.
// Otherwise, something bad happened while writing to stdout, so bubble // Otherwise, something bad happened while writing to stdout, so bubble
// it up. // it up.
if err.kind() != io::ErrorKind::BrokenPipe { if !err.is_broken_pipe() {
return Err(err.into()); return Err(err);
} }
} }
Ok(matched.load(SeqCst)) Ok(matched.load(SeqCst))
@@ -281,22 +286,29 @@ fn files_parallel(args: &Args) -> Result<bool> {
/// The top-level entry point for --type-list. /// The top-level entry point for --type-list.
fn types(args: &Args) -> Result<bool> { fn types(args: &Args) -> Result<bool> {
write_types(args.stdout(), &args.type_defs()?)
.eager_context(err::WriteTypes)
}
fn write_types<W: io::Write>(
mut wtr: W,
defs: &[ignore::types::FileTypeDef],
) -> io::Result<bool> {
let mut count = 0; let mut count = 0;
let mut stdout = args.stdout(); for def in defs {
for def in args.type_defs()? {
count += 1; count += 1;
stdout.write_all(def.name().as_bytes())?; wtr.write_all(def.name().as_bytes())?;
stdout.write_all(b": ")?; wtr.write_all(b": ")?;
let mut first = true; let mut first = true;
for glob in def.globs() { for glob in def.globs() {
if !first { if !first {
stdout.write_all(b", ")?; wtr.write_all(b", ")?;
} }
stdout.write_all(glob.as_bytes())?; wtr.write_all(glob.as_bytes())?;
first = false; first = false;
} }
stdout.write_all(b"\n")?; wtr.write_all(b"\n")?;
} }
Ok(count > 0) Ok(count > 0)
} }
@@ -304,7 +316,7 @@ fn types(args: &Args) -> Result<bool> {
/// The top-level entry point for --pcre2-version. /// The top-level entry point for --pcre2-version.
fn pcre2_version(args: &Args) -> Result<bool> { fn pcre2_version(args: &Args) -> Result<bool> {
#[cfg(feature = "pcre2")] #[cfg(feature = "pcre2")]
fn imp(args: &Args) -> Result<bool> { fn imp(args: &Args) -> io::Result<bool> {
use grep::pcre2; use grep::pcre2;
let mut stdout = args.stdout(); let mut stdout = args.stdout();
@@ -319,11 +331,11 @@ fn pcre2_version(args: &Args) -> Result<bool> {
} }
#[cfg(not(feature = "pcre2"))] #[cfg(not(feature = "pcre2"))]
fn imp(args: &Args) -> Result<bool> { fn imp(args: &Args) -> io::Result<bool> {
let mut stdout = args.stdout(); let mut stdout = args.stdout();
writeln!(stdout, "PCRE2 is not available in this build of ripgrep.")?; writeln!(stdout, "PCRE2 is not available in this build of ripgrep.")?;
Ok(false) Ok(false)
} }
imp(args) imp(args).eager_context(err::PCRE2Version)
} }

View File

@@ -2,8 +2,11 @@ use std::io;
use std::path::Path; use std::path::Path;
use grep::printer::{ColorSpecs, PrinterPath}; use grep::printer::{ColorSpecs, PrinterPath};
use snafu::ResultExt;
use termcolor::WriteColor; use termcolor::WriteColor;
use crate::err::{self, Result};
/// A configuration for describing how paths should be written. /// A configuration for describing how paths should be written.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct Config { struct Config {
@@ -87,7 +90,11 @@ pub struct PathPrinter<W> {
impl<W: WriteColor> PathPrinter<W> { impl<W: WriteColor> PathPrinter<W> {
/// Write the given path to the underlying writer. /// Write the given path to the underlying writer.
pub fn write_path(&mut self, path: &Path) -> io::Result<()> { pub fn write_path(&mut self, path: &Path) -> Result<()> {
self.write(path).eager_context(err::IO)
}
fn write(&mut self, path: &Path) -> io::Result<()> {
let ppath = PrinterPath::with_separator(path, self.config.separator); let ppath = PrinterPath::with_separator(path, self.config.separator);
if !self.wtr.supports_color() { if !self.wtr.supports_color() {
self.wtr.write_all(ppath.as_bytes())?; self.wtr.write_all(ppath.as_bytes())?;

View File

@@ -315,24 +315,7 @@ 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> {
let bin = self.search_impl(subject)
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.
@@ -358,6 +341,30 @@ 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 {
@@ -385,23 +392,11 @@ impl<W: WriteColor> SearchWorker<W> {
&mut self, &mut self,
path: &Path, path: &Path,
) -> io::Result<SearchResult> { ) -> io::Result<SearchResult> {
let bin = self.config.preprocessor.as_ref().unwrap(); let bin = self.config.preprocessor.clone().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 let rdr = self.command_builder.build(&mut cmd)?;
.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,

2
termcolor/README.md Normal file
View File

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

View File

@@ -341,14 +341,6 @@ 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

@@ -392,8 +392,8 @@ rgtest!(r428_unrecognized_style, |_: Dir, mut cmd: TestCommand| {
let output = cmd.cmd().output().unwrap(); let output = cmd.cmd().output().unwrap();
let stderr = String::from_utf8_lossy(&output.stderr); let stderr = String::from_utf8_lossy(&output.stderr);
let expected = "\ let expected = "\
unrecognized style attribute ''. Choose from: nobold, bold, nointense, \ invalid --colors spec: unrecognized style attribute ''. \
intense, nounderline, underline. Choose from: nobold, bold, nointense, intense, nounderline, underline.
"; ";
eqnice!(expected, stderr); eqnice!(expected, stderr);
}); });
@@ -706,18 +706,6 @@ rgtest!(r1203_reverse_suffix_literal, |dir: Dir, _: TestCommand| {
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 // See: https://github.com/BurntSushi/ripgrep/issues/1259
rgtest!(r1259_drop_last_byte_nonl, |dir: Dir, mut cmd: TestCommand| { rgtest!(r1259_drop_last_byte_nonl, |dir: Dir, mut cmd: TestCommand| {
dir.create("patterns-nonl", "[foo]"); dir.create("patterns-nonl", "[foo]");
@@ -728,13 +716,3 @@ rgtest!(r1259_drop_last_byte_nonl, |dir: Dir, mut cmd: TestCommand| {
cmd = dir.command(); cmd = dir.command();
eqnice!("fz\n", cmd.arg("-f").arg("patterns-nl").arg("test").stdout()); 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()
);
});

2
wincolor/README.md Normal file
View File

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