Skip to content

Commit

Permalink
cli: make ripgrep work in non-existent directories
Browse files Browse the repository at this point in the history
It turns out that querying the CWD while in a directory that no longer
exists results in an error. Since the CWD is queried every time ripgrep
starts---whether it needs it or not---for dealing with glob matching,
ripgrep winds up being completely useless inside a non-existent
directory.

We fix this in a few different ways:

* Firstly, if std::env::current_dir() fails, then we fall back to trying
  to read the `PWD` environment variable.
* If that fails, that we return a more sensible error message so that a
  user can at least react to the problem. Previously, the error message
  was inscrutable.
* Finally, we try to avoid the problem altogether by building empty glob
  matchers if not globs were provided, thus side-stepping querying the
  CWD completely.

Fixes #1291, Closes #1400
  • Loading branch information
BurntSushi committed Feb 17, 2020
1 parent 297b428 commit 0c3b673
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Feature enhancements:

Bug fixes:

* [BUG #1291](https://github.com/BurntSushi/ripgrep/issues/1291):
ripgrep now works in non-existent directories.
* [BUG #1335](https://github.com/BurntSushi/ripgrep/issues/1335):
Fixes a performance bug when searching plain text files with very long lines.
* [BUG #1344](https://github.com/BurntSushi/ripgrep/issues/1344):
Expand Down
42 changes: 37 additions & 5 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1277,17 +1277,23 @@ impl ArgMatches {

/// Builds the set of glob overrides from the command line flags.
fn overrides(&self) -> Result<Override> {
let mut builder = OverrideBuilder::new(env::current_dir()?);
let globs = self.values_of_lossy_vec("glob");
let iglobs = self.values_of_lossy_vec("iglob");
if globs.is_empty() && iglobs.is_empty() {
return Ok(Override::empty());
}

let mut builder = OverrideBuilder::new(current_dir()?);
// Make all globs case insensitive with --glob-case-insensitive.
if self.is_present("glob-case-insensitive") {
builder.case_insensitive(true).unwrap();
}
for glob in self.values_of_lossy_vec("glob") {
for glob in globs {
builder.add(&glob)?;
}
// This only enables case insensitivity for subsequent globs.
builder.case_insensitive(true).unwrap();
for glob in self.values_of_lossy_vec("iglob") {
for glob in iglobs {
builder.add(&glob)?;
}
Ok(builder.build()?)
Expand Down Expand Up @@ -1489,8 +1495,12 @@ impl ArgMatches {
/// flag. If no --pre-globs are available, then this always returns an
/// empty set of globs.
fn preprocessor_globs(&self) -> Result<Override> {
let mut builder = OverrideBuilder::new(env::current_dir()?);
for glob in self.values_of_lossy_vec("pre-glob") {
let globs = self.values_of_lossy_vec("pre-glob");
if globs.is_empty() {
return Ok(Override::empty());
}
let mut builder = OverrideBuilder::new(current_dir()?);
for glob in globs {
builder.add(&glob)?;
}
Ok(builder.build()?)
Expand Down Expand Up @@ -1794,3 +1804,25 @@ where I: IntoIterator<Item=T>,
let _ = write!(io::stdout(), "{}", err);
process::exit(0);
}

/// Attempts to discover the current working directory. This mostly just defers
/// to the standard library, however, such things will fail if ripgrep is in
/// a directory that no longer exists. We attempt some fallback mechanisms,
/// such as querying the PWD environment variable, but otherwise return an
/// error.
fn current_dir() -> Result<PathBuf> {
let err = match env::current_dir() {
Err(err) => err,
Ok(cwd) => return Ok(cwd),
};
if let Some(cwd) = env::var_os("PWD") {
if !cwd.is_empty() {
return Ok(PathBuf::from(cwd));
}
}
Err(format!(
"failed to get current working directory: {} \
--- did your CWD get deleted?",
err,
).into())
}

0 comments on commit 0c3b673

Please sign in to comment.