commit de84c9b7304783a843ec84ee9ee4189e44a6727e
parent 327a377941dd4b3095f696e8e29001389613cc4b
Author: Leah (ctucx) <leah@ctu.cx>
Date: Fri, 27 May 2022 13:29:16 +0200
parent 327a377941dd4b3095f696e8e29001389613cc4b
Author: Leah (ctucx) <leah@ctu.cx>
Date: Fri, 27 May 2022 13:29:16 +0200
machines/osterei/git: use stagit to generate git-repo pages for my public git repos
4 files changed, 346 insertions(+), 89 deletions(-)
A
|
94
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M
|
91
++++---------------------------------------------------------------------------
A
|
246
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/machines/osterei/git/cgit.nix b/machines/osterei/git/cgit.nix @@ -0,0 +1,94 @@ +{ config, lib, pkgs, ... }: + +let + cgitAssets = ./cgit-assets; + cgitConfig = pkgs.writeText "cgitrc" (lib.generators.toKeyValue { } { + css = "/assets/cgit.css"; + logo = "/cgit.png"; + + virtual-root = "/"; + + root-title = "ctucx.cgit"; + root-desc = "my personal git repos"; + + local-time = 1; + cache-size = 30; + + about-filter = "${pkgs.cgit}/lib/cgit/filters/about-formatting.sh"; + source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; + + clone-url = (lib.concatStringsSep " " [ + "https://cgit.ctu.cx/$CGIT_REPO_URL" + "ssh://git@${config.networking.hostName}.${config.networking.domain}:$CGIT_REPO_URL" + ]); + + snapshots = (lib.concatStringsSep " " [ + "tar.gz" + "tar.bz2" + "zip" + ]); + + max-stats-quarter = "quarter"; + + enable-commit-graph = 1; + + enable-index-links = 1; + enable-index-owner = 0; + + enable-log-filecount = 1; + enable-log-linecount = 1; + + enable-blame = 1; + + enable-git-config = 1; + + remove-suffix = 1; + project-list = "/var/lib/gitolite/projects.list"; + scan-path = "/var/lib/gitolite/repositories"; + }); + +in { + + services = { + + fcgiwrap = { + enable = true; + user = "git"; + group = "git"; + }; + + nginx = { + enable = true; + virtualHosts."cgit.ctu.cx" = { + enableACME = true; + forceSSL = true; + locations = { + "/".tryFiles = "$uri @cgit"; + "/assets/".alias = "${cgitAssets}/"; + "~ '^/[a-zA-Z0-9._-]+/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$'".extraConfig = '' + if ($query_string = service=git-receive-pack) { + return 403; + } + + include "${pkgs.nginx}/conf/fastcgi_params"; + fastcgi_param SCRIPT_FILENAME "${pkgs.git}/libexec/git-core/git-http-backend"; + fastcgi_param GIT_PROJECT_ROOT /var/lib/gitolite/repositories; + fastcgi_param PATH_INFO $uri; + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + ''; + "@cgit".extraConfig = '' + include "${pkgs.nginx}/conf/fastcgi_params"; + fastcgi_param CGIT_CONFIG "${cgitConfig}"; + fastcgi_param SCRIPT_FILENAME "${pkgs.cgit}/cgit/cgit.cgi"; + fastcgi_param PATH_INFO $uri; + fastcgi_param QUERY_STRING $args; + fastcgi_param HTTP_HOST $server_name; + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + ''; + }; + }; + }; + + }; + +}
diff --git a/machines/osterei/git/default.nix b/machines/osterei/git/default.nix @@ -1,57 +1,13 @@ { config, lib, pkgs, ... }: -let - cgitAssets = ./cgit-assets; - cgitConfig = pkgs.writeText "cgitrc" (lib.generators.toKeyValue { } { - css = "/assets/cgit.css"; - logo = "/cgit.png"; - - virtual-root = "/"; - - root-title = "ctucx.cgit"; - root-desc = "my personal git repos"; - - local-time = 1; - cache-size = 30; - - about-filter = "${pkgs.cgit}/lib/cgit/filters/about-formatting.sh"; - source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; - - clone-url = (lib.concatStringsSep " " [ - "https://cgit.ctu.cx/$CGIT_REPO_URL" - "ssh://git@${config.networking.hostName}.${config.networking.domain}:$CGIT_REPO_URL" - ]); - - snapshots = (lib.concatStringsSep " " [ - "tar.gz" - "tar.bz2" - "zip" - ]); - - max-stats-quarter = "quarter"; - - enable-commit-graph = 1; - - enable-index-links = 1; - enable-index-owner = 0; - - enable-log-filecount = 1; - enable-log-linecount = 1; - - enable-blame = 1; - - enable-git-config = 1; - - remove-suffix = 1; - project-list = "/var/lib/gitolite/projects.list"; - scan-path = "/var/lib/gitolite/repositories"; - }); - -in { +{ imports = [ +# ./cgit.nix + ./stagit.nix ./options.nix ]; + age.secrets.restic-gitolite.file = ../../../secrets/osterei/restic/gitolite.age; restic-backups.gitolite = { @@ -72,45 +28,6 @@ in { push( @{$RC{ENABLE}}, 'cgit' ); ''; }; - - fcgiwrap = { - enable = true; - user = "git"; - group = "git"; - }; - - nginx = { - enable = true; - virtualHosts."cgit.ctu.cx" = { - enableACME = true; - forceSSL = true; - locations = { - "/".tryFiles = "$uri @cgit"; - "/assets/".alias = "${cgitAssets}/"; - "~ '^/[a-zA-Z0-9._-]+/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$'".extraConfig = '' - if ($query_string = service=git-receive-pack) { - return 403; - } - - include "${pkgs.nginx}/conf/fastcgi_params"; - fastcgi_param SCRIPT_FILENAME "${pkgs.git}/libexec/git-core/git-http-backend"; - fastcgi_param GIT_PROJECT_ROOT /var/lib/gitolite/repositories; - fastcgi_param PATH_INFO $uri; - fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; - ''; - "@cgit".extraConfig = '' - include "${pkgs.nginx}/conf/fastcgi_params"; - fastcgi_param CGIT_CONFIG "${cgitConfig}"; - fastcgi_param SCRIPT_FILENAME "${pkgs.cgit}/cgit/cgit.cgi"; - fastcgi_param PATH_INFO $uri; - fastcgi_param QUERY_STRING $args; - fastcgi_param HTTP_HOST $server_name; - fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; - ''; - }; - }; - }; - }; }
diff --git a/machines/osterei/git/stagit.nix b/machines/osterei/git/stagit.nix @@ -0,0 +1,246 @@ +{ config, lib, pkgs, ... }: + +let + stagit = pkgs.callPackage ../../../pkgs/stagit.nix {}; + + rebuildScript = pkgs.writeShellScript "init-stagit" '' + systemctl start init-stagit; + systemctl status init-stagit; + ''; + + stagitFunctions = '' + export LC_CTYPE="en_US.UTF-8" + + is_public_and_listed() { + if [ ! -f "$1/git-daemon-export-ok" ]; then + return 1 + fi + return 0 + } + + make_stagit_index() { + printf "Generating stagit index... " + + # generate index arguments + args="-n 'ctucx.git' -e 'git@ctu.cx'" + + for category in "etc" "nimlang" "nimlang libraries" "php" "archive"; do + args="$args -c '$category'" + for repo in "$HOME/repositories/"*.git/; do + repo="''${repo%/}" + is_public_and_listed "$repo" || continue + [[ "$repo" == "/var/lib/gitolite/repositories/bikemap.git" ]] && continue + + [ "$(${pkgs.gawk}/bin/awk -F '=' '/category/ {print $2}' $repo/config | ${pkgs.gnused}/bin/sed -e 's/^[[:space:]]*//')" = "$category" ] && args="$args $repo" + done + done + + # make index + echo "$args" | xargs ${stagit}/bin/stagit-index > /var/lib/stagit/index.html + + # set correct permissions + chmod 755 /var/lib/stagit/index.html; + chown git:git /var/lib/stagit/index.html; + + echo "done" + } + ''; + +in { + + security.sudo.extraRules = [{ + users = [ "git" ]; + commands = [ + { command = "${rebuildScript}"; options = [ "SETENV" "NOPASSWD" ]; } + ]; + }]; + + systemd = { + services.init-stagit = { + script = '' + ${stagitFunctions} + + make_repo_web() { + reponame="$(basename "$1" ".git")" + printf "[%s] stagit HTML pages... " "$reponame" + + mkdir -p "/var/lib/stagit/$reponame" + cd "/var/lib/stagit/$reponame" || return 1 + + # make pages + ${stagit}/bin/stagit -c '.stagit-build-cache' -n 'ctucx.git' -h 'https://git.ctu.cx/' -s 'git@${config.networking.hostName}.ctu.cx:' "$1" + + echo "done" + } + + # clean webdir + rm -rf /var/lib/stagit/* + + # set assets if not already there + ln -s "${stagit}/share/doc/stagit/style.css" "/var/lib/stagit/style.css" 2> /dev/null + + # make files per repo + for repo in "$HOME/repositories/"*.git/; do + repo="''${repo%/}" + is_public_and_listed "$repo" || continue + + make_repo_web "$repo" + done + + make_stagit_index + ''; + + serviceConfig = { + Type = "oneshot"; + + User = "git"; + Group = "git"; + + WorkingDirectory = "~"; + StateDirectory = "stagit"; + StateDirectoryMode = "755"; + + NoNewPrivileges = true; + PrivateTmp = true; + PrivateDevices = true; + + RestrictAddressFamilies = "AF_INET AF_INET6"; + RestrictNamespaces = true; + RestrictRealtime = true; + + ProtectSystem = "full"; + ProtectControlGroups = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + + DevicePolicy = "closed"; + LockPersonality = true; + }; + }; + }; + + services = { + gitolite.hooks.postReceive = '' + ${stagitFunctions} + + is_forced_update() { + test "$oldrev" = "0000000000000000000000000000000000000000" && return 1 + test "$newrev" = "0000000000000000000000000000000000000000" && return 1 + + hasrevs="$(${pkgs.git}/bin/git rev-list "$oldrev" "^$newrev" | ${pkgs.gnused}/bin/sed 1q)" + if test -n "$hasrevs"; then + return 0 + fi + return 1 + } + + make_repo_web() { + reponame="$(basename "$1" ".git")" + printf "[%s] stagit HTML pages... " "$reponame" + + # if forced update, remove directory and cache file + is_forced_update && printf "forced update... " && rm -rf "/var/lib/stagit/$reponame" + + mkdir -p "/var/lib/stagit/$reponame" + cd "/var/lib/stagit/$reponame" || return 1 + + # make pages + ${stagit}/bin/stagit -c '.stagit-build-cache' -n 'ctucx.git' -h 'https://git.ctu.cx/' -s 'git@${config.networking.hostName}.ctu.cx:' "$1" + + # set correct permissions + chmod 755 -R /var/lib/stagit/$reponame; + chown git:git -R /var/lib/stagit/$reponame; + + echo "done" + } + + update_stagit_repo() { + repo="$(pwd)" + + cd "$repo" || return 1 + is_public_and_listed "$repo" || return 0 + + make_repo_web "$repo" + make_stagit_index + } + + update_stagit_repo "$1" + + #rebuild stagit + [ "$GL_REPO" == "gitolite-admin" ] && sudo ${rebuildScript} + ''; + + fcgiwrap = { + enable = true; + user = "git"; + group = "git"; + }; + + nginx = { + enable = true; + virtualHosts = { + "cgit.ctu.cx" = { + enableACME = true; + forceSSL = true; + locations = { + "~ '^/[a-zA-Z0-9._-]+/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$'".return = "307 https://git.ctu.cx$request_uri"; + "~ '^/([a-zA-Z0-9_.]+)/*$'".return = "307 https://git.ctu.cx/$1"; + "~ '^/([a-zA-Z0-9_.]+)/tree/([a-zA-Z0-9_./-]+[a-zA-Z0-9_-])/*$'".return = "307 https://git.ctu.cx/$1/tree/$2.html"; + "~ '^/([a-zA-Z0-9_.]+)/tree/*$'".return = "307 https://git.ctu.cx/$1/tree.html"; + "~ '^/([a-zA-Z0-9_.]+)/log/*$'".return = "307 https://git.ctu.cx/$1/log.html"; + "~ '^/([a-zA-Z0-9_.]+)/commit/*$'".extraConfig = '' + if ($arg_id) { + return 307 https://git.ctu.cx/$1/commit/$arg_id.html; + } + + return 307 https://git.ctu.cx/$1/log.html; + ''; + }; + }; + + "git.ctu.cx" = { + enableACME = true; + forceSSL = true; + root = "/var/lib/stagit"; + locations = { + "~ '^/[a-zA-Z0-9._-]+/raw'".extraConfig = '' + types { + application/json json; + + application/wasm wasm; + font/woff woff; + font/woff2 woff2; + + application/pdf pdf; + + image/gif gif; + image/jpeg jpeg jpg; + image/png png; + image/svg+xml svg svgz; + image/webp webp; + image/x-icon ico; + } + + default_type text/plain; + try_files $uri =404; + ''; + + "~ '^/[a-zA-Z0-9._-]+/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$'".extraConfig = '' + if ($query_string = service=git-receive-pack) { + return 403; + } + + include "${pkgs.nginx}/conf/fastcgi_params"; + fastcgi_param SCRIPT_FILENAME "${pkgs.git}/libexec/git-core/git-http-backend"; + fastcgi_param GIT_PROJECT_ROOT /var/lib/gitolite/repositories; + fastcgi_param PATH_INFO $uri; + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + ''; + }; + }; + }; + }; + + }; + +}
diff --git a/pkgs/stagit.nix b/pkgs/stagit.nix @@ -5,8 +5,8 @@ stdenv.mkDerivation rec { src = fetchgit { url = "https://cgit.ctu.cx/stagit"; - rev = "932edf13bf1bf92c98a6c916c96858fa7080ca8b"; - sha256 = "12ljxlcj8flfffvd6cf0md2ii7ap37xzxk7dyyh9xakilzppl2ja"; + rev = "015f2404ed670cab591b04a6a7a190662f1bce6e"; + sha256 = "0jvidgqrkhd8nxasjiy01aqqr6p1lzr3vh0767dxaycwr14wq973"; }; makeFlags = [ "PREFIX=$(out)" ];