acts-package-shell 0.17.0

acts package for shell
Documentation
use acts::{
    ActError, ActPackage, ActPackageCatalog, ActPackageMeta, ActRunAs, Result, Vars, include_json,
};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use std::process::Command;
use strum::AsRefStr;

const DATA_KEY: &str = "data";

#[derive(Debug, Clone, Deserialize, Serialize, AsRefStr)]
pub enum Shell {
    #[allow(clippy::enum_variant_names)]
    #[serde(rename(deserialize = "nu"))]
    #[strum(serialize = "nu")]
    NuShell,
    #[serde(rename(deserialize = "bash"))]
    #[strum(serialize = "bash")]
    Bash,
    #[allow(clippy::enum_variant_names)]
    #[serde(rename(deserialize = "powershell"))]
    #[strum(serialize = "powershell")]
    PowerShell,
}

#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum ContentType {
    #[serde(rename(deserialize = "text"))]
    Text,
    #[serde(rename(deserialize = "json"))]
    Json,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ShellPackage {
    shell: Shell,
    script: String,
    #[serde(rename(deserialize = "content-type"))]
    content_type: Option<ContentType>,
}

impl ActPackage for ShellPackage {
    fn meta() -> ActPackageMeta {
        ActPackageMeta {
            name: "acts.app.shell",
            desc: "do shell script with nushell, bash or powershell",
            version: "0.1.0",
            icon: "icon-shell",
            doc: "",
            schema: include_json!("./schema.json"),
            run_as: ActRunAs::Irq,
            resources: vec![],
            catalog: ActPackageCatalog::App,
        }
    }
}

impl ShellPackage {
    pub fn create(inputs: &Vars) -> Result<Self> {
        let params = inputs
            .get::<serde_json::Value>("params")
            .ok_or(ActError::Package("missing 'params' in package".to_string()))?;
        let package = serde_json::from_value::<Self>(params)?;
        Ok(package)
    }

    pub async fn run(&self) -> Result<Vars> {
        let mut ret = Vars::new();
        let output = Command::new(self.shell.as_ref())
            .arg("-c")
            .arg(&self.script)
            .output()
            .map_err(|err| ActError::Package(format!("{}", err)))?;

        if !output.status.success() {
            let err = String::from_utf8(output.stderr)?;
            return Err(ActError::Package(err));
        }
        let data = String::from_utf8(output.stdout)?;
        let content_type = self.content_type.as_ref().unwrap_or(&ContentType::Text);
        match content_type {
            ContentType::Text => ret.set(DATA_KEY, data),
            ContentType::Json => ret.set(
                DATA_KEY,
                serde_json::from_str::<JsonValue>(&data).map_err(|err| {
                    ActError::Package(format!("failed to convert data to json: {}", err))
                })?,
            ),
        }

        Ok(ret)
    }
}