use crate::inventory::value::{Hash, Key, Value};
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyList};
use std::rc::Rc;
fn bool_to_py(b: bool, py: Python<'_>) -> PyObject {
let borrowed = pyo3::types::PyBool::new(py, b);
let bound = borrowed.to_owned();
bound.into_any().unbind()
}
pub fn key_to_py(key: &Key, py: Python<'_>) -> PyResult<PyObject> {
match key {
Key::String(s) => Ok(s.into_pyobject(py)?.into_any().unbind()),
Key::Integer(i) => Ok(i.into_pyobject(py)?.into_any().unbind()),
Key::Boolean(b) => Ok(bool_to_py(*b, py)),
Key::Null => Ok(py.None()),
}
}
pub fn value_to_py(val: &Value, py: Python<'_>) -> PyResult<PyObject> {
match val {
Value::Hash(rc_hash) => hash_to_py(rc_hash, py),
Value::Array(rc_arr) => array_to_py(rc_arr, py),
Value::String(s) => Ok(s.into_pyobject(py)?.into_any().unbind()),
Value::Integer(i) => Ok(i.into_pyobject(py)?.into_any().unbind()),
Value::Boolean(b) => Ok(bool_to_py(*b, py)),
Value::Null => Ok(py.None()),
Value::Real(s) => match s.parse::<f64>() {
Ok(f) => Ok(f.into_pyobject(py)?.into_any().unbind()),
Err(_) => Ok(s.into_pyobject(py)?.into_any().unbind()),
},
Value::Reference(segments) => {
let s = format!("{:?}", segments);
Ok(s.into_pyobject(py)?.into_any().unbind())
}
Value::StringWithReference(parts) => {
let s = format!("{:?}", parts);
Ok(s.into_pyobject(py)?.into_any().unbind())
}
Value::InvQuery(data) => {
let s = format!("{:?}", data);
Ok(s.into_pyobject(py)?.into_any().unbind())
}
Value::StringWithInvQuery(parts) => {
let s = format!("{:?}", parts);
Ok(s.into_pyobject(py)?.into_any().unbind())
}
Value::DeferredMerge(vals) => {
let s = format!("{:?}", vals);
Ok(s.into_pyobject(py)?.into_any().unbind())
}
Value::OverrideMarker(inner) => value_to_py(inner.as_ref(), py),
Value::ConstantMarker(inner) => value_to_py(inner.as_ref(), py),
}
}
fn hash_to_py(rc_hash: &Rc<Hash>, py: Python<'_>) -> PyResult<PyObject> {
let dict = PyDict::new(py);
for (k, v) in rc_hash.iter() {
let py_key = key_to_py(k, py)?;
let py_val = value_to_py(v, py)?;
dict.set_item(py_key, py_val)?;
}
Ok(dict.into_any().unbind())
}
fn array_to_py(rc_arr: &Rc<Vec<Value>>, py: Python<'_>) -> PyResult<PyObject> {
let list = PyList::empty(py);
for v in rc_arr.iter() {
let py_val = value_to_py(v, py)?;
list.append(py_val)?;
}
Ok(list.into_any().unbind())
}
pub fn parameters_to_pillar_dict(
parameters: &Hash,
nodename: &str,
classes: &[String],
applications: &[String],
environment: &dyn std::fmt::Display,
py: Python<'_>,
) -> PyResult<PyObject> {
let mut params: Hash = parameters.clone();
let reclass_key = Key::String("__reclass__".to_string());
let mut reclass_hash = match params.remove(&reclass_key) {
Some(Value::Hash(h)) => Rc::try_unwrap(h).unwrap_or_else(|rc| (*rc).clone()),
_ => Hash::new(),
};
reclass_hash.insert(
Key::String("nodename".to_string()),
Value::String(nodename.to_string()),
);
reclass_hash.insert(
Key::String("classes".to_string()),
Value::Array(Rc::new(
classes.iter().cloned().map(Value::String).collect(),
)),
);
reclass_hash.insert(
Key::String("applications".to_string()),
Value::Array(Rc::new(
applications.iter().cloned().map(Value::String).collect(),
)),
);
reclass_hash.insert(
Key::String("environment".to_string()),
Value::String(environment.to_string()),
);
params.insert(reclass_key, Value::Hash(Rc::new(reclass_hash)));
value_to_py(&Value::Hash(Rc::new(params)), py)
}
pub fn top_to_py<'py>(
data: &hashlink::LinkedHashMap<String, hashlink::LinkedHashMap<String, Vec<String>>>,
py: Python<'py>,
) -> PyResult<PyObject> {
let dict = PyDict::new(py);
for (env, nodes) in data {
let nodes_dict = PyDict::new(py);
for (node, apps) in nodes {
let py_apps = PyList::new(py, apps)?;
nodes_dict.set_item(node, py_apps)?;
}
dict.set_item(env, nodes_dict)?;
}
Ok(dict.into_any().unbind())
}
pub fn single_top_to_py<'py>(
environment: &dyn std::fmt::Display,
applications: &[String],
py: Python<'py>,
) -> PyResult<PyObject> {
let dict = PyDict::new(py);
let py_apps = PyList::new(py, applications)?;
dict.set_item(environment.to_string(), py_apps)?;
Ok(dict.into_any().unbind())
}