1060c9de0SPhilipp Schuster // Copyright © 2025 Cyberus Technology GmbH
2060c9de0SPhilipp Schuster //
3060c9de0SPhilipp Schuster // SPDX-License-Identifier: Apache-2.0
46ea13270SPhilipp Schuster
56ea13270SPhilipp Schuster use std::error::Error;
6060c9de0SPhilipp Schuster
7060c9de0SPhilipp Schuster /// Prints a chain of errors to the user in a consistent manner.
8060c9de0SPhilipp Schuster /// The user will see a clear chain of errors, followed by debug output
9060c9de0SPhilipp Schuster /// 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*190a11f2SPhilipp Schuster pub fn cli_print_error_chain<'a>(
11*190a11f2SPhilipp Schuster top_error: &'a (dyn Error + 'static),
12*190a11f2SPhilipp Schuster component: &str,
13*190a11f2SPhilipp Schuster // Function optionally returning the display representation of an error.
14*190a11f2SPhilipp Schuster display_modifier: impl Fn(
15*190a11f2SPhilipp Schuster /* level */ usize,
16*190a11f2SPhilipp Schuster /*indention */ usize,
17*190a11f2SPhilipp Schuster &'a (dyn Error + 'static),
18*190a11f2SPhilipp Schuster ) -> Option<String>,
19*190a11f2SPhilipp Schuster ) {
20060c9de0SPhilipp Schuster eprint!("Error: {component} exited with the following ");
21060c9de0SPhilipp Schuster if top_error.source().is_none() {
22060c9de0SPhilipp Schuster eprintln!("error:");
23060c9de0SPhilipp Schuster eprintln!(" {top_error}");
24060c9de0SPhilipp Schuster } else {
25060c9de0SPhilipp Schuster eprintln!("chain of errors:");
26060c9de0SPhilipp Schuster std::iter::successors(Some(top_error), |sub_error| {
276ea13270SPhilipp Schuster // Dereference necessary to mitigate rustc compiler bug.
286ea13270SPhilipp Schuster // See <https://github.com/rust-lang/rust/issues/141673>
296ea13270SPhilipp Schuster (*sub_error).source()
30060c9de0SPhilipp Schuster })
31060c9de0SPhilipp Schuster .enumerate()
32060c9de0SPhilipp Schuster .for_each(|(level, error)| {
33*190a11f2SPhilipp Schuster // Special case: handling of HTTP Server responses in ch-remote
34*190a11f2SPhilipp Schuster if let Some(message) = display_modifier(level, 2, error) {
35*190a11f2SPhilipp Schuster eprintln!("{message}");
36*190a11f2SPhilipp Schuster } else {
37*190a11f2SPhilipp Schuster eprintln!(" {level}: {error}");
38*190a11f2SPhilipp Schuster }
39060c9de0SPhilipp Schuster });
40060c9de0SPhilipp Schuster }
41060c9de0SPhilipp Schuster
42060c9de0SPhilipp Schuster eprintln!();
43060c9de0SPhilipp Schuster eprintln!("Debug Info: {top_error:?}");
44060c9de0SPhilipp Schuster }
45