ctucx.git: nixfiles

ctucx' nixfiles

commit de84c9b7304783a843ec84ee9ee4189e44a6727e
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
machines/osterei/git/cgit.nix
|
94
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M
machines/osterei/git/default.nix
|
91
++++---------------------------------------------------------------------------
A
machines/osterei/git/stagit.nix
|
246
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M
pkgs/stagit.nix
|
4
++--
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)" ];