Skip to content

Commit 1a1c663

Browse files
authored
Merge pull request #109 from rage/panic-handling
added handling for panics in CLI
2 parents 1dbaf17 + 8a94c30 commit 1a1c663

File tree

1 file changed

+47
-12
lines changed

1 file changed

+47
-12
lines changed

tmc-langs-cli/src/lib.rs

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,49 @@ use toml::{map::Map as TomlMap, Value as TomlValue};
5252
use url::Url;
5353
use walkdir::WalkDir;
5454

55+
// wraps the run_inner function that actually does the work and handles any panics that occur
56+
// any langs library should never panic by itself, but other libraries used may in some rare circumstances
5557
pub fn run() {
58+
// run the inner function and catch any panics
59+
match std::panic::catch_unwind(run_inner) {
60+
Ok(res) => {
61+
// no panic, output was printed properly
62+
match res {
63+
Ok(_) => {
64+
// inner returned Ok, exit with 0
65+
quit::with_code(0);
66+
}
67+
Err(_) => {
68+
// inner returned Err, exit with 1
69+
quit::with_code(1);
70+
}
71+
}
72+
}
73+
Err(err) => {
74+
// panicked, likely before any output was printed
75+
// currently only prints a message if the panic is called with str or String; this should be good enough
76+
let error_message = if let Some(string) = err.downcast_ref::<&str>() {
77+
format!("Process panicked unexpectedly with message: {}", string)
78+
} else if let Some(string) = err.downcast_ref::<String>() {
79+
format!("Process panicked unexpectedly with message: {}", string)
80+
} else {
81+
"Process panicked unexpectedly without an error message".to_string()
82+
};
83+
let output = Output::OutputData(OutputData {
84+
status: Status::Crashed,
85+
message: error_message,
86+
result: OutputResult::Error,
87+
data: None,
88+
});
89+
print_output(&output, false).expect("this should never fail");
90+
quit::with_code(1);
91+
}
92+
}
93+
}
94+
95+
// sets up warning and progress reporting and calls run_app and does error handling for its result
96+
// returns Ok if we should exit with code 0, Err if we should exit with 1
97+
fn run_inner() -> Result<(), ()> {
5698
let matches = app::create_app().get_matches();
5799
let pretty = matches.is_present("pretty");
58100

@@ -90,18 +132,11 @@ pub fn run() {
90132
trace: causes,
91133
}),
92134
});
93-
if let Err(err) = print_output_with_file(&error_output, pretty, sandbox_path) {
94-
// the above function shouldn't fail ever, but in theory some data could
95-
// have a flawed Serialize implementation, so better safe than sorry
96-
let output = Output::OutputData(OutputData {
97-
status: Status::Crashed,
98-
message: err.to_string(),
99-
result: OutputResult::Error,
100-
data: None,
101-
});
102-
print_output(&output, pretty).expect("this should never fail");
103-
}
104-
quit::with_code(1);
135+
print_output_with_file(&error_output, pretty, sandbox_path)
136+
.expect("failed to print output");
137+
Err(())
138+
} else {
139+
Ok(())
105140
}
106141
}
107142

0 commit comments

Comments
 (0)