Skip to content

Commit d895ee0

Browse files
authored
[red-knot] Handle pipe-errors gracefully (#16354)
1 parent 4732c58 commit d895ee0

File tree

1 file changed

+21
-12
lines changed

1 file changed

+21
-12
lines changed

crates/red_knot/src/main.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::io::{self, BufWriter, Write};
1+
use std::io::{self, stdout, BufWriter, Write};
22
use std::process::{ExitCode, Termination};
33

44
use anyhow::Result;
@@ -39,6 +39,15 @@ pub fn main() -> ExitStatus {
3939
// the configuration it is help to chain errors ("resolving configuration failed" ->
4040
// "failed to read file: subdir/pyproject.toml")
4141
for cause in error.chain() {
42+
// Exit "gracefully" on broken pipe errors.
43+
//
44+
// See: https://github.com/BurntSushi/ripgrep/blob/bf63fe8f258afc09bae6caa48f0ae35eaf115005/crates/core/main.rs#L47C1-L61C14
45+
if let Some(ioerr) = cause.downcast_ref::<io::Error>() {
46+
if ioerr.kind() == io::ErrorKind::BrokenPipe {
47+
return ExitStatus::Success;
48+
}
49+
}
50+
4251
writeln!(stderr, " {} {cause}", "Cause:".bold()).ok();
4352
}
4453

@@ -121,7 +130,7 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
121130
let exit_status = if watch {
122131
main_loop.watch(&mut db)?
123132
} else {
124-
main_loop.run(&mut db)
133+
main_loop.run(&mut db)?
125134
};
126135

127136
tracing::trace!("Counts for entire CLI run:\n{}", countme::get_all());
@@ -181,7 +190,7 @@ impl MainLoop {
181190
)
182191
}
183192

184-
fn watch(mut self, db: &mut ProjectDatabase) -> anyhow::Result<ExitStatus> {
193+
fn watch(mut self, db: &mut ProjectDatabase) -> Result<ExitStatus> {
185194
tracing::debug!("Starting watch mode");
186195
let sender = self.sender.clone();
187196
let watcher = watch::directory_watcher(move |event| {
@@ -190,12 +199,12 @@ impl MainLoop {
190199

191200
self.watcher = Some(ProjectWatcher::new(watcher, db));
192201

193-
self.run(db);
202+
self.run(db)?;
194203

195204
Ok(ExitStatus::Success)
196205
}
197206

198-
fn run(mut self, db: &mut ProjectDatabase) -> ExitStatus {
207+
fn run(mut self, db: &mut ProjectDatabase) -> Result<ExitStatus> {
199208
self.sender.send(MainLoopMessage::CheckWorkspace).unwrap();
200209

201210
let result = self.main_loop(db);
@@ -205,7 +214,7 @@ impl MainLoop {
205214
result
206215
}
207216

208-
fn main_loop(&mut self, db: &mut ProjectDatabase) -> ExitStatus {
217+
fn main_loop(&mut self, db: &mut ProjectDatabase) -> Result<ExitStatus> {
209218
// Schedule the first check.
210219
tracing::debug!("Starting main loop");
211220

@@ -248,9 +257,9 @@ impl MainLoop {
248257
.any(|diagnostic| diagnostic.severity() >= min_error_severity);
249258

250259
if check_revision == revision {
251-
#[allow(clippy::print_stdout)]
260+
let mut stdout = stdout().lock();
252261
for diagnostic in result {
253-
println!("{}", diagnostic.display(db, &display_config));
262+
writeln!(stdout, "{}", diagnostic.display(db, &display_config))?;
254263
}
255264
} else {
256265
tracing::debug!(
@@ -259,11 +268,11 @@ impl MainLoop {
259268
}
260269

261270
if self.watcher.is_none() {
262-
return if failed {
271+
return Ok(if failed {
263272
ExitStatus::Failure
264273
} else {
265274
ExitStatus::Success
266-
};
275+
});
267276
}
268277

269278
tracing::trace!("Counts after last check:\n{}", countme::get_all());
@@ -283,14 +292,14 @@ impl MainLoop {
283292
// TODO: Don't use Salsa internal APIs
284293
// [Zulip-Thread](https://salsa.zulipchat.com/#narrow/stream/333573-salsa-3.2E0/topic/Expose.20an.20API.20to.20cancel.20other.20queries)
285294
let _ = db.zalsa_mut();
286-
return ExitStatus::Success;
295+
return Ok(ExitStatus::Success);
287296
}
288297
}
289298

290299
tracing::debug!("Waiting for next main loop message.");
291300
}
292301

293-
ExitStatus::Success
302+
Ok(ExitStatus::Success)
294303
}
295304
}
296305

0 commit comments

Comments
 (0)