Squashed 'third_party/rules_rust/' content from commit bf59038ca

git-subtree-dir: third_party/rules_rust
git-subtree-split: bf59038cac11798cbaef9f3bf965bad8182b97fa
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I5a20e403203d670df467ea97dde9a4ac40339a8d
diff --git a/proto/optional_output_wrapper.rs b/proto/optional_output_wrapper.rs
new file mode 100644
index 0000000..59eba1b
--- /dev/null
+++ b/proto/optional_output_wrapper.rs
@@ -0,0 +1,57 @@
+// Copyright 2020 The Bazel Authors. All rights reserved.

+//

+// Licensed under the Apache License, Version 2.0 (the "License");

+// you may not use this file except in compliance with the License.

+// You may obtain a copy of the License at

+//

+//    http://www.apache.org/licenses/LICENSE-2.0

+//

+// Unless required by applicable law or agreed to in writing, software

+// distributed under the License is distributed on an "AS IS" BASIS,

+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+// See the License for the specific language governing permissions and

+// limitations under the License.

+

+use std::env::args;

+use std::error;

+use std::fs::File;

+use std::path::Path;

+use std::process::Command;

+

+// A simple wrapper around a binary to ensure we always create some outputs

+// Optional outputs are not available in Skylark :(

+// Syntax: $0 output1 output2 ... -- program  [arg1...argn]

+fn ensure() -> Result<i32, Box<dyn error::Error>> {

+    let index = args().position(|a| a == "--").ok_or("no --")?;

+    let optional_outputs = args().take(index).collect::<Vec<String>>();

+    let exe = args().nth(index + 1).ok_or("no exe")?;

+    let exe_args = args().skip(index + 2).collect::<Vec<String>>();

+    if exe_args.is_empty() {

+        return Err("no exe args".into());

+    }

+    match Command::new(exe).args(exe_args).status()?.code() {

+        Some(code) => {

+            if code == 0 {

+                for out in optional_outputs {

+                    if !Path::new(&out).exists() {

+                        let _ = File::create(out)?;

+                    }

+                }

+            }

+            Ok(code)

+        }

+        None => Err("process killed".into()),

+    }

+}

+

+fn main() {

+    std::process::exit(match ensure() {

+        Ok(exit_code) => exit_code,

+        Err(e) => {

+            println!("Usage: [optional_output1...optional_outputN] -- program [arg1...argn]");

+            println!("{:?}", args());

+            println!("{:?}", e);

+            -1

+        }

+    });

+}