diff --git a/.travis.yml b/.travis.yml index d47249a03..a99407cc5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,13 +62,13 @@ matrix: # Minimum Rust supported channel. We enable these to make sure ripgrep # continues to work on the advertised minimum Rust version. - os: linux - rust: 1.23.0 + rust: 1.28.0 env: TARGET=x86_64-unknown-linux-gnu - os: linux - rust: 1.23.0 + rust: 1.28.0 env: TARGET=x86_64-unknown-linux-musl - os: linux - rust: 1.23.0 + rust: 1.28.0 env: TARGET=arm-unknown-linux-gnueabihf GCC_VERSION=4.8 addons: apt: diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ebe1bb36..f4885e54d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ format. **BREAKING CHANGES**: +* The minimum version required to compile Rust has now changed to track the + latest stable version of Rust. Patch releases will continue to compile with + the same version of Rust as the previous patch release, but new minor + versions will use the current stable version of the Rust compile as its + minimum supported version. * The match semantics of `-w/--word-regexp` have changed slightly. They used to be `\b(?:)\b`, but now it's `(?:^|\W)(?:)(?:$|\W)`. @@ -53,12 +58,16 @@ Bug fixes: Matching empty lines now works correctly in several corner cases. * [BUG #764](https://github.com/BurntSushi/ripgrep/issues/764): Color escape sequences now coalesce, which reduces output size. +* [BUG #842](https://github.com/BurntSushi/ripgrep/issues/842): + Add man page to binary Debian package. * [BUG #922](https://github.com/BurntSushi/ripgrep/issues/922): ripgrep is now more robust with respect to memory maps failing. * [BUG #937](https://github.com/BurntSushi/ripgrep/issues/937): Color escape sequences are no longer emitted for empty matches. * [BUG #940](https://github.com/BurntSushi/ripgrep/issues/940): Context from the `--passthru` flag should not impact process exit status. +* [BUG #984](https://github.com/BurntSushi/ripgrep/issues/984): + Fixes bug in `ignore` crate where first path was always treated as a symlink. * [BUG #1013](https://github.com/BurntSushi/ripgrep/issues/1013): Add compile time and runtime CPU features to `--version` output. diff --git a/Cargo.lock b/Cargo.lock index 7368d2633..c64a6adf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,14 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arrayvec" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "atty" version = "0.2.11" @@ -35,7 +43,7 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -53,7 +61,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -68,15 +76,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.10.0 (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 = "crossbeam" -version = "0.3.2" +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]] +name = "crossbeam-channel" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -106,7 +147,7 @@ name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -143,7 +184,7 @@ dependencies = [ "grep-regex 0.1.0", "grep-searcher 0.1.0", "termcolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -170,8 +211,8 @@ dependencies = [ "grep-matcher 0.1.0", "grep-regex 0.1.0", "grep-searcher 0.1.0", - "serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.72 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.72 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -207,7 +248,7 @@ dependencies = [ name = "ignore" version = "0.4.3" dependencies = [ - "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "globset 0.4.1", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -216,7 +257,7 @@ dependencies = [ "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (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.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -238,6 +279,15 @@ name = "libc" version = "0.2.43" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lock_api" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.4" @@ -263,6 +313,16 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memoffset" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nodrop" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "num_cpus" version = "1.8.0" @@ -271,12 +331,40 @@ dependencies = [ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "owning_ref" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pcre2" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "pcre2-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -288,7 +376,7 @@ name = "pcre2-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -324,6 +412,23 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.5.5" +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-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "redox_syscall" version = "0.1.40" @@ -379,8 +484,8 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.72 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.72 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -404,19 +509,24 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "scopeguard" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -426,7 +536,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.72 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -434,6 +544,19 @@ name = "simd" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stable_deref_trait" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "strsim" version = "0.7.0" @@ -441,7 +564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.14.8" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -507,6 +630,14 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "utf8-ranges" version = "1.0.0" @@ -517,9 +648,14 @@ name = "version_check" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "walkdir" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -556,15 +692,19 @@ dependencies = [ [metadata] "checksum aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c6d463cbe7ed28720b5b489e7c083eeb8f90d08be2a0d6bb9e1ffea9ce1afa" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "85415d2594767338a74a30c1d370b2f3262ec1b4ed2d7bba5b3faf4de40467d9" -"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f861d9ce359f56dbcb6e0c2a1cb84e52ad732cadb57b806adeb3c7668caccbd8" "checksum byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8389c509ec62b9fe8eca58c502a0acaf017737355615243496cde4994f8fa4f9" -"checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275" +"checksum cc 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "850d5f0c639adf4715b8cdf0272db2a4f1da26135b180e1f94bac592a8fc8e6d" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" -"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6c0a94250b0278d7fc5a894c3d276b11ea164edc8bf8feb10ca1ea517b44a649" +"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" +"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum encoding_rs 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2a91912d6f37c6a8fef8a2316a862542d036f13c923ad518b5aca7bcaac7544c" "checksum encoding_rs_io 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f222ff554d6e172f3569a2d7d0fd8061d54215984ef67b24ce031c1fcbf2c9b3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" @@ -574,16 +714,24 @@ dependencies = [ "checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" "checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" +"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" "checksum log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cba860f648db8e6f269df990180c2217f333472b4a6e901e97446858487971e2" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" +"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" +"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" +"checksum parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69376b761943787ebd5cc85a5bc95958651a22609c5c1c2b65de21786baec72b" +"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" "checksum pcre2 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c16ec0e30c17f938a2da8ff970ad9a4100166d0538898dcc035b55c393cab54" "checksum pcre2-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a9027f9474e4e13d3b965538aafcaebe48c803488ad76b3c97ef061a8324695f" "checksum pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "104630aa1c83213cbc76db0703630fcb0421dac3585063be4ce9a8a2feeaa745" "checksum proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ee5697238f0d893c7f0ecc59c0999f18d2af85e424de441178bcacc9f9e6cf67" "checksum quote 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ed7d650913520df631972f21e104a4fa2f9c82a14afc65d17b388a2e29731e7c" "checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" +"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" +"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5bbbea44c5490a1e84357ff28b7d518b4619a159fed5d25f6c1de2d19cc42814" @@ -592,12 +740,15 @@ dependencies = [ "checksum ryu 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0568787116e13c652377b6846f5931454a363a8fdf8ae50463ee40935b278b" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" -"checksum serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)" = "6dfad05c8854584e5f72fb859385ecdfa03af69c3fd0572f0da2d4c95f060bdb" -"checksum serde_derive 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)" = "b719c6d5e9f73fbc37892246d5852333f040caa617b8873c6aced84bcb28e7bb" +"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum serde 1.0.72 (registry+https://github.com/rust-lang/crates.io-index)" = "98b72cb11d2f90a50789254281aac9211092fd1ba87e067b45c94652fffe1cf1" +"checksum serde_derive 1.0.72 (registry+https://github.com/rust-lang/crates.io-index)" = "ccb40724ad173e215530b5217ffba55cdf34ef811e90023a43c948c5b04dc41f" "checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae" "checksum simd 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3686dd9418ebcc3a26a0c0ae56deab0681e53fe899af91f5bbcee667ebffb1" +"checksum smallvec 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "211a489e65e94b103926d2054ae515a1cdb5d515ea0ef414fee23b7e043ce748" +"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum syn 0.14.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b7bfcbb0c068d0f642a0ffbd5c604965a360a61f99e8add013cef23a838614f3" +"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum termcolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "722426c4a0539da2c4ffd9b419d90ad540b4cff4a053be9069c908d4d07e2836" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" @@ -606,9 +757,11 @@ dependencies = [ "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" -"checksum walkdir 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1b768ba943161a9226ccd59b26bcd901e5d60e6061f4fcad3034784e0c7372b" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum walkdir 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "99363cca565f12a1a4bfb0cd5b966afb2989117ce9f1c18add0ecbb87f46718c" "checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 208a07b55..48296bdc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,3 +84,25 @@ pcre2 = ["grep/pcre2"] [profile.release] debug = 1 + +[package.metadata.deb] +features = ["pcre2"] +assets = [ + ["target/release/rg", "usr/bin/", "755"], + ["COPYING", "usr/share/doc/ripgrep/", "644"], + ["LICENSE-MIT", "usr/share/doc/ripgrep/", "644"], + ["UNLICENSE", "usr/share/doc/ripgrep/", "644"], + ["CHANGELOG.md", "usr/share/doc/ripgrep/CHANGELOG", "644"], + ["README.md", "usr/share/doc/ripgrep/README", "644"], + ["FAQ.md", "usr/share/doc/ripgrep/FAQ", "644"], + # The man page is automatically generated by ripgrep's build process, so + # this file isn't actually commited. Instead, to create a dpkg, either + # create a deployment directory and copy the man page to it, or use the + # 'ci/build_deb.sh' script. + ["deployment/rg.1", "usr/share/man/man1/rg.1", "644"], +] +extended-description = """\ +ripgrep (rg) recursively searches your current directory for a regex pattern. +By default, ripgrep will respect your .gitignore and automatically skip hidden +files/directories and binary files. +""" diff --git a/README.md b/README.md index 351de3897..5544ec31f 100644 --- a/README.md +++ b/README.md @@ -292,7 +292,7 @@ $ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/0.9.0/ripgrep $ sudo dpkg -i ripgrep_0.9.0_amd64.deb ``` -If you run Debian Buster (currently Debian testing) 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). ``` $ sudo apt-get install ripgrep @@ -326,7 +326,7 @@ If you're a **NetBSD** user, then you can install ripgrep from If you're a **Rust programmer**, ripgrep can be installed with `cargo`. -* Note that the minimum supported version of Rust for ripgrep is **1.23.0**, +* Note that the minimum supported version of Rust for ripgrep is **1.28.0**, although ripgrep may work with older versions. * Note that the binary may be bigger than expected because it contains debug symbols. This is intentional. To remove debug symbols and therefore reduce @@ -347,7 +347,10 @@ ripgrep isn't currently in any other package repositories. ripgrep is written in Rust, so you'll need to grab a [Rust installation](https://www.rust-lang.org/) in order to compile it. -ripgrep compiles with Rust 1.23.0 (stable) or newer. Building is easy: +ripgrep compiles with Rust 1.28.0 (stable) or newer. In general, ripgrep tracks +the latest stable release of the Rust compiler. + +To build ripgrep: ``` $ git clone https://github.com/BurntSushi/ripgrep diff --git a/build.rs b/build.rs index 638f76468..b7f26f17c 100644 --- a/build.rs +++ b/build.rs @@ -4,7 +4,6 @@ extern crate clap; extern crate lazy_static; use std::env; -use std::ffi::OsString; use std::fs::{self, File}; use std::io::{self, Read, Write}; use std::path::Path; @@ -19,22 +18,6 @@ use app::{RGArg, RGArgKind}; mod app; fn main() { - // If our version of Rust has runtime SIMD detection, then set a cfg so - // we know we can test for it. We use this when generating ripgrep's - // --version output. - let version = rustc_version(); - let parsed = match Version::parse(&version) { - Ok(parsed) => parsed, - Err(err) => { - eprintln!("failed to parse `rustc --version`: {}", err); - return; - } - }; - let minimum = Version { major: 1, minor: 27, patch: 0 }; - if version.contains("nightly") || parsed >= minimum { - println!("cargo:rustc-cfg=ripgrep_runtime_cpu"); - } - // OUT_DIR is set by Cargo and it's where any additional build artifacts // are written. let outdir = match env::var_os("OUT_DIR") { @@ -199,63 +182,3 @@ fn formatted_doc_txt(arg: &RGArg) -> io::Result { fn ioerr(msg: String) -> io::Error { io::Error::new(io::ErrorKind::Other, msg) } - -fn rustc_version() -> String { - let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc")); - let output = process::Command::new(&rustc) - .arg("--version") - .output() - .unwrap() - .stdout; - String::from_utf8(output).unwrap() -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] -struct Version { - major: u32, - minor: u32, - patch: u32, -} - -impl Version { - fn parse(mut s: &str) -> Result { - if !s.starts_with("rustc ") { - return Err(format!("unrecognized version string: {}", s)); - } - s = &s["rustc ".len()..]; - - let parts: Vec<&str> = s.split(".").collect(); - if parts.len() < 3 { - return Err(format!("not enough version parts: {:?}", parts)); - } - - let mut num = String::new(); - for c in parts[0].chars() { - if !c.is_digit(10) { - break; - } - num.push(c); - } - let major = num.parse::().map_err(|e| e.to_string())?; - - num.clear(); - for c in parts[1].chars() { - if !c.is_digit(10) { - break; - } - num.push(c); - } - let minor = num.parse::().map_err(|e| e.to_string())?; - - num.clear(); - for c in parts[2].chars() { - if !c.is_digit(10) { - break; - } - num.push(c); - } - let patch = num.parse::().map_err(|e| e.to_string())?; - - Ok(Version { major, minor, patch }) - } -} diff --git a/ci/build_deb.sh b/ci/build_deb.sh new file mode 100755 index 000000000..eb516191e --- /dev/null +++ b/ci/build_deb.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +set -e + +# This script builds a binary dpkg for Debian based distros. It does not +# currently run in CI, and is instead run manually and the resulting dpkg is +# uploaded to GitHub via the web UI. +# +# Note that this requires 'cargo deb', which can be installed with +# 'cargo install cargo-deb'. +# +# This should be run from the root of the ripgrep repo. + +if ! command -V cargo-deb > /dev/null 2>&1; then + echo "cargo-deb command missing" >&2 + exit 1 +fi + +# 'cargo deb' does not seem to provide a way to specify an asset that is +# created at build time, such as ripgrep's man page. To work around this, +# we force a debug build, copy out the man page produced from that build, put +# it into a predictable location and then build the deb, which knows where to +# look. + +mkdir -p deployment +cargo build +manpage="$(find ./target/debug -name rg.1 -print0 | xargs -0 ls -t | head -n1)" +cp "$manpage" deployment/ +# Since we're distributing the dpkg, we don't know whether the user will have +# PCRE2 installed, so just do a static build. +PCRE2_SYS_STATIC=1 cargo deb diff --git a/complete/_rg b/complete/_rg index 490e6a183..fcb5bbf9a 100644 --- a/complete/_rg +++ b/complete/_rg @@ -166,8 +166,8 @@ _rg() { $no'(pcre2-unicode)--no-pcre2[disable matching with PCRE2]' + '(pcre2-unicode)' # PCRE2 Unicode options - $no'(--no-pcre2-unicode)--pcre2-unicode[enable PCRE2 Unicode mode (with -P)]' - '(--no-pcre2-unicode)--no-pcre2-unicode[disable PCRE2 Unicode mode (with -P)]' + $no'(--no-pcre2 --no-pcre2-unicode)--pcre2-unicode[enable PCRE2 Unicode mode (with -P)]' + '(--no-pcre2 --pcre2-unicode)--no-pcre2-unicode[disable PCRE2 Unicode mode (with -P)]' + '(pre)' # Preprocessing options '(-z --search-zip)--pre=[specify preprocessor utility]:preprocessor utility:_command_names -e' diff --git a/doc/rg.1.txt.tpl b/doc/rg.1.txt.tpl index ab1ef78f3..558aadc3d 100644 --- a/doc/rg.1.txt.tpl +++ b/doc/rg.1.txt.tpl @@ -28,27 +28,37 @@ Synopsis DESCRIPTION ----------- ripgrep (rg) recursively searches your current directory for a regex pattern. -By default, ripgrep will respect your `.gitignore` and automatically skip -hidden files/directories and binary files. +By default, ripgrep will respect your .gitignore and automatically skip hidden +files/directories and binary files. -ripgrep's regex engine uses finite automata and guarantees linear time -searching. Because of this, features like backreferences and arbitrary -lookaround are not supported. +ripgrep's default regex engine uses finite automata and guarantees linear +time searching. Because of this, features like backreferences and arbitrary +look-around are not supported. However, if ripgrep is built with PCRE2, then +the --pcre2 flag can be used to enable backreferences and look-around. + +ripgrep supports configuration files. Set RIPGREP_CONFIG_PATH to a +configuration file. The file can specify one shell argument per line. Lines +starting with '#' are ignored. For more details, see the man page or the +README. REGEX SYNTAX ------------ -ripgrep uses Rust's regex engine, which documents its syntax: -https://docs.rs/regex/0.2.5/regex/#syntax +ripgrep uses Rust's regex engine by default, which documents its syntax: +https://docs.rs/regex/*/regex/#syntax ripgrep uses byte-oriented regexes, which has some additional documentation: -https://docs.rs/regex/0.2.5/regex/bytes/index.html#syntax +https://docs.rs/regex/*/regex/bytes/index.html#syntax To a first approximation, ripgrep uses Perl-like regexes without look-around or backreferences. This makes them very similar to the "extended" (ERE) regular expressions supported by `egrep`, but with a few additional features like Unicode character classes. +If you're using ripgrep with the --pcre2 flag, then please consult +https://www.pcre.org or the PCRE2 man pages for documentation on the supported +syntax. + POSITIONAL ARGUMENTS -------------------- diff --git a/grep-printer/src/standard.rs b/grep-printer/src/standard.rs index 6146a8b9e..183fa4b5c 100644 --- a/grep-printer/src/standard.rs +++ b/grep-printer/src/standard.rs @@ -1201,6 +1201,9 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> { if !self.wtr().borrow().supports_color() || spec.is_none() { return self.write_line(line); } + if self.exceeds_max_columns(line) { + return self.write_exceeded_line(); + } let mut last_written = if !self.config().trim_ascii { diff --git a/grep/Cargo.toml b/grep/Cargo.toml index 48a3aaaba..b9a83cea3 100644 --- a/grep/Cargo.toml +++ b/grep/Cargo.toml @@ -22,7 +22,7 @@ grep-searcher = { version = "0.1.0", path = "../grep-searcher" } [dev-dependencies] atty = "0.2.11" termcolor = "1" -walkdir = "2.2.0" +walkdir = "2.2.1" [features] avx-accel = ["grep-searcher/avx-accel"] diff --git a/ignore/Cargo.toml b/ignore/Cargo.toml index 42b043bf6..82b128553 100644 --- a/ignore/Cargo.toml +++ b/ignore/Cargo.toml @@ -18,7 +18,7 @@ name = "ignore" bench = false [dependencies] -crossbeam = "0.3" +crossbeam-channel = "0.2" globset = { version = "0.4.0", path = "../globset" } lazy_static = "1" log = "0.4" @@ -26,7 +26,7 @@ memchr = "2" regex = "1" same-file = "1" thread_local = "0.3.2" -walkdir = "2.2.0" +walkdir = "2.2.1" [target.'cfg(windows)'.dependencies.winapi] version = "0.3" diff --git a/ignore/examples/walk.rs b/ignore/examples/walk.rs index ad64e015c..67432b71a 100644 --- a/ignore/examples/walk.rs +++ b/ignore/examples/walk.rs @@ -1,14 +1,12 @@ -extern crate crossbeam; +extern crate crossbeam_channel as channel; extern crate ignore; extern crate walkdir; use std::env; use std::io::{self, Write}; use std::path::Path; -use std::sync::Arc; use std::thread; -use crossbeam::sync::MsQueue; use ignore::WalkBuilder; use walkdir::WalkDir; @@ -16,7 +14,7 @@ fn main() { let mut path = env::args().nth(1).unwrap(); let mut parallel = false; let mut simple = false; - let queue: Arc>> = Arc::new(MsQueue::new()); + let (tx, rx) = channel::bounded::(100); if path == "parallel" { path = env::args().nth(2).unwrap(); parallel = true; @@ -25,10 +23,9 @@ fn main() { simple = true; } - let stdout_queue = queue.clone(); let stdout_thread = thread::spawn(move || { let mut stdout = io::BufWriter::new(io::stdout()); - while let Some(dent) = stdout_queue.pop() { + for dent in rx { write_path(&mut stdout, dent.path()); } }); @@ -36,26 +33,26 @@ fn main() { if parallel { let walker = WalkBuilder::new(path).threads(6).build_parallel(); walker.run(|| { - let queue = queue.clone(); + let tx = tx.clone(); Box::new(move |result| { use ignore::WalkState::*; - queue.push(Some(DirEntry::Y(result.unwrap()))); + tx.send(DirEntry::Y(result.unwrap())); Continue }) }); } else if simple { let walker = WalkDir::new(path); for result in walker { - queue.push(Some(DirEntry::X(result.unwrap()))); + tx.send(DirEntry::X(result.unwrap())); } } else { let walker = WalkBuilder::new(path).build(); for result in walker { - queue.push(Some(DirEntry::Y(result.unwrap()))); + tx.send(DirEntry::Y(result.unwrap())); } } - queue.push(None); + drop(tx); stdout_thread.join().unwrap(); } diff --git a/ignore/src/lib.rs b/ignore/src/lib.rs index b97e267a6..190794f52 100644 --- a/ignore/src/lib.rs +++ b/ignore/src/lib.rs @@ -46,7 +46,7 @@ See the documentation for `WalkBuilder` for many other options. #![deny(missing_docs)] -extern crate crossbeam; +extern crate crossbeam_channel as channel; extern crate globset; #[macro_use] extern crate lazy_static; diff --git a/ignore/src/walk.rs b/ignore/src/walk.rs index fc36b4e25..70bbdc20a 100644 --- a/ignore/src/walk.rs +++ b/ignore/src/walk.rs @@ -10,7 +10,7 @@ use std::thread; use std::time::Duration; use std::vec; -use crossbeam::sync::MsQueue; +use channel; use same_file::Handle; use walkdir::{self, WalkDir}; @@ -84,7 +84,8 @@ impl DirEntry { /// Returns an error, if one exists, associated with processing this entry. /// /// An example of an error is one that occurred while parsing an ignore - /// file. + /// file. Errors related to traversing a directory tree itself are reported + /// as part of yielding the directory entry, and not with this method. pub fn error(&self) -> Option<&Error> { self.err.as_ref() } @@ -215,19 +216,6 @@ impl DirEntryInner { } /// Returns true if and only if this entry points to a directory. - /// - /// This works around a bug in Rust's standard library: - /// https://github.com/rust-lang/rust/issues/46484 - #[cfg(windows)] - fn is_dir(&self) -> bool { - self.metadata().map(|md| metadata_is_dir(&md)).unwrap_or(false) - } - - /// Returns true if and only if this entry points to a directory. - /// - /// This works around a bug in Rust's standard library: - /// https://github.com/rust-lang/rust/issues/46484 - #[cfg(not(windows))] fn is_dir(&self) -> bool { self.file_type().map(|ft| ft.is_dir()).unwrap_or(false) } @@ -252,10 +240,6 @@ struct DirEntryRaw { ino: u64, /// The underlying metadata (Windows only). We store this on Windows /// because this comes for free while reading a directory. - /// - /// We use this to determine whether an entry is a directory or not, which - /// works around a bug in Rust's standard library: - /// https://github.com/rust-lang/rust/issues/46484 #[cfg(windows)] metadata: fs::Metadata, } @@ -375,21 +359,29 @@ impl DirEntryRaw { } #[cfg(not(unix))] - fn from_link(depth: usize, pb: PathBuf) -> Result { + fn from_path( + depth: usize, + pb: PathBuf, + link: bool, + ) -> Result { let md = fs::metadata(&pb).map_err(|err| { Error::Io(err).with_path(&pb) })?; Ok(DirEntryRaw { path: pb, ty: md.file_type(), - follow_link: true, + follow_link: link, depth: depth, metadata: md, }) } #[cfg(unix)] - fn from_link(depth: usize, pb: PathBuf) -> Result { + fn from_path( + depth: usize, + pb: PathBuf, + link: bool, + ) -> Result { use std::os::unix::fs::MetadataExt; let md = fs::metadata(&pb).map_err(|err| { @@ -398,7 +390,7 @@ impl DirEntryRaw { Ok(DirEntryRaw { path: pb, ty: md.file_type(), - follow_link: true, + follow_link: link, depth: depth, ino: md.ino(), }) @@ -508,7 +500,7 @@ impl WalkBuilder { (p.to_path_buf(), None) } else { let mut wd = WalkDir::new(p); - wd = wd.follow_links(follow_links || path_is_file(p)); + wd = wd.follow_links(follow_links || p.is_file()); if let Some(max_depth) = max_depth { wd = wd.max_depth(max_depth); } @@ -775,7 +767,7 @@ impl Walk { return false; } - let is_dir = walkdir_entry_is_dir(ent); + let is_dir = ent.file_type().is_dir(); let max_size = self.max_filesize; let should_skip_path = skip_path(&self.ig, ent.path(), is_dir); let should_skip_filesize = if !is_dir && max_size.is_some() { @@ -804,7 +796,7 @@ impl Iterator for Walk { } Some((path, Some(it))) => { self.it = Some(it); - if path_is_dir(&path) { + if path.is_dir() { let (ig, err) = self.ig_root.add_parents(path); self.ig = ig; if let Some(err) = err { @@ -894,7 +886,7 @@ impl Iterator for WalkEventIter { None => None, Some(Err(err)) => Some(Err(err)), Some(Ok(dent)) => { - if walkdir_entry_is_dir(&dent) { + if dent.file_type().is_dir() { self.depth += 1; Some(Ok(WalkEvent::Dir(dent))) } else { @@ -956,7 +948,14 @@ impl WalkParallel { ) where F: FnMut() -> Box) -> WalkState + Send + 'static> { let mut f = mkf(); let threads = self.threads(); - let queue = Arc::new(MsQueue::new()); + // TODO: Figure out how to use a bounded channel here. With an + // unbounded channel, the workers can run away and will up memory + // with all of the file paths. But a bounded channel doesn't work since + // our producers are also are consumers, so they end up getting stuck. + // + // We probably need to rethink parallel traversal completely to fix + // this. + let (tx, rx) = channel::unbounded(); let mut any_work = false; // Send the initial set of root paths to the pool of workers. // Note that we only send directories. For files, we send to them the @@ -966,7 +965,7 @@ impl WalkParallel { if path == Path::new("-") { DirEntry::new_stdin() } else { - match DirEntryRaw::from_link(0, path) { + match DirEntryRaw::from_path(0, path, false) { Ok(dent) => DirEntry::new_raw(dent, None), Err(err) => { if f(Err(err)).is_quit() { @@ -976,7 +975,7 @@ impl WalkParallel { } } }; - queue.push(Message::Work(Work { + tx.send(Message::Work(Work { dent: dent, ignore: self.ig_root.clone(), })); @@ -994,7 +993,8 @@ impl WalkParallel { for _ in 0..threads { let worker = Worker { f: mkf(), - queue: queue.clone(), + tx: tx.clone(), + rx: rx.clone(), quit_now: quit_now.clone(), is_waiting: false, is_quitting: false, @@ -1007,6 +1007,8 @@ impl WalkParallel { }; handles.push(thread::spawn(|| worker.run())); } + drop(tx); + drop(rx); for handle in handles { handle.join().unwrap(); } @@ -1099,8 +1101,10 @@ impl Work { struct Worker { /// The caller's callback. f: Box) -> WalkState + Send + 'static>, - /// A queue of work items. This is multi-producer and multi-consumer. - queue: Arc>, + /// The push side of our mpmc queue. + tx: channel::Sender, + /// The receive side of our mpmc queue. + rx: channel::Receiver, /// Whether all workers should quit at the next opportunity. Note that /// this is distinct from quitting because of exhausting the contents of /// a directory. Instead, this is used when the caller's callback indicates @@ -1213,7 +1217,7 @@ impl Worker { let is_symlink = dent.file_type().map_or(false, |ft| ft.is_symlink()); if self.follow_links && is_symlink { let path = dent.path().to_path_buf(); - dent = match DirEntryRaw::from_link(depth, path) { + dent = match DirEntryRaw::from_path(depth, path, true) { Ok(dent) => DirEntry::new_raw(dent, None), Err(err) => { return (self.f)(Err(err)); @@ -1235,7 +1239,7 @@ impl Worker { }; if !should_skip_path && !should_skip_filesize { - self.queue.push(Message::Work(Work { + self.tx.send(Message::Work(Work { dent: dent, ignore: ig.clone(), })); @@ -1252,7 +1256,7 @@ impl Worker { if self.is_quit_now() { return None; } - match self.queue.try_pop() { + match self.rx.try_recv() { Some(Message::Work(work)) => { self.waiting(false); self.quitting(false); @@ -1294,7 +1298,7 @@ impl Worker { self.quitting(false); if self.num_waiting() == self.threads { for _ in 0..self.threads { - self.queue.push(Message::Quit); + self.tx.send(Message::Quit); } } else { // You're right to consider this suspicious, but it's @@ -1421,62 +1425,6 @@ fn skip_path(ig: &Ignore, path: &Path, is_dir: bool) -> bool { } } -/// Returns true if and only if this path points to a directory. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn path_is_dir(path: &Path) -> bool { - fs::metadata(path).map(|md| metadata_is_dir(&md)).unwrap_or(false) -} - -/// Returns true if and only if this entry points to a directory. -#[cfg(not(windows))] -fn path_is_dir(path: &Path) -> bool { - path.is_dir() -} - -/// Returns true if and only if this path points to a file. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn path_is_file(path: &Path) -> bool { - !path_is_dir(path) -} - -/// Returns true if and only if this entry points to a directory. -#[cfg(not(windows))] -fn path_is_file(path: &Path) -> bool { - path.is_file() -} - -/// Returns true if and only if the given walkdir entry points to a directory. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn walkdir_entry_is_dir(dent: &walkdir::DirEntry) -> bool { - dent.metadata().map(|md| metadata_is_dir(&md)).unwrap_or(false) -} - -/// Returns true if and only if the given walkdir entry points to a directory. -#[cfg(not(windows))] -fn walkdir_entry_is_dir(dent: &walkdir::DirEntry) -> bool { - dent.file_type().is_dir() -} - -/// Returns true if and only if the given metadata points to a directory. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn metadata_is_dir(md: &fs::Metadata) -> bool { - use std::os::windows::fs::MetadataExt; - use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; - md.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 -} - #[cfg(test)] mod tests { use std::fs::{self, File}; @@ -1486,7 +1434,7 @@ mod tests { use tempdir::TempDir; - use super::{WalkBuilder, WalkState}; + use super::{DirEntry, WalkBuilder, WalkState}; fn wfile>(path: P, contents: &str) { let mut file = File::create(path).unwrap(); @@ -1537,28 +1485,32 @@ mod tests { prefix: &Path, builder: &WalkBuilder, ) -> Vec { - let paths = Arc::new(Mutex::new(vec![])); - let prefix = Arc::new(prefix.to_path_buf()); + let mut paths = vec![]; + for dent in walk_collect_entries_parallel(builder) { + let path = dent.path().strip_prefix(prefix).unwrap(); + if path.as_os_str().is_empty() { + continue; + } + paths.push(normal_path(path.to_str().unwrap())); + } + paths.sort(); + paths + } + + fn walk_collect_entries_parallel(builder: &WalkBuilder) -> Vec { + let dents = Arc::new(Mutex::new(vec![])); builder.build_parallel().run(|| { - let paths = paths.clone(); - let prefix = prefix.clone(); + let dents = dents.clone(); Box::new(move |result| { - let dent = match result { - Err(_) => return WalkState::Continue, - Ok(dent) => dent, - }; - let path = dent.path().strip_prefix(&**prefix).unwrap(); - if path.as_os_str().is_empty() { - return WalkState::Continue; + if let Ok(dent) = result { + dents.lock().unwrap().push(dent); } - let mut paths = paths.lock().unwrap(); - paths.push(normal_path(path.to_str().unwrap())); WalkState::Continue }) }); - let mut paths = paths.lock().unwrap(); - paths.sort(); - paths.to_vec() + + let dents = dents.lock().unwrap(); + dents.to_vec() } fn mkpaths(paths: &[&str]) -> Vec { @@ -1753,6 +1705,27 @@ mod tests { ]); } + #[cfg(unix)] // because symlinks on windows are weird + #[test] + fn first_path_not_symlink() { + let td = TempDir::new("walk-test-").unwrap(); + mkdirp(td.path().join("foo")); + + let dents = WalkBuilder::new(td.path().join("foo")) + .build() + .into_iter() + .collect::, _>>() + .unwrap(); + assert_eq!(1, dents.len()); + assert!(!dents[0].path_is_symlink()); + + let dents = walk_collect_entries_parallel( + &WalkBuilder::new(td.path().join("foo")), + ); + assert_eq!(1, dents.len()); + assert!(!dents[0].path_is_symlink()); + } + #[cfg(unix)] // because symlinks on windows are weird #[test] fn symlink_loop() { diff --git a/src/app.rs b/src/app.rs index 62ceca5f1..35009fca1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -13,12 +13,13 @@ use clap::{self, App, AppSettings}; const ABOUT: &str = " ripgrep (rg) recursively searches your current directory for a regex pattern. -By default, ripgrep will respect your `.gitignore` and automatically skip -hidden files/directories and binary files. +By default, ripgrep will respect your .gitignore and automatically skip hidden +files/directories and binary files. -ripgrep's regex engine uses finite automata and guarantees linear time -searching. Because of this, features like backreferences and arbitrary -lookaround are not supported. +ripgrep's default regex engine uses finite automata and guarantees linear +time searching. Because of this, features like backreferences and arbitrary +look-around are not supported. However, if ripgrep is built with PCRE2, then +the --pcre2 flag can be used to enable backreferences and look-around. ripgrep supports configuration files. Set RIPGREP_CONFIG_PATH to a configuration file. The file can specify one shell argument per line. Lines @@ -125,7 +126,7 @@ fn compile_cpu_features() -> Vec<&'static str> { } /// Returns the relevant CPU features enabled at runtime. -#[cfg(all(ripgrep_runtime_cpu, target_arch = "x86_64"))] +#[cfg(target_arch = "x86_64")] fn runtime_cpu_features() -> Vec<&'static str> { // This is kind of a dirty violation of abstraction, since it assumes // knowledge about what specific SIMD features are being used. @@ -145,7 +146,7 @@ fn runtime_cpu_features() -> Vec<&'static str> { } /// Returns the relevant CPU features enabled at runtime. -#[cfg(not(all(ripgrep_runtime_cpu, target_arch = "x86_64")))] +#[cfg(not(target_arch = "x86_64"))] fn runtime_cpu_features() -> Vec<&'static str> { vec![] } @@ -582,13 +583,13 @@ pub fn all_args_and_flags() -> Vec { flag_no_ignore_parent(&mut args); flag_no_ignore_vcs(&mut args); flag_no_messages(&mut args); + flag_no_pcre2_unicode(&mut args); flag_null(&mut args); flag_null_data(&mut args); flag_only_matching(&mut args); flag_path_separator(&mut args); flag_passthru(&mut args); flag_pcre2(&mut args); - flag_pcre2_unicode(&mut args); flag_pre(&mut args); flag_pretty(&mut args); flag_quiet(&mut args); @@ -1568,6 +1569,48 @@ This flag can be disabled with the --messages flag. args.push(arg); } +fn flag_no_pcre2_unicode(args: &mut Vec) { + const SHORT: &str = "Disable Unicode mode for PCRE2 matching."; + const LONG: &str = long!("\ +When PCRE2 matching is enabled, this flag will disable Unicode mode, which is +otherwise enabled by default. If PCRE2 matching is not enabled, then this flag +has no effect. + +When PCRE2's Unicode mode is enabled, several different types of patterns +become Unicode aware. This includes '\\b', '\\B', '\\w', '\\W', '\\d', '\\D', +'\\s' and '\\S'. Similarly, the '.' meta character will match any Unicode +codepoint instead of any byte. Caseless matching will also use Unicode simple +case folding instead of ASCII-only case insensitivity. + +Unicode mode in PCRE2 represents a critical trade off in the user experience +of ripgrep. In particular, unlike the default regex engine, PCRE2 does not +support the ability to search possibly invalid UTF-8 with Unicode features +enabled. Instead, PCRE2 *requires* that everything it searches when Unicode +mode is enabled is valid UTF-8. (Or valid UTF-16/UTF-32, but for the purposes +of ripgrep, we only discuss UTF-8.) This means that if you have PCRE2's Unicode +mode enabled and you attempt to search invalid UTF-8, then the search for that +file will halt and print an error. For this reason, when PCRE2's Unicode mode +is enabled, ripgrep will automatically \"fix\" invalid UTF-8 sequences by +replacing them with the Unicode replacement codepoint. + +If you would rather see the encoding errors surfaced by PCRE2 when Unicode mode +is enabled, then pass the --no-encoding flag to disable all transcoding. + +Related flags: --pcre2 + +This flag can be disabled with --pcre2-unicode. +"); + let arg = RGArg::switch("no-pcre2-unicode") + .help(SHORT).long_help(LONG) + .overrides("pcre2-unicode"); + args.push(arg); + + let arg = RGArg::switch("pcre2-unicode") + .hidden() + .overrides("no-pcre2-unicode"); + args.push(arg); +} + fn flag_null(args: &mut Vec) { const SHORT: &str = "Print a NUL byte after file paths."; const LONG: &str = long!("\ @@ -1658,6 +1701,8 @@ 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 an error message and exiting. +Related flags: --no-pcre2-unicode + This flag can be disabled with --no-pcre2. "); let arg = RGArg::switch("pcre2").short("P") @@ -1671,46 +1716,6 @@ This flag can be disabled with --no-pcre2. args.push(arg); } -fn flag_pcre2_unicode(args: &mut Vec) { - const SHORT: &str = "Enable Unicode mode for PCRE2 matching."; - const LONG: &str = long!("\ -When PCRE2 matching is enabled, this flag will enable Unicode mode. If PCRE2 -matching is not enabled, then this flag has no effect. - -This flag is enabled by default when PCRE2 matching is enabled. - -When PCRE2's Unicode mode is enabled several different types of patterns become -Unicode aware. This includes '\\b', '\\B', '\\w', '\\W', '\\d', '\\D', '\\s' -and '\\S'. Similarly, the '.' meta character will match any Unicode codepoint -instead of any byte. Caseless matching will also use Unicode simple case -folding instead of ASCII-only case insensitivity. - -Unicode mode in PCRE2 represents a critical trade off in the user experience -of ripgrep. In particular, unlike the default regex engine, PCRE2 does not -support the ability to search possibly invalid UTF-8 with Unicode features -enabled. Instead, PCRE2 *requires* that everything it searches when Unicode -mode is enabled is valid UTF-8. (Or valid UTF-16/UTF-32, but for the purposes -of ripgrep, we only discuss UTF-8.) This means that if you have PCRE2's Unicode -mode enabled and you attempt to search invalid UTF-8, then the search for that -file will halt and print an error. For this reason, when PCRE2's Unicode mode -is enabled, ripgrep will automatically \"fix\" invalid UTF-8 sequences by -replacing them with the Unicode replacement codepoint. - -If you would rather see the encoding errors surfaced by PCRE2 when Unicode mode -is enabled, then pass the --no-encoding flag to disable all transcoding. - -This flag can be disabled with --no-pcre2-unicode. -"); - let arg = RGArg::switch("pcre2-unicode") - .help(SHORT).long_help(LONG); - args.push(arg); - - let arg = RGArg::switch("no-pcre2-unicode") - .hidden() - .overrides("pcre2-unicode"); - args.push(arg); -} - fn flag_pretty(args: &mut Vec) { const SHORT: &str = "Alias for --color always --heading --line-number."; const LONG: &str = long!("\ diff --git a/src/subject.rs b/src/subject.rs index 61b345549..741b4fddc 100644 --- a/src/subject.rs +++ b/src/subject.rs @@ -172,36 +172,11 @@ impl Subject { } /// Returns true if and only if this subject points to a directory. - /// - /// This works around a bug in Rust's standard library: - /// https://github.com/rust-lang/rust/issues/46484 - #[cfg(windows)] - fn is_dir(&self) -> bool { - use std::os::windows::fs::MetadataExt; - use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; - - self.dent.metadata().map(|md| { - md.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 - }).unwrap_or(false) - } - - /// Returns true if and only if this subject points to a directory. - #[cfg(not(windows))] fn is_dir(&self) -> bool { self.dent.file_type().map_or(false, |ft| ft.is_dir()) } /// Returns true if and only if this subject points to a file. - /// - /// This works around a bug in Rust's standard library: - /// https://github.com/rust-lang/rust/issues/46484 - #[cfg(windows)] - fn is_file(&self) -> bool { - !self.is_dir() - } - - /// Returns true if and only if this subject points to a file. - #[cfg(not(windows))] fn is_file(&self) -> bool { self.dent.file_type().map_or(false, |ft| ft.is_file()) } diff --git a/tests/json.rs b/tests/json.rs index 4433103d3..7a7bd4d0d 100644 --- a/tests/json.rs +++ b/tests/json.rs @@ -241,6 +241,49 @@ rgtest!(notutf8, |dir: Dir, mut cmd: TestCommand| { ); }); +rgtest!(notutf8_file, |dir: Dir, mut cmd: TestCommand| { + use std::ffi::OsStr; + + // This test does not work with PCRE2 because PCRE2 does not support the + // `u` flag. + if dir.is_pcre2() { + return; + } + + let name = "foo"; + let contents = &b"quux\xFFbaz"[..]; + + // APFS does not support creating files with invalid UTF-8 bytes, so just + // skip the test if we can't create our file. + if !dir.try_create_bytes(OsStr::new(name), contents).is_ok() { + return; + } + cmd.arg("--json").arg(r"(?-u)\xFF"); + + let msgs = json_decode(&cmd.stdout()); + + assert_eq!( + msgs[0].unwrap_begin(), + Begin { path: Some(Data::text("foo")) } + ); + assert_eq!( + msgs[1].unwrap_match(), + Match { + path: Some(Data::text("foo")), + lines: Data::bytes("cXV1eP9iYXo="), + line_number: Some(1), + absolute_offset: 0, + submatches: vec![ + SubMatch { + m: Data::bytes("/w=="), + start: 4, + end: 5, + }, + ], + } + ); +}); + // See: https://github.com/BurntSushi/ripgrep/issues/416 // // This test in particular checks that our match does _not_ include the `\r` diff --git a/tests/util.rs b/tests/util.rs index f8fa51a90..6cfa6fc7f 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -103,6 +103,7 @@ impl Dir { /// Try to create a new file with the given name and contents in this /// directory. + #[allow(dead_code)] // unused on Windows pub fn try_create>( &self, name: P, @@ -222,6 +223,7 @@ impl Dir { /// Creates a file symlink to the src with the given target name /// in this directory. #[cfg(windows)] + #[allow(dead_code)] // unused on Windows pub fn link_file, T: AsRef>( &self, src: S,