mirror of
https://github.com/crate-ci/typos.git
synced 2026-10-17 01:25:12 +02:00
Merge pull request #1617 from nightah/fix-1444-walk-canonicalize-panic
fix(cli): Don't panic when canonicalize fails mid-walk
This commit is contained in:
Generated
+8
-1
@@ -960,7 +960,14 @@ fn walk_entry(
|
||||
(path, cwd)
|
||||
} else {
|
||||
let path = entry.path();
|
||||
let abs_path = report_result(path.canonicalize(), Some(path), reporter)?;
|
||||
let abs_path = match path.canonicalize() {
|
||||
Ok(abs_path) => abs_path,
|
||||
Err(err) => {
|
||||
report_error(err, Some(path), reporter)?;
|
||||
// Avoid a failed `engine.policy` lookup
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
(path, abs_path)
|
||||
};
|
||||
let policy = engine.policy(&lookup_path);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
//! Regression test for <https://github.com/crate-ci/typos/issues/1444>
|
||||
//!
|
||||
//! `walk_entry` canonicalizes each entry's path to look up its policy. When that failed,
|
||||
//! `report_result` reported the error and then handed back `PathBuf::default()`, an empty
|
||||
//! path that is never a key in `ConfigEngine`'s directory map, so the `policy()` call
|
||||
//! right after it panicked with `` `walk()` should be called first ``.
|
||||
#![cfg(unix)]
|
||||
|
||||
struct CollectingReporter {
|
||||
errors: std::sync::Mutex<Vec<String>>,
|
||||
}
|
||||
|
||||
impl CollectingReporter {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
errors: std::sync::Mutex::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl typos_cli::report::Report for CollectingReporter {
|
||||
fn report(&self, msg: typos_cli::report::Message<'_>) -> Result<(), std::io::Error> {
|
||||
if msg.is_error() {
|
||||
self.errors.lock().unwrap().push(format!("{msg:?}"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn walk_path_reports_file_removed_mid_walk() {
|
||||
let temp = assert_fs::TempDir::new().unwrap();
|
||||
let vanishing = temp.path().join("vanishing.txt");
|
||||
std::fs::write(&vanishing, b"helllo world\n").unwrap();
|
||||
|
||||
let storage = typos_cli::policy::ConfigStorage::new();
|
||||
let mut engine = typos_cli::policy::ConfigEngine::new(&storage);
|
||||
engine.set_isolated(true);
|
||||
engine.set_overrides(typos_cli::config::Config::default());
|
||||
let cwd = temp.path().canonicalize().unwrap();
|
||||
engine.init_dir(&cwd).unwrap();
|
||||
|
||||
// Remove the file as the walker visits it. `ignore` still yields it as an `Ok` entry,
|
||||
// but the `canonicalize()` in `walk_entry` then fails with `NotFound` -- the same
|
||||
// outcome as a file that a concurrent process removes mid-scan.
|
||||
let mut builder = ignore::WalkBuilder::new(temp.path());
|
||||
let target = vanishing.clone();
|
||||
let removed = std::sync::atomic::AtomicBool::new(false);
|
||||
builder.filter_entry(move |entry| {
|
||||
if entry.path() == target && !removed.swap(true, std::sync::atomic::Ordering::SeqCst) {
|
||||
std::fs::remove_file(&target).unwrap();
|
||||
}
|
||||
true
|
||||
});
|
||||
let reporter = CollectingReporter::new();
|
||||
|
||||
let result = typos_cli::file::walk_path(
|
||||
builder.build(),
|
||||
&typos_cli::file::Typos,
|
||||
&engine,
|
||||
&reporter,
|
||||
false,
|
||||
);
|
||||
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"walk_path should not surface an ignore::Error: {result:?}"
|
||||
);
|
||||
assert!(
|
||||
!reporter.errors.lock().unwrap().is_empty(),
|
||||
"expected the vanished file's canonicalize() failure to be reported"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user