1 // Copyright © 2025 Cyberus Technology GmbH
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 use std::error::Error;
6
7 /// Prints a chain of errors to the user in a consistent manner.
8 /// The user will see a clear chain of errors, followed by debug output
9 /// for opening issues.
cli_print_error_chain<'a>( top_error: &'a (dyn Error + 'static), component: &str, display_modifier: impl Fn( usize, usize, &'a (dyn Error + 'static), ) -> Option<String>, )10 pub fn cli_print_error_chain<'a>(
11 top_error: &'a (dyn Error + 'static),
12 component: &str,
13 // Function optionally returning the display representation of an error.
14 display_modifier: impl Fn(
15 /* level */ usize,
16 /*indention */ usize,
17 &'a (dyn Error + 'static),
18 ) -> Option<String>,
19 ) {
20 eprint!("Error: {component} exited with the following ");
21 if top_error.source().is_none() {
22 eprintln!("error:");
23 eprintln!(" {top_error}");
24 } else {
25 eprintln!("chain of errors:");
26 std::iter::successors(Some(top_error), |sub_error| {
27 // Dereference necessary to mitigate rustc compiler bug.
28 // See <https://github.com/rust-lang/rust/issues/141673>
29 (*sub_error).source()
30 })
31 .enumerate()
32 .for_each(|(level, error)| {
33 // Special case: handling of HTTP Server responses in ch-remote
34 if let Some(message) = display_modifier(level, 2, error) {
35 eprintln!("{message}");
36 } else {
37 eprintln!(" {level}: {error}");
38 }
39 });
40 }
41
42 eprintln!();
43 eprintln!("Debug Info: {top_error:?}");
44 }
45