Skip to main content

mz_testdrive/action/
protobuf.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10use std::path::{self, PathBuf};
11use std::{env, iter};
12
13use anyhow::{Context, bail};
14use tokio::process::Command;
15
16use crate::action::{ControlFlow, State};
17use crate::parser::BuiltinCommand;
18
19pub async fn run_compile_descriptors(
20    mut cmd: BuiltinCommand,
21    state: &mut State,
22) -> Result<ControlFlow, anyhow::Error> {
23    let inputs: Vec<String> = cmd
24        .args
25        .string("inputs")?
26        .split(',')
27        .map(|s| s.into())
28        .collect();
29    let output = cmd.args.string("output")?;
30    let set_var = cmd.args.opt_string("set-var");
31    cmd.args.done()?;
32    for path in inputs.iter().chain(iter::once(&output)) {
33        if path.contains(path::MAIN_SEPARATOR) {
34            // The goal isn't security, but preventing mistakes.
35            bail!("separators in paths are forbidden");
36        }
37    }
38    let protoc = match env::var_os("PROTOC") {
39        None => mz_build_tools::protoc(),
40        Some(protoc) => PathBuf::from(protoc),
41    };
42    let protoc_include = match env::var_os("PROTOC_INCLUDE") {
43        None => mz_build_tools::protoc_include(),
44        Some(include) => PathBuf::from(include),
45    };
46    let output_path = state.temp_path.join(&output);
47    let status = Command::new(protoc)
48        .arg("--include_imports")
49        .arg("-I")
50        .arg(&state.temp_path)
51        .arg("-I")
52        .arg(&protoc_include)
53        .arg("--descriptor_set_out")
54        .arg(state.temp_path.join(&output).clone())
55        .args(&inputs)
56        .status()
57        .await
58        .context("invoking protoc failed")?;
59    if !status.success() {
60        bail!("protoc exited unsuccessfully");
61    }
62    if let Some(var) = set_var {
63        let res = std::fs::read(output_path)?;
64        let hex_encoded = hex::encode(res);
65        state.cmd_vars.insert(var, format!("\\x{hex_encoded}"));
66    }
67    Ok(ControlFlow::Continue)
68}