summary refs log blame commit diff
path: root/nixos/modules/hardware/printers.nix
blob: ef07542950bace9b513b149c96efb06a412f4ed1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                                         
                                         























































                                                                                                      
                                            

                                                                     
                 






                                                                                               

                                                                                                                   








                                                                              

                                          













                                                                                                                  
                                          




                                                                                                    



                           
                               

        
                                                                        



                                                                                                            
{ 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 &lt;printer-name&gt;</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);
    };
  };
}