Preserve and tidy stdout on failure (#350)
Rather than discarding lines which are not directives to cargo, print
them.
Also, print a friendly message, rather than a backtrace, if the build
script itself exits non-0.
diff --git a/cargo/cargo_build_script.bzl b/cargo/cargo_build_script.bzl
index c885d92..348901b 100644
--- a/cargo/cargo_build_script.bzl
+++ b/cargo/cargo_build_script.bzl
@@ -35,7 +35,6 @@
"HOST": toolchain.exec_triple,
"OPT_LEVEL": compilation_mode_opt_level,
"RUSTC": toolchain.rustc.path,
- "RUST_BACKTRACE": "full",
"TARGET": toolchain.target_triple,
# OUT_DIR is set by the runner itself, rather than on the action.
}
diff --git a/cargo/cargo_build_script_runner/bin.rs b/cargo/cargo_build_script_runner/bin.rs
index c7a871b..1a26c5f 100644
--- a/cargo/cargo_build_script_runner/bin.rs
+++ b/cargo/cargo_build_script_runner/bin.rs
@@ -21,9 +21,9 @@
use std::ffi::OsString;
use std::fs::{create_dir_all, write};
use std::path::Path;
-use std::process::{exit, Command};
+use std::process::Command;
-fn main() {
+fn main() -> Result<(), String> {
// We use exec_root.join rather than std::fs::canonicalize, to avoid resolving symlinks, as
// some execution strategies and remote execution environments may use symlinks in ways which
// canonicalizing them may break them, e.g. by having input files be symlinks into a /cas
@@ -49,7 +49,8 @@
.current_dir(manifest_dir.clone())
.env("OUT_DIR", out_dir_abs)
.env("CARGO_MANIFEST_DIR", manifest_dir)
- .env("RUSTC", rustc);
+ .env("RUSTC", rustc)
+ .env("RUST_BACKTRACE", "full");
if let Some(cc_path) = env::var_os("CC") {
command.env("CC", absolutify(&exec_root, cc_path));
@@ -65,7 +66,17 @@
}
}
- let output = BuildScriptOutput::from_command(&mut command);
+ let output = BuildScriptOutput::from_command(&mut command).map_err(|exit_code| {
+ format!(
+ "Build script process failed{}",
+ if let Some(exit_code) = exit_code {
+ format!(" with exit code {}", exit_code)
+ } else {
+ String::new()
+ }
+ )
+ })?;
+
write(&envfile, BuildScriptOutput::to_env(&output).as_bytes())
.expect(&format!("Unable to write file {:?}", envfile));
write(&depenvfile, BuildScriptOutput::to_dep_env(&output, &crate_name).as_bytes())
@@ -77,10 +88,10 @@
.expect(&format!("Unable to write file {:?}", flagfile));
write(&linkflags, link_flags.as_bytes())
.expect(&format!("Unable to write file {:?}", linkflags));
+ Ok(())
}
_ => {
- eprintln!("Usage: $0 progname crate_name out_dir envfile flagfile linkflagfile depenvfile [arg1...argn]");
- exit(1);
+ Err("Usage: $0 progname crate_name out_dir envfile flagfile linkflagfile depenvfile [arg1...argn]".to_owned())
}
}
}
diff --git a/cargo/cargo_build_script_runner/lib.rs b/cargo/cargo_build_script_runner/lib.rs
index a802fc7..c203dae 100644
--- a/cargo/cargo_build_script_runner/lib.rs
+++ b/cargo/cargo_build_script_runner/lib.rs
@@ -50,12 +50,15 @@
fn new(line: &str) -> Option<BuildScriptOutput> {
let split = line.splitn(2, '=').collect::<Vec<_>>();
if split.len() <= 1 {
+ // Not a cargo directive.
+ print!("{}", line);
return None;
}
let param = split[1].trim().to_owned();
let key_split = split[0].splitn(2, ':').collect::<Vec<_>>();
if key_split.len() <= 1 || key_split[0] != "cargo" {
// Not a cargo directive.
+ print!("{}", line);
return None
}
match key_split[1] {
@@ -97,7 +100,7 @@
}
/// Take a [Command], execute it and converts its input into a vector of [BuildScriptOutput]
- pub fn from_command(cmd: &mut Command) -> Vec<BuildScriptOutput> {
+ pub fn from_command(cmd: &mut Command) -> Result<Vec<BuildScriptOutput>, Option<i32>> {
let mut child = cmd.stdout(Stdio::piped()).spawn().expect("Unable to start binary");
let ecode = child.wait().expect("failed to wait on child");
let reader = BufReader::new(
@@ -106,8 +109,13 @@
.as_mut()
.expect("Failed to open stdout"),
);
- assert!(ecode.success());
- Self::from_reader(reader)
+ let output = Self::from_reader(reader);
+ if ecode.success() {
+ Ok(output)
+ } else {
+ Err(ecode.code())
+ }
+
}
/// Convert a vector of [BuildScriptOutput] into a list of environment variables.