nixos/klipper: preserve SAVE_CONFIG for nixos-managed config

Klipper macros that use `SAVE_CONFIG` (eg. bed mesh calibration, PID
tuning, ...) don't currently work with a nixos-managed config.

This can be worked around by using `services.klipper.mutableConfig =
true`, but then you lose out on being able to configure klipper from
NixOS.

This changes the default behaviour so that:

1. The config is stored in `services.klipper.configDir` instead of `/etc`
2. The config is copied instead of symlinked (keeping a timestamped backup of the existing config)
3. The `SAVE_CONFIG` section from the backup is copied over into the new config
4. The backup is deleted if the final config is identical
This commit is contained in:
Kira Bruneau
2025-01-12 13:58:51 +04:00
committed by Cabia Rangris
parent 7093d6908e
commit 809f97881d
+34 -23
View File
@@ -18,6 +18,13 @@ let
};
in
{
imports = [
(lib.mkRenamedOptionModule
[ "services" "klipper" "mutableConfigFolder" ]
[ "services" "klipper" "configDir" ]
)
];
##### interface
options = {
services.klipper = {
@@ -52,23 +59,22 @@ in
default = false;
example = true;
description = ''
Whether to copy the config to a mutable directory instead of using the one directly from the nix store.
This will only copy the config if the file at `services.klipper.mutableConfigPath` doesn't exist.
Whether to manage the config outside of NixOS.
It will still be initialized with the defined NixOS config if the file doesn't already exist.
'';
};
mutableConfigFolder = lib.mkOption {
configDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/klipper";
description = "Path to mutable Klipper config file.";
description = "Path to Klipper config file.";
};
configFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Path to default Klipper config.
'';
description = "Path to default Klipper config.";
};
octoprintIntegration = lib.mkOption {
@@ -162,11 +168,6 @@ in
}
];
environment.etc = lib.mkIf (!cfg.mutableConfig) {
"klipper.cfg".source =
if cfg.settings != null then format.generate "klipper.cfg" cfg.settings else cfg.configFile;
};
services.klipper = lib.mkIf cfg.octoprintIntegration {
user = config.services.octoprint.user;
group = config.services.octoprint.group;
@@ -178,9 +179,7 @@ in
"--input-tty=${cfg.inputTTY}"
+ lib.optionalString (cfg.apiSocket != null) " --api-server=${cfg.apiSocket}"
+ lib.optionalString (cfg.logFile != null) " --logfile=${cfg.logFile}";
printerConfigPath =
if cfg.mutableConfig then cfg.mutableConfigFolder + "/printer.cfg" else "/etc/klipper.cfg";
printerConfigFile =
printerConfig =
if cfg.settings != null then format.generate "klipper.cfg" cfg.settings else cfg.configFile;
in
{
@@ -188,19 +187,31 @@ in
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
preStart = ''
mkdir -p ${cfg.mutableConfigFolder}
${lib.optionalString (cfg.mutableConfig) ''
[ -e ${printerConfigPath} ] || {
cp ${printerConfigFile} ${printerConfigPath}
chmod +w ${printerConfigPath}
mkdir -p ${cfg.configDir}
pushd ${cfg.configDir}
if [ -e printer.cfg ]; then
${
if cfg.mutableConfig then
":"
else
''
# Backup existing config using the same date format klipper uses for SAVE_CONFIG
old_config="printer-$(date +"%Y%m%d_%H%M%S").cfg"
mv printer.cfg "$old_config"
# Preserve SAVE_CONFIG section from the existing config
cat ${printerConfig} <(printf "\n") <(sed -n '/#*# <---------------------- SAVE_CONFIG ---------------------->/,$p' "$old_config") > printer.cfg
${pkgs.diffutils}/bin/cmp printer.cfg "$old_config" && rm "$old_config"
''
}
''}
mkdir -p ${cfg.mutableConfigFolder}/gcodes
else
cat ${printerConfig} > printer.cfg
fi
popd
'';
serviceConfig =
{
ExecStart = "${cfg.package}/bin/klippy ${klippyArgs} ${printerConfigPath}";
ExecStart = "${cfg.package}/bin/klippy ${klippyArgs} ${cfg.configDir}/printer.cfg";
RuntimeDirectory = "klipper";
StateDirectory = "klipper";
SupplementaryGroups = [ "dialout" ];