|
1 | 1 | use std::io::Write; |
2 | 2 | use std::process::ExitCode; |
3 | 3 |
|
| 4 | +use anyhow::Context; |
4 | 5 | use clap::Parser; |
5 | 6 | use colored::Colorize; |
6 | 7 |
|
@@ -39,39 +40,46 @@ pub fn main() -> ExitCode { |
39 | 40 | } |
40 | 41 |
|
41 | 42 | let args = wild::args_os(); |
42 | | - let args = argfile::expand_args_from(args, argfile::parse_fromfile, argfile::PREFIX).unwrap(); |
| 43 | + let args = match argfile::expand_args_from(args, argfile::parse_fromfile, argfile::PREFIX) |
| 44 | + .context("Failed to read CLI arguments from files") |
| 45 | + { |
| 46 | + Ok(args) => args, |
| 47 | + Err(err) => return report_error(&err), |
| 48 | + }; |
43 | 49 |
|
44 | 50 | let args = Args::parse_from(args); |
45 | 51 |
|
46 | 52 | match run(args) { |
47 | 53 | Ok(code) => code.into(), |
48 | | - Err(err) => { |
49 | | - { |
50 | | - // Exit "gracefully" on broken pipe errors. |
51 | | - // |
52 | | - // See: https://github.com/BurntSushi/ripgrep/blob/bf63fe8f258afc09bae6caa48f0ae35eaf115005/crates/core/main.rs#L47C1-L61C14 |
53 | | - for cause in err.chain() { |
54 | | - if let Some(ioerr) = cause.downcast_ref::<std::io::Error>() { |
55 | | - if ioerr.kind() == std::io::ErrorKind::BrokenPipe { |
56 | | - return ExitCode::from(0); |
57 | | - } |
58 | | - } |
59 | | - } |
60 | | - |
61 | | - // Use `writeln` instead of `eprintln` to avoid panicking when the stderr pipe is broken. |
62 | | - let mut stderr = std::io::stderr().lock(); |
| 54 | + Err(err) => report_error(&err), |
| 55 | + } |
| 56 | +} |
63 | 57 |
|
64 | | - // This communicates that this isn't a linter error but ruff itself hard-errored for |
65 | | - // some reason (e.g. failed to resolve the configuration) |
66 | | - writeln!(stderr, "{}", "ruff failed".red().bold()).ok(); |
67 | | - // Currently we generally only see one error, but e.g. with io errors when resolving |
68 | | - // the configuration it is help to chain errors ("resolving configuration failed" -> |
69 | | - // "failed to read file: subdir/pyproject.toml") |
70 | | - for cause in err.chain() { |
71 | | - writeln!(stderr, " {} {cause}", "Cause:".bold()).ok(); |
| 58 | +fn report_error(err: &anyhow::Error) -> ExitCode { |
| 59 | + { |
| 60 | + // Exit "gracefully" on broken pipe errors. |
| 61 | + // |
| 62 | + // See: https://github.com/BurntSushi/ripgrep/blob/bf63fe8f258afc09bae6caa48f0ae35eaf115005/crates/core/main.rs#L47C1-L61C14 |
| 63 | + for cause in err.chain() { |
| 64 | + if let Some(ioerr) = cause.downcast_ref::<std::io::Error>() { |
| 65 | + if ioerr.kind() == std::io::ErrorKind::BrokenPipe { |
| 66 | + return ExitCode::from(0); |
72 | 67 | } |
73 | 68 | } |
74 | | - ExitStatus::Error.into() |
| 69 | + } |
| 70 | + |
| 71 | + // Use `writeln` instead of `eprintln` to avoid panicking when the stderr pipe is broken. |
| 72 | + let mut stderr = std::io::stderr().lock(); |
| 73 | + |
| 74 | + // This communicates that this isn't a linter error but ruff itself hard-errored for |
| 75 | + // some reason (e.g. failed to resolve the configuration) |
| 76 | + writeln!(stderr, "{}", "ruff failed".red().bold()).ok(); |
| 77 | + // Currently we generally only see one error, but e.g. with io errors when resolving |
| 78 | + // the configuration it is help to chain errors ("resolving configuration failed" -> |
| 79 | + // "failed to read file: subdir/pyproject.toml") |
| 80 | + for cause in err.chain() { |
| 81 | + writeln!(stderr, " {} {cause}", "Cause:".bold()).ok(); |
75 | 82 | } |
76 | 83 | } |
| 84 | + ExitStatus::Error.into() |
77 | 85 | } |
0 commit comments