at 25.11-pre 5.4 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.hardware.printers; 9 10 ensurePrinter = 11 p: 12 let 13 args = lib.cli.toGNUCommandLineShell { } ( 14 { 15 p = p.name; 16 v = p.deviceUri; 17 m = p.model; 18 } 19 // lib.optionalAttrs (p.location != null) { 20 L = p.location; 21 } 22 // lib.optionalAttrs (p.description != null) { 23 D = p.description; 24 } 25 // lib.optionalAttrs (p.ppdOptions != { }) { 26 o = lib.mapAttrsToList (name: value: "${name}=${value}") p.ppdOptions; 27 } 28 ); 29 in 30 '' 31 # shellcheck disable=SC2016 32 ${pkgs.cups}/bin/lpadmin ${args} -E 33 ''; 34 35 ensureDefaultPrinter = name: '' 36 ${pkgs.cups}/bin/lpadmin -d '${name}' 37 ''; 38 39 # "graph but not # or /" can't be implemented as regex alone due to missing lookahead support 40 noInvalidChars = str: lib.all (c: c != "#" && c != "/") (lib.stringToCharacters str); 41 printerName = (lib.types.addCheck (lib.types.strMatching "[[:graph:]]+") noInvalidChars) // { 42 description = "printable string without spaces, # and /"; 43 }; 44 45in 46{ 47 options = { 48 hardware.printers = { 49 ensureDefaultPrinter = lib.mkOption { 50 type = lib.types.nullOr printerName; 51 default = null; 52 description = '' 53 Ensures the named printer is the default CUPS printer / printer queue. 54 ''; 55 }; 56 ensurePrinters = lib.mkOption { 57 description = '' 58 Will regularly ensure that the given CUPS printers are configured as declared here. 59 If a printer's options are manually changed afterwards, they will be overwritten eventually. 60 This option will never delete any printer, even if removed from this list. 61 You can check existing printers with {command}`lpstat -s` 62 and remove printers with {command}`lpadmin -x <printer-name>`. 63 Printers not listed here can still be manually configured. 64 ''; 65 default = [ ]; 66 type = lib.types.listOf ( 67 lib.types.submodule { 68 options = { 69 name = lib.mkOption { 70 type = printerName; 71 example = "BrotherHL_Workroom"; 72 description = '' 73 Name of the printer / printer queue. 74 May contain any printable characters except "/", "#", and space. 75 ''; 76 }; 77 location = lib.mkOption { 78 type = lib.types.nullOr lib.types.str; 79 default = null; 80 example = "Workroom"; 81 description = '' 82 Optional human-readable location. 83 ''; 84 }; 85 description = lib.mkOption { 86 type = lib.types.nullOr lib.types.str; 87 default = null; 88 example = "Brother HL-5140"; 89 description = '' 90 Optional human-readable description. 91 ''; 92 }; 93 deviceUri = lib.mkOption { 94 type = lib.types.str; 95 example = lib.literalExpression '' 96 "ipp://printserver.local/printers/BrotherHL_Workroom" 97 "usb://HP/DESKJET%20940C?serial=CN16E6C364BH" 98 ''; 99 description = '' 100 How to reach the printer. 101 {command}`lpinfo -v` shows a list of supported device URIs and schemes. 102 ''; 103 }; 104 model = lib.mkOption { 105 type = lib.types.str; 106 example = lib.literalExpression '' 107 "gutenprint.''${lib.versions.majorMinor (lib.getVersion pkgs.gutenprint)}://brother-hl-5140/expert" 108 ''; 109 description = '' 110 Location of the ppd driver file for the printer. 111 {command}`lpinfo -m` shows a list of supported models. 112 ''; 113 }; 114 ppdOptions = lib.mkOption { 115 type = lib.types.attrsOf lib.types.str; 116 example = { 117 PageSize = "A4"; 118 Duplex = "DuplexNoTumble"; 119 }; 120 default = { }; 121 description = '' 122 Sets PPD options for the printer. 123 {command}`lpoptions [-p printername] -l` shows supported PPD options for the given printer. 124 ''; 125 }; 126 }; 127 } 128 ); 129 }; 130 }; 131 }; 132 133 config = lib.mkIf (cfg.ensurePrinters != [ ] && config.services.printing.enable) { 134 systemd.services.ensure-printers = { 135 description = "Ensure NixOS-configured CUPS printers"; 136 wantedBy = [ "multi-user.target" ]; 137 wants = [ "cups.service" ]; 138 after = [ "cups.service" ]; 139 140 serviceConfig = { 141 Type = "oneshot"; 142 RemainAfterExit = true; 143 }; 144 145 script = lib.concatStringsSep "\n" [ 146 (lib.concatMapStrings ensurePrinter cfg.ensurePrinters) 147 (lib.optionalString (cfg.ensureDefaultPrinter != null) ( 148 ensureDefaultPrinter cfg.ensureDefaultPrinter 149 )) 150 # Note: if cupsd is "stateless" the service can't be stopped, 151 # otherwise the configuration will be wiped on the next start. 152 (lib.optionalString ( 153 with config.services.printing; startWhenNeeded && !stateless 154 ) "systemctl stop cups.service") 155 ]; 156 }; 157 }; 158}