use std::ops::Not;
use indexmap::IndexMap;
use serde::Serialize;
#[derive(Debug, Clone, Default, Serialize)]
pub(crate) struct Volume {
#[serde(skip_serializing_if = "Not::not")]
pub(crate) external: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) name: Option<String>,
#[serde(skip_serializing_if = "IndexMap::is_empty")]
pub(crate) labels: IndexMap<String, String>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub(crate) enum Mount {
Short(String),
Long(LongMount),
}
impl From<String> for Mount {
fn from(short: String) -> Mount {
Mount::Short(short)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub(crate) enum LongMount {
Volume {
source: String,
target: String,
volume: VolumeOptions,
},
Tmpfs {
target: String,
tmpfs: TmpfsOptions,
},
}
#[derive(Debug, Clone, Serialize)]
pub(crate) struct VolumeOptions {
pub(crate) subpath: String,
}
#[derive(Debug, Clone, Serialize)]
pub(crate) struct TmpfsOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) size: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) mode: Option<u32>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_long_mount_says_its_type_first() {
let folder = LongMount::Volume {
source: "data".into(),
target: "/srv".into(),
volume: VolumeOptions { subpath: "web".into() },
};
let tmpfs = LongMount::Tmpfs {
target: "/run".into(),
tmpfs: TmpfsOptions {
size: None,
mode: Some(0o1777),
},
};
let yaml = serde_yaml_ng::to_string(&[Mount::Long(folder), Mount::Long(tmpfs)]).expect("serializes");
assert_eq!(
yaml,
"- type: volume\n source: data\n target: /srv\n volume:\n subpath: web\n- type: tmpfs\n target: /run\n tmpfs:\n mode: 1023\n"
);
}
}