Skip to content

Commit

Permalink
inject error message into mdbook rather than failing preprocessor
Browse files Browse the repository at this point in the history
  • Loading branch information
tomeichlersmith committed Sep 8, 2024
1 parent 62a382d commit 6f61a39
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 35 deletions.
86 changes: 63 additions & 23 deletions src/cmdrun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,53 @@ impl CmdRun {

// This method is public for unit tests
pub fn run_cmdrun(command: String, working_dir: &str, inline: bool) -> Result<String> {
let (command, correct_exit_code): (String, Option<i32>) = if let Some(first_word) = command.split_whitespace().next() {
let (command, correct_exit_code): (String, Option<i32>) = if let Some(first_word) =
command.split_whitespace().next()
{
if first_word.starts_with('-') {
let (_, exit_code) = first_word.rsplit_once('-').unwrap_or(("","0"));
(
command.split_whitespace().skip(1).collect::<Vec<&str>>().join(" "),
Some(exit_code.parse()?)
)
if first_word.starts_with("--") {
// double-tick long form
match first_word {
"--strict" => (
command
.split_whitespace()
.skip(1)
.collect::<Vec<&str>>()
.join(" "),
Some(0),
),
"--expect-return-code" => {
if let Some(second_word) = command.split_whitespace().skip(1).next() {
(
command
.split_whitespace()
.skip(2)
.collect::<Vec<&str>>()
.join(" "),
Some(second_word.parse()?),
)
} else {
// no second word after return code, print error
return Ok(format!("**cmdrun error**: No return code after '--expect-return-code' for command {command}."));
}
}
some_other_word => {
// unrecognized flag, print error
return Ok(format!("**cmdrun error**: Unrecognized cmdrun flag {some_other_word} in 'cmdrun {command}'"));
}
}
} else {
// single-tick short form
let (_, exit_code) = first_word.rsplit_once('-').unwrap_or(("", "0"));
(
command
.split_whitespace()
.skip(1)
.collect::<Vec<&str>>()
.join(" "),
Some(exit_code.parse()?),
)
}
} else {
(command, None)
}
Expand All @@ -179,25 +219,25 @@ impl CmdRun {
.output()
.with_context(|| "Fail to run shell")?;

let stdout = Self::format_whitespace(String::from_utf8_lossy(&output.stdout), inline);
match (output.status.code(), correct_exit_code) {
(None, _) => return Err(anyhow::Error::msg(format!("'{command}' was ended before completing."))),
(Some(code), Some(correct_code)) => if code != correct_code {
return Err(
anyhow::Error::msg(format!("'{command}' returned exit code {code} instead of {correct_code}."))
.context(String::from_utf8_lossy(&output.stderr).to_string())
(None, _) => Ok(format!("'{command}' was ended before completing.")),
(Some(code), Some(correct_code)) => {
if code != correct_code {
Ok(
format!(
"**cmdrun error**: '{command}' returned exit code {code} instead of {correct_code}.\n{0}\n{1}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr))
)
},
(Some(code), None) => ()
} else {
Ok(stdout)
}
}
(Some(_code), None) => {
// no correct code specified, program exited with some code _code
// could put default check requiring code to be zero here but
// that would break current behavior
Ok(stdout)
}
}

let stdout = Self::format_whitespace(String::from_utf8_lossy(&output.stdout), inline);

// let stderr = String::from_utf8_lossy(&output.stderr).to_string();

// eprintln!("command: {}", command);
// eprintln!("stdout: {:?}", stdout);
// eprintln!("stderr: {:?}", stderr);

Ok(stdout)
}
}
38 changes: 26 additions & 12 deletions tests/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,18 @@ cfg_if! {

// the inline flag only affects the output and here I'm just checking exit codes
// so I only test without the inline flag
add_test!(match_fail_exit_code, "-1 exit 1", "", false);
add_test!(match_pass_exit_code, "-0 exit 0", "", false);
add_test!(pass_without_exit_code_spec, "exit 1", "", false);

#[test]
fn exit_code_mismatch() {
assert!(CmdRun::run_cmdrun("-0 exit 1".to_string(), ".", false).is_err())
}

#[test]
fn bad_exit_code_spec() {
assert!(CmdRun::run_cmdrun("-O exit 0".to_string(), ".", false).is_err())
}
add_test!(short_match_fail_exit_code, "-1 exit 1", "", false);
add_test!(short_match_pass_exit_code, "-0 exit 0", "", false);
add_test!(short_exit_code_mismatch, "-0 exit 1",
"**cmdrun error**: 'exit 1' returned exit code 1 instead of 0.\n\n", false);
add_test!(long_match_fail_exit_code, "--expect-return-code 1 exit 1", "", false);
add_test!(long_match_pass_exit_code1, "--expect-return-code 0 exit 0", "", false);
add_test!(long_match_pass_exit_code2, "--strict exit 0", "", false);
add_test!(long_exit_code_mismatch1, "--expect-return-code 0 exit 1",
"**cmdrun error**: 'exit 1' returned exit code 1 instead of 0.\n\n", false);
add_test!(long_exit_code_mismatch2, "--strict exit 1",
"**cmdrun error**: 'exit 1' returned exit code 1 instead of 0.\n\n", false);

add_test!(
mixed_inline1,
Expand Down Expand Up @@ -104,5 +103,20 @@ cfg_if! {
"42 \r\n42 \r\n42 \r\n42 \r\n", false
);

// the inline flag only affects the output and here I'm just checking exit codes
// so I only test without the inline flag
add_test!(pass_without_exit_code_spec, "exit 1", "", false);
add_test!(short_match_fail_exit_code, "-1 exit 1", "", false);
add_test!(short_match_pass_exit_code, "-0 exit 0", "", false);
add_test!(short_exit_code_mismatch, "-0 exit 1",
"**cmdrun error**: 'exit 1' returned exit code 1 instead of 0.\n\n", false);
add_test!(long_match_fail_exit_code, "--expect-return-code 1 exit 1", "", false);
add_test!(long_match_pass_exit_code1, "--expect-return-code 0 exit 0", "", false);
add_test!(long_match_pass_exit_code2, "--strict exit 0", "", false);
add_test!(long_exit_code_mismatch1, "--expect-return-code 0 exit 1",
"**cmdrun error**: 'exit 1' returned exit code 1 instead of 0.\n\n", false);
add_test!(long_exit_code_mismatch2, "--strict exit 1",
"**cmdrun error**: 'exit 1' returned exit code 1 instead of 0.\n\n", false);

}
}

0 comments on commit 6f61a39

Please sign in to comment.