use isoloom_spec::model::Machine;
use isoloom_spec::shell::quote;
use crate::powershell;
pub(super) fn linux(m: &Machine) -> Option<String> {
if m.environment.is_empty() && m.sysctls.is_empty() && m.ulimits.is_empty() {
return None;
}
Some(format!(
"set -e\nmkdir -p /etc/systemd/system.conf.d\n{}{}{}systemctl daemon-reexec 2>/dev/null || true\n",
environment(m),
sysctls(m),
ulimits(m)
))
}
fn environment(m: &Machine) -> String {
if m.environment.is_empty() {
return String::new();
}
let keys = m.environment.keys().map(|k| regex_escape(k)).collect::<Vec<_>>().join("|");
let lines: String = m.environment.iter().map(|(k, v)| format!("{k}={v}\n")).collect::<Vec<_>>().concat();
let systemd = m
.environment
.iter()
.map(|(k, v)| format!("\"{k}={}\"", v.replace('\\', "\\\\").replace('"', "\\\"")))
.collect::<Vec<_>>()
.join(" ");
format!(
"grep -v -E '^({keys})=' /etc/environment > /etc/environment.isoloom 2>/dev/null || true\nprintf %s {} >> /etc/environment.isoloom && mv /etc/environment.isoloom /etc/environment\nprintf '[Manager]\\nDefaultEnvironment=%s\\n' {} > /etc/systemd/system.conf.d/90-isoloom-environment.conf\n",
quote(&lines),
quote(&systemd)
)
}
fn sysctls(m: &Machine) -> String {
if m.sysctls.is_empty() {
return String::new();
}
let lines: String = m.sysctls.iter().map(|(k, v)| format!("{k} = {v}\n")).collect::<Vec<_>>().concat();
format!(
"printf %s {} > /etc/sysctl.d/90-isoloom.conf\nsysctl -q -p /etc/sysctl.d/90-isoloom.conf\n",
quote(&lines)
)
}
fn ulimits(m: &Machine) -> String {
if m.ulimits.is_empty() {
return String::new();
}
let limits: String = m
.ulimits
.iter()
.flat_map(|(name, u)| ["*", "root"].map(|who| format!("{who} soft {name} {}\n{who} hard {name} {}\n", u.soft(), u.hard())))
.collect();
let defaults: String = m
.ulimits
.iter()
.map(|(name, u)| format!("DefaultLimit{}={}:{}\n", name.to_uppercase(), u.soft(), u.hard()))
.collect::<Vec<_>>()
.concat();
format!(
"mkdir -p /etc/security/limits.d && printf %s {} > /etc/security/limits.d/90-isoloom.conf\nprintf %s {} > /etc/systemd/system.conf.d/90-isoloom-limits.conf\n",
quote(&limits),
quote(&format!("[Manager]\n{defaults}"))
)
}
pub(super) fn windows(m: &Machine) -> Option<String> {
if m.environment.is_empty() {
return None;
}
Some(
m.environment
.iter()
.map(|(k, v)| {
format!(
"[Environment]::SetEnvironmentVariable({}, {}, 'Machine')",
powershell::quote(k),
powershell::quote(v)
)
})
.collect::<Vec<_>>()
.join("; "),
)
}
fn regex_escape(text: &str) -> String {
text.chars()
.flat_map(|c| ".[]{}()*+?^$|\\".contains(c).then_some('\\').into_iter().chain([c]))
.collect()
}
#[cfg(test)]
mod tests;