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.