diff options
Diffstat (limited to 'nixos/modules/hardware/printers.nix')
-rw-r--r-- | nixos/modules/hardware/printers.nix | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/nixos/modules/hardware/printers.nix b/nixos/modules/hardware/printers.nix new file mode 100644 index 00000000000..ef07542950b --- /dev/null +++ b/nixos/modules/hardware/printers.nix @@ -0,0 +1,130 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.hardware.printers; + ppdOptionsString = options: optionalString (options != {}) + (concatStringsSep " " + (mapAttrsToList (name: value: "-o '${name}'='${value}'") options) + ); + ensurePrinter = p: '' + ${pkgs.cups}/bin/lpadmin -p '${p.name}' -E \ + ${optionalString (p.location != null) "-L '${p.location}'"} \ + ${optionalString (p.description != null) "-D '${p.description}'"} \ + -v '${p.deviceUri}' \ + -m '${p.model}' \ + ${ppdOptionsString p.ppdOptions} + ''; + 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: all (c: c != "#" && c != "/") (stringToCharacters str); + printerName = (types.addCheck (types.strMatching "[[:graph:]]+") noInvalidChars) + // { description = "printable string without spaces, # and /"; }; + + +in { + options = { + hardware.printers = { + ensureDefaultPrinter = mkOption { + type = types.nullOr printerName; + default = null; + description = '' + Ensures the named printer is the default CUPS printer / printer queue. + ''; + }; + ensurePrinters = mkOption { + description = '' + Will regularly ensure that the given CUPS printers are configured as declared here. + If a printer's options are manually changed afterwards, they will be overwritten eventually. + This option will never delete any printer, even if removed from this list. + You can check existing printers with <command>lpstat -s</command> + and remove printers with <command>lpadmin -x <printer-name></command>. + Printers not listed here can still be manually configured. + ''; + default = []; + type = types.listOf (types.submodule { + options = { + name = mkOption { + type = printerName; + example = "BrotherHL_Workroom"; + description = '' + Name of the printer / printer queue. + May contain any printable characters except "/", "#", and space. + ''; + }; + location = mkOption { + type = types.nullOr types.str; + default = null; + example = "Workroom"; + description = '' + Optional human-readable location. + ''; + }; + description = mkOption { + type = types.nullOr types.str; + default = null; + example = "Brother HL-5140"; + description = '' + Optional human-readable description. + ''; + }; + deviceUri = mkOption { + type = types.str; + example = literalExpression '' + "ipp://printserver.local/printers/BrotherHL_Workroom" + "usb://HP/DESKJET%20940C?serial=CN16E6C364BH" + ''; + description = '' + How to reach the printer. + <command>lpinfo -v</command> shows a list of supported device URIs and schemes. + ''; + }; + model = mkOption { + type = types.str; + example = literalExpression '' + "gutenprint.''${lib.versions.majorMinor (lib.getVersion pkgs.gutenprint)}://brother-hl-5140/expert" + ''; + description = '' + Location of the ppd driver file for the printer. + <command>lpinfo -m</command> shows a list of supported models. + ''; + }; + ppdOptions = mkOption { + type = types.attrsOf types.str; + example = { + PageSize = "A4"; + Duplex = "DuplexNoTumble"; + }; + default = {}; + description = '' + Sets PPD options for the printer. + <command>lpoptions [-p printername] -l</command> shows suported PPD options for the given printer. + ''; + }; + }; + }); + }; + }; + }; + + config = mkIf (cfg.ensurePrinters != [] && config.services.printing.enable) { + systemd.services.ensure-printers = let + cupsUnit = if config.services.printing.startWhenNeeded then "cups.socket" else "cups.service"; + in { + description = "Ensure NixOS-configured CUPS printers"; + wantedBy = [ "multi-user.target" ]; + requires = [ cupsUnit ]; + after = [ cupsUnit ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + + script = concatMapStringsSep "\n" ensurePrinter cfg.ensurePrinters + + optionalString (cfg.ensureDefaultPrinter != null) (ensureDefaultPrinter cfg.ensureDefaultPrinter); + }; + }; +} |