greentic-operator 0.4.43

Greentic operator CLI for local dev and demo orchestration.
Documentation
use std::path::Path;
use std::process::Command;

use serde_json::Value;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RunnerFlavor {
    RunSubcommand,
    RunnerCli,
}

pub struct RunFlowOptions<'a> {
    pub dist_offline: bool,
    pub tenant: Option<&'a str>,
    pub team: Option<&'a str>,
    pub artifacts_dir: Option<&'a Path>,
    pub runner_flavor: RunnerFlavor,
}

pub struct RunnerOutput {
    pub status: std::process::ExitStatus,
    pub stdout: String,
    pub stderr: String,
    pub parsed: Option<Value>,
}

pub fn run_flow(
    runner: &Path,
    pack: &Path,
    flow: &str,
    input: &Value,
) -> anyhow::Result<RunnerOutput> {
    run_flow_with_options(
        runner,
        pack,
        flow,
        input,
        RunFlowOptions {
            dist_offline: false,
            tenant: None,
            team: None,
            artifacts_dir: None,
            runner_flavor: RunnerFlavor::RunSubcommand,
        },
    )
}

pub fn run_flow_with_options(
    runner: &Path,
    pack: &Path,
    flow: &str,
    input: &Value,
    options: RunFlowOptions<'_>,
) -> anyhow::Result<RunnerOutput> {
    let input_str = serde_json::to_string(input)?;
    let mut command = Command::new(runner);
    match options.runner_flavor {
        RunnerFlavor::RunSubcommand => {
            command
                .args(["run", "--pack"])
                .arg(pack)
                .args(["--flow", flow, "--input"])
                .arg(&input_str);
            if options.dist_offline {
                command.arg("--offline");
            }
        }
        RunnerFlavor::RunnerCli => {
            command
                .arg("--pack")
                .arg(pack)
                .args(["--flow", flow, "--input"])
                .arg(&input_str);
            if let Some(tenant) = options.tenant {
                command.args(["--tenant", tenant]);
            }
            if let Some(team) = options.team {
                command.args(["--team", team]);
            }
            if let Some(artifacts_dir) = options.artifacts_dir {
                command.arg("--artifacts-dir").arg(artifacts_dir);
            }
            if options.dist_offline {
                command.arg("--offline");
            }
        }
    }
    let output = command.output()?;

    let stdout = String::from_utf8_lossy(&output.stdout).to_string();
    let stderr = String::from_utf8_lossy(&output.stderr).to_string();
    let parsed = serde_json::from_str(&stdout).ok();

    Ok(RunnerOutput {
        status: output.status,
        stdout,
        stderr,
        parsed,
    })
}

pub fn detect_runner_flavor(runner: &Path) -> RunnerFlavor {
    let name = runner
        .file_name()
        .and_then(|value| value.to_str())
        .unwrap_or_default();
    if name.contains("runner-cli") {
        RunnerFlavor::RunnerCli
    } else {
        RunnerFlavor::RunSubcommand
    }
}