nixos/cgit: init
This commit is contained in:
parent
996c7879db
commit
218c7795a6
|
@ -793,6 +793,7 @@
|
||||||
./services/networking/bitlbee.nix
|
./services/networking/bitlbee.nix
|
||||||
./services/networking/blockbook-frontend.nix
|
./services/networking/blockbook-frontend.nix
|
||||||
./services/networking/blocky.nix
|
./services/networking/blocky.nix
|
||||||
|
./services/networking/cgit.nix
|
||||||
./services/networking/charybdis.nix
|
./services/networking/charybdis.nix
|
||||||
./services/networking/chisel-server.nix
|
./services/networking/chisel-server.nix
|
||||||
./services/networking/cjdns.nix
|
./services/networking/cjdns.nix
|
||||||
|
|
201
nixos/modules/services/networking/cgit.nix
Normal file
201
nixos/modules/services/networking/cgit.nix
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
{ config, lib, pkgs, ...}:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfgs = config.services.cgit;
|
||||||
|
|
||||||
|
settingType = with types; oneOf [ bool int str ];
|
||||||
|
|
||||||
|
genAttrs' = names: f: listToAttrs (map f names);
|
||||||
|
|
||||||
|
regexEscape =
|
||||||
|
let
|
||||||
|
# taken from https://github.com/python/cpython/blob/05cb728d68a278d11466f9a6c8258d914135c96c/Lib/re.py#L251-L266
|
||||||
|
special = [
|
||||||
|
"(" ")" "[" "]" "{" "}" "?" "*" "+" "-" "|" "^" "$" "\\" "." "&" "~"
|
||||||
|
"#" " " "\t" "\n" "\r" "\v" "\f"
|
||||||
|
];
|
||||||
|
in
|
||||||
|
replaceStrings special (map (c: "\\${c}") special);
|
||||||
|
|
||||||
|
stripLocation = cfg: removeSuffix "/" cfg.nginx.location;
|
||||||
|
|
||||||
|
regexLocation = cfg: regexEscape (stripLocation cfg);
|
||||||
|
|
||||||
|
mkFastcgiPass = cfg: ''
|
||||||
|
${if cfg.nginx.location == "/" then ''
|
||||||
|
fastcgi_param PATH_INFO $uri;
|
||||||
|
'' else ''
|
||||||
|
fastcgi_split_path_info ^(${regexLocation cfg})(/.+)$;
|
||||||
|
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||||
|
''
|
||||||
|
}fastcgi_pass unix:${config.services.fcgiwrap.socketAddress};
|
||||||
|
'';
|
||||||
|
|
||||||
|
cgitrcLine = name: value: "${name}=${
|
||||||
|
if value == true then
|
||||||
|
"1"
|
||||||
|
else if value == false then
|
||||||
|
"0"
|
||||||
|
else
|
||||||
|
toString value
|
||||||
|
}";
|
||||||
|
|
||||||
|
mkCgitrc = cfg: pkgs.writeText "cgitrc" ''
|
||||||
|
# global settings
|
||||||
|
${concatStringsSep "\n" (
|
||||||
|
mapAttrsToList
|
||||||
|
cgitrcLine
|
||||||
|
({ virtual-root = cfg.nginx.location; } // cfg.settings)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
${optionalString (cfg.scanPath != null) (cgitrcLine "scan-path" cfg.scanPath)}
|
||||||
|
|
||||||
|
# repository settings
|
||||||
|
${concatStrings (
|
||||||
|
mapAttrsToList
|
||||||
|
(url: settings: ''
|
||||||
|
${cgitrcLine "repo.url" url}
|
||||||
|
${concatStringsSep "\n" (
|
||||||
|
mapAttrsToList (name: cgitrcLine "repo.${name}") settings
|
||||||
|
)
|
||||||
|
}
|
||||||
|
'')
|
||||||
|
cfg.repos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
# extra config
|
||||||
|
${cfg.extraConfig}
|
||||||
|
'';
|
||||||
|
|
||||||
|
mkCgitReposDir = cfg:
|
||||||
|
if cfg.scanPath != null then
|
||||||
|
cfg.scanPath
|
||||||
|
else
|
||||||
|
pkgs.runCommand "cgit-repos" {
|
||||||
|
preferLocalBuild = true;
|
||||||
|
allowSubstitutes = false;
|
||||||
|
} ''
|
||||||
|
mkdir -p "$out"
|
||||||
|
${
|
||||||
|
concatStrings (
|
||||||
|
mapAttrsToList
|
||||||
|
(name: value: ''
|
||||||
|
ln -s ${escapeShellArg value.path} "$out"/${escapeShellArg name}
|
||||||
|
'')
|
||||||
|
cfg.repos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
services.cgit = mkOption {
|
||||||
|
description = mdDoc "Configure cgit instances.";
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf (types.submodule ({ config, ... }: {
|
||||||
|
options = {
|
||||||
|
enable = mkEnableOption (mdDoc "cgit");
|
||||||
|
|
||||||
|
nginx.virtualHost = mkOption {
|
||||||
|
description = mdDoc "VirtualHost to serve cgit on, defaults to the attribute name.";
|
||||||
|
type = types.str;
|
||||||
|
default = config._module.args.name;
|
||||||
|
example = "git.example.com";
|
||||||
|
};
|
||||||
|
|
||||||
|
nginx.location = mkOption {
|
||||||
|
description = mdDoc "Location to serve cgit under.";
|
||||||
|
type = types.str;
|
||||||
|
default = "/";
|
||||||
|
example = "/git/";
|
||||||
|
};
|
||||||
|
|
||||||
|
repos = mkOption {
|
||||||
|
description = mdDoc "cgit repository settings, see cgitrc(5)";
|
||||||
|
type = with types; attrsOf (attrsOf settingType);
|
||||||
|
default = {};
|
||||||
|
example = {
|
||||||
|
blah = {
|
||||||
|
path = "/var/lib/git/example";
|
||||||
|
desc = "An example repository";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
scanPath = mkOption {
|
||||||
|
description = mdDoc "A path which will be scanned for repositories.";
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
example = "/var/lib/git";
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = mkOption {
|
||||||
|
description = mdDoc "cgit configuration, see cgitrc(5)";
|
||||||
|
type = types.attrsOf settingType;
|
||||||
|
default = {};
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
enable-follow-links = true;
|
||||||
|
source-filter = "''${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
description = mdDoc "These lines go to the end of cgitrc verbatim.";
|
||||||
|
type = types.lines;
|
||||||
|
default = "";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (any (cfg: cfg.enable) (attrValues cfgs)) {
|
||||||
|
assertions = mapAttrsToList (vhost: cfg: {
|
||||||
|
assertion = !cfg.enable || (cfg.scanPath == null) != (cfg.repos == {});
|
||||||
|
message = "Exactly one of services.cgit.${vhost}.scanPath or services.cgit.${vhost}.repos must be set.";
|
||||||
|
}) cfgs;
|
||||||
|
|
||||||
|
services.fcgiwrap.enable = true;
|
||||||
|
|
||||||
|
services.nginx.enable = true;
|
||||||
|
|
||||||
|
services.nginx.virtualHosts = mkMerge (mapAttrsToList (_: cfg: {
|
||||||
|
${cfg.nginx.virtualHost} = {
|
||||||
|
locations = (
|
||||||
|
genAttrs'
|
||||||
|
[ "cgit.css" "cgit.png" "favicon.ico" "robots.txt" ]
|
||||||
|
(name: nameValuePair "= ${stripLocation cfg}/${name}" {
|
||||||
|
extraConfig = ''
|
||||||
|
alias ${pkgs.cgit}/cgit/${name};
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
) // {
|
||||||
|
"~ ${regexLocation cfg}/.+/(info/refs|git-upload-pack)" = {
|
||||||
|
fastcgiParams = rec {
|
||||||
|
SCRIPT_FILENAME = "${pkgs.git}/libexec/git-core/git-http-backend";
|
||||||
|
GIT_HTTP_EXPORT_ALL = "1";
|
||||||
|
GIT_PROJECT_ROOT = mkCgitReposDir cfg;
|
||||||
|
HOME = GIT_PROJECT_ROOT;
|
||||||
|
};
|
||||||
|
extraConfig = mkFastcgiPass cfg;
|
||||||
|
};
|
||||||
|
"${stripLocation cfg}/" = {
|
||||||
|
fastcgiParams = {
|
||||||
|
SCRIPT_FILENAME = "${pkgs.cgit}/cgit/cgit.cgi";
|
||||||
|
QUERY_STRING = "$args";
|
||||||
|
HTTP_HOST = "$server_name";
|
||||||
|
CGIT_CONFIG = mkCgitrc cfg;
|
||||||
|
};
|
||||||
|
extraConfig = mkFastcgiPass cfg;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) cfgs);
|
||||||
|
};
|
||||||
|
}
|
|
@ -124,6 +124,7 @@ in {
|
||||||
ceph-single-node-bluestore = handleTestOn ["x86_64-linux"] ./ceph-single-node-bluestore.nix {};
|
ceph-single-node-bluestore = handleTestOn ["x86_64-linux"] ./ceph-single-node-bluestore.nix {};
|
||||||
certmgr = handleTest ./certmgr.nix {};
|
certmgr = handleTest ./certmgr.nix {};
|
||||||
cfssl = handleTestOn ["aarch64-linux" "x86_64-linux"] ./cfssl.nix {};
|
cfssl = handleTestOn ["aarch64-linux" "x86_64-linux"] ./cfssl.nix {};
|
||||||
|
cgit = handleTest ./cgit.nix {};
|
||||||
charliecloud = handleTest ./charliecloud.nix {};
|
charliecloud = handleTest ./charliecloud.nix {};
|
||||||
chromium = (handleTestOn ["aarch64-linux" "x86_64-linux"] ./chromium.nix {}).stable or {};
|
chromium = (handleTestOn ["aarch64-linux" "x86_64-linux"] ./chromium.nix {}).stable or {};
|
||||||
cinnamon = handleTest ./cinnamon.nix {};
|
cinnamon = handleTest ./cinnamon.nix {};
|
||||||
|
|
59
nixos/tests/cgit.nix
Normal file
59
nixos/tests/cgit.nix
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import ./make-test-python.nix ({ pkgs, ...} : {
|
||||||
|
name = "cgit";
|
||||||
|
meta = with pkgs.lib.maintainers; {
|
||||||
|
maintainers = [ schnusch ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
server = { ... }: {
|
||||||
|
services.cgit."localhost" = {
|
||||||
|
enable = true;
|
||||||
|
nginx.location = "/(c)git/";
|
||||||
|
repos = {
|
||||||
|
some-repo = {
|
||||||
|
path = "/srv/git/some-repo";
|
||||||
|
desc = "some-repo description";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [ pkgs.git ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = { nodes, ... }: ''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
server.wait_for_unit("nginx.service")
|
||||||
|
server.wait_for_unit("network.target")
|
||||||
|
server.wait_for_open_port(80)
|
||||||
|
|
||||||
|
server.succeed("curl -fsS http://localhost/%28c%29git/robots.txt")
|
||||||
|
|
||||||
|
server.succeed(
|
||||||
|
"curl -fsS http://localhost/%28c%29git/ | grep -F 'some-repo description'"
|
||||||
|
)
|
||||||
|
|
||||||
|
server.fail("curl -fsS http://localhost/robots.txt")
|
||||||
|
|
||||||
|
server.succeed("${pkgs.writeShellScript "setup-cgit-test-repo" ''
|
||||||
|
set -e
|
||||||
|
git init --bare -b master /srv/git/some-repo
|
||||||
|
git init -b master reference
|
||||||
|
cd reference
|
||||||
|
git remote add origin /srv/git/some-repo
|
||||||
|
date > date.txt
|
||||||
|
git add date.txt
|
||||||
|
git -c user.name=test -c user.email=test@localhost commit -m 'add date'
|
||||||
|
git push -u origin master
|
||||||
|
''}")
|
||||||
|
|
||||||
|
server.succeed(
|
||||||
|
"curl -fsS 'http://localhost/%28c%29git/some-repo/plain/date.txt?id=master' | diff -u reference/date.txt -"
|
||||||
|
)
|
||||||
|
|
||||||
|
server.succeed(
|
||||||
|
"git clone http://localhost/%28c%29git/some-repo && diff -u reference/date.txt some-repo/date.txt"
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
})
|
Loading…
Reference in a new issue