nixos/printing: refactor module

Combine attrs under `config`, and move several let-binding closer to
where they are references.
This commit is contained in:
h7x4
2026-09-15 17:03:53 +09:00
parent 633c07a28b
commit d6c83dc6e4

View File

@@ -21,98 +21,12 @@ let
submodule
;
ensurePrinter =
p:
let
args = lib.cli.toCommandLineShellGNU { } (
{
p = p.name;
v = p.deviceUri;
m = p.model;
}
// lib.optionalAttrs (p.location != null) {
L = p.location;
}
// lib.optionalAttrs (p.description != null) {
D = p.description;
}
// lib.optionalAttrs (p.ppdOptions != { }) {
o = lib.mapAttrsToList (name: value: "${name}=${value}") p.ppdOptions;
}
);
in
''
# shellcheck disable=SC2016
${pkgs.cups}/bin/lpadmin ${args} -E
'';
ensureDefaultPrinter = name: ''
${pkgs.cups}/bin/lpadmin -d '${name}'
'';
# "graph but not # or /" can't be implemented as regex alone due to missing lookahead support
noInvalidChars = str: lib.all (c: c != "#" && c != "/") (lib.stringToCharacters str);
printerName = (lib.types.addCheck (lib.types.strMatching "[[:graph:]]+") noInvalidChars) // {
description = "printable string without spaces, # and /";
};
getPrinters =
class:
lib.uniqueStrings (
lib.concatLists (
lib.textClosureList (lib.mapAttrs (
_:
{
classes ? [ ],
printers ? [ ],
...
}:
{
deps = classes;
text = printers;
}
) cfg.ensureClasses) [ class ]
)
);
mkClass = name: ''
lpadmin -p _tmp -v file:/dev/null
lpadmin -p _tmp -c ${escapeShellArg name}
lpadmin -x _tmp
'';
populateClass =
name:
{
description ? null,
location ? null,
...
}:
lib.concatStringsSep "\n" [
(lib.optionalString (location != null) ''
lpadmin -p ${escapeShellArg name} -L ${escapeShellArg location}
'')
(lib.optionalString (description != null) ''
lpadmin -p ${escapeShellArg name} -D ${escapeShellArg description}
'')
];
addPrintersToClass =
className: class:
let
printers = getPrinters className;
addToClass = printer: ''
lpadmin -p ${escapeShellArg printer} -c ${escapeShellArg className}
'';
in
map addToClass printers;
enableClass = className: ''
cupsenable ${escapeShellArg className}
cupsaccept ${escapeShellArg className}
'';
# if CUPS is configured only to start when it's needed, we can kill the service
# once the printer setup is done. However, if stateless is configured then we
# can't shut down the servive without losing the printers (and classes) we
@@ -272,163 +186,248 @@ in
};
};
config.assertions = lib.mkIf config.services.printing.enable [
(
let
referencedClasses = lib.unique (
lib.flatten (
lib.mapAttrsToList (
_:
{
classes ? [ ],
...
}:
classes
) cfg.ensureClasses
)
);
definedClasses = lib.attrNames cfg.ensureClasses;
missingClasses = lib.subtractLists definedClasses referencedClasses;
getReferencingClasses =
missingClass:
(lib.mapAttrsToList (name: _: "`${name}`") (
lib.filterAttrs (
_:
{
classes ? [ ],
...
}:
builtins.elem missingClass classes
) cfg.ensureClasses
));
in
{
assertion = missingClasses == [ ];
message = ''
One or more values of `config.hardware.printers.ensureClasses.<name>.classes`
contained values not present in `config.hardware.printers.ensureClasses`
config = lib.mkIf config.services.printing.enable {
assertions = [
(
let
referencedClasses = lib.unique (
lib.flatten (
lib.mapAttrsToList (
_:
{
classes ? [ ],
...
}:
classes
) cfg.ensureClasses
)
);
definedClasses = lib.attrNames cfg.ensureClasses;
missingClasses = lib.subtractLists definedClasses referencedClasses;
getReferencingClasses =
missingClass:
(lib.mapAttrsToList (name: _: "`${name}`") (
lib.filterAttrs (
_:
{
classes ? [ ],
...
}:
builtins.elem missingClass classes
) cfg.ensureClasses
));
in
{
assertion = missingClasses == [ ];
message = ''
One or more values of `config.hardware.printers.ensureClasses.<name>.classes`
contained values not present in `config.hardware.printers.ensureClasses`
Missing classes:
${lib.concatMapStringsSep "\n" (
p: " - `${p}` (included in class(es): ${lib.concatStringsSep ", " (getReferencingClasses p)})"
) missingClasses}
'';
}
)
(
let
referencedPrinters = lib.unique (
lib.flatten (
lib.mapAttrsToList (
_:
{
printers ? [ ],
...
}:
printers
) cfg.ensureClasses
)
);
definedPrinters = lib.catAttrs "name" cfg.ensurePrinters;
missingPrinters = lib.subtractLists definedPrinters referencedPrinters;
getReferencingClasses =
missingPrinter:
(lib.mapAttrsToList (name: _: "`${name}`") (
lib.filterAttrs (
_:
{
printers ? [ ],
...
}:
builtins.elem missingPrinter printers
) cfg.ensureClasses
));
in
{
assertion = missingPrinters == [ ];
message = ''
One or more values of `config.hardware.printers.ensureClasses.<name>.printers`
contained values not present in `config.hardware.printers.ensurePrinters`
Missing printers:
${lib.concatMapStringsSep "\n" (
p: " - `${p}` (included in class(es): ${lib.concatStringsSep ", " (getReferencingClasses p)})"
) missingPrinters}
'';
}
)
];
config.systemd.services.ensure-printer-classes =
lib.mkIf (cfg.ensureClasses != { } && config.services.printing.enable)
{
description = "Ensure NixOS-configured CUPS classes";
wantedBy = [ "multi-user.target" ];
wants = [
"cups.service"
];
after = [
"cups.service"
"ensure-printers.service"
];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
path = with pkgs; [ cups ];
script =
let
attrMap = fn: l: map fn (builtins.attrNames l);
classDefs = lib.pipe cfg.ensureClasses [
(attrMap mkClass)
concatLines
];
classAdds = lib.pipe cfg.ensureClasses [
(lib.mapAttrsToList addPrintersToClass)
lib.flatten
concatLines
];
populatedClasses = lib.pipe cfg.ensureClasses [
(lib.mapAttrsToList populateClass)
concatLines
];
enables = lib.pipe cfg.ensureClasses [
(attrMap enableClass)
concatLines
];
in
''
#### CLASS DEFINITIONS ####
${classDefs}
#### ADDING PRINTERS TO CLASSES ####
${classAdds}
#### POPULATING CLASSES ####
${populatedClasses}
#### ENABLING CLASSES ####
${enables}
${lib.optionalString ultimatelyStopCups "systemctl stop cups.service"}
Missing classes:
${lib.concatMapStringsSep "\n" (
p: " - `${p}` (included in class(es): ${lib.concatStringsSep ", " (getReferencingClasses p)})"
) missingClasses}
'';
}
)
(
let
referencedPrinters = lib.unique (
lib.flatten (
lib.mapAttrsToList (
_:
{
printers ? [ ],
...
}:
printers
) cfg.ensureClasses
)
);
definedPrinters = lib.catAttrs "name" cfg.ensurePrinters;
missingPrinters = lib.subtractLists definedPrinters referencedPrinters;
getReferencingClasses =
missingPrinter:
(lib.mapAttrsToList (name: _: "`${name}`") (
lib.filterAttrs (
_:
{
printers ? [ ],
...
}:
builtins.elem missingPrinter printers
) cfg.ensureClasses
));
in
{
assertion = missingPrinters == [ ];
message = ''
One or more values of `config.hardware.printers.ensureClasses.<name>.printers`
contained values not present in `config.hardware.printers.ensurePrinters`
Missing printers:
${lib.concatMapStringsSep "\n" (
p: " - `${p}` (included in class(es): ${lib.concatStringsSep ", " (getReferencingClasses p)})"
) missingPrinters}
'';
}
)
];
systemd.services.ensure-printer-classes = lib.mkIf (cfg.ensureClasses != { }) {
description = "Ensure NixOS-configured CUPS classes";
wantedBy = [ "multi-user.target" ];
wants = [
"cups.service"
];
after = [
"cups.service"
"ensure-printers.service"
];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
path = with pkgs; [ cups ];
script =
let
mkClass = name: ''
lpadmin -p _tmp -v file:/dev/null
lpadmin -p _tmp -c ${escapeShellArg name}
lpadmin -x _tmp
'';
populateClass =
name:
{
description ? null,
location ? null,
...
}:
lib.concatStringsSep "\n" [
(lib.optionalString (location != null) ''
lpadmin -p ${escapeShellArg name} -L ${escapeShellArg location}
'')
(lib.optionalString (description != null) ''
lpadmin -p ${escapeShellArg name} -D ${escapeShellArg description}
'')
];
getPrinters =
class:
lib.uniqueStrings (
lib.concatLists (
lib.textClosureList (lib.mapAttrs (
_:
{
classes ? [ ],
printers ? [ ],
...
}:
{
deps = classes;
text = printers;
}
) cfg.ensureClasses) [ class ]
)
);
addPrintersToClass =
className: class:
let
printers = getPrinters className;
addToClass = printer: ''
lpadmin -p ${escapeShellArg printer} -c ${escapeShellArg className}
'';
in
map addToClass printers;
enableClass = className: ''
cupsenable ${escapeShellArg className}
cupsaccept ${escapeShellArg className}
'';
attrMap = fn: l: map fn (builtins.attrNames l);
classDefs = lib.pipe cfg.ensureClasses [
(attrMap mkClass)
concatLines
];
classAdds = lib.pipe cfg.ensureClasses [
(lib.mapAttrsToList addPrintersToClass)
lib.flatten
concatLines
];
populatedClasses = lib.pipe cfg.ensureClasses [
(lib.mapAttrsToList populateClass)
concatLines
];
enables = lib.pipe cfg.ensureClasses [
(attrMap enableClass)
concatLines
];
in
''
#### CLASS DEFINITIONS ####
${classDefs}
#### ADDING PRINTERS TO CLASSES ####
${classAdds}
#### POPULATING CLASSES ####
${populatedClasses}
#### ENABLING CLASSES ####
${enables}
${lib.optionalString ultimatelyStopCups "systemctl stop cups.service"}
'';
};
systemd.services.ensure-printers = lib.mkIf (cfg.ensurePrinters != [ ]) {
description = "Ensure NixOS-configured CUPS printers";
wantedBy = [ "multi-user.target" ];
wants = [ "cups.service" ];
after = [ "cups.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
config.systemd.services.ensure-printers =
lib.mkIf (cfg.ensurePrinters != [ ] && config.services.printing.enable)
{
description = "Ensure NixOS-configured CUPS printers";
wantedBy = [ "multi-user.target" ];
wants = [ "cups.service" ];
after = [ "cups.service" ];
script =
let
ensurePrinter =
p:
let
args = lib.cli.toCommandLineShellGNU { } (
{
p = p.name;
v = p.deviceUri;
m = p.model;
}
// lib.optionalAttrs (p.location != null) {
L = p.location;
}
// lib.optionalAttrs (p.description != null) {
D = p.description;
}
// lib.optionalAttrs (p.ppdOptions != { }) {
o = lib.mapAttrsToList (name: value: "${name}=${value}") p.ppdOptions;
}
);
in
''
# shellcheck disable=SC2016
${pkgs.cups}/bin/lpadmin ${args} -E
'';
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = lib.concatStringsSep "\n" [
ensureDefaultPrinter = name: ''
${pkgs.cups}/bin/lpadmin -d '${name}'
'';
in
lib.concatStringsSep "\n" [
(lib.concatMapStrings ensurePrinter cfg.ensurePrinters)
(lib.optionalString (cfg.ensureDefaultPrinter != null) (
ensureDefaultPrinter cfg.ensureDefaultPrinter
@@ -439,5 +438,6 @@ in
ultimatelyStopCups && !(config.systemd.services ? ensure-printer-classes)
) "systemctl stop cups.service")
];
};
};
};
}