use std::collections::BTreeMap;
use serde::Serialize;
use shep_core::config::AppConfig;
use shep_core::values::{MemSize, UpDuration};
#[derive(Debug, Serialize)]
struct Rendered {
name: String,
script: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
args: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
cwd: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
interpreter: Option<String>,
#[serde(skip_serializing_if = "is_one")]
instances: u32,
#[serde(skip_serializing_if = "is_true")]
autorestart: bool,
#[serde(skip_serializing_if = "Option::is_none")]
restart_delay: Option<UpDuration>,
#[serde(skip_serializing_if = "Option::is_none")]
max_memory: Option<MemSize>,
#[serde(skip_serializing_if = "is_false")]
merge_logs: bool,
#[serde(skip_serializing_if = "is_false")]
reuse_port: bool,
#[serde(skip_serializing_if = "Option::is_none")]
increment_var: Option<String>,
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
env: BTreeMap<String, String>,
}
fn is_one(instances: &u32) -> bool {
*instances == 1
}
fn is_true(value: &bool) -> bool {
*value
}
fn is_false(value: &bool) -> bool {
!*value
}
impl From<&AppConfig> for Rendered {
fn from(app: &AppConfig) -> Self {
Self {
name: app.name.clone(),
script: app.script.clone(),
args: app.args.clone(),
cwd: app.cwd.clone(),
interpreter: app.interpreter.clone(),
instances: app.instances,
autorestart: app.autorestart,
restart_delay: app.restart_delay,
max_memory: app.max_memory,
merge_logs: app.merge_logs,
reuse_port: app.reuse_port,
increment_var: app.increment_var.clone(),
env: app.env.clone(),
}
}
}
#[derive(Debug, Serialize)]
struct Doc {
#[serde(rename = "app")]
apps: Vec<Rendered>,
}
pub(crate) fn flockfile(apps: &[AppConfig]) -> Result<String, toml::ser::Error> {
let doc = Doc {
apps: apps.iter().map(Rendered::from).collect(),
};
toml::to_string(&doc)
}
#[cfg(test)]
mod tests {
use shep_core::config::{FlockFormat, Flockfile};
use super::*;
use crate::commands::import::convert::convert;
use crate::commands::import::dump;
#[test]
fn flockfile_round_trips_through_the_real_parser() {
let apps = convert(dump::parse(include_str!("testdata/dump.pm2.json")).unwrap())
.unwrap()
.apps;
let rendered = flockfile(&apps).unwrap();
let parsed = Flockfile::parse(&rendered, FlockFormat::Toml).unwrap();
assert_eq!(parsed.apps, apps);
}
#[test]
fn defaults_are_left_out() {
let rendered = flockfile(&[AppConfig::minimal("web", "./srv")]).unwrap();
assert_eq!(
rendered.trim(),
"[[app]]\nname = \"web\"\nscript = \"./srv\""
);
}
#[test]
fn newtype_values_render_in_their_string_form() {
let mut app = AppConfig::minimal("web", "./srv");
app.max_memory = Some(MemSize::from_bytes(536_870_912));
app.restart_delay = Some(UpDuration::from_millis(5000));
let rendered = flockfile(&[app]).unwrap();
assert!(rendered.contains("max_memory = \"512M\""), "{rendered}");
assert!(rendered.contains("restart_delay = \"5s\""), "{rendered}");
}
}