use std::{fs, io};
use std::path::Path;
use serde::Serialize;
use json;
use chrono::Datelike;
use crate::pixiconfig::PixiConfig;
fn phoenix_save_json_value(name: &String, value: &String) -> String{
format!("\t{}: {},\n", json::stringify(name.as_str()), json::stringify(value.as_str()))
}
fn phoenix_save_json_value_end(name: &String, value: &String) -> String{
format!("\t{}: {}\n", json::stringify(name.as_str()), json::stringify(value.as_str()))
}
#[derive(Debug, Serialize)]
pub struct AffiliationConfig{
#[serde(rename = "@type")]
p_type: String,
#[serde(rename = "name")]
p_name: String,
}
impl Default for AffiliationConfig {
fn default() -> Self {
AffiliationConfig{
p_type: String::from("Organization"),
p_name: String::from("LAPP, Univ. Savoie Mont-Blanc, CNRS")
}
}
}
impl AffiliationConfig{
fn to_json_string(&self) -> String{
let mut body: String = String::from("\t\t\t\"affiliation\": {\n");
body += &format!("\t\t\t{}", phoenix_save_json_value(&String::from("@type"), &self.p_type));
body += &format!("\t\t\t{}", phoenix_save_json_value_end(&String::from("name"), &self.p_name));
body += &String::from("\t\t\t}\n");
return body;
}
}
#[derive(Debug, Serialize)]
pub struct PersonConfig{
#[serde(rename = "@type")]
p_type: String,
#[serde(rename = "givenName")]
p_name: String,
#[serde(rename = "familyName")]
p_familly_name: String,
#[serde(rename = "affiliation")]
p_affiliation: AffiliationConfig,
}
impl Default for PersonConfig {
fn default() -> Self {
PersonConfig{
p_type: String::from("Person"),
p_name: String::from("Pierre"),
p_familly_name: String::from("Aubert"),
p_affiliation: Default::default()
}
}
}
impl PersonConfig {
pub fn new(name: &String, familly_name: &String) -> Self {
PersonConfig{
p_type: String::from("Person"),
p_name: name.to_owned(),
p_familly_name: familly_name.to_owned(),
p_affiliation: Default::default()
}
}
fn to_json_string(&self) -> String{
let mut body: String = String::from("\t\t{\n");
body += &format!("\t\t{}", phoenix_save_json_value(&String::from("@type"), &self.p_type));
body += &format!("\t\t{}", phoenix_save_json_value(&String::from("givenName"), &self.p_name));
body += &format!("\t\t{}", phoenix_save_json_value(&String::from("familyName"), &self.p_familly_name));
body += &self.p_affiliation.to_json_string();
body += &String::from("\t\t}");
return body;
}
}
#[derive(Debug, Serialize)]
pub struct CodeMetaConfig{
#[serde(rename = "@context")]
p_context: String,
#[serde(rename = "@type")]
p_type: String,
#[serde(rename = "license")]
p_license: String,
#[serde(rename = "codeRepository")]
p_code_repository: String,
#[serde(rename = "contIntegration")]
p_continuous_integration: String,
#[serde(rename = "dateCreated")]
p_date_created: String,
#[serde(rename = "datePublished")]
p_date_published: String,
#[serde(rename = "dateModified")]
p_date_modified: String,
#[serde(rename = "downloadUrl")]
p_download_url: String,
#[serde(rename = "issueTracker")]
p_issue_tracker: String,
#[serde(rename = "name")]
p_name: String,
#[serde(rename = "version")]
p_version: String,
#[serde(rename = "softwareVersion")]
p_software_version: String,
#[serde(rename = "readme")]
p_readme: String,
#[serde(rename = "description")]
p_description: String,
#[serde(rename = "keywords")]
p_vec_keyword: Vec<String>,
#[serde(rename = "author")]
p_vec_author: Vec<PersonConfig>,
#[serde(rename = "contributor")]
p_vec_contributor: Vec<PersonConfig>,
#[serde(rename = "maintainer")]
p_maintainer: PersonConfig,
}
impl CodeMetaConfig{
pub fn from(config: &PixiConfig, vec_keyword: &Vec<String>, creation_date: &String) -> Self{
let current_date = chrono::Utc::now();
let year = current_date.year();
let month = current_date.month();
let day = current_date.day();
let date: String = String::from(format!("{}-{:02}-{:02}", year, month, day));
CodeMetaConfig {
p_context: String::from("https://doi.org/10.5063/schema/codemeta-2.0"),
p_type: String::from("SoftwareSourceCode"),
p_license: String::from("https://spdx.org/licenses/CECILL-C"),
p_code_repository: config.get_repository(),
p_continuous_integration: config.get_continuous_integration(),
p_date_created: creation_date.to_owned(),
p_date_published: date.clone(),
p_date_modified: date.clone(),
p_download_url: config.get_download_url(),
p_issue_tracker: config.get_issue_tracker(),
p_name: config.get_name().to_owned(),
p_version: config.get_version().to_owned(),
p_software_version: config.get_version().to_owned(),
p_readme: config.get_readme(),
p_description: config.get_description().to_owned(),
p_vec_keyword: vec_keyword.to_owned(),
p_vec_author: vec![
PersonConfig::new(&String::from("Pierre"), &String::from("Aubert")),
PersonConfig::new(&String::from("Vincent"), &String::from("Pollet")),
PersonConfig::new(&String::from("Thibaut"), &String::from("Oprinsen"))
],
p_vec_contributor: vec![
PersonConfig::new(&String::from("Pierre"), &String::from("Aubert")),
PersonConfig::new(&String::from("Vincent"), &String::from("Pollet")),
PersonConfig::new(&String::from("Thibaut"), &String::from("Oprinsen"))
],
p_maintainer: Default::default()
}
}
}
pub fn save_codemeta_json(filename: &Path, config: &CodeMetaConfig) -> io::Result<()>{
let mut body = String::from("{\n");
body += &phoenix_save_json_value(&String::from("@context"), &config.p_context);
body += &phoenix_save_json_value(&String::from("@type"), &config.p_type);
body += &phoenix_save_json_value(&String::from("license"), &config.p_license);
body += &phoenix_save_json_value(&String::from("codeRepository"), &config.p_code_repository);
body += &phoenix_save_json_value(&String::from("contIntegration"), &config.p_continuous_integration);
body += &phoenix_save_json_value(&String::from("dateCreated"), &config.p_date_created);
body += &phoenix_save_json_value(&String::from("dateModified"), &config.p_date_modified);
body += &phoenix_save_json_value(&String::from("datePublished"), &config.p_date_published);
body += &phoenix_save_json_value(&String::from("downloadUrl"), &config.p_download_url);
body += &phoenix_save_json_value(&String::from("issueTracker"), &config.p_issue_tracker);
body += &phoenix_save_json_value(&String::from("name"), &config.p_name);
body += &phoenix_save_json_value(&String::from("version"), &config.p_version);
body += &phoenix_save_json_value(&String::from("softwareVersion"), &config.p_software_version);
body += &phoenix_save_json_value(&String::from("readme"), &config.p_readme);
body += &phoenix_save_json_value(&String::from("description"), &config.p_description);
body += &String::from("\t\"keywords\": [");
let mut comma_keyword = String::from("");
for key in config.p_vec_keyword.iter(){
body += &comma_keyword;
body += &json::stringify(key.to_owned());
comma_keyword = String::from(", ");
}
body += &String::from("],\n");
body += &String::from(r#" "relatedLink": [
"https://gitlab.in2p3.fr/CTA-LAPP/PHOENIX_LIBS2/PHOENIX2"
],
"#);
body += &String::from("\t\"author\": [\n");
let mut author_comma = String::from("");
for person in config.p_vec_author.iter(){
body += &author_comma;
body += &person.to_json_string();
author_comma = String::from(",\n");
}
body += &String::from("\n\t],\n");
body += &String::from("\t\"contributor\": [\n");
let mut contributor_comma = String::from("");
for person in config.p_vec_contributor.iter(){
body += &contributor_comma;
body += &person.to_json_string();
contributor_comma = String::from(",\n");
}
body += &String::from("\n\t],\n");
body += &String::from("\t\"maintainer\":\n");
body += &config.p_maintainer.to_json_string();
body += &String::from("\n}\n");
fs::write(filename, body)?;
Ok(())
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use super::*;
#[test]
fn test_codemeta_to_json(){
fs::create_dir_all("generated/").unwrap();
let config: CodeMetaConfig = CodeMetaConfig {
p_context: String::from("https://doi.org/10.5063/schema/codemeta-2.0"),
p_type: String::from("SoftwareSourceCode"),
p_license: String::from("https://spdx.org/licenses/CECILL-C"),
p_code_repository: String::from(""),
p_continuous_integration: String::from(""),
p_date_created: String::from("2026-03-02"),
p_date_published: String::from(""),
p_date_modified: String::from(""),
p_download_url: String::from(""),
p_issue_tracker: String::from(""),
p_name: String::from(""),
p_version: String::from("0.42.0"),
p_software_version: String::from("0.42.0"),
p_readme: String::from(""),
p_description: String::from("Very important project"),
p_vec_keyword: vec![String::from("Phoenix2")],
p_vec_author: vec![
PersonConfig::new(&String::from("Pierre"), &String::from("Aubert")),
PersonConfig::new(&String::from("Vincent"), &String::from("Pollet")),
PersonConfig::new(&String::from("Thibaut"), &String::from("Oprinsen"))
],
p_vec_contributor: vec![
PersonConfig::new(&String::from("Pierre"), &String::from("Aubert")),
PersonConfig::new(&String::from("Vincent"), &String::from("Pollet")),
PersonConfig::new(&String::from("Thibaut"), &String::from("Oprinsen"))
],
p_maintainer: Default::default()
};
let filename: PathBuf = PathBuf::from("generated/codemeta.json");
save_codemeta_json(&filename, &config).unwrap();
}
}