{ config, lib, pkgs, ... }: with lib; let globalConfig = config; settingsFormat = { type = with lib.types; let value = oneOf [ int str ] // { description = "INI-like atom (int or string)"; }; values = coercedTo value lib.singleton (listOf value) // { description = value.description + " or a list of them for duplicate keys"; }; in attrsOf (values); generate = name: values: pkgs.writeText name (lib.generators.toKeyValue { listsAsDuplicateKeys = true; } values); }; in { options.services.nginx.virtualHosts = mkOption { type = types.attrsOf (types.submodule ({ config, ... }: let cfg = config.cgit; # These are the global options for this submodule, but for nicer UX they # are inlined into the freeform settings. Hence they MUST NOT INTERSECT # with any settings from cgitrc! options = { enable = mkEnableOption "cgit"; location = mkOption { default = "/"; type = types.str; description = '' Location to serve cgit on. ''; }; allowCrawlers = mkOption { default = true; type = types.bool; description = '' Allow search engines to crawl and index this site. ''; }; }; # Remove the global options for serialization into cgitrc settings = removeAttrs cfg (attrNames options); in { options.cgit = mkOption { type = types.submodule { freeformType = settingsFormat.type; inherit options; config = { css = mkDefault "/cgit.css"; logo = mkDefault "/cgit.png"; favicon = mkDefault "/favicon.ico"; }; }; default = { }; example = literalExample '' { enable = true; virtual-root = "/"; source-filter = "''${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; about-filter = "''${pkgs.cgit}/lib/cgit/filters/about-formatting.sh"; cache-size = 1000; scan-path = "/srv/git"; include = [ (builtins.toFile "cgitrc-extra-1" ''' # Anything that has to be in a particular order ''') (builtins.toFile "cgitrc-extra-2" ''' # Anything that has to be in a particular order ''') ]; } ''; description = '' Verbatim contents of the cgit runtime configuration file. Documentation (with cgitrc example file) is available in "man cgitrc". Or online: http://git.zx2c4.com/cgit/tree/cgitrc.5.txt ''; }; config = let location = removeSuffix "/" cfg.location; in mkIf cfg.enable { locations."${location}/" = { root = "${pkgs.cgit}/cgit/"; tryFiles = "$uri @cgit"; }; locations."~ ^${location}/(cgit.(css|png)|favicon.ico|robots.txt)$" = { alias = "${pkgs.cgit}/cgit/$1"; }; locations."@cgit" = { extraConfig = '' include ${pkgs.nginx}/conf/fastcgi_params; fastcgi_param CGIT_CONFIG ${settingsFormat.generate "cgitrc" settings}; fastcgi_param SCRIPT_FILENAME ${pkgs.cgit}/cgit/cgit.cgi; fastcgi_param QUERY_STRING $args; fastcgi_param HTTP_HOST $server_name; fastcgi_pass unix:${globalConfig.services.fcgiwrap.socketAddress}; '' + ( if cfg.location == "/" then '' fastcgi_param PATH_INFO $uri; '' else '' fastcgi_split_path_info ^(${location}/)(/?.+)$; fastcgi_param PATH_INFO $fastcgi_path_info; '' ) + ( if !cfg.allowCrawlers then '' add_header X-Robots-Tag "noindex, follow" always; '' else "" ); }; }; })); }; config = let vhosts = config.services.nginx.virtualHosts; in mkIf (any (name: vhosts.${name}.cgit.enable) (attrNames vhosts)) { # make the cgitrc manpage available environment.systemPackages = [ pkgs.cgit ]; services.fcgiwrap.enable = true; }; meta = { maintainers = with lib.maintainers; [ bsima ]; # afix-space hmenke ]; }; }