lol

nixos/cgit: init

schnusch 218c7795 996c7879

+262
+1
nixos/modules/module-list.nix
··· 793 793 ./services/networking/bitlbee.nix 794 794 ./services/networking/blockbook-frontend.nix 795 795 ./services/networking/blocky.nix 796 + ./services/networking/cgit.nix 796 797 ./services/networking/charybdis.nix 797 798 ./services/networking/chisel-server.nix 798 799 ./services/networking/cjdns.nix
+201
nixos/modules/services/networking/cgit.nix
··· 1 + { config, lib, pkgs, ...}: 2 + 3 + with lib; 4 + 5 + let 6 + cfgs = config.services.cgit; 7 + 8 + settingType = with types; oneOf [ bool int str ]; 9 + 10 + genAttrs' = names: f: listToAttrs (map f names); 11 + 12 + regexEscape = 13 + let 14 + # taken from https://github.com/python/cpython/blob/05cb728d68a278d11466f9a6c8258d914135c96c/Lib/re.py#L251-L266 15 + special = [ 16 + "(" ")" "[" "]" "{" "}" "?" "*" "+" "-" "|" "^" "$" "\\" "." "&" "~" 17 + "#" " " "\t" "\n" "\r" "\v" "\f" 18 + ]; 19 + in 20 + replaceStrings special (map (c: "\\${c}") special); 21 + 22 + stripLocation = cfg: removeSuffix "/" cfg.nginx.location; 23 + 24 + regexLocation = cfg: regexEscape (stripLocation cfg); 25 + 26 + mkFastcgiPass = cfg: '' 27 + ${if cfg.nginx.location == "/" then '' 28 + fastcgi_param PATH_INFO $uri; 29 + '' else '' 30 + fastcgi_split_path_info ^(${regexLocation cfg})(/.+)$; 31 + fastcgi_param PATH_INFO $fastcgi_path_info; 32 + '' 33 + }fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; 34 + ''; 35 + 36 + cgitrcLine = name: value: "${name}=${ 37 + if value == true then 38 + "1" 39 + else if value == false then 40 + "0" 41 + else 42 + toString value 43 + }"; 44 + 45 + mkCgitrc = cfg: pkgs.writeText "cgitrc" '' 46 + # global settings 47 + ${concatStringsSep "\n" ( 48 + mapAttrsToList 49 + cgitrcLine 50 + ({ virtual-root = cfg.nginx.location; } // cfg.settings) 51 + ) 52 + } 53 + ${optionalString (cfg.scanPath != null) (cgitrcLine "scan-path" cfg.scanPath)} 54 + 55 + # repository settings 56 + ${concatStrings ( 57 + mapAttrsToList 58 + (url: settings: '' 59 + ${cgitrcLine "repo.url" url} 60 + ${concatStringsSep "\n" ( 61 + mapAttrsToList (name: cgitrcLine "repo.${name}") settings 62 + ) 63 + } 64 + '') 65 + cfg.repos 66 + ) 67 + } 68 + 69 + # extra config 70 + ${cfg.extraConfig} 71 + ''; 72 + 73 + mkCgitReposDir = cfg: 74 + if cfg.scanPath != null then 75 + cfg.scanPath 76 + else 77 + pkgs.runCommand "cgit-repos" { 78 + preferLocalBuild = true; 79 + allowSubstitutes = false; 80 + } '' 81 + mkdir -p "$out" 82 + ${ 83 + concatStrings ( 84 + mapAttrsToList 85 + (name: value: '' 86 + ln -s ${escapeShellArg value.path} "$out"/${escapeShellArg name} 87 + '') 88 + cfg.repos 89 + ) 90 + } 91 + ''; 92 + 93 + in 94 + { 95 + options = { 96 + services.cgit = mkOption { 97 + description = mdDoc "Configure cgit instances."; 98 + default = {}; 99 + type = types.attrsOf (types.submodule ({ config, ... }: { 100 + options = { 101 + enable = mkEnableOption (mdDoc "cgit"); 102 + 103 + nginx.virtualHost = mkOption { 104 + description = mdDoc "VirtualHost to serve cgit on, defaults to the attribute name."; 105 + type = types.str; 106 + default = config._module.args.name; 107 + example = "git.example.com"; 108 + }; 109 + 110 + nginx.location = mkOption { 111 + description = mdDoc "Location to serve cgit under."; 112 + type = types.str; 113 + default = "/"; 114 + example = "/git/"; 115 + }; 116 + 117 + repos = mkOption { 118 + description = mdDoc "cgit repository settings, see cgitrc(5)"; 119 + type = with types; attrsOf (attrsOf settingType); 120 + default = {}; 121 + example = { 122 + blah = { 123 + path = "/var/lib/git/example"; 124 + desc = "An example repository"; 125 + }; 126 + }; 127 + }; 128 + 129 + scanPath = mkOption { 130 + description = mdDoc "A path which will be scanned for repositories."; 131 + type = types.nullOr types.path; 132 + default = null; 133 + example = "/var/lib/git"; 134 + }; 135 + 136 + settings = mkOption { 137 + description = mdDoc "cgit configuration, see cgitrc(5)"; 138 + type = types.attrsOf settingType; 139 + default = {}; 140 + example = literalExpression '' 141 + { 142 + enable-follow-links = true; 143 + source-filter = "''${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; 144 + } 145 + ''; 146 + }; 147 + 148 + extraConfig = mkOption { 149 + description = mdDoc "These lines go to the end of cgitrc verbatim."; 150 + type = types.lines; 151 + default = ""; 152 + }; 153 + }; 154 + })); 155 + }; 156 + }; 157 + 158 + config = mkIf (any (cfg: cfg.enable) (attrValues cfgs)) { 159 + assertions = mapAttrsToList (vhost: cfg: { 160 + assertion = !cfg.enable || (cfg.scanPath == null) != (cfg.repos == {}); 161 + message = "Exactly one of services.cgit.${vhost}.scanPath or services.cgit.${vhost}.repos must be set."; 162 + }) cfgs; 163 + 164 + services.fcgiwrap.enable = true; 165 + 166 + services.nginx.enable = true; 167 + 168 + services.nginx.virtualHosts = mkMerge (mapAttrsToList (_: cfg: { 169 + ${cfg.nginx.virtualHost} = { 170 + locations = ( 171 + genAttrs' 172 + [ "cgit.css" "cgit.png" "favicon.ico" "robots.txt" ] 173 + (name: nameValuePair "= ${stripLocation cfg}/${name}" { 174 + extraConfig = '' 175 + alias ${pkgs.cgit}/cgit/${name}; 176 + ''; 177 + }) 178 + ) // { 179 + "~ ${regexLocation cfg}/.+/(info/refs|git-upload-pack)" = { 180 + fastcgiParams = rec { 181 + SCRIPT_FILENAME = "${pkgs.git}/libexec/git-core/git-http-backend"; 182 + GIT_HTTP_EXPORT_ALL = "1"; 183 + GIT_PROJECT_ROOT = mkCgitReposDir cfg; 184 + HOME = GIT_PROJECT_ROOT; 185 + }; 186 + extraConfig = mkFastcgiPass cfg; 187 + }; 188 + "${stripLocation cfg}/" = { 189 + fastcgiParams = { 190 + SCRIPT_FILENAME = "${pkgs.cgit}/cgit/cgit.cgi"; 191 + QUERY_STRING = "$args"; 192 + HTTP_HOST = "$server_name"; 193 + CGIT_CONFIG = mkCgitrc cfg; 194 + }; 195 + extraConfig = mkFastcgiPass cfg; 196 + }; 197 + }; 198 + }; 199 + }) cfgs); 200 + }; 201 + }
+1
nixos/tests/all-tests.nix
··· 124 124 ceph-single-node-bluestore = handleTestOn ["x86_64-linux"] ./ceph-single-node-bluestore.nix {}; 125 125 certmgr = handleTest ./certmgr.nix {}; 126 126 cfssl = handleTestOn ["aarch64-linux" "x86_64-linux"] ./cfssl.nix {}; 127 + cgit = handleTest ./cgit.nix {}; 127 128 charliecloud = handleTest ./charliecloud.nix {}; 128 129 chromium = (handleTestOn ["aarch64-linux" "x86_64-linux"] ./chromium.nix {}).stable or {}; 129 130 cinnamon = handleTest ./cinnamon.nix {};
+59
nixos/tests/cgit.nix
··· 1 + import ./make-test-python.nix ({ pkgs, ...} : { 2 + name = "cgit"; 3 + meta = with pkgs.lib.maintainers; { 4 + maintainers = [ schnusch ]; 5 + }; 6 + 7 + nodes = { 8 + server = { ... }: { 9 + services.cgit."localhost" = { 10 + enable = true; 11 + nginx.location = "/(c)git/"; 12 + repos = { 13 + some-repo = { 14 + path = "/srv/git/some-repo"; 15 + desc = "some-repo description"; 16 + }; 17 + }; 18 + }; 19 + 20 + environment.systemPackages = [ pkgs.git ]; 21 + }; 22 + }; 23 + 24 + testScript = { nodes, ... }: '' 25 + start_all() 26 + 27 + server.wait_for_unit("nginx.service") 28 + server.wait_for_unit("network.target") 29 + server.wait_for_open_port(80) 30 + 31 + server.succeed("curl -fsS http://localhost/%28c%29git/robots.txt") 32 + 33 + server.succeed( 34 + "curl -fsS http://localhost/%28c%29git/ | grep -F 'some-repo description'" 35 + ) 36 + 37 + server.fail("curl -fsS http://localhost/robots.txt") 38 + 39 + server.succeed("${pkgs.writeShellScript "setup-cgit-test-repo" '' 40 + set -e 41 + git init --bare -b master /srv/git/some-repo 42 + git init -b master reference 43 + cd reference 44 + git remote add origin /srv/git/some-repo 45 + date > date.txt 46 + git add date.txt 47 + git -c user.name=test -c user.email=test@localhost commit -m 'add date' 48 + git push -u origin master 49 + ''}") 50 + 51 + server.succeed( 52 + "curl -fsS 'http://localhost/%28c%29git/some-repo/plain/date.txt?id=master' | diff -u reference/date.txt -" 53 + ) 54 + 55 + server.succeed( 56 + "git clone http://localhost/%28c%29git/some-repo && diff -u reference/date.txt some-repo/date.txt" 57 + ) 58 + ''; 59 + })