114 lines
2.9 KiB
Rust
114 lines
2.9 KiB
Rust
use miette::{Context, Diagnostic, IntoDiagnostic};
|
|
use mlua::{prelude::*, Lua};
|
|
use std::{path::PathBuf, process::Command};
|
|
use thiserror::Error;
|
|
|
|
use serde::Deserialize;
|
|
|
|
pub struct Config<'lua> {
|
|
pub steps: Vec<Step<'lua>>,
|
|
pub shell: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct Step<'lua> {
|
|
pub command: CfgCommand,
|
|
#[serde(default)]
|
|
pub interactive: bool,
|
|
pub unint_alt: Option<CfgCommand>,
|
|
pub workdir: Option<PathBuf>,
|
|
|
|
#[serde(skip)]
|
|
pub when: Option<LuaFunction<'lua>>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
#[serde(untagged)]
|
|
pub enum CfgCommand {
|
|
Shell(String),
|
|
Args(Vec<String>),
|
|
}
|
|
|
|
impl ToString for CfgCommand {
|
|
fn to_string(&self) -> String {
|
|
match self {
|
|
Self::Shell(cmd) => cmd.clone(),
|
|
Self::Args(args) => args.join(" "),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Error, Diagnostic)]
|
|
#[diagnostic(code)]
|
|
pub enum IntoCommandError {
|
|
#[error("Command has empty args!")]
|
|
EmptyArgs,
|
|
|
|
#[error("Shell command is empty!")]
|
|
EmptyShell,
|
|
}
|
|
|
|
impl CfgCommand {
|
|
pub fn into_command(self, shell: &[String]) -> Result<Command, IntoCommandError> {
|
|
match self {
|
|
Self::Args(args) => {
|
|
let mut cmd = Command::new(args.first().ok_or(IntoCommandError::EmptyArgs)?);
|
|
cmd.args(&args[1..]);
|
|
Ok(cmd)
|
|
},
|
|
Self::Shell(shell_cmd) => {
|
|
let mut cmd = Command::new(shell.first().ok_or(IntoCommandError::EmptyShell)?);
|
|
cmd.args(&shell[1..]).arg(shell_cmd);
|
|
Ok(cmd)
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn run_config<'lua>(lua: &'lua Lua, content: &[u8]) -> miette::Result<Config<'lua>> {
|
|
lua.load(content)
|
|
.set_name("config")
|
|
.into_diagnostic()?
|
|
.exec()
|
|
.into_diagnostic()?;
|
|
|
|
let lua_conf = lua.globals();
|
|
|
|
let mut conf = Config {
|
|
steps: vec![],
|
|
shell: lua_conf
|
|
.get::<_, Option<_>>("shell")
|
|
.into_diagnostic()
|
|
.wrap_err("config must declare `shell` variable!")?
|
|
.unwrap_or_else(|| vec!["sh".to_string(), "-c".to_string()]),
|
|
};
|
|
|
|
for pair in lua_conf
|
|
.get::<_, LuaTable>("steps")
|
|
.into_diagnostic()
|
|
.wrap_err("config must declare `steps` variable!")?
|
|
.pairs::<LuaValue, LuaTable>()
|
|
{
|
|
let (_, step) = pair.into_diagnostic()?;
|
|
|
|
let when = step
|
|
.get::<_, Option<LuaFunction>>("when")
|
|
.into_diagnostic()
|
|
.wrap_err("Failed to get `when` from step")?;
|
|
|
|
let mut step = lua
|
|
.from_value_with::<Step>(
|
|
LuaValue::Table(step),
|
|
mlua::serde::de::Options::new().deny_unsupported_types(false),
|
|
)
|
|
.into_diagnostic()
|
|
.wrap_err("Failed to deserialize step")?;
|
|
|
|
step.when = when;
|
|
|
|
conf.steps.push(step);
|
|
}
|
|
|
|
Ok(conf)
|
|
}
|