summaryrefslogtreecommitdiff
path: root/Biz/Cloud/Cgit.nix
blob: 0b3a71b379cbde582de2e865c3af1afebcdc3a0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
{ 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 ];
  };
}