Skip to content

find: Fix -execdir + working incorrectly for the root path #533

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 59 additions & 2 deletions src/find/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ fn process_dir(
// As WalkDir seems not providing a function to check its stack,
// using current_dir is a workaround to check leaving directory.
let mut current_dir: Option<PathBuf> = None;
let mut depth = 0;
while let Some(result) = it.next() {
match WalkEntry::from_walkdir(result, config.follow) {
Err(err) => {
Expand All @@ -188,11 +189,16 @@ fn process_dir(
Ok(entry) => {
let mut matcher_io = matchers::MatcherIO::new(deps);

let new_dir = entry.path().parent().map(|x| x.to_path_buf());
if new_dir != current_dir {
let new_dir = entry
.path()
.parent()
.or_else(|| Some(entry.path()))
.map(|x| x.to_path_buf());
if entry.depth() != depth || new_dir != current_dir {
if let Some(dir) = current_dir.take() {
matcher.finished_dir(dir.as_path(), &mut matcher_io);
}
depth = entry.depth();
current_dir = new_dir;
}

Expand Down Expand Up @@ -327,6 +333,7 @@ pub fn find_main(args: &[&str], deps: &dyn Dependencies) -> i32 {
#[cfg(test)]
mod tests {

use std::cell::Cell;
use std::fs;
use std::io::{Cursor, ErrorKind, Read};
use std::time::Duration;
Expand All @@ -341,6 +348,7 @@ mod tests {
use crate::find::matchers::time::ChangeTime;
use crate::find::matchers::MatcherIO;

use super::matchers::Matcher;
use super::*;

#[cfg(windows)]
Expand Down Expand Up @@ -397,6 +405,37 @@ mod tests {
}
}

// A fake matcher struct that records finished and finished_dir arguments.
pub struct FakeMatcher {
pub finished_dir_result: RefCell<Vec<PathBuf>>,
pub finished_result: Cell<u32>,
}

impl FakeMatcher {
pub fn new() -> Self {
Self {
finished_dir_result: RefCell::new(Vec::new()),
finished_result: Cell::new(0),
}
}
}

impl Matcher for FakeMatcher {
fn matches(&self, _: &WalkEntry, _: &mut MatcherIO) -> bool {
true
}

fn finished_dir(&self, finished_directory: &std::path::Path, _: &mut MatcherIO) {
self.finished_dir_result
.borrow_mut()
.push(finished_directory.to_path_buf());
}

fn finished(&self, _: &mut MatcherIO) {
self.finished_result.set(self.finished_result.get() + 1);
}
}

fn create_file_link() {
#[cfg(unix)]
if let Err(e) = symlink("abbbc", "test_data/links/link-f") {
Expand Down Expand Up @@ -1534,4 +1573,22 @@ mod tests {

assert_eq!(rc, 0);
}

#[test]
fn test_finished_in_root_directory() {
let config = Config {
max_depth: 1,
..Default::default()
};
let deps = FakeDependencies::new();
let mut quit = false;
let matcher = FakeMatcher::new();
process_dir("/", &config, &deps, &matcher, &mut quit);

let dir_result = matcher.finished_dir_result.borrow();
assert_eq!(dir_result.len(), 2);
assert_eq!(dir_result[0], PathBuf::from("/"));
assert_eq!(dir_result[1], PathBuf::from("/"));
assert_eq!(matcher.finished_result.get(), 1);
}
}
54 changes: 54 additions & 0 deletions tests/find_exec_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,57 @@ fn find_execdir_multi() {
))
);
}

#[test]
fn find_execdir_multi_in_root_directory() {
let temp_dir = Builder::new()
.prefix("find_execdir_multi_in_root_directory")
.tempdir()
.unwrap();
let temp_dir_path = temp_dir.path().to_string_lossy();
let deps = FakeDependencies::new();

let cwd = env::current_dir().expect("no current directory");
let root_dir = cwd
.ancestors()
.last()
.expect("current directory has no root");

// only look at files because the "size" of a directory is a system (and filesystem)
// dependent thing and we want these tests to be universal.
let rc = find_main(
&[
"find",
&fix_up_slashes(&root_dir.to_string_lossy()),
"-maxdepth",
"0",
"-execdir",
&path_to_testing_commandline(),
temp_dir_path.as_ref(),
"--sort",
")",
"{}",
"+",
],
&deps,
);

assert_eq!(rc, 0);
// exec has side effects, so we won't output anything unless -print is
// explicitly passed in.
assert_eq!(deps.get_output_as_string(), "");

// check the executable ran as expected
let mut f = File::open(temp_dir.path().join("1.txt")).expect("Failed to open output file");
let mut s = String::new();
f.read_to_string(&mut s)
.expect("failed to read output file");
assert_eq!(
s,
fix_up_slashes(&format!(
"cwd={}\nargs=\n)\n--sort\n{}\n",
root_dir.to_string_lossy(),
root_dir.to_string_lossy(),
))
);
}
Loading