cuddle/cuddle/src/model.rs
kjuulh 0ebe88a470
Some checks reported errors
continuous-integration/drone/push Build encountered an error
feat: allow arrays
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-05-27 22:59:11 +02:00

239 lines
6.2 KiB
Rust

use std::collections::HashMap;
use serde::Deserialize;
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(untagged)]
pub enum CuddleBase {
Bool(bool),
String(String),
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct CuddleShellScriptArgEnv {
pub key: String,
pub description: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct CuddleShellScriptArgFlag {
pub name: String,
pub description: Option<String>,
pub required: Option<bool>,
pub default_value: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(tag = "type")]
pub enum CuddleShellScriptArg {
#[serde(alias = "env")]
Env(CuddleShellScriptArgEnv),
#[serde(alias = "flag")]
Flag(CuddleShellScriptArgFlag),
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct CuddleShellScript {
pub description: Option<String>,
pub args: Option<HashMap<String, CuddleShellScriptArg>>,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct CuddleDaggerScript {
pub description: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct CuddleLuaScript {
pub description: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub enum CuddleRustUpstream {
#[serde(alias = "gitea")]
Gitea { url: String },
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct CuddleRustScript {
pub description: Option<String>,
pub upstream: CuddleRustUpstream,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(tag = "type")]
pub enum CuddleScript {
#[serde(alias = "shell")]
Shell(CuddleShellScript),
#[serde(alias = "dagger")]
Dagger(CuddleDaggerScript),
#[serde(alias = "lua")]
Lua(CuddleLuaScript),
#[serde(alias = "rust")]
Rust(CuddleRustScript),
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct CuddlePlan {
pub base: CuddleBase,
pub vars: Option<CuddlePlanVariables>,
pub scripts: Option<HashMap<String, CuddleScript>>,
}
#[derive(Deserialize, Debug, Clone, PartialEq)]
pub struct CuddlePlanVariables(HashMap<String, CuddlePlanVar>);
impl From<CuddlePlanVariables> for Vec<CuddleVariable> {
fn from(value: CuddlePlanVariables) -> Self {
let variables: CuddleVariables = value.0.into();
let mut vars = variables.0;
vars.sort_by(|a, b| a.name.partial_cmp(&b.name).unwrap());
vars
}
}
#[derive(Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum CuddlePlanVar {
Str(String),
Nested(HashMap<String, CuddlePlanVar>),
Array(Vec<CuddlePlanVar>),
}
#[derive(Clone, Debug, PartialEq)]
struct CuddleVariables(Vec<CuddleVariable>);
impl From<HashMap<String, CuddlePlanVar>> for CuddleVariables {
fn from(value: HashMap<String, CuddlePlanVar>) -> Self {
let mut variables = Vec::new();
for (k, v) in value {
match v {
CuddlePlanVar::Str(value) => variables.push(CuddleVariable::new(k, value)),
CuddlePlanVar::Nested(nested) => {
let nested_variables: CuddleVariables = nested.into();
let mut combined_variables: Vec<_> = nested_variables
.0
.into_iter()
.map(|v| CuddleVariable::new(format!("{}_{}", k, v.name), v.value))
.collect();
variables.append(&mut combined_variables);
}
CuddlePlanVar::Array(_) => {}
}
}
CuddleVariables(variables)
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, serde::Serialize)]
#[allow(dead_code)]
pub struct CuddleVariable {
pub name: String,
pub value: String,
}
impl CuddleVariable {
pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
Self {
name: name.into(),
value: value.into(),
}
}
}
impl From<HashMap<String, CuddlePlanVar>> for CuddlePlanVar {
fn from(value: HashMap<String, CuddlePlanVar>) -> Self {
CuddlePlanVar::Nested(value)
}
}
impl From<HashMap<&str, CuddlePlanVar>> for CuddlePlanVar {
fn from(value: HashMap<&str, CuddlePlanVar>) -> Self {
CuddlePlanVar::Nested(value.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
}
}
impl From<String> for CuddlePlanVar {
fn from(value: String) -> Self {
CuddlePlanVar::Str(value)
}
}
impl From<&str> for CuddlePlanVar {
fn from(value: &str) -> Self {
CuddlePlanVar::Str(value.to_string())
}
}
#[cfg(test)]
mod test {
use std::collections::HashMap;
use super::{CuddlePlanVariables, CuddleVariable};
#[test]
pub fn parse_cuddle_variables() {
let cuddle = r#"
someKey: someValue
someNestedKey:
someNestedNestedKey:
someKey: key
someKey: key
"#;
let cuddle_var: CuddlePlanVariables = serde_yaml::from_str(cuddle).unwrap();
let mut expected = HashMap::new();
expected.insert("someKey", "someValue".into());
let mut nested_key = HashMap::new();
nested_key.insert("someKey", "key".into());
let mut nested_nested_key = HashMap::new();
nested_nested_key.insert("someKey", "key".into());
nested_key.insert("someNestedNestedKey", nested_nested_key.into());
expected.insert("someNestedKey", nested_key.into());
assert_eq!(
CuddlePlanVariables(
expected
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect()
),
cuddle_var
);
}
#[test]
pub fn to_cuddle_variables() {
let cuddle = r#"
someKey: someValue
someNestedKey:
someNestedNestedKey:
someKey: key
someKey: key
"#;
let cuddle_var: CuddlePlanVariables = serde_yaml::from_str(cuddle).unwrap();
let variables: Vec<CuddleVariable> = cuddle_var.into();
let mut expected: Vec<CuddleVariable> = vec![
CuddleVariable::new("someKey", "someValue"),
CuddleVariable::new("someNestedKey_someKey", "key"),
CuddleVariable::new("someNestedKey_someNestedNestedKey_someKey", "key"),
];
expected.sort_by(|a, b| a.name.partial_cmp(&b.name).unwrap());
assert_eq!(expected, variables);
}
}