use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::{fs::File, io::Read, path::Path};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HostManifest {
#[doc(hidden)]
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub actors: Vec<String>,
#[doc(hidden)]
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub capabilities: Vec<Capability>,
#[doc(hidden)]
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub links: Vec<LinkEntry>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[doc(hidden)]
pub struct Capability {
pub image_ref: String,
pub link_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[doc(hidden)]
pub struct LinkEntry {
pub actor: String,
pub contract_id: String,
pub provider_id: String,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub link_name: Option<String>,
pub values: Option<HashMap<String, String>>,
}
impl HostManifest {
pub fn from_path(
path: impl AsRef<Path>,
expand_env: bool,
) -> std::result::Result<HostManifest, Box<dyn std::error::Error + Send + Sync>> {
let mut contents = String::new();
let mut file = File::open(path.as_ref())?;
file.read_to_string(&mut contents)?;
if expand_env {
contents = Self::expand_env(&contents);
}
match path.as_ref().extension() {
Some(e) => {
let e = e.to_str().unwrap().to_lowercase(); if e == "yaml" || e == "yml" {
serde_yaml::from_str::<HostManifest>(&contents).map_err(|e| e.into())
} else {
serde_json::from_str::<HostManifest>(&contents).map_err(|e| e.into())
}
}
None => serde_yaml::from_str::<HostManifest>(&contents).map_err(|e| e.into()),
}
}
fn expand_env(contents: &str) -> String {
let mut options = envmnt::ExpandOptions::new();
options.default_to_empty = false; options.expansion_type = Some(envmnt::ExpansionType::UnixBracketsWithDefaults);
envmnt::expand(contents, Some(options))
}
}