use std::{fs, path::Path};
use regex::Regex;
use relative_path::RelativePathBuf;
use serde::{Deserialize, Serialize};
use url::Url;
use crate::{
macros::rgx,
oxrl::{Odrl, Otrl},
};
use super::{ParseError, SerError};
pub type DSString = String;
pub const OKHV: &str = "OKH-LOSHv1.0";
pub const MANIFEST_FILE_NAME: &str = "okh.toml";
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "kebab-case")]
pub struct Software {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub release: Option<Url>,
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "kebab-case")]
pub struct SubMosh {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub image: Vec<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub tsdc: Option<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub source: Vec<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub export: Vec<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub auxiliary: Vec<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub part: Vec<SubMosh>,
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Okh {
pub okhv: DSString,
pub name: DSString,
pub repo: Url,
pub version: DSString,
pub license: DSString,
pub licensor: DSString,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub upload_method: Option<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub organisation: Option<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub readme: Option<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub contribution_guide: Option<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub image: Vec<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub documentation_language: Option<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub attestation: Vec<Url>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub standard_compliance: Vec<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub cpc_patent_class: Option<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub tsdc: Option<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub bom: Option<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub release: Option<Url>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub timestamp: Option<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub fork_of: Option<Url>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub function: Option<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub documentation_readiness_level: Option<Odrl>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub technology_readiness_level: Option<Otrl>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub user_manual: Option<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub manufacturing_instructions: Vec<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub software: Vec<Software>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub standard: Vec<DSString>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub source: Vec<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub export: Vec<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub auxiliary: Vec<RelativePathBuf>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub part: Vec<SubMosh>,
}
impl Okh {
pub fn from_toml(toml_str: &str) -> Result<Self, ParseError> {
log::debug!("Parsing TOML to v2 ...");
let parsed = toml::from_str::<Self>(toml_str)?;
Ok(parsed)
}
pub fn from_toml_file<OP>(toml_file: OP) -> Result<Self, ParseError>
where
OP: AsRef<Path>,
{
log::debug!("Reading TOML file to string ...");
let toml_str = fs::read_to_string(toml_file)?;
Self::from_toml(&toml_str)
}
pub fn to_toml(&self) -> Result<String, SerError> {
log::debug!("Serializing to TOML ...");
Ok(toml::to_string(self)?)
}
pub fn to_toml_file<OP>(&self, toml_file: OP) -> Result<(), SerError>
where
OP: AsRef<Path>,
{
let serialized = self.to_toml()?;
log::debug!("Writing to TOML file ...");
fs::write(toml_file, serialized)?;
Ok(())
}
pub fn ext_matcher() -> &'static Regex {
rgx!(r"(^|\.)[tT][oO][mM][lL]$")
}
pub fn file_matcher() -> &'static Regex {
rgx!(r"okh\.[tT][oO][mM][lL]$")
}
}