mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-09-18 05:39:58 +00:00
nixos/printing: refactor module
Combine attrs under `config`, and move several let-binding closer to where they are references.
This commit is contained in:
@@ -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")
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user